Skip to main content
Glama

ytmcp

Unofficial YouTube API + MCP server — let AI agents control a YouTube channel end-to-end.

CI Python License: MIT MCP

ytmcp is a Python library, REST API, CLI, and Model Context Protocol server that wraps an unofficial YouTube client. It lets AI agents (Claude Desktop, Cursor, custom agents…) upload videos, edit metadata, manage playlists, moderate comments, and read analytics — all through MCP tools.


⚠️ Disclaimer

This project is provided for educational and research purposes only.

  • It uses reverse-engineered, undocumented YouTube endpoints that may change or break at any time.

  • Automating YouTube may violate YouTube's Terms of Service.

  • Using this software can result in account suspension or termination.

  • The authors accept no liability for any consequences arising from its use.

Use at your own risk, ideally with a test account. You are solely responsible for complying with all applicable terms and laws.


Related MCP server: youtube-live-mcp

✨ Features

Domain

Capabilities

Video

upload (resumable), update metadata, set visibility, set thumbnail, delete, get info

Playlist

create, list, add/remove videos, delete

Comments

list, reply, moderate (approve/hold/reject)

Channel

get info, subscriber count, update branding/links

Analytics

views, watch-time, subscriber growth, top videos

Search

search videos, list channel uploads

Three interfaces share one core:

  1. 🐍 Python library — from ytmcp.core import YouTubeClient

  2. 🤖 MCP server — ytmcp serve (stdio / HTTP)

  3. 🌐 REST API — ytmcp api (FastAPI, auto docs at /docs)


🔐 Authentication (hybrid)

ytmcp supports two auth methods and picks automatically (auth_mode = auto):

Option A — Browser cookies (fastest)

  1. Export cookies for youtube.com with a browser extension (e.g. Get cookies.txt) or yt-dlp --cookies-from-browser chrome --cookies cookies.txt.

  2. Point ytmcp at the file:

export YTMCP_AUTH_MODE=cookie
export YTMCP_COOKIE_FILE=/path/to/cookies.txt
uv run ytmcp auth verify-cookies /path/to/cookies.txt

Supports Netscape cookies.txt and JSON exports (including Playwright storage_state).

Option B — OAuth 2.0 (device flow)

  1. Create an OAuth client (type TVs and Limited Input devices) in Google Cloud Console.

  2. Configure and log in:

export YTMCP_AUTH_MODE=oauth
export YTMCP_OAUTH_CLIENT_ID=...
export YTMCP_OAUTH_CLIENT_SECRET=...
uv run ytmcp auth login

Tokens are cached in ~/.ytmcp/oauth_token.json and refreshed automatically.

Check status any time:

uv run ytmcp auth status

🚀 Quick start

# 1. Install
git clone https://github.com/Lightforce325/ytmcp.git
cd ytmcp
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"

# 2. Configure auth (see above)
cp .env.example .env  # then edit

# 3. Run the MCP server
uv run ytmcp serve

# or the REST API
uv run ytmcp api     # http://127.0.0.1:8765/docs

🤖 Connect to Claude Desktop (MCP)

Add this to claude_desktop_config.json:

{
  "mcpServers": {
    "ytmcp": {
      "command": "uv",
      "args": [
        "--directory", "/ABSOLUTE/PATH/TO/ytmcp",
        "run", "ytmcp", "serve"
      ],
      "env": {
        "YTMCP_AUTH_MODE": "cookie",
        "YTMCP_COOKIE_FILE": "/ABSOLUTE/PATH/TO/cookies.txt"
      }
    }
  }
}

Restart Claude Desktop — the agent will now see 20 tools for controlling your channel.

See examples/claude_desktop_config.json and docs/TOOLS.md.


🧰 MCP tools

Tool

Auth

Description

upload_video

✅

Upload a video file with metadata

update_video_metadata

✅

Edit title/description/tags/category

set_video_visibility

✅

public / unlisted / private / scheduled

delete_video

✅

Permanently delete a video

get_video_info

—

Fetch video details

search_videos

—

Search YouTube

list_channel_videos

—

List a channel's uploads

create_playlist

✅

Create a playlist

list_playlists

—

List channel playlists

add_video_to_playlist

✅

Add a video to a playlist

remove_video_from_playlist

✅

Remove a video from a playlist

delete_playlist

✅

Delete a playlist

list_comments

—

List video comments

reply_to_comment

✅

Reply to a comment

moderate_comment

✅

Approve / hold / reject a comment

get_channel_info

—

Channel metadata

get_subscriber_count

—

Subscriber count

update_channel_branding

✅

Banner / avatar / links

get_analytics

✅

Views, watch-time, growth

get_top_videos

—

Most-viewed videos


🧩 Example agent workflow

"Upload intro.mp4 as a private video titled Hello World, add it to my Demos playlist, then reply to the latest comment."

The agent chains: upload_video → list_playlists → add_video_to_playlist → list_comments → reply_to_comment. See examples/agent_batch_upload.py.


🏗️ Architecture

AI Agent ──MCP──► mcp/server.py ──► core/* ──► YouTube endpoints
                     api/app.py  ──►
                     cli.py      ──►

See docs/ARCHITECTURE.md for the full breakdown.


🧪 Development

uv pip install -e ".[dev]"    # install dev dependencies
uv run ruff check .           # lint
uv run ruff format .          # format
uv run mypy src               # type-check

Testing

The suite lives in tests/ and runs on pytest with pytest-asyncio (asyncio_mode = "auto") and respx for HTTP mocking — no network access or credentials are needed for the default run.

# Run the whole suite (unit tests + integration tests, which skip by default)
uv run pytest

# Run only the unit tests
uv run pytest tests/unit

# Run a single file / test
uv run pytest tests/unit/test_upload.py -q
uv run pytest tests/unit/test_config.py::test_settings_defaults -q

Coverage

Coverage is configured with pytest-cov and coverage.py. Configuration lives in pyproject.toml under [tool.coverage.run] (source = src/ytmcp, branch coverage enabled) and [tool.coverage.report].

# Terminal report highlighting missing lines
uv run pytest --cov=src/ytmcp --cov-report=term-missing

# HTML report (written to htmlcov/, git-ignored)
uv run pytest --cov=src/ytmcp --cov-report=html
open htmlcov/index.html

# Fail the run if total coverage drops below a threshold
uv run pytest --cov=src/ytmcp --cov-report=term-missing --cov-fail-under=70

Integration tests (opt-in)

End-to-end multi-service flows live in tests/integration/. They are marked integration and skipped by default; opt in with the environment variable:

# Run everything, including integration tests
YTMCP_RUN_INTEGRATION=1 uv run pytest -m integration

# Run only the integration marker
YTMCP_RUN_INTEGRATION=1 uv run pytest tests/integration -m integration

Quality gates

uv run pytest                                  # tests
uv run pytest --cov=src/ytmcp --cov-report=term-missing  # tests + coverage
uv run ruff check .                            # lint
uv run mypy src                                # type-check

📄 License

MIT — provided as-is, without warranty. See the disclaimer above.

Available Tools

20 tools
add_video_to_playlistC

Add a video to a playlist.

Args: playlist_id: Target playlist id (starts with 'PL'). video_id: Video id to add.

Inputs: video_id (required), playlist_id (required). Returns: result

create_playlistB

Create a new playlist on the channel.

Args: title: Playlist title. description: Playlist description. visibility: One of 'public', 'unlisted', 'private'.

Inputs: title (required), visibility, description. Returns: result

delete_playlistC

Delete a playlist.

Args: playlist_id: Playlist id to delete.

Inputs: playlist_id (required). Returns: result

delete_videoB

Permanently delete a video from the channel.

Args: video_id: The YouTube video id to delete.

Inputs: video_id (required). Returns: result

get_analyticsB

Get channel analytics (views, watch-time, subscribers gained/lost).

Args: channel_id: Channel id. period_days: Reporting window in days (default 28).

Inputs: channel_id (required), period_days. Returns: result

get_channel_infoB

Get information about a channel (title, description, banner).

Args: channel_id: Channel id; if omitted, uses the authenticated channel.

Inputs: channel_id. Returns: result

get_subscriber_countB

Get the subscriber count of a channel.

Args: channel_id: Channel id; if omitted, uses the authenticated channel.

Inputs: channel_id. Returns: result

get_top_videosC

Get a channel's most-viewed videos.

Args: channel_id: Channel id. limit: Maximum number of videos to return.

Inputs: channel_id (required), limit. Returns: result

get_video_infoB

Get detailed information about a video (title, views, description).

Args: video_id: The YouTube video id.

Inputs: video_id (required). Returns: result

list_channel_videosB

List a channel's uploaded videos (newest first).

Args: channel_id: The channel id (starts with 'UC'). limit: Maximum number of videos to return.

Inputs: channel_id (required), limit. Returns: result

list_commentsB

List top-level comments for a video.

Args: video_id: The YouTube video id. limit: Maximum number of comments to return.

Inputs: video_id (required), limit. Returns: result

list_playlistsC

List all playlists belonging to a channel.

Args: channel_id: The channel id (starts with 'UC').

Inputs: channel_id (required). Returns: result

moderate_commentB

Moderate a comment (approve, hold, or reject).

Args: comment_id: Target comment id. action: One of 'published', 'heldForReview', 'rejected'.

Inputs: comment_id (required), action. Returns: result

remove_video_from_playlistC

Remove a video from a playlist.

Args: playlist_id: Target playlist id. video_id: Video id to remove.

Inputs: video_id (required), playlist_id (required). Returns: result

reply_to_commentB

Reply to a comment on a video.

Args: video_id: The video id the comment belongs to. comment_id: The comment to reply to. text: Reply text.

Inputs: text (required), video_id (required), comment_id (required). Returns: result

search_videosC

Search YouTube for videos.

Args: query: Search keywords. limit: Maximum number of results (default 20).

Inputs: query (required), limit. Returns: result

set_video_visibilityB

Change a video's visibility.

Args: video_id: The YouTube video id. visibility: One of 'public', 'unlisted', 'private', 'scheduled'. publish_at: ISO-8601 datetime; required for 'scheduled'.

Inputs: video_id (required), visibility (required), publish_at. Returns: result

update_channel_brandingB

Update channel branding: banner, avatar, and profile links.

Args: banner_path: Local path to a new banner image. avatar_path: Local path to a new avatar image. links: List of {'title': ..., 'url': ...} profile links.

Inputs: links, avatar_path, banner_path. Returns: result

update_video_metadataB

Update the metadata of an existing video.

Args: video_id: The YouTube video id to edit. title: New title (optional). description: New description (optional). tags: New tag list (optional). category_id: New category id (optional). default_language: New default language code, e.g. 'en' (optional).

Inputs: video_id (required), tags, title, category_id, +2 more. Returns: result

upload_videoA

Upload a video file to the authenticated YouTube channel.

Args: file_path: Absolute path to the video file on the local machine. title: Video title (max 100 chars). description: Video description text. tags: Optional list of tags/keywords. visibility: One of 'public', 'unlisted', 'private', 'scheduled'. category_id: YouTube category id (default '22' = People & Blogs). publish_at: ISO-8601 datetime; required when visibility='scheduled'. made_for_kids: COPPA compliance flag. thumbnail_path: Optional path to a custom thumbnail image.

Inputs: title (required), file_path (required), tags, publish_at, +5 more. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.2/5.0

    Scored across 20 tools

    Disambiguation4/5

    Most tools have clearly distinct purposes, but a few channel-video retrieval and channel-info tools have closely related scopes (e.g., get_top_videos vs list_channel_videos, get_channel_info vs get_subscriber_count), which could cause minor misselection.

    Naming Consistency5/5

    All tool names use a consistent snake_case verb_noun pattern (get_, list_, create_, update_, delete_, etc.) with no mixed conventions, making them predictable and readable.

    Tool Count4/5

    20 tools is on the higher side but reasonable for the broad YouTube channel management domain, covering videos, playlists, comments, analytics, and channel branding without obvious redundancy.

    Completeness3/5

    Core CRUD exists for videos and playlists, but notable gaps remain: no way to list videos within a playlist, no update_playlist, no update_channel_description/title, and no delete comment. These missing operations could hinder full playlist and channel management.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers