YouTube MCP

السجل الرسمي البحث والويب

Independent, unofficial project for YouTube metadata, transcripts, comments, and search.

ماذا يمكنك أن تفعل مع YouTube MCP؟

  • content: short human-readable text for chat-style MCP clients
  • structuredContent: JSON-shaped data for agents that need reliable fields

التثبيت

أضف هذا إلى إعدادات MCP في عميلك (Claude Desktop: claude_desktop_config.json، وCursor: ‏.cursor/mcp.json، ويستخدم VS Code وغيره الصيغة نفسها «mcpServers»).

NPM package @granitebps/youtube-mcp
Claude Code
claude mcp add youtube-mcp -e 'YT_PROVIDER=innertube' -e 'YOUTUBE_API_KEY=<your youtube_api_key>' -- npx -y @granitebps/youtube-mcp@1.1.1
إعداد JSON (Claude Desktop وCursor وVS Code)
{
    "mcpServers": {
        "youtube-mcp": {
            "command": "npx",
            "args": [
                "-y",
                "@granitebps/youtube-mcp@1.1.1"
            ],
            "env": {
                "YT_PROVIDER": "innertube",
                "YOUTUBE_API_KEY": "<your youtube_api_key>"
            }
        }
    }
}

متغيرات البيئة

  • YT_PROVIDER Video info/comments/search: "innertube" (default, unofficial, no key) or "api" (official YouTube Data API v3). Transcripts always use unofficial youtube-transcript-plus.
  • YOUTUBE_API_KEY سري Your own YouTube Data API v3 key (BYOK). Required when YT_PROVIDER is "api"; not used for transcripts.

التوثيق

مأخوذ من ملف README للمشروع على GitHub ويُحدَّث أسبوعيًا. تفتح الروابط على GitHub.

المحتويات
  1. YouTube MCP
  2. Access model
  3. Features
  4. Requirements
  5. Quick start
  6. Run from a cloned repository
  7. Client configuration
  8. VPS deployment (Streamable HTTP)
  9. Usage Examples
  10. Tool Response Format
  11. Providers
  12. Configuration
  13. Tool Details
  14. Development
  15. Release verification
  16. Rate Limits
  17. License

YouTube MCP

YouTube MCP lets an MCP client read YouTube video metadata, caption transcripts, comments, and search results. By default it needs no YouTube API key or account; an optional official YouTube Data API provider serves metadata, comments, and search with an API key.

Supports both stdio (local) and Streamable HTTP (VPS/remote) transports.

Access model

This is an independent, unofficial open-source project. It is not affiliated with, endorsed by, or sponsored by YouTube or Google.

  • The default innertube provider serves metadata, comments, and search through youtubei.js, using an unofficial/internal YouTube interface without a YouTube Data API key. Unofficial access may change, break, be restricted, or be blocked.
  • Select YT_PROVIDER=api and supply your own YOUTUBE_API_KEY to use the official YouTube Data API v3 for those three tools.
  • Transcript tools always use youtube-transcript-plus, regardless of YT_PROVIDER. Transcript retrieval remains unofficial and does not use the official Data API path or your API key.

Users are responsible for deciding whether an access method suits their use and for complying with applicable service terms and law. See access methods and service terms for the tool/backend mapping, BYOK setup, limitations, and software licenses.

Features

ToolDescription
search_youtubeSearch videos with filters for upload date and popularity
get_video_infoVideo metadata: title, channel, description, duration, views, likes, upload date, tags
get_video_commentsComment threads with author info, likes, and the replies YouTube includes
get_video_transcriptTranscripts (manual + auto-generated captions) with timestamps
get_transcript_languagesLists available manual and auto-generated caption languages
get_server_infoServer version, active provider, and the backend serving each tool

Requirements

  • Node.js 22 or newer. CI checks Node 22.21.0 and Node 24.

No YouTube API key required by default. The default innertube provider uses youtubei.js (an unofficial/internal YouTube interface) for video info, comments, and search. Transcripts always use youtube-transcript-plus. Neither needs an API key or authentication. See Providers for the optional official API.

Quick start

Your MCP client can run the published package without a clone:

npx -y @granitebps/youtube-mcp

The server uses stdio. Keep stdout reserved for MCP traffic.

Run from a cloned repository

To develop the server or use a clone directly:

