Skip to main content
Glama

yts — YouTube Transcript MCP Server

Minimal MCP server that downloads YouTube video transcripts via the yt-dlp CLI. Runs over stdio (for Claude Code / IDE integrations) or SSE (for Docker deploys and remote clients).


Tools

Tool

Description

get_transcript(url, language=None, auto_subs=True, format="cues")

Download subs for a video. language=None picks the original-audio track (-orig) with English fallback. formatcues/text/both/vtt.

list_subtitles(url)

List which subtitle and auto-caption languages the video offers.

get_video_info(url)

Return metadata (title, channel, duration, description, tags).

set_cookies(cookies_text)

Load Netscape-format cookies for this process. Bypasses rate-limit / captcha errors.

clear_cookies()

Discard the in-memory cookies. Idempotent.

check_cookies(url=None)

Probe a random video from the built-in list (or an explicit url) to verify cookies work. Never raises — returns {ok, ...}.

health()

Return yt-dlp version + whether cookies are loaded.

All success responses are dict. Failures surface as MCP protocol errors (isError: true), so clients see red error UI rather than a "success" wrapping a {"error": "..."} payload.


Related MCP server: youtube-mcp

Bypassing "This video is not available" / captcha errors

YouTube's bot detection rate-limits guest sessions to ~300 videos/hour per IP. When it triggers, yt-dlp masks the real reason as "This video is not available". The fix is authenticated cookies from a signed-in browser:

  1. In your browser, sign in to YouTube.

  2. Install a cookies-export extension (e.g. "Get cookies.txt LOCALLY" — Chrome/Firefox).

  3. Export cookies for youtube.com — the extension gives you Netscape-format text.

  4. Call set_cookies(cookies_text=<the exported text>) on the running server (via MCP Inspector, Claude Code, etc.).

  5. All subsequent tool calls will run with --cookies injected automatically.

Cookies live only in the server process (chmod-600 tempfile). They do not survive docker compose restart — re-inject after each restart. Call clear_cookies() any time to drop them.


Requirements

  • Python 3.10+

  • yt-dlp on PATH (installed automatically by setup.sh inside the venv, or by the Docker image)

  • ffmpeg — optional but recommended (handles subtitle format conversion)

  • A JS runtime (node, deno, bun, or quickjs) — strongly recommended. YouTube protects many videos with a JS n challenge; without a runtime, yt-dlp masks the failure as "This video is not available". The Docker image installs nodejs by default. Locally, install one you already have (brew install node on macOS).


Quick start (Docker Compose)

Every push to main publishes a multi-arch image to Docker Hub: josetonyp/yts-mcp:latest (see the CI / published image section below). If you just want to run the server without building:

docker compose pull                     # fetch the pre-built image
docker compose up -d                    # start it
curl -N http://localhost:8765/sse       # verify the SSE endpoint responds
docker compose logs -f yts-mcp          # follow the yt-dlp trace log
docker compose down                     # stop & remove

To build locally from your working tree instead (dev flow):

docker compose up -d --build

Point at a different published tag (e.g. a specific commit) with the YTS_IMAGE env var:

YTS_IMAGE=josetonyp/yts-mcp:sha-abc1234 docker compose up -d

Then register with your MCP client:

{
  "mcpServers": {
    "yts": { "url": "http://127.0.0.1:8765/sse" }
  }
}

Docker CLI (no Compose)

If you don't want to use Compose, the same server runs via docker build + docker run:

# 1. Build the image (tag it 'yts-mcp' for convenience).
docker build -t yts-mcp .

# 2. Run it. --rm auto-removes on stop; -d detaches; -p publishes the SSE port.
docker run -d --rm \
  --name yts-mcp \
  -p 8765:8765 \
  yts-mcp

# 3. Verify.
curl -N http://localhost:8765/sse
docker logs -f yts-mcp                  # stream yt-dlp command log

Common variants

# Run in the foreground (Ctrl+C to stop) — useful for one-off debugging:
docker run --rm -p 8765:8765 yts-mcp

# Bind to a different host port:
docker run -d --rm --name yts-mcp -p 9000:8765 yts-mcp

# Tighter timeout (default is 120s per yt-dlp call):
docker run -d --rm --name yts-mcp -p 8765:8765 \
  -e YTDLP_TIMEOUT=60 \
  yts-mcp

# Verbose logs (adds yt-dlp stderr on successful calls):
docker run -d --rm --name yts-mcp -p 8765:8765 \
  -e YTS_LOG_LEVEL=DEBUG \
  yts-mcp

# Pin a specific yt-dlp release at build time:
docker build --build-arg YTDLP_VERSION=2025.09.05 -t yts-mcp:pinned .
docker run -d --rm --name yts-mcp -p 8765:8765 yts-mcp:pinned

# Stop, restart, remove:
docker stop yts-mcp
docker start yts-mcp
docker rm -f yts-mcp

Upgrading yt-dlp

YouTube changes their internals often; yt-dlp ships fixes weekly.

# With Compose:
docker compose build --no-cache --build-arg YTDLP_VERSION=latest
docker compose up -d

