← Projects
MIT · Open source

mcp-youtube

MCP server for YouTube — create, prune, and clean up playlists conversationally from Claude

Features

  • Full YouTube Data API v3 coverage — 52 tools spanning playlists, videos, channels & sections, subscriptions, comments, captions, thumbnails, watermarks, playlist cover images, and read-only reference data, all under the youtube.force-ssl scope
  • Quota-aware by design — every tool documents its cost up front, from 1-unit reads to the 1600-unit upload-video
  • Guarded destructive actions — every delete, unsubscribe, moderation action, or other irreversible/outward tool refuses to run without confirm: true
  • Full-replace done safely — YouTube's update methods overwrite an entire resource part; tools like update-video, update-playlist, update-channel, and update-channel-section read the current resource first so an update that only changes one field never silently blanks the rest
  • Safe bulk cleanupclean-playlist scans for [Deleted video]/[Private video] tombstones, duplicates, and videos from named channels, then defaults to a dry run so you see the plan before anything is removed
  • Local-file media uploads — videos, captions, thumbnails, watermarks, and playlist cover images all upload from a local file path via resumable upload where the API requires it
  • One-time OAuth setup — a desktop-flow npm run setup handles Google authorisation and prints a refresh token; you supply it (and the client id/secret) to the server via environment variables, from any store you like
  • Typed end to end — Zod-validated tool schemas and a Vitest suite covering every handler

Install

The server works with any MCP-compatible client — Claude Desktop, Claude Code, Cursor, Cline, Zed, Continue, and others.

Install the package:

npm install -g @kud/mcp-youtube

In Claude Code or Claude Desktop you can instead install it as a plugin, which wires up the registration for you:

/plugin install youtube@kud

Either way, run the one-time OAuth setup before first use:

npm run setup

This walks you through creating a Google Cloud OAuth client (Desktop app type), opens a browser to authorise the youtube.force-ssl scope, and prints the resulting credentials — it writes nothing to disk. Stash them wherever you keep secrets (keychain, secrets manager, your MCP client's env block) and expose them to the server as environment variables:

VariableHolds
MCP_YOUTUBE_CLIENT_IDOAuth client ID
MCP_YOUTUBE_CLIENT_SECRETOAuth client secret
MCP_YOUTUBE_REFRESH_TOKENlong-lived refresh token

The server reads these three from the environment only — it's store-agnostic, so how they get there is up to you. A keychain-backed export works well:

export MCP_YOUTUBE_REFRESH_TOKEN=$(security find-generic-password -s mcp-youtube-refresh-token -w)

Tip: set the OAuth app's publishing status to In production in Google Cloud. youtube.force-ssl is a sensitive scope, and while the app sits in Testing the refresh token expires after 7 days.

Configuration

Register the server with your MCP client. The exact config file and its location depend on the client — Claude Desktop, for example, uses claude_desktop_config.json (Settings → Developer → Edit Config); Cursor, Cline, Zed, and Continue each have their own. The registration follows the standard mcpServers shape:

{
  "mcpServers": {
    "youtube": {
      "command": "npx",
      "args": ["-y", "@kud/mcp-youtube"],
      "env": {
        "MCP_YOUTUBE_CLIENT_ID": "your-client-id",
        "MCP_YOUTUBE_CLIENT_SECRET": "your-client-secret",
        "MCP_YOUTUBE_REFRESH_TOKEN": "your-refresh-token"
      }
    }
  }
}

If you installed via /plugin install youtube@kud, the plugin handles registration — you only need to supply the three environment variables above.

Usage

YouTube's Data API v3 gives every project a fixed 10,000 quota units/day. A single careless search, bulk delete, or video upload can burn through a meaningful chunk of that, so every tool documents its cost up front — and every destructive or outward-irreversible tool requires an explicit confirm: true.

52 tools cover the full read/write surface reachable under the youtube.force-ssl scope:

CategoryToolsDocs
Searchingsearch, list-playlists, get-playlistSearching
Playlistscreate-playlist, update-playlist, add-to-playlist, update-playlist-itemCreating & Adding
Cleaningclean-playlistCleaning Playlists
Deletingremove-from-playlist, delete-playlistDeleting & Pruning
Videoslist-videos, update-video, rate-video, get-video-rating, delete-video, upload-video, report-video-abuseVideos
Channels & sectionsupdate-channel, list-channels, list-channel-sections, create-channel-section, update-channel-section, delete-channel-sectionChannels & Sections
Communitylist-subscriptions, subscribe, unsubscribe, list-comment-threads, create-comment-thread, list-comments, reply-to-comment, update-comment, delete-comment, set-comment-moderation-statusCommunity
Captions & medialist-captions, upload-caption, update-caption, download-caption, delete-caption, set-thumbnail, set-watermark, unset-watermark, list-playlist-images, upload-playlist-image, update-playlist-image, delete-playlist-imageCaptions & Media
Reference datalist-activities, list-video-categories, list-i18n-languages, list-i18n-regions, list-video-abuse-report-reasons, list-members, list-membership-levelsReference Data

Once installed, just ask your MCP client:

> Clean up the tombstones in my "Focus" playlist

Scanned 214 items — found 6 tombstones ([Deleted video]/[Private video]).
This is a dry run, no changes made. Estimated cost to delete: 300 units.
Want me to go ahead?

> Yes, and dedupe it too

Deleted 6 tombstones and 3 duplicates (9 items, 450 units).

clean-playlist always returns its plan first — pass dryRun: false (or just confirm in conversation) to actually delete.

Development

git clone https://github.com/kud/mcp-youtube.git
cd mcp-youtube
npm install
npm run dev
ScriptPurpose
npm run devRun the server directly from source (tsx)
npm run buildCompile to dist/
npm testRun the Vitest suite
npm run typecheckType-check without emitting
npm run inspect:devLaunch the MCP Inspector against source