git clone https://github.com/granitebps/youtube-mcp.git
cd youtube-mcp
npm ci
npm run build

Point your MCP client at the compiled entry point:

node /absolute/path/to/youtube-mcp/dist/index.js

Run npm run build after each source change. Do not use src or npm run dev as the client's stdio command; build output on stdout can corrupt MCP messages.

Client configuration

Each example starts with the npm package, followed by the local equivalent. Replace /absolute/path/to/youtube-mcp with your clone's path. Settings from Configuration can be added as environment variables.

Claude

Add the npm package to Claude Code:

claude mcp add youtube -- npx -y @granitebps/youtube-mcp

For a local build:

claude mcp add youtube -- node /absolute/path/to/youtube-mcp/dist/index.js

Claude Code uses local scope by default. Add --scope user before youtube to make the server available across projects.

Claude Desktop reads the same server from claude_desktop_config.json (on macOS, ~/Library/Application Support/Claude/claude_desktop_config.json). Restart the app after editing the file.

{
  "mcpServers": {
    "youtube": {
      "command": "npx",
      "args": ["-y", "@granitebps/youtube-mcp"]
    }
  }
}

For a local build, replace command and args with:

{
  "command": "node",
  "args": ["/absolute/path/to/youtube-mcp/dist/index.js"]
}
Codex

Add the npm package to ~/.codex/config.toml, or to .codex/config.toml in a trusted project:

[mcp_servers.youtube]
command = "npx"
args = ["-y", "@granitebps/youtube-mcp"]

For a local build:

[mcp_servers.youtube]
command = "node"
args = ["/absolute/path/to/youtube-mcp/dist/index.js"]

Restart Codex after editing the file.

OpenCode

Add the npm package to opencode.json or opencode.jsonc:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "youtube": {
      "type": "local",
      "command": ["npx", "-y", "@granitebps/youtube-mcp"],
      "enabled": true
    }
  }
}

For a local build, replace the command array with:

{
  "command": ["node", "/absolute/path/to/youtube-mcp/dist/index.js"]
}
Cursor

Add the npm package to .cursor/mcp.json in a project, or to ~/.cursor/mcp.json for global use:

{
  "mcpServers": {
    "youtube": {
      "command": "npx",
      "args": ["-y", "@granitebps/youtube-mcp"]
    }
  }
}

For a local build, replace command and args with:

{
  "command": "node",
  "args": ["/absolute/path/to/youtube-mcp/dist/index.js"]
}
GitHub Copilot (VS Code)

Add to your VS Code settings.json:

{
  "mcp": {
    "servers": {
      "youtube": {
        "command": "npx",
        "args": ["-y", "@granitebps/youtube-mcp"]
      }
    }
  }
}

VPS deployment (Streamable HTTP)

For remote deployment, the server runs as a persistent HTTP service using the Streamable HTTP transport (the current MCP standard, replacing the deprecated SSE transport).

1. Deploy to your VPS
# On your VPS
git clone https://github.com/granitebps/youtube-mcp.git
cd youtube-mcp
npm ci
npm run build

# Create .env (optional, for HTTP mode)
cp .env.example .env
# Uncomment TRANSPORT=http, PORT, HOST as needed

YouTube often blocks datacenter IPs. If get_video_info returns ACCESS_BLOCKED with "Sign in to confirm you're not a bot", set YT_PROVIDER=api and YOUTUBE_API_KEY to serve metadata, comments, and search through the official API. See Providers.

2. Run with HTTP transport
# Using --http flag
node dist/index.js --http

# Or using environment variable
TRANSPORT=http PORT=3000 node dist/index.js

# Or using npm script
npm run start:http

The server will listen on http://0.0.0.0:3000/mcp.

3. Set up Nginx reverse proxy with TLS
server {
    listen 443 ssl;
    server_name mcp.yourdomain.com;

    ssl_certificate     /etc/letsencrypt/live/mcp.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mcp.yourdomain.com/privkey.pem;

    location /mcp {
        proxy_pass http://127.0.0.1:3000/mcp;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Required for SSE streaming
        proxy_set_header Connection '';
        proxy_buffering off;
        proxy_cache off;
        chunked_transfer_encoding on;
    }
}

Get a free TLS certificate:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d mcp.yourdomain.com
4. Keep it running with systemd

Create /etc/systemd/system/youtube-mcp.service:

[Unit]
Description=YouTube MCP Server
After=network.target

[Service]
Type=simple
User=your_user
WorkingDirectory=/path/to/youtube-mcp
ExecStart=/usr/bin/node dist/index.js --http
Restart=always
RestartSec=5
Environment=TRANSPORT=http
Environment=PORT=3000
Environment=HOST=127.0.0.1

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable youtube-mcp
sudo systemctl start youtube-mcp
sudo systemctl status youtube-mcp
5. Connect MCP clients to your VPS
GitHub Copilot (VS Code) — Remote
{
  "mcp": {
    "servers": {
      "youtube": {
        "type": "http",
        "url": "https://mcp.yourdomain.com/mcp"
      }
    }
  }
}
Claude Desktop — Remote
{
  "mcpServers": {
    "youtube": {
      "type": "streamable-http",
      "url": "https://mcp.yourdomain.com/mcp"
    }
  }
}

Usage Examples

Once connected, you can ask your AI agent things like:

  • *"Get info about this YouTube video: https://www.youtube.com/watch?v=dQw4w9WgXcQ"*
  • "Show me the top comments on video ID abc123"
  • "Get the transcript of this video in English"
  • *"Summarize the transcript of https://youtu.be/xyz789"*
  • "Search for Node.js tutorials uploaded this week, sorted by views"
  • "Find the most popular React videos from the last month"

Tool Response Format

All tools return:

  • content: short human-readable text for chat-style MCP clients
  • structuredContent: JSON-shaped data for agents that need reliable fields

The server is intentionally JSON-first, text-second. Agents should prefer structuredContent when they need to filter, transform, or chain tool results.

Example shape from get_video_info:

{
  "content": [
    {
      "type": "text",
      "text": "📹 Example title\n\nChannel: Example channel\n..."
    }
  ],
  "structuredContent": {
    "videoId": "dQw4w9WgXcQ",
    "title": "Example title",
    "description": "Example description",
    "channelName": "Example channel",
    "channelId": "UC123",
    "uploadedAt": "Sep 14, 2017",
    "duration": "3m 33s",
    "durationSeconds": 213,
    "viewCount": "123456",
    "likeCount": "7890",
    "commentCount": null,
    "tags": ["music", "pop"],
    "thumbnailUrl": "https://..."
  }
}

Values YouTube did not provide are null, never placeholders such as "0", "N/A" or "Unknown".

Errors

Failures return isError: true. The text starts with a code (❌ [ACCESS_BLOCKED] ...) and _meta["youtube-mcp/error"] carries the details:

{
  "isError": true,
  "content": [{ "type": "text", "text": "❌ [ACCESS_BLOCKED] YouTube requires sign-in to access video C7OQHIpDlvA: Sign in to confirm you’re not a bot" }],
  "_meta": {
    "youtube-mcp/error": {
      "code": "ACCESS_BLOCKED",
      "message": "...",
      "retryable": false,
      "upstream": { "playabilityStatus": "LOGIN_REQUIRED", "reason": "Sign in to confirm you’re not a bot", "accessKind": "login_required" }
    }
  }
}

The error is in _meta, not structuredContent, because MCP SDK clients validate any structuredContent against the tool's output schema, even on error results.

CodeMeaning
INVALID_INPUTNot a YouTube URL or 11-character video ID, or an invalid language code
ACCESS_BLOCKEDYouTube refused this client: HTTP 429/403, CAPTCHA, consent page, sign-in or bot check. upstream.accessKind is rate_limited, forbidden, login_required, consent_required, or quota_exceeded (official API quota used up). Says nothing about whether the video exists or has captions
VIDEO_UNAVAILABLEYouTube reports the video as ERROR, UNPLAYABLE, private or offline. upstream.reason is YouTube's own text
CAPTIONS_UNAVAILABLE / LANGUAGE_UNAVAILABLEUsed internally; transcript tools return these as available: false results, not errors
COMMENTS_UNAVAILABLEComments are disabled or YouTube returned no comments section
PARSE_ERRORYouTube answered but the response could not be interpreted (layout change, wrong video ID returned)
LIMIT_EXCEEDEDA configured size limit was hit
TIMEOUTA configured deadline expired; the underlying requests were aborted
CANCELLEDThe MCP client cancelled the request, or the server is shutting down
UPSTREAM_ERROROther HTTP or network failure (retryable: true)

