Youtube Player MCP
Um servidor MCP e serviço de reprodução de mídia que permite que um assistente de IA toque música em um alto-falante real. Peça ao seu assistente para "tocar um pouco de lo-fi", "colocar na fila as próximas três faixas daquele álbum" ou "adicionar essa música à minha playlist de treino", e o áudio toca na máquina que executa o serviço, inclusive via Bluetooth.
Documentação
yt-player
Um servidor MCP e serviço de reprodução de mídia que permite a um assistente de IA tocar música em um alto-falante real. Peça ao seu assistente para "tocar um lo-fi", "colocar na fila as próximas três faixas daquele álbum" ou "adicionar esta música à minha playlist de treino", e o áudio toca na máquina que executa o serviço, inclusive via Bluetooth.
Ele tem duas partes, ambas iniciadas pelo comando yt-player:
- Serviço de reprodução (
yt-player serve): um aplicativo FastAPI que transmite áudio com yt-dlp e ffplay. Ele gerencia uma fila, playlists e histórico de reprodução, e os armazena em SQLite. Ele também serve uma API REST e um fluxo de eventos WebSocket, para que outros clientes também possam usá-lo. - Servidor MCP (
yt-player mcp, ouyt-player-mcp): uma camada MCP leve sobre a API HTTP do serviço. Ele suporta transportes stdio, HTTP streamable e SSE.
O servidor MCP é uma instalação leve que depende apenas de mcp e httpx. Ele pode ser executado em uma máquina diferente do serviço de reprodução.
YouTube é a primeira fonte suportada. Os modelos de API são neutros em relação à fonte: os clientes trabalham com faixas, estado de reprodução, filas, playlists e comandos de reprodução.
Requisitos
O serviço de reprodução toca áudio na máquina em que é executado.
| Plataforma | Como executar o serviço de reprodução | Áudio |
|---|---|---|
| Linux | Docker Compose (recomendado) ou yt-player serve | PulseAudio, PipeWire, ALSA ou JACK |
| macOS | yt-player serve (não Docker) | CoreAudio |
| Windows | Não suportado; use WSL ou uma máquina Linux |
Para executá-lo sem Docker, você precisa de Python 3.10+, ffmpeg (que fornece ffplay) e um runtime JavaScript. Eles podem estar no PATH, ou você pode informar suas localizações com FFPLAY_PATH e JS_RUNTIME. O YouTube exige que o yt-dlp resolva um desafio JavaScript. Qualquer um desses runtimes funciona:
| Runtime | Versão mínima | JS_RUNTIME |
|---|---|---|
| Deno (padrão, recomendado) | 2.3.0 | deno |
| Node.js | 22.0.0 | node |
| Bun | 1.2.11 | bun |
| QuickJS | 2023-12-09 | quickjs |
Ferramentas opcionais:
pactlaltera o volume de uma faixa em reprodução sem interrompê-la. Sem ele, uma alteração de volume reinicia o fluxo na posição atual, o que causa uma pequena pausa.bluetoothctl(BlueZ, somente Linux) permite que o serviço conecte um alto-falante Bluetooth por conta própria.
O Docker Desktop no macOS e no Windows não pode passar o áudio do host para os contêineres, portanto use o Docker apenas no Linux. Qualquer máquina pode executar o servidor MCP e controlar um serviço de reprodução em execução em outro lugar (veja Controlando um player remoto).
O servidor MCP precisa de Python 3.10+ e acesso de rede ao serviço de reprodução.
Início rápido
-
Clone o repositório e crie seu arquivo de configurações:
git clone https://github.com/karunstha/yt-player.git cd yt-player cp .env.example .env mkdir -p dataCrie o
data/você mesmo para que seja seu. Se o Docker o criar, ele pertencerá ao root. -
Edite o
.env. Por padrão, o contêiner reproduz através do seu socket PulseAudio ou PipeWire. OPULSE_RUNTIME_DIRdeve apontar para/run/user/<UID>/pulse; executeid -upara descobrir seu UID. Para escolher um alto-falante ou usar ALSA, veja Saída de áudio. -
Opcional, mas recomendado: adicione cookies do YouTube, o que torna menos provável que o YouTube bloqueie solicitações como bot. Exporte seus cookies no formato Netscape (por exemplo, com uma extensão de navegador "cookies.txt") e salve-os como
data/cookies.txt. O serviço funciona sem eles. -
Inicie o serviço de reprodução:
docker compose up -d -
Verifique se ele responde:
curl http://127.0.0.1:5454/player/state -
Conecte um cliente MCP usando uma das opções abaixo.
Executando sem Docker
No Linux ou macOS, com as ferramentas do sistema listadas em Requisitos:
pip install "yt-player[server] @ git+https://github.com/karunstha/yt-player"
yt-player serve
Sem Docker, o serviço vincula-se a 127.0.0.1:5454, armazena dados em ~/.local/share/yt-player e reproduz através da saída de áudio padrão do sistema. Use --host/--port ou as variáveis de configuração para alterar isso, seja no ambiente ou em um arquivo .env no diretório a partir do qual você o inicia. No macOS, instale as ferramentas do sistema primeiro com brew install ffmpeg deno. Se você já tiver Node.js 22+, pode pular o Deno e definir JS_RUNTIME=node.
Na inicialização, o serviço imprime as configurações que está usando e avisa sobre qualquer coisa que impediria a reprodução, como um ffplay ou runtime JavaScript ausente. Serviços iniciados por launchd ou systemd recebem um PATH mínimo que geralmente exclui Homebrew e nvm. Nesse caso, defina FFPLAY_PATH e JS_RUNTIME com caminhos completos, por exemplo FFPLAY_PATH=/opt/homebrew/bin/ffplay.
Saída de áudio
Por padrão, o áudio vai para o dispositivo de saída padrão do sistema. Duas configurações alteram isso, em .env ou no ambiente:
AUDIO_DRIVERescolhe o sistema de som:pulseaudio,pipewire,alsa,jackoucoreaudio. Se não definido, o mais adequado é escolhido automaticamente. O Docker Compose definepulseaudio.AUDIO_DEVICEescolhe o dispositivo de saída nesse sistema de som.
| Sistema de som | AUDIO_DRIVER | AUDIO_DEVICE | Liste dispositivos com |
|---|---|---|---|
| PulseAudio | pulseaudio | Nome do sink, ex.: alsa_output.usb-DAC-00.analog-stereo | pactl list short sinks |
| PipeWire | pulseaudio (através de pipewire-pulse) | Nome do sink, como acima | pactl list short sinks |
| ALSA | alsa | Dispositivo, ex.: plughw:1,0 | aplay -l |
| JACK, CoreAudio, PipeWire nativo | como nomeado | Não suportado; usa o padrão do sistema |
Alto-falantes Bluetooth. O DEFAULT_BLUETOOTH_DEVICE_ID apenas conecta o alto-falante, antes da inicialização e antes de cada faixa. Para garantir que o áudio realmente vá para ele, defina também AUDIO_DEVICE para o sink dele, por exemplo bluez_output.AA_BB_CC_DD_EE_FF.1 no PipeWire ou bluez_sink.AA_BB_CC_DD_EE_FF.a2dp_sink no PulseAudio. O nome exato aparece em pactl list short sinks enquanto o alto-falante está conectado.
ALSA no Docker. Em hosts sem PulseAudio ou PipeWire, defina estes em .env:
AUDIO_DRIVER=alsa
AUDIO_DEVICE=plughw:1,0
O ALSA precisa de acesso exclusivo à placa de som, então a reprodução falha com "device busy" se um servidor de som no host já estiver usando essa placa. O Compose ainda monta PULSE_RUNTIME_DIR, então em um host sem PulseAudio, o Docker cria um diretório /run/user/<UID>/pulse vazio. É seguro ignorar.
Erros de áudio do ffplay aparecem no log do serviço (docker compose logs yt-player). Audio target '<name>' not available significa que o ffplay foi compilado sem esse sistema de som; escolha outro AUDIO_DRIVER ou deixe vazio.
Conectando um cliente MCP
Opção A: stdio (recomendado para clientes de desktop)
Seu cliente MCP inicia o servidor como um processo local. A maneira mais simples é uv, que o instala na primeira execução sem uma etapa de configuração separada.
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 e outros clientes configurados por 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"
}
}
}
}
Sem uv, instale o pacote e aponte seu cliente para o comando yt-player-mcp:
pipx install git+https://github.com/karunstha/yt-player
Se seu cliente puder executar comandos Docker, você pode usar a imagem que já construiu:
docker run --rm -i --network host \
-e MEDIA_SERVICE_URL=http://127.0.0.1:5454 \
yt-player yt-player mcp
Opção B: HTTP streamable (de longa duração, Dockerizado)
Inicie o servidor MCP junto com o serviço de reprodução usando o perfil opcional do Compose:
docker compose --profile mcp up -d
O servidor então escuta em:
http://127.0.0.1:5455/mcp
Para Claude Code:
claude mcp add --transport http yt-player http://127.0.0.1:5455/mcp
Fora do Docker, o mesmo servidor é executado com yt-player mcp --transport streamable-http.
Controlando um player remoto
O servidor MCP apenas faz chamadas HTTP ao serviço de reprodução, então ele pode ser executado em uma máquina diferente do alto-falante. Por exemplo, o serviço de reprodução pode ser executado em um mini PC Linux conectado aos seus alto-falantes enquanto seu assistente roda em um laptop. Aponte MEDIA_SERVICE_URL para o player:
MEDIA_SERVICE_URL=http://media-box.local:5454
Leia Segurança antes de expor qualquer uma das portas em uma rede.
Ferramentas MCP
| Área | Ferramentas |
|---|---|
| Status | health, get_playback_state, get_current_track |
| Pesquisa | search_media |
| Reprodução | play_media, pause_playback, resume_playback, stop_playback, seek_playback, next_track, previous_track, set_volume, set_shuffle, set_repeat |
| Histórico | get_playback_history (paginado com next_before) |
| Fila | get_queue, append_queue_track, insert_queue_track_next, queue_playlist, remove_queue_item, clear_queue, replace_queue_with_playlist |
| Playlists | 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 |
| Salvando a fila | save_queue_as_playlist, add_queue_to_playlist |
| Importar/exportar | export_playlists, import_playlists |
Ferramentas que recebem uma faixa (play_media, append_queue_track, insert_queue_track_next, add_track_to_playlist) aceitam uma query de pesquisa ou um url.
Pesquisas e consultas aceitam um search_type opcional que define o que procurar:
search_type | Pesquisas | Exemplo |
|---|---|---|
songs (padrão) | Músicas do YouTube Music | "tocar Bohemian Rhapsody" |
music_videos | Vídeos do YouTube Music | "tocar o vídeo oficial de…" |
podcasts | Episódios de podcast do YouTube Music | "tocar o episódio do Lex Fridman com Sam Altman" |
videos | Todo o YouTube | tutoriais, palestras, transmissões ao vivo |
Altere o padrão com DEFAULT_SEARCH_TYPE. add_tracks_to_playlist aceita uma lista onde cada entrada é uma URL ou uma consulta de pesquisa.
Uma playlist guarda cada faixa uma única vez. Adicionar uma faixa que já está lá falha com uma mensagem informando isso. Adições em lote (add_tracks_to_playlist, save_queue_as_playlist, add_queue_to_playlist) pulam duplicatas e as listam no resultado como skipped. Faixas que não puderam ser encontradas são listadas como failed. As playlists podem ser referenciadas por ID, nome ou um slug do nome.
Solução de problemas
- O serviço inicia com avisos. Corrija o que eles indicam: instale a ferramenta ausente ou aponte
FFPLAY_PATHouJS_RUNTIMEpara ela. - O estado de reprodução mostra
error, ou nada toca. Verifique o log do serviço (docker compose logs yt-player, ou o terminal executandoyt-player serve). Erros do yt-dlp e do ffplay aparecem lá. Para problemas de áudio, veja Saída de áudio. - O YouTube diz "Sign in to confirm you're not a bot". Adicione cookies como
cookies.txtno diretório de dados (veja Início rápido). - O assistente relata "Could not reach the media service". O serviço de reprodução não está em execução, ou
MEDIA_SERVICE_URLna configuração do seu cliente MCP aponta para o host ou porta errados.
Segurança
Nem o serviço de reprodução nem o servidor MCP têm autenticação.
- Sob Docker Compose, o serviço de reprodução vincula-se a
0.0.0.0:5454com rede do host, então qualquer pessoa na sua rede pode controlar a reprodução. DefinaSERVICE_HOST=127.0.0.1em.envse apenas esta máquina precisar de acesso. Caso contrário, execute-o apenas em uma rede confiável, ou coloque-o atrás de um firewall ou proxy reverso com autenticação. Fora do Docker,yt-player servevincula-se a127.0.0.1por padrão. - O transporte HTTP do MCP vincula-se a
127.0.0.1por padrão. MantenhaMCP_HOST=127.0.0.1a menos que você queira intencionalmente que outras máquinas controlem a reprodução. Se você o vincular a0.0.0.0, proteja a porta da mesma forma. - O contêiner de reprodução é executado com
privileged: truee monta o estado D-Bus e Bluetooth do host para poder gerenciar dispositivos Bluetooth. Remova essas configurações se não precisar de Bluetooth. cookies.txtcontém sua sessão do YouTube. O diretóriodata/e.envestão listados em.gitignore; nunca os envie para o controle de versão.
Configuração
Ambas as partes leem variáveis de ambiente. yt-player serve também carrega um arquivo .env do diretório em que é iniciado. O servidor MCP não lê .env; defina suas variáveis na configuração do seu cliente MCP, como nos exemplos acima.
Valores vazios (como SERVICE_PORT=) usam o padrão. Valores inválidos interrompem a inicialização com uma mensagem nomeando a configuração.
Docker Compose (definido em .env, veja .env.example):
PULSE_RUNTIME_DIR: diretório PulseAudio do host montado no contêiner. O padrão é/run/user/1000/pulse.DATA_PATH: diretório do host montado em/data. O padrão é./data.SERVICE_HOST,SERVICE_PORT,AUDIO_DRIVER,AUDIO_DEVICE,DEFAULT_BLUETOOTH_DEVICE_ID,DEFAULT_VOLUME,DEFAULT_SEARCH_TYPE,MCP_HOST,MCP_PORT: repassados para os contêineres (veja abaixo). No Compose,SERVICE_HOSTtem como padrão0.0.0.0eAUDIO_DRIVERtem como padrãopulseaudio.
Serviço de reprodução:
SERVICE_HOST: host de bind. O padrão é127.0.0.1.SERVICE_PORT: porta de bind. O padrão é5454.DATA_DIR: diretório para dados persistentes do serviço. O padrão é$XDG_DATA_HOME/yt-player(geralmente~/.local/share/yt-player); a imagem Docker usa/data.DATABASE_PATH: caminho do banco de dados SQLite. O padrão é$DATA_DIR/media_service.sqlite3.COOKIES_FILE: arquivo de cookies no formato Netscape passado ao yt-dlp, usado apenas se existir. O padrão é$DATA_DIR/cookies.txt.AUDIO_DRIVER: sistema de som usado para reprodução. Vazio escolhe um automaticamente. Veja Saída de áudio.AUDIO_DEVICE: dispositivo de saída nesse sistema de som. Vazio usa o padrão do sistema.DEFAULT_BLUETOOTH_DEVICE_ID: endereço MAC opcional de dispositivo Bluetooth para conectar na inicialização e antes da reprodução.DEFAULT_VOLUME: volume inicial de0.0a1.0. O padrão é0.8.FFPLAY_PATH: o executávelffplay. O padrão éffplayno PATH.DEFAULT_SEARCH_TYPE: o que as buscas procuram quando uma solicitação não especifica:songs,music_videos,podcastsouvideos. O padrão ésongs.JS_RUNTIME: runtime JavaScript que o yt-dlp usa para o desafio do YouTube:deno,node,bunouquickjs. Adicione um caminho comonode:/usr/local/bin/nodese não estiver no PATH. Forneça vários, separados por vírgula, para fallback na ordem de prioridade do yt-dlp (deno, node, quickjs, bun). O padrão édeno. A imagem Docker inclui apenas Deno.YTDLP_REMOTE_COMPONENTS: o que o yt-dlp pode baixar se o solucionador de desafio incluído (yt-dlp-ejs) estiver ausente ou não corresponder à versão instalada do yt-dlp:ejs:github,ejs:npmounone. O padrão éejs:github. Normalmente nada é baixado, porque o extraserverinstala o solucionador correspondente.PLAYBACK_COMPLETION_GRACE_SECONDS: saídas de backend com falha dentro deste número de segundos após o fim da faixa são tratadas como concluídas. O padrão é5.PLAYBACK_RECOVERY_RETRIES: reinícios automáticos de stream por faixa após uma saída não limpa do backend. O padrão é2.
Servidor MCP:
MEDIA_SERVICE_URL: URL base do serviço de reprodução. O padrão éhttp://127.0.0.1:5454.MEDIA_SERVICE_TIMEOUT_SECONDS: timeout HTTP para chamadas ao serviço de reprodução. O padrão é30.MCP_TRANSPORT:stdio,streamable-httpousse. O padrão éstdio.MCP_HOST: host de bind para transportes HTTP. O padrão é127.0.0.1.MCP_PORT: porta de bind para transportes HTTP. O padrão é5455.MCP_STREAMABLE_HTTP_PATH: caminho HTTP streamable. O padrão é/mcp.MCP_SSE_PATH: caminho de eventos SSE. O padrão é/sse.MCP_MESSAGE_PATH: caminho de mensagens SSE. O padrão é/messages/.
O Docker Compose monta DATA_PATH (padrão ./data) em /data, para que playlists, metadados de faixas salvos, histórico de reprodução e cookies sobrevivam à substituição do contêiner.
API HTTP
O servidor MCP é um cliente desta API. Você também pode chamá-la diretamente ou construir sua própria interface sobre ela.
Reprodução:
POST /player/playcom um deurl,queryoutrackGET /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
Busca:
GET /search?q=...&count=10&type=songs:typeésongs,music_videos,podcastsouvideos- Solicitações que aceitam um
query(itens/player/play,/queue,/queue/tracks,/playlists/{id}/tracksebulk) também aceitamsearch_type
Fila:
GET /queuePOST /queueDELETE /queuePOST /queue/tracksPOST /queue/tracks/nextPOST /queue/playlists/{id}complay_nexteshuffleopcionais: adiciona as faixas de uma playlist sem substituir a filaDELETE /queue/items/{item_id}
Playlists:
POST /playlistsGET /playlistsGET /playlists/{id}PATCH /playlists/{id}DELETE /playlists/{id}POST /playlists/{id}/tracksPOST /playlists/{id}/tracks/bulkcomitems(até 50 faixas): retornaadded,skippedefailedPOST /playlists/{id}/tracks/queue: anexa a fila atual, retorna o mesmo formato quebulkPOST /playlists/{id}/tracks/currentDELETE /playlists/{id}/tracks/{track_id}POST /playlists/{id}/tracks/{track_id}/movecom umpositionbaseado em 0POST /playlists/{id}/tracks/reorderDELETE /playlists/{id}/tracksPOST /playlists/{id}/playPOST /playlists/{id}/shuffleGET /playlists/exportGET /playlists/{id}/exportPOST /playlists/import
Eventos em tempo real:
WS /events
O WebSocket envia playback.sync na conexão e depois transmite eventos significativos como track.changed, playback.state_changed, playback.seeked, queue.changed, playlist.changed e track.completed. Durante a reprodução, emite atualizações de playback.sync em baixa frequência aproximadamente a cada 3 segundos.
API legada
Os endpoints originais ainda estão disponíveis:
POST /playPOST /stopGET /statusPOST /searchPOST /play-searchPOST /shuffle
Estrutura do projeto
yt_player/cli.py: o comandoyt-playere seus modosserveemcp.yt_player/factory.py: criação do app FastAPI, gerenciamento de ciclo de vida, conexão de serviços e manipuladores de erro.yt_player/env.py: análise de variáveis de ambiente compartilhada entre o serviço e o servidor MCP.yt_player/core/: configuração do serviço, opções do yt-dlp (ytdlp.py), erros estruturados do serviço e utilitários compartilhados.yt_player/player/: rotas de reprodução, rotas de fila, rotas legadas de reprodução, controlador de reprodução, serviço de fila, backend ffplay/yt-dlp e modelos de player/fila.yt_player/playlists/: rotas de playlist, serviço persistente de playlist, repositório SQLite e modelos de playlist.yt_player/sources/: integrações de fontes de mídia. O YouTube está implementado atualmente emyt_player/sources/youtube.py.yt_player/events/: rota WebSocket, transmissor de eventos e modelos de eventos.yt_player/mcp/: servidor MCP e wrapper de cliente HTTP para a API do serviço de mídia.main.py: ponto de entrada ASGI para executar o app diretamente com Uvicorn (uvicorn main:app).
Desenvolvimento
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest