YouTube MCP Server
Provides tools for searching YouTube videos, channels, and playlists, reading video and comment data, and managing playlists, including creating private playlists and previewing mutations before applying them.
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 ServerTurn these songs into a private YouTube playlist, showing me matches first."
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 Server
An open-source Model Context Protocol (MCP) server for using YouTube from MCP clients such as Claude Desktop, Claude Code, and Codex.
The primary workflow is:
Give an MCP client a list of songs.
Review ranked YouTube matches before anything is changed.
Create a private playlist from the selected videos.
The server will also provide quota-conscious tools for searching YouTube and reading videos, channels, playlists, and comments.
The TypeScript package, stdio server, public and authenticated reads, PKCE OAuth, music preparation, confirmed new-playlist creation, and full previewed playlist mutations are implemented and tested. A prepared music draft can be committed to a new playlist or appended to an existing owned playlist.
Design goals
Safe playlist writes with preview-before-commit semantics.
Official YouTube Data API v3 endpoints only.
Bring-your-own Google OAuth client; the project never ships shared Google credentials.
Secrets stored in the operating-system keychain whenever possible.
Predictable quota use, pagination, caching, retries, and normalized errors.
Local
stdiotransport for simple installation and a small attack surface.Structured, bounded tool outputs that treat YouTube content as untrusted data.
Cross-platform TypeScript support on Node.js 20.17 or newer.
Related MCP server: yt-curator-mcp
Planned v1 scope
Read tools
Search videos, channels, and playlists.
Read video, channel, playlist, and comment data.
Read the authenticated user's channel, uploads, and playlists.
Return provider page tokens for explicit, stateless pagination.
Music playlist workflow
Accept up to 50 structured tracks per preparation request.
Search and rank likely YouTube music-video matches.
Show ambiguity and alternatives instead of silently choosing weak matches.
Commit explicitly selected matches to a new playlist or an existing owned playlist.
Default new playlists to
private.
Comment management
Post a top-level comment on a video, or reply to an existing comment.
Delete a comment, or set its moderation status, behind a preview and a one-time handle.
Uses the
youtube.force-sslscope already requested for playlist writes, so no additional consent is needed.
Playlist management
Create playlists and add videos.
Update playlist metadata or privacy.
Reorder or remove playlist items.
Delete playlists after a short-lived, one-time confirmation handle is issued.
Playlist updates, item removal/reordering, and deletion use two tools: youtube_prepare_playlist_mutation returns the exact diff and a 10-minute handle without writing; youtube_apply_playlist_mutation rechecks ownership and the playlist snapshot before consuming that handle once.
Video upload and lifecycle
Upload a local video file through a resumable upload, defaulting to
private.Update title, description, tags, or privacy on a video you own. Unspecified fields are carried forward rather than cleared.
Set a custom thumbnail from a local JPEG or PNG.
Preview and then permanently delete a video you own.
Video writes require the additional youtube.upload scope and refuse outright when a profile was authorized without it. youtube_plan_video_upload validates the file and reports the cost without contacting YouTube, because videos.insert costs 1600 units — about 16% of a default daily budget per upload. An upload is never retried: if the outcome is unknown, that is reported so you can check for a partial upload instead of publishing a duplicate.
Playlist, comment, and video management are the implemented write surfaces. Analytics reporting (0.8) is on the roadmap and is not callable yet. Ratings, subscriptions, and channel-settings writes remain permanently out of scope.
Setup
The npm package has not been published yet, so the server is built and run from a clone. Work through the steps in order.
Step 1 — check for Node.js and npm
node -v
npm -vIf node -v prints v20.17 or newer and npm -v prints a version, skip to Step 3. If either command reports "command not found", continue with Step 2.
Step 2 — install Node.js and npm (only if Step 1 failed)
npm ships with Node.js; installing Node installs both. Pick one row for your platform, then re-run Step 1 to confirm.
Platform | Command |
macOS (Homebrew) |
|
macOS / Windows / Linux (no package manager) | Download the LTS installer from nodejs.org/en/download and run it |
Windows (winget) |
|
Debian / Ubuntu |
|
Fedora / RHEL |
|
If you would rather not install Node system-wide, or you need several Node versions side by side, use a version manager:
# macOS and Linux
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
nvm install 22
nvm use 22On Windows the equivalent is nvm-windows: nvm install 22 then nvm use 22.
Close and reopen the terminal after installing, then re-run node -v and npm -v.
Step 3 — install dependencies and build
git clone <repository-url>
cd "Youtube MCP"
npm ci
npm run buildnpm ci installs the exact versions in package-lock.json; use npm install only when you intend to change dependencies. The build writes the executable to dist/cli/index.js, which every command below invokes.
Verify the build and the local data directory:
node dist/cli/index.js doctorStep 4 — create the Google credentials
Everything below comes from your own Google Cloud project. This project never ships shared Google credentials.
Create or select a project in the Google Cloud console.
Enable YouTube Data API v3 for that project.
Create an API key (Credentials → Create credentials → API key). This covers public reads.
Configure the OAuth consent screen. While the project is in Testing status, add your own Google account under Test users, or
loginwill be refused.Create an OAuth client of type Desktop app, then copy both its client ID and its client secret.
Google requires client_secret in the authorization-code exchange even for installed applications, so PKCE supplements the secret here rather than replacing it.
Step 5 — the credentials the server needs
Four credentials exist in total. You supply the first three; the fourth is obtained for you by login.
Credential | Needed for | Where it comes from | How you supply it | Where it is kept |
| Public reads (search, videos, channels, public playlists, comments) | Step 4.3 | Process environment only | Not persisted. It is read from the environment on every start, so an MCP client must pass it in each launch. |
| Any account action: reading your own playlists, creating playlists | Step 4.5 |
| Profile JSON in the data directory. It is not a secret. |
| The authorization-code exchange during | Step 4.5 |
| Operating-system keychain, per profile. Never written to the profile JSON. |
OAuth refresh token | Staying signed in across restarts | Produced by | — | Operating-system keychain, per profile. Access tokens stay in memory only. |
Optional environment variables: YOUTUBE_MCP_PROFILE (default default), YOUTUBE_MCP_DATA_DIR, and YOUTUBE_MCP_LOG_LEVEL (error, warn, info, debug). See .env.example.
Never paste any of these into a chat message, a shared MCP configuration file, or a command that will be committed. Prefer the interactive prompts or your client's environment/secret-injection field.
Step 6 — run setup, then log in
Run these in order. setup rewrites the profile's stored scopes and channel identity, so running it after login discards that state and requires logging in again.
macOS and Linux:
YOUTUBE_OAUTH_CLIENT_ID="YOUR_DESKTOP_CLIENT_ID" \
YOUTUBE_OAUTH_CLIENT_SECRET="YOUR_DESKTOP_CLIENT_SECRET" \
node dist/cli/index.js setup
node dist/cli/index.js login
node dist/cli/index.js statusWindows PowerShell:
$env:YOUTUBE_OAUTH_CLIENT_ID = "YOUR_DESKTOP_CLIENT_ID"
$env:YOUTUBE_OAUTH_CLIENT_SECRET = "YOUR_DESKTOP_CLIENT_SECRET"
node dist\cli\index.js setup
node dist\cli\index.js login
node dist\cli\index.js status
Remove-Item Env:\YOUTUBE_OAUTH_CLIENT_SECRETTo avoid putting the secret in shell history or the process table at all, omit both variables and let setup prompt for them:
node dist/cli/index.js setupsetup prompts for each missing value when the terminal is interactive.
login opens Google's authorization page and returns through a random loopback port on 127.0.0.1, using PKCE S256 and a random state value. It fails immediately, before opening a browser, when no client secret is stored for the profile.
To revoke and remove the stored credential:
node dist/cli/index.js logoutStep 7 — start the server
YOUTUBE_API_KEY="your-api-key" node dist/cli/index.js serveThe server speaks MCP over stdio, so it is normally launched by a client rather than by hand. Available commands are serve, doctor, status, setup, login, and logout.
Local data location
Profiles, the quota ledger, drafts, and operation journals live in a 0700 directory:
Platform | Default path |
macOS |
|
Linux |
|
Windows |
|
Override with YOUTUBE_MCP_DATA_DIR. To remove all local state, run logout and then delete that directory. Keychain entries are removed by logout.
Connecting a client to the local build
Until the package is published, point clients at the absolute path of your built dist/cli/index.js.
Claude Code
claude mcp add youtube --scope user \
--env YOUTUBE_MCP_PROFILE=default \
--env YOUTUBE_API_KEY=your-api-key -- \
node /absolute/path/to/Youtube\ MCP/dist/cli/index.js serveClaude Desktop
{
"mcpServers": {
"youtube": {
"command": "node",
"args": ["/absolute/path/to/Youtube MCP/dist/cli/index.js", "serve"],
"env": {
"YOUTUBE_MCP_PROFILE": "default",
"YOUTUBE_API_KEY": "your-api-key"
}
}
}
}Codex
[mcp_servers.youtube]
command = "node"
args = ["/absolute/path/to/Youtube MCP/dist/cli/index.js", "serve"]
[mcp_servers.youtube.env]
YOUTUBE_MCP_PROFILE = "default"
YOUTUBE_API_KEY = "your-api-key"Re-run npm run build after pulling changes; clients execute the compiled dist output, not src.
Google authorization for this local server is performed by its own setup and login commands. Client-level MCP login commands do not replace the downstream Google OAuth flow.
Post-publication client configuration
Once the package is released, pin a released version instead of using latest so an MCP client cannot change behavior unexpectedly.
Claude Desktop
{
"mcpServers": {
"youtube": {
"command": "npx",
"args": ["-y", "@youtube-mcp/server@0.7.0", "serve"],
"env": {
"YOUTUBE_MCP_PROFILE": "default"
}
}
}
}On native Windows, use "command": "cmd" and prefix the arguments with "/c", "npx".
Claude Code
claude mcp add youtube --scope user \
--env YOUTUBE_MCP_PROFILE=default -- \
npx -y @youtube-mcp/server@0.7.0 serveCodex
codex mcp add youtube \
--env YOUTUBE_MCP_PROFILE=default -- \
npx -y @youtube-mcp/server@0.7.0 serveEquivalent Codex configuration:
[mcp_servers.youtube]
command = "npx"
args = ["-y", "@youtube-mcp/server@0.7.0", "serve"]
[mcp_servers.youtube.env]
YOUTUBE_MCP_PROFILE = "default"How much can be added in one go
Hard schema limits per tool call:
Operation | Maximum per call |
Tracks per | 50 |
Selections per | 50 |
Video IDs per | 50 |
Item removals per playlist mutation | 50 |
Reorder moves per playlist mutation | 50 |
Items per read page | 50 |
So 50 songs is the ceiling for a single commit. A longer list is handled by committing in batches of 50: create the playlist with the first batch, then pass its target_playlist_id on each subsequent commit to append. Duplicates already present are skipped and reported rather than inserted twice.
The daily quota is the tighter constraint in practice. Against Google's default 10,000 units per project per day, one 50-song run costs roughly:
Step | Calls | Published unit cost | Subtotal |
| 50 | 100 | 5,000 |
| 1–5 | 1 | 1–5 |
| 1 | 50 | 50 |
| 50 | 50 | 2,500 |
Total | ≈ 7,550 |
That means roughly one 50-song playlist per project per day. A second full run the same day will exhaust the quota and fail partway through insertion. Preparing the same list twice is especially expensive: the searches are charged again even though the answers are unchanged.
Quota resets at midnight US Pacific time, which is the day boundary the local ledger uses.
Quota expectations
youtube_quota_status reports locally observed usage, not an authoritative Google balance. General units and search.list calls are tracked separately because Google applies a separate default daily search-call limit.
search.list is billed at its published 100 units, so general_units reflects real consumption. Releases before 0.5.0 recorded it as 1 unit and therefore under-reported usage by 99 units per search; a write could be rejected for quota while the reported figure still looked low. Upgrade if you are on an earlier build.
Quota values can change. Implementation and release work must verify the current official cost table instead of treating values in this README as permanent constants.
Troubleshooting
A commit reports status: "partial" with empty completed and everything in pending. The playlist was created but the first insert was rejected — most often the daily quota. Nothing is retried blindly, so no duplicate items are written. Check youtube_quota_status, delete the empty playlist, and re-run after the Pacific-time reset. Because a draft is single-use, re-running requires a fresh youtube_prepare_music_playlist.
login fails before a browser opens. No client secret is stored for the profile. Run setup first, and confirm you are on the intended YOUTUBE_MCP_PROFILE.
Authorization succeeds, then stops working about a week later. Google OAuth projects left in Testing status issue refresh tokens that expire after seven days. Publish the consent screen or re-run login.
403 on a public read. YOUTUBE_API_KEY is missing from the server's environment. It is never persisted, so it must be present in every launch — including the env block of the MCP client configuration.
Authentication model
Public reads require
YOUTUBE_API_KEYin the process environment.Account reads require OAuth with the
youtube.readonlyscope.Playlist creation and comment writes require
youtube.force-sslbecause Google does not provide a playlist-only scope.Video upload and lifecycle require
youtube.upload. It is requested separately, and video tools refuse when a profile was authorized without it. Add it to your consent screen and re-runloginbefore uploading.The server counteracts that broad Google scope with a strict endpoint allowlist: only playlist and playlist-item write endpoints are callable.
Installed applications use Authorization Code + PKCE, a random
state, and a loopback redirect on127.0.0.1with a random port.Service accounts are not supported for ordinary YouTube accounts.
Never commit API keys, OAuth client data, access tokens, refresh tokens, local databases, debug logs, or .env files.
Captions and analytics
General public transcript retrieval is not part of v1. The official captions download endpoint is permission-gated and expensive, so unofficial scraping will not be used. Owner-authorized caption management may be considered later.
YouTube Analytics and Reporting APIs are also deferred. They require separate OAuth, data models, and operational behavior and should not complicate the initial playlist-focused server.
Development
The implemented stack is TypeScript, Node.js 20.17+, ESM, the official MCP TypeScript SDK, Zod validation, direct typed REST calls to approved Google endpoints, SQLite for local quota/draft/journal state, and an OS-keychain adapter for OAuth refresh tokens.
Current checks:
npm run format:check
npm run lint
npm run typecheck
npm test
npm run buildImplementation should follow the phases and acceptance gates in PLAN.md. Agent-specific constraints and definitions of done are in AGENTS.md. Claude Code should begin with CLAUDE.md.
Project status
Product and security architecture
Repository development instructions
TypeScript package scaffold
Public read tools
OAuth and profiles
Music matching and preview
Confirmed new-playlist creation
Previewed playlist update, reorder, removal, and deletion
Existing-playlist target for music draft commits (0.5)
Correct
search.listgeneral-unit accounting in the quota ledger (0.5)Comment insert, reply, delete, and moderation (0.6)
Video upload, metadata update, delete, and thumbnails (0.7)
YouTube Analytics reporting (0.8)
Cross-client integration tests
First npm release
License
Licensed under the Apache License 2.0. The complete license text is in LICENSE.
References
This server cannot be deployed
Maintenance
Related MCP Connectors
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.
YouTube discovery, transcripts, library search, and monitors with API keys or OAuth.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables interaction with YouTube via MCP, including search, transcript retrieval, trending videos, and AI community discovery.MIT
- AlicenseAqualityBmaintenanceEnables YouTube playlist curation including inventory, deduplication, merging, and deletion via MCP tools.12MIT
- AlicenseNot gradedqualityAmaintenanceProvides read-only MCP tools to search YouTube, retrieve video metadata, transcripts, comments, channel information, and popular videos.3MIT
- FlicenseNot gradedqualityCmaintenanceAn MCP server that enables AI applications to search YouTube music videos and manage playlists via the YouTube Data API v3, with OAuth support for playlist and subscription management.3-