The server never retries on its own.

Providers

YT_PROVIDER selects the backend for get_video_info, get_video_comments, and search_youtube. get_video_transcript and get_transcript_languages always use youtube-transcript-plus, whichever provider is active. get_server_info reports the active provider.

ProviderSelect withNeedsNotes
InnerTubeDefault, or YT_PROVIDER=innertubeNothingUses an unofficial/internal interface through youtubei.js, with no Data API key. YouTube may restrict or block access, including from datacenter IPs (VPS, cloud)
Official APIYT_PROVIDER=apiYOUTUBE_API_KEYUses the YouTube Data API v3. Subject to your Google Cloud project's quota, key restrictions, and applicable service terms

This server does not use the Data API for captions. Google's caption-download endpoint requires OAuth authorization and permission to edit the video; an API key alone is insufficient. Transcript tools use the unofficial youtube-transcript-plus path and can return ACCESS_BLOCKED with either provider.

Using the official API

Bring your own key (BYOK). The key belongs to you; the project does not distribute or host a shared YouTube API key. Supply these settings through the process or MCP client environment; the server does not automatically load .env files.

  1. In the Google Cloud console, create a project, enable YouTube Data API v3, and create an API key. Restricting the key to that API is recommended.
  2. Start the server with:
YT_PROVIDER=api YOUTUBE_API_KEY=your_api_key npx -y @granitebps/youtube-mcp

Quota (costs): the default allocation is 10,000 units per day, plus a separate allowance of 100 search.list calls per day.

ToolAPI calls
get_video_infovideos.list: 1 unit
get_video_commentscommentThreads.list: 1 unit per page. page: N walks the N-1 pages before it, so it costs N units
search_youtubesearch.list (search allowance) plus one videos.list for views and durations: 1 unit

Results are cached as with the default provider (video info 30 min, comments 10 min, search 15 min), so repeated calls cost nothing. A used-up quota returns ACCESS_BLOCKED with upstream.accessKind: "quota_exceeded"; an invalid key or disabled API returns ACCESS_BLOCKED with accessKind: "forbidden".

