mcp-youtube
Provides tools for managing a YouTube channel: upload local video files with resumable chunked uploads (private by default, optional thumbnail and playlist), follow upload progress, and merge-safe updates to title, description, tags, privacy, scheduling and disclosures. Also lists the channel's videos (including private, unlisted and scheduled), playlists and categories, creates playlists, adds videos to them, sets custom thumbnails, deletes videos, and can call arbitrary YouTube Data API v3 endpoints, with OAuth login/logout and channel/scopes status reporting.
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., "@mcp-youtube upload /Users/me/Videos/demo.mp4 as private, title 'Demo', add to Tutorials playlist"
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.
@mgcrea/mcp-youtube
A Model Context Protocol server that lets an agent upload videos to a YouTube channel and manage them: metadata, privacy and scheduling, thumbnails, playlists.
The server is read-only by default. Uploading and every other mutating tool are not merely refused when writes are off: they are never registered, so an agent cannot call them at all.
Features
Resumable, chunked uploads that survive dropped connections. The server asks YouTube how far it got and resumes from there, so a failure costs one chunk instead of the whole file. Large files upload in the background:
youtube_upload_videowaits up towait_seconds, then hands back anupload_idforyoutube_get_upload. MCP progress notifications are sent when the client asks for them.Safe defaults for an agent. Uploads default to private (the API itself defaults to public). The made-for-kids declaration is required, with no default. Only video files can be uploaded, from absolute paths.
The channel is always visible. The Google consent screen picks the channel, so the token decides where an upload lands. Every response carries
channel.YOUTUBE_CHANNEL_IDmakes every tool refuse when the token belongs to a different channel.Merge-safe updates.
videos.updatereplaces every part it is sent, soyoutube_update_videoreads the video first and changes only the fields you pass.Remedies, not just errors. Google's
reasoncodes (quotaExceeded,uploadLimitExceeded,invalid_grant, ...) come back with what to do next.
Related MCP server: YouTube MCP
Setup
YouTube uploads need an OAuth client from a Google Cloud project you own. This takes about five minutes, once.
Enable the YouTube Data API v3.
Configure the consent screen in Google Auth Platform:
Branding: an app name and your email.
Audience: External, then Publish app. While the app is in Testing, Google expires refresh tokens after 7 days. An unverified app in production is fine for your own account; you click past one warning at login.
Go to Clients → Create client and choose application type Desktop app. You don't register a redirect URI, because Desktop clients accept any loopback port.
Set
YOUTUBE_CLIENT_IDandYOUTUBE_CLIENT_SECRET, and start the server.Ask the agent to call
youtube_auth_login. It opens the consent screen. Pick the channel uploads should go to; Brand Account channels are listed separately.
The refresh token is stored with mode 600 in ~/.config/youtube/tokens.json. You don't need to
restart afterwards.
Configure
Environment first, then ~/.config/youtube/config.json (camelCase keys, strict), field by
field.
Variable | Required | Description |
| yes | Desktop-app OAuth client id ( |
| yes | Its secret. Google requires it even with PKCE. |
| no |
|
| no | Expected channel ( |
| no | Use this refresh token (memory only) instead of the token file. |
| no | Where the login is stored. Defaults to |
| no | Upload chunk size, default 16. |
| no | Config file path. |
A read-only install asks for youtube.readonly only. If you turn writes on after logging in,
youtube_auth_status reports the missing scope; log in again.
Quota
Quota is counted per Google Cloud project and resets at midnight Pacific time.
Uploads have their own bucket of 100
videos.insertcalls per day (since 2026-06-01).Everything else shares 10,000 units per day. A list or get costs 1 unit. An update, delete, thumbnail or playlist write costs 50.
YouTube also applies its own per-channel upload limit (uploadLimitExceeded), separate from
API quota.
Tools
Tool | What it does | Writes |
| Configured? Signed in? Which channel, scopes, quota model, setup steps | no |
| Google consent in the browser, then stores the refresh token | no |
| Revokes the token at Google and deletes it locally | no |
| Your channel, including whether videos over 15 minutes are allowed | no |
| Your uploads, including private, unlisted and scheduled ones | no |
| One video in full, including processing progress | no |
| Your playlists | no |
| Assignable categories for a region | no |
| Any Data API v3 endpoint (GET only unless writes are on) | gated |
| Upload a local video, optionally with a thumbnail and playlist | yes |
| Follow an upload: progress, then video id and processing state | no¹ |
| Merge-update title, description, tags, privacy, schedule, disclosures | yes |
| Custom thumbnail (needs a verified channel) | yes |
| New playlist, private by default | yes |
| Add a video to a playlist | yes |
| Permanent delete, requires | yes |
¹ Registered only with writes on, since without them no upload can exist.
Things worth knowing
YouTube has no Shorts flag. A vertical or square video up to 3 minutes becomes a Short automatically.
A channel without phone verification can't upload videos longer than 15 minutes or set custom thumbnails. Verify at https://www.youtube.com/verify.
Uploads live in the server process. If the server restarts mid-upload, the upload is gone; start it again. An incomplete upload never creates a video.
youtube_upload_videois not idempotent: every call creates a new video.
Quick start
pnpm install
pnpm buildThen copy .mcp.json.example to .mcp.json and fill it in.
Develop
pnpm dev # tsdown --watch
pnpm test # vitest
pnpm typecheck
pnpm lint
pnpm formatPublish
pnpm dlx release-it # bump, commit, tag
git push --follow-tags # CI publishes to npm + GHCR from the tagLicense
MIT
Available Tools
9 toolsyoutube_auth_loginYouTube: LoginAIdempotent
Sign in with Google: opens the consent screen in the browser and waits for it to finish, then stores a refresh token (mode 600) and reports which channel it acts as. On the account chooser, pick the channel uploads should go to — a Brand Account channel is listed separately from the personal one. The app is unverified, so Google shows a warning first: Advanced → Go to (app). If no browser can be opened, or the wait runs out, returns the authorize URL instead and keeps listening for 5 minutes; call youtube_auth_status afterwards. Logging in again replaces the stored login.
Inputs: open, wait_seconds.
youtube_auth_logoutYouTube: LogoutADestructiveIdempotent
Revoke the stored refresh token at Google and delete it locally. Recoverable by calling youtube_auth_login again. Uploads already in progress fail at their next chunk.
Inputs: no named parameters.
youtube_auth_statusYouTube: Auth StatusARead-only
Whether the server is configured and signed in, which channel the token acts as (the token picks the channel, so this is where uploads land), the granted scopes, whether write tools are registered, and the daily quota model. When unconfigured, returns the exact setup steps. Call this first when a tool you expected is missing. Costs 1 quota unit the first time it resolves the channel, then nothing.
Inputs: no named parameters.
youtube_get_channelYouTube: Get ChannelARead-only
The channel the signed-in token acts as: id, handle, uploads playlist, subscriber/video/view counts, and long_uploads — whether videos longer than 15 minutes are allowed. Check that before uploading anything long: an unverified channel (disallowed or eligible) cannot, and the failure only shows after the whole file has been sent. Verify by phone at https://www.youtube.com/verify. Costs 1 quota unit.
Inputs: no named parameters.
youtube_get_videoYouTube: Get VideoARead-only
One video in full: snippet, status (privacy, uploadStatus, failure/rejection reason, publishAt, madeForKids), contentDetails, statistics, and — for your own videos — processingDetails (processing progress after an upload) and fileDetails. Use it to follow processing after youtube_upload_video finishes: processingStatus goes processing → succeeded. Costs 1 quota unit.
Inputs: video_id (required).
youtube_list_categoriesYouTube: List CategoriesARead-only
The video categories that can be assigned to an upload in a region, as {id, title}. Pass the id as categoryId to youtube_upload_video or youtube_update_video. Categories vary slightly by region, and some listed ones (e.g. Movies, Shows) are not assignable and are filtered out here. Costs 1 quota unit.
Inputs: region, language.
youtube_list_playlistsYouTube: List PlaylistsARead-only
This channel's playlists, including private ones: id, title, privacy and item count. The id is what youtube_add_to_playlist and youtube_upload_video's playlistId take. Costs 1 quota unit per page.
Inputs: limit, page_token.
youtube_list_videosYouTube: List VideosARead-only
This channel's uploads, newest first, including private, unlisted and scheduled ones: id, title, privacy, upload status, duration, views/likes/comments and URL. A video still processing shows upload_status uploaded; one that failed shows failure_reason or rejection_reason. A just-uploaded video can take a minute or more to appear here, because the uploads playlist is eventually consistent — youtube_get_video finds it at once. Costs 2 quota units per page (+1 the first time, to find the uploads playlist). For one video's full detail use youtube_get_video.
Inputs: limit, page_token.
youtube_requestYouTube: RequestARead-only
Escape hatch: call any YouTube Data API v3 endpoint (https://developers.google.com/youtube/v3/docs) that has no dedicated tool, e.g. GET /captions, GET /commentThreads, GET /search. The path is relative to /youtube/v3; parameters go in query. Returns the raw response, unshaped — prefer the dedicated tools. Media uploads (captions, banners) are not possible through it. Watch the cost: GET /search costs 100 units and has its own daily bucket. Writes are DISABLED: only GET is permitted. Set YOUTUBE_ALLOW_WRITES=1 to allow mutations.
Inputs: path (required), body, query, method.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 9 tools
The existing tools are cleanly separated: three auth tools, three read tools targeting distinct resources (channel, videos, playlists), a category lookup, and an explicit escape hatch. The only overlap is youtube_request, which can duplicate every other read tool, but it is clearly framed as a fallback that should be preferred less. The bigger confusion source is that several descriptions point at tools that do not exist (youtube_upload_video, youtube_update_video, youtube_add_to_playlist), sending an agent hunting for phantom tools.
All names are snake_case with a consistent youtube_ prefix, and get_/list_ verb patterns are used predictably for reads. Minor deviations: the auth tools use a noun-namespace form (auth_login/status/logout) rather than verb_noun, and youtube_request is a bare noun. These are readable and conventional enough not to cause misselection.
Nine tools is a well-scoped count for a YouTube server and nothing feels padded. The composition is slightly lopsided — three of nine tools are auth lifecycle — but each earns its place given the OAuth flow described. The number itself is appropriate; the issue is which tools are present rather than how many.
The surface is read-only in practice: no upload, update, delete, playlist mutation, or comment tools exist, yet descriptions extensively document upload behavior (long_uploads checks, categoryId passing, processing follow-up) for tools that are absent. Writes are even disabled in youtube_request unless an env var is set, so there is no workaround path. This will cause agent failures on the server's apparent primary use case.
Maintenance
Related MCP Connectors
YouTube transcripts, search, channel/playlist listings and upload tracking for AI agents.
Hosted MCP for YouTube Studio: uploads, metadata, playlists, comments, analytics, captions.
The YouTube autopilot: plan, write and schedule YouTube videos, and upload from your machine.
Manage videos and live streams, inspect captions, players and webhooks, and read play analytics.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables managing a YouTube channel through natural language: upload videos, edit metadata, set thumbnails, run pseudo A/B thumbnail tests, and pull analytics.-
- FlicenseNot gradedqualityDmaintenanceEnables YouTube video upload, metadata updates, thumbnail management, stats retrieval, and analytics via the YouTube Data API v3 and Analytics API using OAuth 2.0.-
- AlicenseAqualityBmaintenanceEnables MCP clients like Claude or Cursor to upload videos from your local machine directly to YouTube, schedule them, and manage channel content through Runsheet.1160 npmMIT
- AlicenseBqualityBmaintenanceEnables AI agents to control a YouTube channel end-to-end by uploading videos, editing metadata, managing playlists, moderating comments, and reading analytics through MCP tools.20MIT