youtube-mcp
A local, single-user YouTube MCP server that turns public YouTube URLs into structured research context and lets you manage your own channel's playlists using your own Google credentials.
Video & channel research — fetch normalized public metadata for a video (
youtube_get_video) or channel (youtube_get_channel), and page through a channel's recent uploads (youtube_get_channel_videos).Video search — run bounded public video searches (max 25 results) with relevance, date, or view-count ordering (
youtube_search_videos).Comments — retrieve one page of public comment threads (
youtube_get_comments), optionally with inline replies and post-retrievalmatchTermsfiltering, or search literal terms across up to 5 comment pages (youtube_find_comments); results are always scoped to retrieved pages only.Public playlists — read one explicit page of a public playlist with item IDs and positions preserved (
youtube_get_playlist_items).Transcripts — list exposed caption tracks (
youtube_list_transcript_languages) and page through timestamped creator or auto-generated caption segments (youtube_get_transcript), using localyt-dlpmetadata with optional Chromium/Firefox fallbacks when YouTube rate-limits.Owned playlist reads — see the authenticated channel (
youtube_get_authenticated_channel) and list its playlists and playlist items with explicit pagination.Owned playlist writes — create (
youtube_create_playlist, defaults to private), update metadata (youtube_update_playlist), and add a public video (youtube_add_playlist_video); removal and reordering requireconfirm: trueand operate on exact item IDs.Safety boundaries — public tools stay read-only, destructive actions need explicit confirmation, writes are read back and verified, and there is no telemetry, media download, ASR generation, or account-library access.
Note — the supplied schema exposes only a subset of the documented tools; the README also lists channel/playlist search, reply fetching, playlist find/cleanup/clone, and transcript search tools not present here.
Provides tools for retrieving public video, channel, and playlist metadata, searching videos, fetching timestamped transcripts, and managing owned playlists via the YouTube Data API.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@youtube-mcp get video metadata and comments from this link: https://youtu.be/abc123"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
youtube-mcp
Local YouTube MCP server for Codex. It turns public video, channel, and playlist URLs into structured context, bounded public-comment retrieval, timestamped caption research, and owned-playlist management.
The repository is public, but the server is intentionally local and single-user: bring your own Google Cloud credentials, authenticate your own YouTube channel, and keep credentials and tokens on your machine. It is not a hosted service or a multi-user connector.
Tools
youtube_get_videoyoutube_get_commentsyoutube_get_comment_repliesyoutube_find_commentsyoutube_get_channelyoutube_get_channel_videosyoutube_search_videosyoutube_search_channelsyoutube_search_playlistsyoutube_get_playlist_itemsyoutube_find_playlist_itemsyoutube_plan_playlist_cleanupyoutube_apply_playlist_cleanupyoutube_list_transcript_languagesyoutube_get_transcriptyoutube_search_transcriptyoutube_get_authenticated_channelyoutube_list_owned_playlistsyoutube_get_owned_playlist_itemsyoutube_create_playlistyoutube_update_playlistyoutube_add_playlist_videoyoutube_remove_playlist_itemyoutube_reorder_playlist_itemyoutube_clone_playlist
Public research tools remain read-only. Authenticated V2 tools manage only playlists owned by the locally authenticated channel; the server does not expose account-library reads, media downloads, ASR generation, or background processing.
Related MCP server: YouTube MCP
Requirements
Node.js 22+
pnpmA Google Cloud project with YouTube Data API v3 enabled
A restricted YouTube Data API key for public read tools
yt-dlponPATHfor transcript tools (orYT_DLP_PATH)
Authenticated playlist tools additionally require a Google OAuth desktop client. ChatGPT access through an OpenAI Secure MCP Tunnel is optional; it is not needed for local Codex use.
Authenticated playlist setup
In Google Cloud, enable YouTube Data API v3, create an OAuth Desktop app client, and configure the loopback redirect URI from YOUTUBE_REDIRECT_URI (by default http://127.0.0.1:8787/callback) as required by that client configuration. Configure its client ID and optional client secret in .env, then run the local PKCE flow once:
pnpm auth:login
pnpm auth:statusTokens are saved outside the repository at ~/.config/youtube-mcp/tokens.json with private filesystem permissions. pnpm auth:logout revokes the local session when possible and removes that file.
youtube_list_owned_playlists and youtube_get_owned_playlist_items use explicit pagination. youtube_create_playlist defaults to private. Update and add operations apply directly; removal and reorder require confirm: true. Only playlists owned by the authenticated channel can be read through the owned workflow or changed.
Set YOUTUBE_SMOKE_OWNED_PLAYLIST_URL only for a private test playlist you own to add an authenticated, read-only ownership smoke check. It does not create, update, add, remove, or reorder items.
Setup
Copy
.env.exampleto.env.Set
YOUTUBE_API_KEYto a restricted YouTube Data API key.Install and build:
pnpm install
pnpm buildRun the stable local stdio server:
pnpm startFor contributor development only, run pnpm dev.
Codex setup
Build the server, then add a local MCP entry to your Codex configuration:
[mcp_servers.youtube]
command = "node"
args = ["--env-file=/absolute/path/to/youtube-mcp/.env", "/absolute/path/to/youtube-mcp/dist/server.js"]Replace /absolute/path/to/youtube-mcp with your clone path. Rebuild after source changes before using the stable server.
Tool behavior
youtube_get_video accepts normal watch, Shorts, live, embed, and youtu.be URLs. It returns public metadata only.
youtube_get_comments accepts limit (default 50, maximum 100), order (relevance or time), an explicit pageToken, includeReplies, and optional matchTerms.
A call fetches one page only and returns
next_page_tokenwhen YouTube supplies one.includeRepliesreturns only the inline reply subset provided by YouTube.replies_truncatedis true when more replies exist.matchTermsapplies a case-insensitive literal OR filter after retrieving the page. When it is used,search_scopeis alwaysretrieved_page_only; it does not search every comment on the video.
youtube_find_comments searches a caller-specified maxPages (1–5) of comment threads for matchTerms. It returns searched_pages, complete, and next_page_token; its search_scope is always retrieved_pages_only.
youtube_get_channel accepts public /channel/CHANNEL_ID and /@handle URLs. youtube_get_channel_videos returns one explicit page of the channel's public uploads playlist.
youtube_search_videos returns one explicit page of public video search results, enriched with normalized video metadata. Search is quota-expensive, so requests are limited to 25 results.
youtube_search_channels and youtube_search_playlists provide the same bounded, enriched discovery flow for public channels and playlists. youtube_get_comment_replies retrieves one explicit reply page for a known parent comment.
youtube_get_playlist_items accepts public /playlist?list=... and /watch?...&list=... URLs and returns one explicit item page. Items retain their playlist item IDs and positions for safe future authenticated workflows.
youtube_find_playlist_items matches literal terms across at most five public or owned-playlist pages. youtube_plan_playlist_cleanup is owned-playlist-only and returns deterministic duplicate/unavailable-item removal recommendations; it never mutates and does not infer subjective sequencing. For a truncated cleanup pass, provide its opaque next_cursor to continue while retaining duplicate-detection context. youtube_apply_playlist_cleanup executes only caller-supplied exact planner removals and requires confirm: true; it checks every item before deleting, then reports a stopped partial result if YouTube rejects a later deletion.
youtube_clone_playlist requires confirm: true and copies at most five explicit source pages (250 items) from a public or owned source into a new owned playlist. It preserves source order and duplicate videos, reports unavailable source items instead of hiding them, and never rolls back a partially copied target. Every playlist write is read back and verified before success is returned.
youtube_add_playlist_videos appends a reviewed list of up to 250 public video URLs to an owned playlist in the supplied order. It requires confirm: true, validates every requested video before its first write, and stops with exact completed, remaining, and indeterminate IDs on a write failure.
youtube_apply_playlist_order applies a reviewed complete item-ID order to an owned playlist of at most 250 items. It requires confirm: true and rejects stale, incomplete, or duplicate item-ID lists before any mutation. Each move and the final full order are read back; a failure reports the observed order along with completed, remaining, and indeterminate IDs.
youtube_list_transcript_languages lists caption tracks exposed for a video. youtube_get_transcript returns one explicit page of timestamped creator or automatic caption segments. It prefers English when no language is requested, then falls back to the video language. Transcript retrieval uses local yt-dlp metadata and YouTube-exposed caption URLs; it never downloads media, writes a cache, or generates ASR text. A transient caption fetch is retried once with fresh metadata, but availability can change and is not guaranteed for every public video.
Caption discovery permits up to 32 MiB of yt-dlp output so videos with many automatic-caption languages can be inspected. Extraction failures return structured diagnostics with the discovery stage, video ID, backend version when available, process status, safe cause, and retryability. Known output-limit, timeout, authentication, rate-limit, blocked-request, and extractor failures are distinguished; diagnostic summaries are also logged to stderr without raw caption URLs or credentials.
youtube_search_transcript applies literal-term matching only to one explicit transcript segment window and returns matching timestamped segments with search_scope: "retrieved_segments_only". It accepts compatible cursors from either transcript tool.
If caption retrieval still returns HTTP 429 after the single fresh-URL retry, the tool reports youtube_rate_limited with retryable: false and guidance to stop transcript retrieval/search retries for that attempt. Try again later or use YouTube's Show transcript panel. A sanitized youtube_caption_fetch_failed stderr event records the video ID, status, and guidance without caption URLs or transcript text.
For an optional browser fallback, run pnpm exec playwright install chromium --no-shell and set YOUTUBE_BROWSER_TRANSCRIPT_FALLBACK=true in your local .env or server environment. After persistent caption-fetch HTTP 429, the server opens Show transcript in a temporary signed-out Chromium session. This fallback currently supports original English captions only. It verifies the browser caption inventory against the requested language and creator/automatic type, rejecting missing or ambiguous matches (including videos with both creator and automatic English tracks). It does not log in, reuse saved cookies, download media, or save transcripts. A browser read has a 45-second deadline after a bounded launch, and only one browser request runs at a time.
Fallback responses identify source: "browser" and durations_inferred: true; durations come from adjacent UI timestamps and the video's end time. Browser cursors keep subsequent retrieval/search on the browser path because its segment boundaries differ from caption tracks. Existing caption-track cursors are never silently switched to browser segments. Each page reopens the transcript without caching. YouTube verification prompts or changes to its page structure can still prevent retrieval.
The fallback reports transcript-panel HTTP rejections immediately instead of waiting for rows in an empty panel. browser_transcript_precondition_failed means YouTube returned HTTP 400 with FAILED_PRECONDITION; a manually opened signed-out browser may still succeed. This error does not establish that login is required or captions are missing. Diagnostics include only fixed lifecycle fields, video ID, status, and the recognized error code; they exclude cookies, verification tokens, signed URLs, upstream messages, and transcript text.
On macOS, an opt-in native Firefox backend uses actual pointer clicks instead of browser-protocol automation. Set YOUTUBE_BROWSER_TRANSCRIPT_BACKEND=firefox-native and YOUTUBE_NATIVE_FIREFOX_PROFILE to the absolute path of an existing dedicated profile, then rebuild. Open that profile in Firefox before requesting a transcript. The helper resolves the process holding that profile's lock; it never selects a default or everyday profile. Signing in is not required. macOS Accessibility access must be available to the MCP runtime; macOS builds also require Apple's Swift command-line tools.
The native backend briefly brings Firefox forward, reuses an existing tab already displaying the requested video, or creates one request window, then expands the description and clicks Show transcript. Before the first click, it moves the pointer within its window for eight seconds and waits another 28 seconds; this preparation runs once per request and stops if focus is lost. It may close and reopen an empty panel once, with a 60-second overall helper deadline. It reads all accessible rows in memory, verifies the requested video and the selected English / English (auto-generated) label, and infers durations as above. It closes only windows it created that still contain the original single tab showing the requested video. If tabs, navigation, or unreadable state make ownership uncertain, it leaves the window open. Existing windows are never closed. Four fresh-page trials on LfGenpmOjDQ retrieved 315 rows each with this preparation, whereas the matched delay-only trial failed. This is limited evidence from one video and session; the backend remains experimental and does not guarantee retrieval. Another app taking focus, an obscured target, or another Firefox window receiving focus stops the request. Only one native request may control the desktop at a time, including across MCP processes. Keep the desktop unlocked and the request window in front while it runs. No cookies or transcript files are exported, and it does not start playback. The Chromium backend and its temporary signed-out session remain the default on other installations.
Optional ChatGPT connection
For opt-in signed-in caption discovery, set YOUTUBE_COOKIES_BROWSER=chrome (or another browser listed in .env.example) in your private local environment, then rebuild and restart. You must also set YOUTUBE_COOKIES_PROFILE to an explicit dedicated profile directory to avoid selecting your everyday profile. yt-dlp reads that browser's local session without exporting a cookie file. macOS may request Keychain access for Chromium cookie decryption. Cookie values are never included in MCP results or diagnostics. This does not change playlist OAuth or the separate signed-out browser fallback.
Keep this server and .env on the Mac. Create an OpenAI Secure MCP Tunnel, run tunnel-client where it can reach the built stdio server, and register the tunnel endpoint in ChatGPT Developer Mode. The tunnel lets ChatGPT reach a private MCP server without a public listener; it is not a public plugin-distribution path.
For an optional persistent macOS setup, see the ChatGPT tunnel runbook. It uses a private runtime-key file and a user LaunchAgent so the tunnel starts again after login and stays available while the Mac is awake and online.
Tool handlers emit JSON timing entries to stderr: tool_start, tool_pending every 15 seconds while running, and tool_end with a success, error, or exception outcome. Entries contain a UTC timestamp, tool name, generated request ID, and elapsed milliseconds; they exclude arguments, response content, and exception details. In the persistent tunnel setup, these entries go to the configured error log. A start without an end identifies an unfinished handler; no start means the request has not reached a tool handler (including requests rejected before handler execution). Timing logs become active after rebuilding and restarting the server.
Do not commit the Google API key, OAuth client credentials, OpenAI runtime key, generated tunnel configuration, or local token file.
Privacy and API terms
This server runs locally. It does not include telemetry, a hosted backend, or a shared credential service. OAuth tokens are stored only in the local token file described above, and YouTube API requests use the credentials configured by the local user.
Users are responsible for their own Google Cloud projects and compliance with the YouTube API Services Terms of Service and YouTube Developer Policies. Caption tools use yt-dlp only to retrieve YouTube-exposed caption tracks; caption availability and extraction behavior can change without notice.
Verification
pnpm format:check
pnpm lint
pnpm typecheck
pnpm test
pnpm build
pnpm transcript:doctor
pnpm auth:status
pnpm smokepnpm smoke makes live read-only requests. It uses YOUTUBE_SMOKE_URL when set; otherwise it uses a default public video. Set YOUTUBE_SMOKE_COMMENTS_URL when you need to require a comments-enabled smoke target, and YOUTUBE_SMOKE_TRANSCRIPT_URL to verify a caption-enabled transcript target.
Available Tools
17 toolsyoutube_add_playlist_videoAdd Video to YouTube PlaylistC
Adds a public video to a playlist owned by the authenticated channel.
Inputs: url (required), video_url (required), position.
youtube_create_playlistCreate YouTube PlaylistB
Creates a playlist owned by the authenticated channel. New playlists default to private.
Inputs: title (required), description, privacy_status.
youtube_find_commentsFind YouTube CommentsA
Finds literal terms across an explicit bounded number of comment pages. Results always describe retrieved pages only, never every comment on the video.
Inputs: url (required), maxPages (required), matchTerms (required), limit, +3 more.
youtube_get_authenticated_channelGet Authenticated YouTube ChannelA
Gets the YouTube channel attached to the local OAuth session.
Inputs: no named parameters.
youtube_get_channelGet YouTube ChannelA
Gets normalized public metadata for a YouTube channel URL using /channel/CHANNEL_ID or /@handle.
Inputs: url (required).
youtube_get_channel_videosGet YouTube Channel VideosB
Gets one explicit page of recent public uploads from a YouTube channel URL.
Inputs: url (required), limit, pageToken.
youtube_get_commentsGet YouTube CommentsC
Gets one explicit page of public YouTube comment threads. matchTerms only filters the retrieved page, not every comment on the video.
Inputs: url (required), limit, order, pageToken, +2 more.
youtube_get_owned_playlist_itemsGet Owned YouTube Playlist ItemsA
Gets one explicit item page from a playlist owned by the authenticated channel.
Inputs: url (required), limit, pageToken.
youtube_get_playlist_itemsGet Public YouTube Playlist ItemsA
Gets one explicit page of a public YouTube playlist, including item IDs and positions.
Inputs: url (required), limit, pageToken.
youtube_get_transcriptGet YouTube TranscriptB
Gets one explicit page of timestamped creator or automatic YouTube caption segments.
Inputs: url (required), cursor, language, maxSegments.
youtube_get_videoGet YouTube VideoA
Gets normalized public metadata for a YouTube video URL.
Inputs: url (required).
youtube_list_owned_playlistsList Owned YouTube PlaylistsA
Gets one explicit page of playlists owned by the authenticated channel.
Inputs: limit, pageToken.
youtube_list_transcript_languagesList YouTube Transcript LanguagesB
Lists creator and automatic caption tracks exposed for a YouTube video.
Inputs: url (required).
youtube_remove_playlist_itemRemove YouTube Playlist ItemA
Removes one exact item from an owned playlist. Requires confirm: true.
Inputs: url (required), confirm (required), playlist_item_id (required).
youtube_reorder_playlist_itemReorder YouTube Playlist ItemA
Moves one exact item in an owned playlist. Requires confirm: true.
Inputs: url (required), confirm (required), position (required), playlist_item_id (required).
youtube_search_videosSearch YouTube VideosA
Searches one explicit page of public YouTube videos and returns normalized metadata.
Inputs: query (required), limit, order, pageToken.
youtube_update_playlistUpdate YouTube PlaylistB
Updates metadata on a playlist owned by the authenticated channel.
Inputs: url (required), title, description, privacy_status.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 17 tools
Each tool targets a distinct resource/action, but some potential confusion exists between get_owned_playlist_items and get_playlist_items, and between find_comments and get_comments. Descriptions clarify the differences, making misselection unlikely but possible.
All tool names follow a consistent youtube_verb_noun pattern, using clear verbs like get, list, create, update, add, remove, reorder, search, and find. No mixing of conventions or vague names.
With 17 tools, the set is slightly above the ideal 3-15 range, but the tools cover a broad yet focused set of YouTube features (playlists, videos, transcripts, comments). The count is reasonable for the apparent scope.
The tool set covers major lifecycle operations for playlists (create, update, add, remove, reorder) and provides video, channel, transcript, and comment retrieval. A notable gap is the lack of a delete playlist tool, which is a minor but real omission.
Maintenance
Related MCP Connectors
Real-time YouTube transcripts, comments, channels & video search MCP. Local npx or hosted OAuth.
YouTube MCP — wraps the YouTube Data API v3 (BYO API key)
YouTube transcripts, search, channel browsing, and playlists for AI agents via MCP.
Hosted MCP for YouTube Studio: uploads, metadata, playlists, comments, analytics, captions.
Related MCP Servers
- AlicenseAqualityBmaintenanceHigh-efficiency YouTube MCP server: Get token-optimized, structured data for your LLMs using the YouTube Data API v3.92,236 npm33MIT
- AlicenseBqualityDmaintenanceLocal read-only MCP server for YouTube Data API v3 and YouTube Analytics API, enabling public video searches and OAuth-based private channel reads.9MIT
- AlicenseAqualityDmaintenanceA Model Context Protocol server enabling AI language models to search, retrieve, and manage YouTube content including videos, channels, transcripts, and playlists.10403 npmMIT
- AlicenseNot gradedqualityCmaintenanceA local, privacy-first MCP server providing direct access to official YouTube Data, Analytics, Reporting, and Live Streaming APIs for creators, enabling channel analysis, research, and guarded management operations.3MIT