# With plain Docker CLI:
docker build --no-cache --build-arg YTDLP_VERSION=latest -t yts-mcp .
docker rm -f yts-mcp
docker run -d --rm --name yts-mcp -p 8765:8765 yts-mcp

Verify with the health tool from your MCP client, or:

docker exec yts-mcp yt-dlp --version

CI / published image

.github/workflows/docker.yml builds a multi-arch (amd64 + arm64) image and pushes it to Docker Hub.

Image URL: josetonyp/yts-mcp

Tags produced per push:

Tag

Meaning

latest

Default branch (main/master) — always the newest passing build

main, <branch>

Every pushed branch keeps a tag

sha-<short>

Every commit — for reproducible pins

1.2.3, 1.2, 1

Git tags matching v* (semver)

Triggers:

  • Push to main/master → build and push

  • Tag v* → build and push semver tags

  • Pull request → build only (validates the Dockerfile), no push

  • workflow_dispatch → manual runs from the Actions tab

First-time setup

  1. Create a Docker Hub access token: https://hub.docker.com/settings/securityNew Access Token → scope Read, Write, Delete. Copy it — shown once.

  2. Create the repo on Docker Hub ahead of first push (recommended so it starts Public): https://hub.docker.com/repository/create → name yts-mcpPublic. Skipping this makes the first push auto-create it Private, and public consumers get denied errors.

  3. Add two GitHub repository secrets: Settings → Secrets and variables → Actions → New repository secret.

    • DOCKERHUB_USERNAME = josetonyp

    • DOCKERHUB_TOKEN = the token from step 1

  4. Init the repo and push to GitHub:

    git init && git add . && git commit -m "initial"
    git remote add origin git@github.com:<owner>/<repo>.git
    git push -u origin main
  5. Wait ~3-5 min for the multi-arch build. Then:

    docker compose pull
    docker compose up -d

Environment variables

Var

Default

Purpose

MCP_HOST

127.0.0.1 (local) / 0.0.0.0 (Docker)

SSE bind address

MCP_PORT

8765

SSE bind port

MCP_TRANSPORT

(unset)

Set to sse to force SSE without the --sse flag

YTDLP_BIN

(auto-detect: venv sibling → PATH)

Override the yt-dlp binary path

YTDLP_TIMEOUT

120

Max seconds a single yt-dlp invocation may run

YTS_LOG_LEVEL

INFO

DEBUG/INFO/WARNING/ERROR on stderr

Pass these to docker run with -e VAR=value or set them in docker-compose.yml under environment:.


Local (stdio) setup

bash setup.sh

The script creates .venv/, installs mcp and yt-dlp, and prints an .mcp.json snippet like:

{
  "mcpServers": {
    "yts": {
      "type": "stdio",
      "command": "/absolute/path/to/yts/.venv/bin/python3",
      "args":    ["/absolute/path/to/yts/src/server.py"]
    }
  }
}

Local (SSE) dev mode

bash dev.sh                  # binds 127.0.0.1:8765
bash dev.sh --port 8888      # custom port

File layout

yts/
├── src/
│   ├── server.py                    ← FastMCP init, tool registration, composition root
│   ├── cookie_store.py              ← CookieStore + InvalidCookiesError (standalone)
│   └── transcript/                  ← yt-dlp adapter package — one class per file
│       ├── __init__.py              ← public API re-exports
│       ├── cue.py                   ← Cue (frozen dataclass)
│       ├── transcript.py            ← Transcript (dataclass + to_dict)
│       ├── video_info.py            ← VideoInfo (dataclass + from_yt_json)
│       ├── probe_videos.py          ← PROBE_VIDEOS list used by check_cookies
│       ├── ytdlp_client.py          ← YtDlpClient + 4 error classes
│       └── parsers/                 ← subtitle-format parsers
│           ├── __init__.py
│           └── vtt_parser.py        ← VttParser (WebVTT → cues, stateless)
├── .github/
│   └── workflows/
│       └── docker.yml               ← CI: build+push multi-arch image to GHCR
├── requirements.txt                 ← mcp + minimal HTTP deps
├── Dockerfile                       ← Python 3.12-slim + ffmpeg + nodejs + yt-dlp (pip)
├── docker-compose.yml               ← Uses Docker Hub image; falls back to local build
├── setup.sh                         ← Local venv + smoke test
├── dev.sh                           ← Launch SSE dev server
├── ARCHITECTURE.md                  ← Design decisions and layer contracts
└── README.md

See ARCHITECTURE.md for the design rationale.

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    An MCP server that enables users to retrieve YouTube transcripts and perform video or channel searches without requiring Google API keys. It supports transcript chunking and provides tools for detailed video content analysis and channel metadata extraction.
    Last updated
    5
    103
    4
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    An MCP server that enables the extraction of transcripts and detailed metadata from YouTube videos. It allows users to retrieve video information like titles and descriptions, as well as transcripts with optional timestamps and language selection.
    Last updated
    2
    MIT

View all related MCP servers

Related MCP Connectors

  • MCP server for Google Veo AI video generation

  • MCP server for AI dialogue using various LLM models via AceDataCloud

  • MCP server for Hailuo (MiniMax) AI video generation

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/josetonyp/yts-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server