youtube-codemode-mcp
Lets Claude operate a YouTube channel by writing short JavaScript programs against a bundled yt client. Covers the YouTube Data API v3, Analytics API v2, and Reporting API v1: listing uploads, videos, playlists, playlist items, comments, and captions; reading video stats and Analytics metrics/dimensions with filters, sorting, and grouping; uploading, updating, deleting videos and setting thumbnails; posting, replying to, and deleting comments; managing Reporting jobs and downloading reports; plus fetching transcripts of public videos and search autocomplete. Read-only and destructive/public actions are supported, with deletes, uploads, comments, and public-visibility changes requiring explicit confirmation. It also tracks YouTube API quota usage across runs and supports public Data API reads via an API key when not signed in.
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-codemode-mcplist my recent uploads with views and likes"
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-codemode-mcp
An MCP server that lets Claude work with your YouTube channel by writing code. It exposes three tools:
Tool | What it does |
| Guides for the |
| Runs JavaScript against the bundled YouTube API specs to find methods and parameters. No network. |
| Runs JavaScript against your channel through a |
Instead of calling 40 narrow tools one at a time, Claude writes one short program: list your uploads, pull their stats, join Analytics, and return a summary. That takes one round trip.
const { rows } = await yt.analytics.query({
metrics: "views,averageViewDuration",
dimensions: "video",
filters: "creatorContentType==shorts",
sort: "-views",
maxResults: 10,
});
const { items } = await yt.data.videos.list({ part: "snippet", id: rows.map((r) => r.video) });
return rows.map((r, i) => ({ title: items.find((v) => v.id === r.video)?.snippet.title, ...r }));It covers the YouTube Data API v3, Analytics v2, and Reporting v1, plus transcripts of public videos and search autocomplete.
Requirements
Node.js 20 or newer
macOS or Linux.
workerdalso ships for Windows x64, but this server has not been tested there.A Google Cloud project with an OAuth client
Related MCP server: youtube-research
Install
Nothing to install up front. Claude starts the server with npx, as shown in Add it to Claude.
To run from source instead:
git clone https://github.com/poamslayer/youtube-codemode-mcp.git
cd youtube-codemode-mcp
npm install
npm run buildThis puts the server at dist/index.js.
Set up Google OAuth
In Google Cloud Console, create or pick a project.
Enable YouTube Data API v3, YouTube Analytics API, and YouTube Reporting API.
Configure the OAuth consent screen. While the app is in testing, add your channel's Google account as a test user.
Under Credentials, create an OAuth client ID of type Desktop app.
Download the JSON and save it as
~/.youtube-mcp/client_secret.json.
The first time Claude calls YouTube, a consent page opens in your browser. Sign in with the account that owns the channel. Manager accounts cannot read Analytics. Approve every permission, then ask Claude to retry.
Add it to Claude
Claude Code:
claude mcp add youtube -- npx -y youtube-codemode-mcpClaude Desktop, in claude_desktop_config.json:
{
"mcpServers": {
"youtube": {
"command": "npx",
"args": ["-y", "youtube-codemode-mcp"]
}
}
}From source, use node /absolute/path/to/youtube-codemode-mcp/dist/index.js as the command instead.
Configuration
Variable | Default | Purpose |
|
| Where the token, client secret, and quota ledger live |
|
| Path to the OAuth client JSON |
| unset | Used for public Data API reads when you have not signed in |
| unset | If set, uploads and thumbnails may only read files inside this folder |
Safety
Credentials stay on the host. Model code runs in a workerd isolate with
globalOutbound: null. It cannot reach the network, read environment variables, or read your files. Its only way out is theytclient, which goes through the host.Destructive and public actions need confirmation. Deletes, uploads, comments, thumbnails, captions, Reporting jobs, live transitions, and anything that sets a video or playlist to public return a dry run and send nothing unless the code passes
{ confirm: true }.Quota is tracked before each call. The ledger lives in
~/.youtube-mcp/quota.json, keyed by Google project and Pacific-time day, with three buckets: 10,000 units, 100 searches, and 100 uploads. PassquotaBudgettoexecuteto cap a single run.Limits per run. 60 seconds of wall clock (upload time excluded), 500
ytcalls, and 100 KB of returned JSON.
Migrating from the Python version (0.x, 40 tools)
Version 1.0 is a rewrite in TypeScript, and the tool surface is different. The 40 tools are gone, and Claude now writes code against yt. docs("analytics") and the other guides hold the same recipes the old tools ran.
Your sign-in carries over. The server reads the same
~/.youtube-mcp/token.jsonandclient_secret.json, in the same format.Change your client config. It used to run
youtube-studio-mcpinstalled with pip or uv. The npm package is namedyoutube-codemode-mcp, and it runs withnpxas shown above.Quota now persists across restarts. The Python version kept it in memory.
Search costs follow Google's 2026 model.
search.listuses one of 100 daily search calls instead of 100 units.Transcripts use the same unofficial method as
youtube-transcript-api. Automatic translation is gone, because YouTube now rate-limits it. When a language is missing, the transcript comes back in another language with a note.
Old tool | Now |
|
|
| Uploads playlist recipe in |
|
|
| Recipes in |
|
|
|
|
|
|
|
|
|
|
|
|
| Sign-in starts on the first call. |
Development
npm test # unit and sandbox integration tests
npm run typecheck
npm run fetch-specs # refresh the Discovery docs in specs/
node scripts/fetch-analytics-fields.mjs # refresh Analytics metrics and dimensions
npm run check-guides # run every guide recipe against your signed-in channel (uses real quota)
ACCEPT_VIDEO_ID=<your video> node scripts/acceptance.mjs # end-to-end acceptance checks (uses real quota)src/host holds the Node side: the MCP server, OAuth, quota, the op registry built from the Discovery docs, and the bridge the sandbox calls. sandbox/ holds the workerd config, the supervisor that loads each run into a fresh isolate, and the yt client that runs inside it. Each execute call spawns its own workerd process, which takes about 13 ms to start, and kills it when the run ends or hits its deadline.
License
MIT
Available Tools
3 toolsdocsA
Guides for the yt client used by execute(): the API surface, quota rules, analytics recipes, publishing gotchas, and error reasons. Read docs("overview") before the first execute() call. Topics: analytics, auth, comments, discovery, overview, playlists, publishing, quota, reporting, transcripts.
| Name | Required | Description | Default |
|---|---|---|---|
| topic | No | Omit for the topic index. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does disclose that this is a read-only informational surface with no side effects. It conveys content coverage (quota rules, error reasons, gotchas) but does not state anything about return format or behavior for an unknown topic.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with what the tool is, followed by the usage rule and an itemized topic list. Every sentence earns its place with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter documentation tool with no output schema or annotations, the description covers what it is, when to use it, and what topics exist. It is essentially complete, with only minor gaps around return shape.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100% ('Omit for the topic index'), but the single schema param has no enum. The description supplies the full list of valid topic values, adding genuine meaning beyond the schema and functions as an informal enum.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It states a specific resource (guides for the yt client) and grounds it against a named sibling, execute(). The enumerated topics make the scope concrete, so an agent can tell this is the documentation-retrieval tool rather than a search or action tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear ordering rule ('Read docs("overview") before the first execute() call') and enumerates topics, which implicitly routes needs like quota or publishing to the matching topic. It lacks explicit when-not/alternative guidance versus the search sibling, but the usage context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
executeA
Run a JavaScript async function body against the user's YouTube channel. Call docs() first for recipes, quota rules, and gotchas. Use search() to look up method parameters.
The yt client:
yt.data..(params, body?, { confirm? }) YouTube Data API v3, e.g. yt.data.videos.list({ part: "snippet,statistics", id: ["a", "b"] })
yt.analytics.query(params) YouTube Analytics v2 reports.query; ids defaults to channel==MINE, dates to the last 28 days; returns { columns, rows: object[] }
yt.reporting..(params, body?) YouTube Reporting v1
yt.reporting.download(downloadUrl, { maxChars? }) CSV text of a report, default cap 50,000 chars
yt.paginate(fn, params, { max }) follows nextPageToken, returns items
yt.transcript(videoId, { lang? }) captions of any public video, no quota: { language, isGenerated, fullText, segments, available }
yt.suggest(query, { lang? }) YouTube search autocomplete, no quota
yt.upload(absPath, { snippet, status }, { confirm }) resumable upload from local disk
yt.setThumbnail(videoId, absPath, { confirm }) JPEG or PNG, 2 MB max
yt.quota() yt.auth.status()
Confirm gate: deletes, uploads, comments, thumbnails, captions, reporting jobs, live transitions, and anything that sets privacyStatus to public return a dry run ({ dryRun, effect, wouldCall, cost }) and send nothing unless the call passes { confirm: true } as its last argument. Show the user the dry run and get approval before confirming. Helpers in scope: formatDuration(iso), durationSeconds(iso), isLikelyShort(iso), toRows(analyticsResponse).
Chain many calls in one program and return a compact, aggregated result. Errors thrown by yt carry status, reason (e.g. quotaExceeded, authRequired, invalidParams), and message, and can be caught. The sandbox has no network, env, or filesystem; credentials stay on the host. Limits: 60s wall clock, 500 yt calls, 100 KB of returned JSON.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Async function body. Use return. | |
| quotaBudget | No | Max Data API units this run may spend. Calls past it throw quotaBudgetExceeded and send nothing. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so thoroughly: the confirm gate enumerates exactly which operations dry-run (deletes, uploads, comments, thumbnails, captions, reporting jobs, live transitions, public privacyStatus), the dry-run return shape is given, error objects expose status/reason/message, and hard limits (60s, 500 calls, 100 KB) plus sandbox isolation and host-side credentials are disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence, the SDK surface is presented as a scannable aligned list, and the constraints are grouped into coherent paragraphs. Given the genuine complexity of the client, the length is largely earned, though the density is high and a couple of lines could be trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a high-complexity code-execution tool with no output schema, the description supplies everything an agent needs: the full client API, helper functions in scope, the confirmation workflow, error model, and execution limits. Nothing material about calling or interpreting the result is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for both parameters, so the schema already documents `code` and `quotaBudget`, including the quotaBudgetExceeded behavior. The description adds implicit intent ('Chain many calls in one program and return a compact, aggregated result') but no syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states a specific verb and resource: 'Run a JavaScript async function body against the user's YouTube channel.' It immediately separates itself from the docs and search siblings by naming them as prerequisites rather than alternatives, so an agent knows this is the execution surface and not a lookup surface.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly routes to the siblings: 'Call docs() first for recipes, quota rules, and gotchas' and 'Use search() to look up method parameters.' The confirm-gate paragraph also states the when-not condition for writing operations (dry run unless { confirm: true }), giving both usage and a control-flow constraint.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchA
Explore the YouTube API specs by running a JavaScript async function body. No network, no auth, no quota.
A global spec holds:
spec.youtube: Data API v3 Discovery doc. Methods live at spec.youtube.resources..methods., with httpMethod, parameters (description, required, repeated, enum), and request/response $ref schemas in spec.youtube.schemas.
spec.analytics: YouTube Analytics v2 Discovery doc (reports.query, groups, groupItems).
spec.analyticsFields: { metrics, dimensions } with descriptions, since the Analytics Discovery doc does not list them.
spec.reporting: YouTube Reporting v1 Discovery doc.
spec.quotaCosts: { "youtube.videos.list": { bucket, cost }, ... }.
Return only what you need. Examples: return Object.entries(spec.youtube.resources.videos.methods).map(([k, m]) => ({ k, params: Object.keys(m.parameters ?? {}) })) return spec.youtube.schemas.VideoSnippet.properties return Object.keys(spec.analyticsFields.metrics).filter((m) => /revenue/i.test(m))
Method ids found here map 1:1 to execute(): spec.youtube.resources.videos.methods.list is yt.data.videos.list(params).
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Async function body. Use return. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: 'No network, no auth, no quota' declares the sandbox constraints, and the global `spec` map tells the agent exactly what data is reachable. It omits error behavior, execution-time limits, and output-size limits, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in sentence one, constraints second, and the data map and examples follow in scannable bullets. Despite its length, every block supplies information needed to write a correct function body; there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex code-execution tool with no output schema and a single fully-documented parameter, the description covers environment constraints, available globals, return guidance, examples, and the hand-off to execute(). Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already explains `code` as 'Async function body. Use return.' The description goes well beyond that by documenting the global `spec` object, its sub-namespaces, and worked examples of valid function bodies, which is exactly the semantics an agent needs to author the parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence names a specific verb (explore), a specific resource (YouTube API specs) and the mechanism (running a JS async function body). It also states the relationship to the sibling execute() ('Method ids found here map 1:1 to execute()'), so an agent can separate discovery from invocation without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description establishes a clear context (exploration/discovery of specs) and explicitly routes the agent onward to execute() for actual calls, plus three concrete example queries. It does not, however, state when to prefer this over the 'docs' sibling or any when-not condition, so a small inference remains.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v1.0.0- First observed
docs - First observed
execute - First observed
search
TDQS
Scored across 3 tools
The three tools have distinguishable roles: docs provides static guides, search explores discovery specs offline, and execute runs authenticated calls against the channel. The only mild overlap is that both search and execute take a JavaScript function body, but the descriptions clearly separate them via 'no network, no auth, no quota' versus the live authenticated client.
All three names are single lowercase tokens (docs, search, execute) following one uniform convention, so there is no mixing of camelCase/snake_case or verb styles. Readable and predictable as a set.
Three tools is a deliberate code-mode design that collapses the entire YouTube Data/Analytics/Reporting surface into one dispatch tool, so the low count is justified rather than thin. It is slightly lean on the documentation/meta side, but each tool clearly earns its place.
Coverage is broad: Data v3, Analytics, Reporting, uploads, thumbnails, transcripts, autocomplete, pagination, and quota are all reachable, so no major domain gaps. The main omission is that auth is host-managed and only surfaced via yt.auth.status(), leaving no in-server login/setup operation.
Related MCP Connectors
YouTube transcripts, search, channel/playlist listings and upload tracking for AI agents.
YouTube transcripts, search, channels, playlists and bulk transcript jobs for AI agents. 14 tools.
AI YouTube analyst in Claude for creators: audit, fix, decide what to make next, grow subs.
Your YouTube library in Claude, ChatGPT and Cursor: transcripts, breakdowns, summaries, search.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables Claude to access and manage YouTube channel data through the YouTube Data API v3 and YouTube Analytics API. Provides tools for reading analytics, fetching video metadata, searching uploads, and updating video SEO directly from Claude.9 npm1MIT
- AlicenseAqualityDmaintenanceEnables YouTube integration with Claude Code, including video search, metadata retrieval, transcript fetching, channel exploration, and trending videos.81MIT
- FlicenseNot gradedqualityCmaintenanceEnables bringing YouTube into Claude Code for video transcripts, search, metadata, channel info, playlists, comments, trending videos, engagement analytics, chapters, SponsorBlock clean transcripts, and most-replayed heatmaps.22 npm-
- FlicenseAqualityCmaintenanceEnables Claude Code to access YouTube features such as video transcripts, search, metadata, channel info, playlists, comments, trending videos, engagement analytics, chapters, SponsorBlock, and most-replayed heatmaps.1522 npm1-