Differences from the default provider:

  • uploadedAt (get_video_info) and publishedAt (comments, search) are ISO 8601 timestamps instead of display text such as "Sep 14, 2017" or "2 days ago"
  • Search viewCount is a plain number such as "1234" instead of "1.2K views", and duration uses the same format as get_video_info ("3m 5s")
  • search_youtube applies all sortBy and uploadDate values exactly and never returns warnings. videoDuration: "short" means under 4 minutes and medium 4 to 20 minutes (YouTube's API definitions)
  • get_video_comments returns only the replies the API includes with each thread (a subset); replyCount is the full count

Configuration

All settings are optional environment variables, except YOUTUBE_API_KEY when YT_PROVIDER=api. Invalid values stop the server at startup with a message on stderr.

VariableDefaultEffect
YT_PROVIDERinnertubeProvider for video info, comments, and search: innertube or api. See Providers
YOUTUBE_API_KEYnoneYour own YouTube Data API v3 key. Required when YT_PROVIDER=api, ignored otherwise
YT_INIT_TIMEOUT_MS15000Deadline for creating the shared YouTube client
YT_REQUEST_TIMEOUT_MS20000Deadline for one tool call's upstream work, including waiting for client init
YT_TRANSCRIPT_MAX_BYTES5000000Maximum bytes read from each response fetched for captions
YT_TRANSCRIPT_MAX_SEGMENTS50000Maximum caption segments processed from one track
YT_TRANSCRIPT_PAGE_MAX_SEGMENTS500Maximum segments returned in one get_video_transcript response

When a deadline expires or the client cancels, the in-flight HTTP requests are aborted, not just abandoned.

Tool Details

search_youtube
  • Input: query (search text), maxResults (1-50, default 10), sortBy (relevance | date | viewCount | rating), uploadDate (any | hour | today | week | month | year), videoDuration (any | short | medium | long)
  • Returns: Human-readable summary in content plus structured JSON results in structuredContent
  • Note: With the default innertube provider, YouTube search only orders by relevance or popularity and only filters uploads from today up. sortBy: "date" keeps relevance order, sortBy: "rating" sorts by popularity, and uploadDate: "hour" is applied as today. Each case adds an entry to the optional warnings array (code, message). The api provider applies every option exactly
get_video_info
  • Input: video (YouTube URL or video ID)
  • Returns: Human-readable summary in content plus structured JSON metadata in structuredContent, including durationSeconds. Metadata is returned even when YouTube refuses playback, as long as it provides the video details
get_video_comments
  • Input: video (URL or ID), maxResults (1-20, default 20), sortBy (relevance or time), page (default 1)
  • Returns: Human-readable summary in content plus structured JSON comment threads, pagination fields, and hasMore in structuredContent
  • Note: replies contains only replies YouTube includes with the thread; replyCount is the full count. Fetching the rest would cost one request per thread
get_video_transcript
  • Input: video (URL or ID), lang (optional language code; omitted means the first manual track, or the first auto-generated one if there is none), maxSegments (default 0: as many as YT_TRANSCRIPT_PAGE_MAX_SEGMENTS allows), startSegment (default 0)
  • Returns: Human-readable transcript in content plus structured JSON segments, plain text, and pagination metadata in structuredContent. Continue with startSegment = nextStartSegment and the returned languageCode as lang while hasMore is true. isAutoGenerated tells whether the track is YouTube's automatic captions
  • No captions: available: false with reason: "NO_CAPTIONS", or reason: "LANGUAGE_UNAVAILABLE" plus availableLanguages. Access problems are errors, never available: false
  • Note: When a language has both manual and automatic tracks, the manual track is returned
  • Note: Does NOT require an API key — works via YouTube's internal caption system. A transcript is caption text only; it is not an analysis of the video's picture
get_transcript_languages
  • Input: video (YouTube URL or video ID)
  • Returns: Human-readable language list in content plus structured JSON language metadata in structuredContent. available: false means the video is playable and has no caption tracks; access problems are errors
get_server_info
  • Input: none
  • Returns: name, version, provider (innertube or api), authenticated, exactSearchFilters, and tools, a map from each tool to the backend serving it

Development

npm test        # builds, then runs the offline test suite (no network access)
npm run check   # tests plus release metadata, package contents, and tarball install checks

See CONTRIBUTING.md.

Release verification

The automated suite covers input parsing, configuration, error classification, cancellation, the compiled stdio entry point, release metadata, and installation from an npm tarball. It never calls YouTube. Live YouTube checks are manual and separate from CI.

Maintainers follow the release guide for the approved-tag npm, MCP Registry, and GitHub release process.

Rate Limits

The default innertube provider and transcript tools use unofficial YouTube interfaces. They do not use the Data API quota system, but this does not imply unrestricted access:

  • Heavy automated usage may trigger CAPTCHAs or temporary blocks
  • Requests from datacenter IPs (VPS, cloud) are often blocked outright
  • Request pacing does not guarantee access or establish permission under service terms

The api provider is limited by your Google Cloud project's YouTube Data API quota instead. See Providers.

License

ISC. The software license is separate from YouTube/Google service terms and rights in retrieved content. See the access guide.

الأسئلة الشائعة

ما هو YouTube MCP؟

Independent, unofficial project for YouTube metadata, transcripts, comments, and search.

كيف أثبّت YouTube MCP؟

يعمل على جهازك. في Claude Code: claude mcp add youtube-mcp -e 'YT_PROVIDER=innertube' -e 'YOUTUBE_API_KEY=<your youtube_api_key>' -- npx -y @granitebps/youtube-mcp@1.1.1. وفي العملاء الآخرين، الصق إعداد JSON من هذه الصفحة في إعدادات MCP الخاصة بهم.

هل يحتاج YouTube MCP إلى مفتاح API؟

نعم. يتطلب YOUTUBE_API_KEY، وتضبطها في إعداداته.

هل YouTube MCP مفتوح المصدر؟

نعم. شيفرته متاحة على GitHub بترخيص ISC.

من يصون YouTube MCP؟

ينشره granitebps. يدرجه AI.tn لكنه لا يصونه ولا يوصي به.

من سجل MCP الرسمي. الإدراج ليس توصية: راجع شيفرة الخادم وصلاحياته قبل منحه الوصول إلى بياناتك.