youtube-mcp
A lightweight MCP server for reading public YouTube data, offering tools to fetch video transcripts, playlist contents, and video metadata without requiring an API key.
README
youtube-mcp
A small MCP server that lets a model read public YouTube data. Three tools, no API key, nothing clever:
| tool | what you get |
|---|---|
youtube_transcript |
what is said in a video, as plain text, optionally trimmed to a time window, plus which language it came back in |
youtube_playlist |
the videos in a playlist, in order |
youtube_video_facts |
title, channel, duration, publish date, views, likes, description, caption languages |
That is the entire surface. The server fetches, checks the link, trims by timestamp and returns. Summarising, searching and ranking are the calling model's job, not this server's.
Requirements
- Python 3.12 or newer
- uv for the short path, though plain pip is fine
Install
git clone https://github.com/chiekh-a/youtube-mcp.git
cd youtube-mcp
uv venv
uv pip install -e ".[dev]"
With pip instead:
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Configuration
Copy the example file and fill in whatever you need:
cp .env.example .env
All of it is optional. With an empty .env the server still runs, it just talks
to YouTube directly from wherever it happens to be.
| variable | default | what it does |
|---|---|---|
YOUTUBE_USE_PROXY |
false |
the switch that turns the proxy on |
YOUTUBE_PROXY_URL |
unset | proxy endpoint, credentials included |
MCP_TRANSPORT |
stdio |
stdio or http |
MCP_HOST |
127.0.0.1 |
bind address, http only |
PORT |
8000 |
bind port, http only |
PUBLIC_BASE_URL |
unset | where the server is reachable, used for the icon URL |
PUBLIC_BASE_URL is only worth setting if you deploy somewhere that is not
Railway. Railway publishes the domain itself and the server picks it up. Leave
it unset over stdio, where the icon travels inline instead.
Why the proxy exists
YouTube is aggressive about blocking datacenter IP ranges. On your own machine you will usually be fine without a proxy. On a server (Railway, a VPS, CI) the transcript requests start coming back as bot checks fairly quickly, and pointing them at a residential proxy is the fix.
Both variables have to be set before anything is routed. A URL sitting in the
environment with YOUTUBE_USE_PROXY=false is ignored, which makes it easy to
flip on and off without editing config.
The proxy URL contains a password. It is never logged, and .env is gitignored.
Please keep it that way.
Run it
Over stdio, which is what a desktop MCP client expects:
uv run python -m youtube_mcp
Over HTTP, for when the server lives somewhere else:
uv run python -m youtube_mcp --transport http --host 0.0.0.0 --port 8000
The endpoint is /mcp, so a local server answers at
http://127.0.0.1:8000/mcp. Leave the trailing slash off. A URL ending in
/mcp/ gets redirected, and the redirect loses the session header, so the
client fails with a confusing 400.
Flags: --transport, --host, --port, --log-level. Logs always go to
stderr, because stdout belongs to the MCP protocol.
Connect a client
Local, over stdio
Drop this into claude_desktop_config.json, or .mcp.json for Claude Code, and
point the path at your checkout:
{
"mcpServers": {
"youtube": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/youtube-mcp",
"run",
"python",
"-m",
"youtube_mcp"
],
"env": {
"YOUTUBE_USE_PROXY": "false"
}
}
}
}
If you would rather not go through uv, call the venv's Python directly:
{
"mcpServers": {
"youtube": {
"command": "/absolute/path/to/youtube-mcp/.venv/bin/python",
"args": ["-m", "youtube_mcp"]
}
}
}
Claude Code can skip the file editing entirely:
claude mcp add youtube -- uv --directory /absolute/path/to/youtube-mcp run python -m youtube_mcp
Remote, over HTTP
Once it is deployed somewhere:
{
"mcpServers": {
"youtube": {
"type": "http",
"url": "https://your-app.up.railway.app/mcp"
}
}
}
No trailing slash on that URL, for the reason above.
Deploy to Railway
There is a Dockerfile and a railway.json in the repo, so Railway needs very
little from you.
- Push the repo to GitHub.
- In Railway, create a project from the repo. It finds the Dockerfile by itself.
- Under Settings, Variables, add:
MCP_TRANSPORT=httpMCP_HOST=0.0.0.0YOUTUBE_USE_PROXY=trueYOUTUBE_PROXY_URL= your proxy endpoint
- Generate a domain under Settings, Networking.
PORT comes from Railway, so leave it alone.
From the CLI instead:
railway login
railway init
railway up
railway domain
Two things to keep in mind about a public deployment. The HTTP endpoint has no
auth on it, so anyone holding the URL can spend your proxy quota. And a hosted
IP will run into YouTube's bot checks without a residential proxy, which is the
whole reason YOUTUBE_USE_PROXY is there.
How it behaves
Small decisions that occasionally surprise people, all of them on purpose:
- Only
https://links, and only onyoutube.com,m.youtube.comoryoutu.be. - Shorts are turned away. Pass a regular video link.
- Captions are tried in this order and the first hit wins: en, ar, fr, es, de, it, pt, ru, zh. If a video has none of those, you get whatever it does have rather than an error, since the model reading it can translate. The response says which language turned up, and whether a human wrote the captions or speech recognition did.
- Trimming is an overlap test, not a containment test. A caption line that
begins before
start_secondsbut is still being spoken at that moment is kept whole, because half a sentence is worth less than a slightly wider clip. start_secondshas to be strictly smaller thanend_seconds. Equal values are an error, and it is caught before any request goes out.- A video with no captions in a supported language is an error. A time window that lands past the end of the video is simply an empty result.
- Only text comes back, never timestamps. They are dead weight in a context window.
youtube_playlistalso accepts a watch link that happens to be playing inside a playlist, since it carries the samelist=id.
When something breaks
"Sign in to confirm you're not a bot", or "YouTube is blocking requests from
your IP". The host is on an IP range YouTube does not trust, which is normal
for any cloud provider. Set YOUTUBE_USE_PROXY=true with a working residential
proxy. Playlist listing often keeps working while transcripts and video facts
fail, so a partial outage like that is usually this.
Tunnel connection failed: 407 Proxy Authentication Required. The proxy is
reachable and it turned your credentials down. Check the username and password,
and check whether the provider expects the client IP to be allowlisted first.
The scheme on the proxy URL is not the problem, http:// and https:// behave
the same here.
A 400 from the HTTP endpoint straight after connecting. The client URL ends
in /mcp/. Drop the trailing slash.
Nothing at all over stdio. Something wrote to stdout. Only this server's own
logging is careful about that, so a stray print in your own changes is the
usual culprit.
Tests
uv run pytest
Nothing in the suite touches the network. An autouse fixture in
tests/conftest.py swaps both clients for tripwires that raise on contact, so a
forgotten stub fails loudly instead of quietly making live requests.
Layout
youtube_mcp/
__main__.py flags, transport choice, start
server.py the FastMCP instance and the three tools
links.py parsing YouTube URLs into ids
captions.py caption fetching and the time window
catalog.py yt-dlp: playlists and video facts
schemas.py what the tools return
settings.py the only module that reads the environment
errors.py the two ways a call can fail
branding.py the icon clients show, and the routes serving it
assets/ the icon itself, as PNG and SVG
The icon is a hand drawn play button rather than YouTube's official artwork, so there is nothing here that belongs to anyone else.
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.