Youtube Player MCP
Un servidor MCP y servicio de reproducción multimedia que permite a un asistente de IA reproducir música en un altavoz real. Pídele a tu asistente que "ponga algo de lo-fi", "añada las siguientes tres pistas de ese álbum a la cola" o "agregue esta canción a mi lista de reproducción de entrenamiento", y el audio se reproducirá desde la máquina que ejecuta el servicio, incluso a través de Bluetooth.
Documentación
yt-player
Un servidor MCP y servicio de reproducción multimedia que permite a un asistente de IA reproducir música en un altavoz real. Pídele a tu asistente que "ponga algo de lo-fi", "añada las siguientes tres pistas de ese álbum a la cola" o "agregue esta canción a mi lista de reproducción de entrenamiento", y el audio se reproducirá desde la máquina que ejecuta el servicio, incluso a través de Bluetooth.
Tiene dos partes, ambas iniciadas por el comando yt-player:
- Servicio de reproducción (
yt-player serve): una aplicación FastAPI que transmite audio con yt-dlp y ffplay. Gestiona una cola, listas de reproducción e historial de reproducción, y los almacena en SQLite. También sirve una API REST y un flujo de eventos WebSocket, para que otros clientes también puedan usarlo. - Servidor MCP (
yt-player mcp, oyt-player-mcp): una capa MCP ligera sobre la API HTTP del servicio. Admite transportes stdio, HTTP transmisible y SSE.
El servidor MCP es una instalación ligera que solo depende de mcp y httpx. Puede ejecutarse en una máquina diferente al servicio de reproducción.
YouTube es la primera fuente compatible. Los modelos de API son neutrales respecto a la fuente: los clientes trabajan con pistas, estado de reproducción, colas, listas de reproducción y comandos de reproducción.
Requisitos
El servicio de reproducción reproduce audio en la máquina donde se ejecuta.
| Plataforma | Cómo ejecutar el servicio de reproducción | Audio |
|---|---|---|
| Linux | Docker Compose (recomendado) o yt-player serve | PulseAudio, PipeWire, ALSA o JACK |
| macOS | yt-player serve (no Docker) | CoreAudio |
| Windows | No compatible; usa WSL o una máquina Linux |
Para ejecutarlo sin Docker necesitas Python 3.10+, ffmpeg (que proporciona ffplay) y un runtime de JavaScript. Pueden estar en el PATH, o puedes indicar sus ubicaciones con FFPLAY_PATH y JS_RUNTIME. YouTube requiere que yt-dlp resuelva un desafío de JavaScript. Cualquiera de estos runtimes funciona:
| Runtime | Versión mínima | JS_RUNTIME |
|---|---|---|
| Deno (predeterminado, recomendado) | 2.3.0 | deno |
| Node.js | 22.0.0 | node |
| Bun | 1.2.11 | bun |
| QuickJS | 2023-12-09 | quickjs |
Herramientas opcionales:
pactlcambia el volumen de una pista en reproducción sin interrumpirla. Sin ella, un cambio de volumen reinicia la transmisión en la posición actual, lo que causa una breve pausa.bluetoothctl(BlueZ, solo Linux) permite que el servicio conecte un altavoz Bluetooth por sí mismo.
Docker Desktop en macOS y Windows no puede pasar el audio del host a los contenedores, así que usa Docker solo en Linux. Cualquier máquina puede ejecutar el servidor MCP y controlar un servicio de reproducción que se ejecute en otro lugar (consulta Controlar un reproductor remoto).
El servidor MCP necesita Python 3.10+ y acceso de red al servicio de reproducción.
Inicio rápido
-
Clona el repositorio y crea tu archivo de configuración:
git clone https://github.com/karunstha/yt-player.git cd yt-player cp .env.example .env mkdir -p dataCrea
data/tú mismo para que sea tuyo. Si Docker lo crea, pertenece a root. -
Edita
.env. Por defecto, el contenedor reproduce a través de tu socket de PulseAudio o PipeWire.PULSE_RUNTIME_DIRdebe apuntar a/run/user/<UID>/pulse; ejecutaid -upara encontrar tu UID. Para elegir un altavoz o usar ALSA en su lugar, consulta Salida de audio. -
Opcional pero recomendado: agrega cookies de YouTube, lo que reduce la probabilidad de que YouTube bloquee las solicitudes como bot. Exporta tus cookies en formato Netscape (por ejemplo, con una extensión de navegador "cookies.txt") y guárdalas como
data/cookies.txt. El servicio funciona sin ellas. -
Inicia el servicio de reproducción:
docker compose up -d -
Verifica que responde:
curl http://127.0.0.1:5454/player/state -
Conecta un cliente MCP usando una de las opciones a continuación.
Ejecutar sin Docker
En Linux o macOS, con las herramientas del sistema listadas en Requisitos:
pip install "yt-player[server] @ git+https://github.com/karunstha/yt-player"
yt-player serve
Sin Docker, el servicio se vincula a 127.0.0.1:5454, almacena datos en ~/.local/share/yt-player y reproduce a través de la salida de audio predeterminada del sistema. Usa --host/--port o las variables de configuración para cambiar eso, ya sea en el entorno o en un archivo .env en el directorio desde el que lo inicias. En macOS, instala primero las herramientas del sistema con brew install ffmpeg deno. Si ya tienes Node.js 22+, puedes omitir Deno y configurar JS_RUNTIME=node.
Al iniciar, el servicio imprime la configuración que está usando y advierte sobre cualquier cosa que detendría la reproducción, como la falta de ffplay o un runtime de JavaScript. Los servicios iniciados por launchd o systemd obtienen un PATH mínimo que generalmente excluye Homebrew y nvm. En ese caso, configura FFPLAY_PATH y JS_RUNTIME con rutas completas, por ejemplo FFPLAY_PATH=/opt/homebrew/bin/ffplay.
Salida de audio
Por defecto, el audio va al dispositivo de salida predeterminado del sistema. Dos configuraciones cambian eso, en .env o en el entorno:
AUDIO_DRIVERelige el sistema de sonido:pulseaudio,pipewire,alsa,jackocoreaudio. Si no se configura, se elige automáticamente el más adecuado. Docker Compose configurapulseaudio.AUDIO_DEVICEelige el dispositivo de salida en ese sistema de sonido.
| Sistema de sonido | AUDIO_DRIVER | AUDIO_DEVICE | Listar dispositivos con |
|---|---|---|---|
| PulseAudio | pulseaudio | Nombre del sink, p. ej. alsa_output.usb-DAC-00.analog-stereo | pactl list short sinks |
| PipeWire | pulseaudio (a través de pipewire-pulse) | Nombre del sink, como arriba | pactl list short sinks |
| ALSA | alsa | Dispositivo, p. ej. plughw:1,0 | aplay -l |
| JACK, CoreAudio, PipeWire nativo | como se nombre | No compatible; usa el predeterminado del sistema |
Altavoces Bluetooth. DEFAULT_BLUETOOTH_DEVICE_ID solo conecta el altavoz, antes del inicio y antes de cada pista. Para asegurarte de que el audio realmente vaya a él, también configura AUDIO_DEVICE con su sink, por ejemplo bluez_output.AA_BB_CC_DD_EE_FF.1 en PipeWire o bluez_sink.AA_BB_CC_DD_EE_FF.a2dp_sink en PulseAudio. El nombre exacto aparece en pactl list short sinks mientras el altavoz está conectado.
ALSA en Docker. En hosts sin PulseAudio o PipeWire, configura esto en .env:
AUDIO_DRIVER=alsa
AUDIO_DEVICE=plughw:1,0
ALSA necesita acceso exclusivo a la tarjeta de sonido, por lo que la reproducción falla con "device busy" si un servidor de sonido en el host ya usa esa tarjeta. Compose aún monta PULSE_RUNTIME_DIR, así que en un host sin PulseAudio, Docker crea un directorio /run/user/<UID>/pulse vacío. Es seguro ignorarlo.
Los errores de audio de ffplay aparecen en el registro del servicio (docker compose logs yt-player). Audio target '<name>' not available significa que ffplay se compiló sin ese sistema de sonido; elige otro AUDIO_DRIVER o déjalo vacío.
Conectar un cliente MCP
Opción A: stdio (recomendado para clientes de escritorio)
Tu cliente MCP inicia el servidor como un proceso local. La forma más sencilla es uv, que lo instala en la primera ejecución sin un paso de configuración adicional.
Claude Code:
claude mcp add yt-player \
-e MEDIA_SERVICE_URL=http://127.0.0.1:5454 \
-- uvx --from git+https://github.com/karunstha/yt-player yt-player-mcp
Claude Desktop, Cursor y otros clientes configurados con JSON:
{
"mcpServers": {
"yt-player": {
"command": "uvx",
"args": ["--from", "git+https://github.com/karunstha/yt-player", "yt-player-mcp"],
"env": {
"MEDIA_SERVICE_URL": "http://127.0.0.1:5454"
}
}
}
}
Sin uv, instala el paquete y apunta tu cliente al comando yt-player-mcp:
pipx install git+https://github.com/karunstha/yt-player
Si tu cliente puede ejecutar comandos de Docker, puedes usar la imagen que ya construiste:
docker run --rm -i --network host \
-e MEDIA_SERVICE_URL=http://127.0.0.1:5454 \
yt-player yt-player mcp
Opción B: HTTP transmisible (de larga duración, Dockerizado)
Inicia el servidor MCP junto con el servicio de reproducción usando el perfil opcional de Compose:
docker compose --profile mcp up -d
El servidor entonces escucha en:
http://127.0.0.1:5455/mcp
Para Claude Code:
claude mcp add --transport http yt-player http://127.0.0.1:5455/mcp
Fuera de Docker, el mismo servidor se ejecuta con yt-player mcp --transport streamable-http.
Controlar un reproductor remoto
El servidor MCP solo hace llamadas HTTP al servicio de reproducción, por lo que puede ejecutarse en una máquina diferente al altavoz. Por ejemplo, el servicio de reproducción puede ejecutarse en un mini PC Linux conectado a tus altavoces mientras tu asistente se ejecuta en una laptop. Apunta MEDIA_SERVICE_URL al reproductor:
MEDIA_SERVICE_URL=http://media-box.local:5454
Lee Seguridad antes de exponer cualquiera de los puertos en una red.
Herramientas MCP
| Área | Herramientas |
|---|---|
| Estado | health, get_playback_state, get_current_track |
| Búsqueda | search_media |
| Reproducción | play_media, pause_playback, resume_playback, stop_playback, seek_playback, next_track, previous_track, set_volume, set_shuffle, set_repeat |
| Historial | get_playback_history (paginado con next_before) |
| Cola | get_queue, append_queue_track, insert_queue_track_next, queue_playlist, remove_queue_item, clear_queue, replace_queue_with_playlist |
| Listas de reproducción | list_playlists, get_playlist, create_playlist, rename_playlist, delete_playlist, add_track_to_playlist, add_tracks_to_playlist, add_current_track_to_playlist, move_playlist_track, remove_track_from_playlist, clear_playlist, play_playlist |
| Guardar la cola | save_queue_as_playlist, add_queue_to_playlist |
| Importar/exportar | export_playlists, import_playlists |
Las herramientas que toman una pista (play_media, append_queue_track, insert_queue_track_next, add_track_to_playlist) aceptan ya sea una query de búsqueda o un url.
Las búsquedas y consultas toman un search_type opcional que define qué buscar:
search_type | Busca | Ejemplo |
|---|---|---|
songs (predeterminado) | Canciones de YouTube Music | "reproduce Bohemian Rhapsody" |
music_videos | Videos de YouTube Music | "reproduce el video oficial de…" |
podcasts | Episodios de podcasts de YouTube Music | "reproduce el episodio de Lex Fridman con Sam Altman" |
videos | Todo YouTube | tutoriales, charlas, transmisiones en vivo |
Cambia el valor predeterminado con DEFAULT_SEARCH_TYPE. add_tracks_to_playlist toma una lista donde cada entrada es una URL o una consulta de búsqueda.
Una lista de reproducción guarda cada pista una sola vez. Agregar una pista que ya está allí falla con un mensaje que lo indica. Las adiciones por lotes (add_tracks_to_playlist, save_queue_as_playlist, add_queue_to_playlist) omiten duplicados y los listan en el resultado como skipped. Las pistas que no se pudieron encontrar se listan como failed. Las listas de reproducción se pueden referenciar por ID, nombre o un slug del nombre.
Solución de problemas
- El servicio se inicia con advertencias. Corrige lo que nombran: instala la herramienta faltante o apunta
FFPLAY_PATHoJS_RUNTIMEhacia ella. - El estado de reproducción muestra
error, o no se reproduce nada. Revisa el registro del servicio (docker compose logs yt-player, o la terminal que ejecutayt-player serve). Los errores de yt-dlp y ffplay aparecen allí. Para problemas de audio, consulta Salida de audio. - YouTube dice "Sign in to confirm you're not a bot". Agrega cookies como
cookies.txten el directorio de datos (consulta Inicio rápido). - El asistente informa "Could not reach the media service". El servicio de reproducción no está en ejecución, o
MEDIA_SERVICE_URLen la configuración de tu cliente MCP apunta al host o puerto incorrecto.
Seguridad
Ni el servicio de reproducción ni el servidor MCP tienen autenticación.
- Bajo Docker Compose, el servicio de reproducción se vincula a
0.0.0.0:5454con red de host, así que cualquiera en tu red puede controlar la reproducción. ConfiguraSERVICE_HOST=127.0.0.1en.envsi solo esta máquina necesita acceso. De lo contrario, ejecútalo solo en una red confiable, o colócalo detrás de un firewall o un proxy inverso con autenticación. Fuera de Docker,yt-player servese vincula a127.0.0.1por defecto. - El transporte HTTP de MCP se vincula a
127.0.0.1por defecto. ManténMCP_HOST=127.0.0.1a menos que quieras intencionalmente que otras máquinas controlen la reproducción. Si lo vinculas a0.0.0.0, protege el puerto de la misma manera. - El contenedor de reproducción se ejecuta con
privileged: truey monta el estado de D-Bus y Bluetooth del host para poder gestionar dispositivos Bluetooth. Elimina esas configuraciones si no necesitas Bluetooth. cookies.txtcontiene tu sesión de YouTube. El directoriodata/y.envestán listados en.gitignore; nunca los confirmes en el repositorio.
Configuración
Ambas partes leen variables de entorno. yt-player serve también carga un archivo .env desde el directorio en el que se inicia. El servidor MCP no lee .env; configura sus variables en la configuración de tu cliente MCP, como en los ejemplos anteriores.
Los valores vacíos (como SERVICE_PORT=) usan el predeterminado. Los valores inválidos detienen el inicio con un mensaje que nombra la configuración.
Docker Compose (configurado en .env, consulta .env.example):
PULSE_RUNTIME_DIR: directorio PulseAudio del host montado en el contenedor. Por defecto es/run/user/1000/pulse.DATA_PATH: directorio del host montado en/data. Por defecto es./data.SERVICE_HOST,SERVICE_PORT,AUDIO_DRIVER,AUDIO_DEVICE,DEFAULT_BLUETOOTH_DEVICE_ID,DEFAULT_VOLUME,DEFAULT_SEARCH_TYPE,MCP_HOST,MCP_PORT: se pasan a los contenedores (ver más abajo). Con Compose,SERVICE_HOSTpor defecto es0.0.0.0yAUDIO_DRIVERespulseaudio.
Servicio de reproducción:
SERVICE_HOST: host de enlace. Por defecto es127.0.0.1.SERVICE_PORT: puerto de enlace. Por defecto es5454.DATA_DIR: directorio para datos persistentes del servicio. Por defecto es$XDG_DATA_HOME/yt-player(normalmente~/.local/share/yt-player); la imagen Docker usa/data.DATABASE_PATH: ruta de la base de datos SQLite. Por defecto es$DATA_DIR/media_service.sqlite3.COOKIES_FILE: archivo de cookies en formato Netscape pasado a yt-dlp, usado solo si existe. Por defecto es$DATA_DIR/cookies.txt.AUDIO_DRIVER: sistema de sonido usado para la reproducción. Vacío elige uno automáticamente. Ver Salida de audio.AUDIO_DEVICE: dispositivo de salida en ese sistema de sonido. Vacío usa el predeterminado del sistema.DEFAULT_BLUETOOTH_DEVICE_ID: dirección MAC opcional de un dispositivo Bluetooth para conectar al inicio y antes de la reproducción.DEFAULT_VOLUME: volumen inicial de0.0a1.0. Por defecto es0.8.FFPLAY_PATH: el ejecutableffplay. Por defecto esffplayen el PATH.DEFAULT_SEARCH_TYPE: qué buscan las búsquedas cuando una solicitud no lo especifica:songs,music_videos,podcastsovideos. Por defecto essongs.JS_RUNTIME: runtime de JavaScript que usa yt-dlp para el desafío de YouTube:deno,node,bunoquickjs. Añade una ruta comonode:/usr/local/bin/nodesi no está en el PATH. Proporciona varios, separados por comas, para recurrir en el orden de prioridad de yt-dlp (deno, node, quickjs, bun). Por defecto esdeno. La imagen Docker incluye solo Deno.YTDLP_REMOTE_COMPONENTS: qué puede descargar yt-dlp si el solucionador de desafíos incluido (yt-dlp-ejs) falta o no coincide con la versión instalada de yt-dlp:ejs:github,ejs:npmonone. Por defecto esejs:github. Normalmente no se descarga nada, porque el extraserverinstala el solucionador correspondiente.PLAYBACK_COMPLETION_GRACE_SECONDS: las salidas fallidas del backend dentro de estos segundos tras el final de la pista se tratan como completadas. Por defecto es5.PLAYBACK_RECOVERY_RETRIES: reinicios automáticos de stream por pista después de una salida no limpia del backend. Por defecto es2.
Servidor MCP:
MEDIA_SERVICE_URL: URL base del servicio de reproducción. Por defecto eshttp://127.0.0.1:5454.MEDIA_SERVICE_TIMEOUT_SECONDS: tiempo de espera HTTP para llamadas al servicio de reproducción. Por defecto es30.MCP_TRANSPORT:stdio,streamable-httposse. Por defecto esstdio.MCP_HOST: host de enlace para transportes HTTP. Por defecto es127.0.0.1.MCP_PORT: puerto de enlace para transportes HTTP. Por defecto es5455.MCP_STREAMABLE_HTTP_PATH: ruta HTTP transmisible. Por defecto es/mcp.MCP_SSE_PATH: ruta de eventos SSE. Por defecto es/sse.MCP_MESSAGE_PATH: ruta de mensajes SSE. Por defecto es/messages/.
Docker Compose monta DATA_PATH (por defecto ./data) en /data, para que las listas de reproducción, los metadatos de pistas guardados, el historial de reproducción y las cookies sobrevivan al reemplazo del contenedor.
API HTTP
El servidor MCP es un cliente de esta API. También puedes llamarla directamente o construir tu propia interfaz sobre ella.
Reproducción:
POST /player/playcon uno deurl,queryotrackGET /player/stateGET /player/currentPOST /player/pausePOST /player/resumePOST /player/stopPOST /player/seekPOST /player/nextPOST /player/previousPOST /player/volumePOST /player/shufflePOST /player/repeatGET /player/history?days=7&before=<iso-date-time>&limit=100
Búsqueda:
GET /search?q=...&count=10&type=songs:typeessongs,music_videos,podcastsovideos- Las solicitudes que toman un
query(elementos/player/play,/queue,/queue/tracks,/playlists/{id}/tracksybulk) también aceptansearch_type
Cola:
GET /queuePOST /queueDELETE /queuePOST /queue/tracksPOST /queue/tracks/nextPOST /queue/playlists/{id}conplay_nextyshuffleopcionales: añade las pistas de una lista de reproducción sin reemplazar la colaDELETE /queue/items/{item_id}
Listas de reproducción:
POST /playlistsGET /playlistsGET /playlists/{id}PATCH /playlists/{id}DELETE /playlists/{id}POST /playlists/{id}/tracksPOST /playlists/{id}/tracks/bulkconitems(hasta 50 pistas): devuelveadded,skippedyfailedPOST /playlists/{id}/tracks/queue: añade la cola actual, devuelve la misma forma quebulkPOST /playlists/{id}/tracks/currentDELETE /playlists/{id}/tracks/{track_id}POST /playlists/{id}/tracks/{track_id}/movecon unpositionbasado en 0POST /playlists/{id}/tracks/reorderDELETE /playlists/{id}/tracksPOST /playlists/{id}/playPOST /playlists/{id}/shuffleGET /playlists/exportGET /playlists/{id}/exportPOST /playlists/import
Eventos en tiempo real:
WS /events
El WebSocket envía playback.sync al conectar y luego transmite eventos significativos como track.changed, playback.state_changed, playback.seeked, queue.changed, playlist.changed y track.completed. Durante la reproducción, emite actualizaciones de playback.sync de baja frecuencia aproximadamente cada 3 segundos.
API heredada
Los endpoints originales siguen disponibles:
POST /playPOST /stopGET /statusPOST /searchPOST /play-searchPOST /shuffle
Estructura del proyecto
yt_player/cli.py: el comandoyt-playery sus modosserveymcp.yt_player/factory.py: creación de la app FastAPI, manejo del ciclo de vida, conexión de servicios y manejadores de errores.yt_player/env.py: análisis de variables de entorno compartido entre el servicio y el servidor MCP.yt_player/core/: configuración del servicio, opciones de yt-dlp (ytdlp.py), errores estructurados del servicio y utilidades compartidas.yt_player/player/: rutas de reproducción, rutas de cola, rutas de reproducción heredadas, controlador de reproducción, servicio de cola, backend ffplay/yt-dlp y modelos de reproductor/cola.yt_player/playlists/: rutas de listas de reproducción, servicio persistente de listas, repositorio SQLite y modelos de listas.yt_player/sources/: integraciones de fuentes de medios. YouTube está implementado actualmente enyt_player/sources/youtube.py.yt_player/events/: ruta WebSocket, transmisor de eventos y modelos de eventos.yt_player/mcp/: servidor MCP y envoltorio del cliente HTTP para la API del servicio de medios.main.py: punto de entrada ASGI para ejecutar la app directamente con Uvicorn (uvicorn main:app).
Desarrollo
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest