Skip to main content
Glama

youtube-context-mcp

An MCP server that gives agents rich context about any YouTube video — what's said, what's popular, and what's on screen:

  • Transcript — plain or [mm:ss]-timestamped text, with optional translation

  • Deep links — watch?v=…&t=… URLs that jump straight to a moment

  • Metadata — title, channel, upload date, duration, view/like counts, chapters, tags

  • Most-replayed moments — the peaks of YouTube's viewer-interest heatmap

  • Visuals (for multimodal models) — a still frame at any moment, or a tiled preview sheet of the whole video

Agents use it to answer questions about a video, summarize it, pull quotes, surface highlights, read what's on screen, or link you to exactly where something is said.

It builds on youtube-transcript-api (transcripts) and yt-dlp (metadata), which do the actual fetching, and shapes them into a focused set of MCP tools designed for agents.

Transcripts are a video's existing captions/subtitles — it does not transcribe audio (no Whisper/ASR). Videos without captions have no transcript to return.

Install

Run it on demand with uv (no install needed):

uvx youtube-context-mcp@latest

Or install it:

pip install youtube-context-mcp

Related MCP server: YouTube Insights MCP Server

Use it with an agent

Add it to your MCP client config:

{
  "mcpServers": {
    "youtube-context": {
      "command": "uvx",
      "args": ["youtube-context-mcp@latest"]
    }
  }
}

Or, in Claude Code:

claude mcp add youtube-context -- uvx youtube-context-mcp@latest

Running over HTTP

By default the server talks stdio (the client launches it). If your client runs on a different host — for example LM Studio on Windows while this server runs in WSL2 — run it as a long-lived HTTP server instead and point the client at a URL:

youtube-context-mcp --transport http --host 0.0.0.0 --port 8000

Then add it by URL:

{
  "mcpServers": {
    "youtube-context": { "url": "http://localhost:8000/mcp" }
  }
}

(--host 0.0.0.0 makes it reachable from the Windows side; WSL2 forwards localhost.)

Tools

In every tool, video accepts a full YouTube URL (watch, youtu.be, shorts, embed, live) or a bare 11-character video ID.

get_transcript

get_transcript(video, languages=["en"], include_timestamps=False, translate_to=None)

Returns the transcript as plain text. Set include_timestamps=True to group it into ~15s [mm:ss] blocks — handy for locating a topic and building a link; translate_to takes an ISO language code.

build_video_link(video, start)

Builds a watch?v=…&t=<seconds> URL that opens the video at a moment, so a user can click straight to it. start is seconds or a "mm:ss" / "h:mm:ss" string. Pairs with get_transcript(include_timestamps=True) to turn "where is X mentioned?" into a clickable link.

list_transcripts

list_transcripts(video)

Lists available transcripts (language, code, manual vs auto-generated, translatable) plus the translation targets. Use it when get_transcript can't find your language.

get_video_metadata

get_video_metadata(video, include_description=False)

Returns the video's title, channel, upload date, duration, view/like counts, chapters and tags — answers "what's this video / who made it?" without fetching the transcript. Set include_description=True to also include the (often long) description.

get_most_replayed

get_most_replayed(video, top_n=8)

Returns the video's most-replayed moments (YouTube's viewer-interest heatmap) as up to top_n distinct high-interest content regions — each with a peak_label/region_label (mm:ss), a clickable jump url, the chapter it falls in, and a relative_intensity (0–1 within the video, 1.0 = its single most-rewatched moment — not a view count). Use it for "what are the best parts?" or to weight a summary by what viewers actually rewatch.

A peak flagged is_opening: true sits at the start (t≈0) — usually a playback-start artifact, not a real rewatch; it's returned in addition to top_n so it can't crowd out the content peaks. has_data is false when YouTube has no heatmap (common for newer/low-traffic videos and some Shorts).

get_video_frame

get_video_frame(video, at, max_width=640)

Captures a single still frame (screenshot) at a moment and returns it as an image, so a multimodal model can answer "what's on screen here?" — read a slide, a burned-in caption, or a UI being demoed. at is seconds or a "mm:ss" / "h:mm:ss" string; the frame is the nearest keyframe at/just before it and is downscaled to max_width (clamped 64–1280) to stay cheap on the image budget. Pairs with get_most_replayed / get_transcript(include_timestamps=True) to pick the moment first. Requires ffmpeg.

get_video_preview

get_video_preview(video, tiles=12, tile_width=320, start=None, end=None)

Returns a contact sheet: tiles frames sampled evenly across the whole video, composited into one tiled grid image, plus a text legend mapping each tile to its mm:ss timestamp — a cheap visual overview of the entire video (a 4×3 sheet costs about 3× one frame). Pass start / end (seconds or "mm:ss" / "h:mm:ss") to preview just a window of the video — e.g. zoom into the part an overview sheet or get_most_replayed flagged as interesting. Tiles are small by design: spot scene changes and pick a moment here, then zoom in further with get_video_frame at a tile's timestamp. Requires ffmpeg.

Media tools (ffmpeg)

get_video_frame and get_video_preview are the only tools that need an ffmpeg binary (everything else is metadata/transcript only). yt-dlp resolves the video stream and ffmpeg grabs downscaled JPEGs; images come back as MCP image content, so the client/model must be able to display images (e.g. a multimodal model such as Gemma in LM Studio).

The system ffmpeg is used when it's on PATH. The optional media extra installs imageio-ffmpeg, whose wheel bundles a static ffmpeg, making the install self-contained:

pip install "youtube-context-mcp[media]"   # or: uvx youtube-context-mcp[media]@latest
# or bring your own: apt install ffmpeg | brew install ffmpeg | see ffmpeg.org

If neither is available, only the two media tools are affected and they return a clear error.

Proxies (optional)

YouTube blocks most datacenter/cloud IPs, so on a server you may hit RequestBlocked / IpBlocked (transcripts) or a "Sign in to confirm you're not a bot" block (metadata). Locally this is rarely needed. The same env vars route both transcript and metadata requests through a proxy:

Env var

Purpose

WEBSHARE_PROXY_USERNAME, WEBSHARE_PROXY_PASSWORD

Use Webshare rotating residential proxies.

WEBSHARE_PROXY_LOCATIONS

Optional CSV of country codes, e.g. us,de.

YT_TRANSCRIPT_HTTP_PROXY, YT_TRANSCRIPT_HTTPS_PROXY

Use a generic HTTP/HTTPS proxy instead.

YT_TRANSCRIPT_TIMEOUT

Per-request timeout in seconds (default 20).

With no env set, requests go out directly.

Troubleshooting

  • RequestBlocked / IpBlocked — YouTube blocked the IP. Set the proxy env vars above.

  • No transcript found — call list_transcripts to see which languages exist for that video.

  • Transcripts disabled — the uploader turned captions off; nothing can be fetched.

  • "ffmpeg is not installed" — the media tools need it; install it or use the [media] extra (Media tools).

  • Frame/preview returns but no image shows — the MCP client/model must support image content; text-only setups drop it silently.

Development

uv sync
uv run ruff check . && uv run ruff format --check .
uv run pytest
uv run mcp dev src/youtube_context_mcp/server.py --with-editable .   # interactive inspector

License

MIT

Credits

Transcript fetching is done by youtube-transcript-api by Jonas Depoix, and metadata by yt-dlp. This project is the MCP adapter that wires them together for agents.

Available Tools

7 tools
get_most_replayedA

Get a YouTube video's "most replayed" moments -- the peaks of its viewer-interest heatmap (the curve shown above the timeline marking where people rewatch most).

Use this for "what are the best / most-rewatched parts?", "jump me to the good part", or to weight a summary toward what viewers actually care about. Each peak is a high-interest region (region_start_seconds..region_end_seconds) with the hottest instant at peak_start_seconds, a ready-to-share url that opens the video at the start of the stretch, and the chapter it falls in. relative_intensity is 0..1 within this video (1.0 = its single most-rewatched moment) -- it is NOT a view count and is not comparable across videos.

A peak with is_opening=True sits at the very start (t~=0): that spot is almost always inflated by playback starting there, not a genuine rewatch, so discount it as a "best part". It is returned in addition to (not counted against) top_n, so the opening can't crowd out content.

To say what is actually happening at a peak, read its peak_label (mm:ss) and look it up with get_transcript(include_timestamps=True); profile is a coarse 0..1 curve for the overall shape (front-loaded vs steady vs spikes near the end).

has_data may be False -- then peaks is empty and note explains why (many newer, low-traffic, or Shorts videos have no heatmap).

Args: video: A YouTube URL (watch, youtu.be, shorts, embed, live) or an 11-character video ID. top_n: Max number of content peak regions (clamped to 1..20; default 8). The flagged opening (t~=0) peak, when present, is returned in addition to these.

Inputs: video (required), top_n. Returns: video_id, has_data, duration_seconds, peaks, +2 more

get_transcriptA

Fetch a YouTube video's existing captions as text so you can answer questions about it.

Returns existing captions/subtitles only; it does not transcribe audio. Videos without captions have nothing to return.

Args: video: A YouTube URL (watch, youtu.be, shorts, embed, live) or an 11-character video ID. languages: Preferred language codes in priority order. Defaults to ["en"]. include_timestamps: If true, group the transcript into ~15s blocks, each prefixed with [mm:ss] (or [h:mm:ss] past an hour). Use this to find where a topic is discussed and pass that [mm:ss] to build_video_link. translate_to: Optional ISO language code to translate the transcript into.

Returns: The transcript as plain text.

Inputs: video (required), languages, include_timestamps, translate_to.

get_video_frameA

Capture a single still frame (screenshot) from a YouTube video at a moment and return it as an image, so a multimodal model can answer "what's on screen here?".

Use this to see the video at a specific time -- e.g. read a slide, a caption burned into the video, or a UI being demoed. Pair it with get_most_replayed or get_transcript(include_timestamps =True) to pick an interesting moment, then grab the frame there.

Requires ffmpeg on the server. The captured frame is the nearest keyframe at or just before the requested moment (it can be off by a second or two) and is downscaled to max_width to keep the response small.

Args: video: A YouTube URL (watch, youtu.be, shorts, embed, live) or an 11-character video ID. at: The moment to capture -- seconds (e.g. 90) or a "mm:ss" / "h:mm:ss" string. max_width: Max width in pixels of the returned image (clamped 64..1280; default 640). Smaller is cheaper on a vision model's image-token budget.

Inputs: video (required), at (required), max_width.

get_video_metadataA

Get a YouTube video's metadata: title, channel, upload date, duration, view/like counts, chapters and tags.

Use this to answer questions about a video (its name, who made it, how long it is, when it came out) without fetching its transcript.

Args: video: A YouTube URL (watch, youtu.be, shorts, embed, live) or an 11-character video ID. include_description: If true, also return the (often long) description; otherwise it's omitted to keep the response small.

Inputs: video (required), include_description. Returns: video_id, title, channel, channel_url, +9 more

get_video_previewA

Get a visual overview of a YouTube video as ONE tiled contact-sheet image: tiles frames sampled evenly across the video (or across a start..end window of it), plus a text legend mapping each tile to its mm:ss timestamp.

Use this to see what's going on across a video (talking head vs slides vs demo footage, scene changes, "is there a chart anywhere?") and to pick moments worth a closer look. To inspect one part in more detail, call it again with start/end around that part -- but pick the window from the transcript, chapters, or get_most_replayed first and zoom once; don't binary-search the video with repeated sheets, since every returned image stays in context. Read each tile's timestamp from the legend -- do not count grid cells yourself. Tiles are small and not readable: to read a slide, caption, or UI, follow up with get_video_frame(video, at=<that tile's timestamp>). Windows under ~1 minute may return near-duplicate tiles (frames land on keyframes, a few seconds apart).

Requires ffmpeg on the server (the system binary, or the one bundled by the [media] extra).

Args: video: A YouTube URL (watch, youtu.be, shorts, embed, live) or an 11-character video ID. tiles: How many frames to sample (clamped 4..24; default 12). tile_width: Width in pixels of each tile (clamped 160..480; default 320). The whole sheet stays around 1000-1300 px wide at the defaults -- cheap on a vision model's image budget while keeping tiles recognizable. start: Optional window start -- seconds (e.g. 90) or a "mm:ss" / "h:mm:ss" string. Defaults to the beginning of the video. end: Optional window end, same forms. Defaults to (and is clamped to) the video's end.

Inputs: video (required), tiles, tile_width, start, +1 more.

list_transcriptsA

List the transcripts available for a YouTube video.

Use this when get_transcript can't find your requested language. It reports each available transcript (language, code, whether it's auto-generated, whether it's translatable) plus the set of languages you can pass to get_transcript's translate_to.

Args: video: A YouTube URL or an 11-character video ID.

Inputs: video (required). Returns: transcripts, translation_languages

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.6/5.0

    Scored across 7 tools

    Disambiguation5/5

    Each tool targets a clearly distinct concern: transcript retrieval, transcript listing, metadata, replayed peaks, a single frame, a preview sheet, and link building. Even the two visual tools are unambiguous because one captures one moment while the other makes a timeline overview.

    Naming Consistency4/5

    The naming is mostly predictable with get_ for retrieval, list_ for enumeration, and build_ for the link helper. The slight inconsistency is that build_video_link breaks the get_/list_ pattern, but it is still a sensible verb for its purpose.

    Tool Count5/5

    Seven tools is well-scoped for a YouTube context server. Each tool covers a distinct aspect of getting information from a video, and none feel redundant or unnecessary.

    Completeness5/5

    The surface covers the core needs for answering questions about a YouTube video: textual transcript, available languages, metadata, engagement peaks, and visual context. There are no obvious dead ends; visual tools complement transcript and metadata tools well.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      Not graded
      maintenance
      An MCP server that provides YouTube data access without API keys or quotas. It enables agents to search videos, retrieve transcripts and metadata, and perform full-text search across cached content for AI context retrieval.
      3 npm
      -
    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server that extracts YouTube video transcripts (including metadata) as Markdown, enabling AI to summarize and discuss video content without watching it.
      MIT