Skip to main content
Glama
YouTube MCP Server

YouTube MCP Server

by l4b4r4b4b4

YouTube MCP Server

A production-ready MCP (Model Context Protocol) server for YouTube integration with intelligent caching via mcp-refcache. Search videos, retrieve transcripts, analyze channels, monitor live streams, and more - all optimized for AI agents with smart caching to minimize API quota usage.

Version: 0.0.0 (Experimental First Release)

Features

🔍 Search & Discovery

  • Video Search - Find videos by keywords with metadata (title, description, views, etc.)

  • Channel Search - Discover channels by query

  • Live Stream Search - Find currently broadcasting live videos

📊 Metadata & Analytics

  • Video Details - Complete metadata including statistics (views, likes, comments)

  • Channel Info - Detailed channel statistics and subscriber counts

  • Live Status - Check if a video is currently streaming with viewer counts

📝 Transcript Management

  • Full Transcripts - Download complete video transcripts with timestamps

  • Transcript Previews - Get summarized transcript snippets for quick context

  • Chunked Access - Navigate large transcripts in manageable pieces

  • Multi-Language Support - List and retrieve transcripts in available languages

💬 Engagement & Live Chat

  • Video Comments - Fetch top comments with engagement metrics

  • Live Chat Monitoring - Real-time access to live stream chat messages

  • Live Chat Pagination - Efficient polling for new chat messages

⚡ Performance & Caching

  • Intelligent Multi-Tier Caching - Optimized for different data volatility:

    • youtube.content - Permanent caching for immutable content (transcripts)

    • youtube.api - 24h cache for general API data (video/channel metadata)

    • youtube.comments - 5m cache for rapidly changing comment data

    • youtube.search - 6h cache for search results

    • Live streaming - 30s-5m cache for real-time data

  • Reference-Based Results - Large datasets returned as references to minimize context usage

  • Preview Generation - Automatic previews for transcript and large data

  • Smart Quota Management - Caching reduces API quota usage by ~75%

Related MCP server: yt

Prerequisites

  • Python 3.12+

  • uv (recommended) or pip

  • YouTube Data API v3 Key - Get one here

Getting Your YouTube API Key

  1. Go to Google Cloud Console

  2. Create a new project or select an existing one

  3. Enable the YouTube Data API v3:

    • Navigate to "APIs & Services" > "Library"

    • Search for "YouTube Data API v3"

    • Click "Enable"

  4. Create credentials:

    • Go to "APIs & Services" > "Credentials"

    • Click "Create Credentials" > "API Key"

    • Copy your API key

  5. (Optional) Restrict your API key:

    • Click on the key to edit

    • Under "API restrictions", select "Restrict key"

    • Choose "YouTube Data API v3"

    • Save

Default Quota: 10,000 units/day (~100 searches or ~10,000 metadata requests)

Quick Start

Installation (Local)

# Clone the repository
git clone https://github.com/l4b4r4b4b4/yt-mcp
cd yt-mcp

# Install dependencies
uv sync

# Set your API key
export YOUTUBE_API_KEY="your-api-key-here"

# Run the server (stdio mode for Claude Desktop)
uv run yt-mcp stdio

Installation (Docker)

# Clone the repository
git clone https://github.com/l4b4r4b4b4/yt-mcp
cd yt-mcp

# Set your API key in .env file
echo "YOUTUBE_API_KEY=your-api-key-here" > .env

# Build and run with docker-compose
docker compose up

The server will be available at http://localhost:8000 in HTTP mode.

Configuration

Environment Variables

Set your YouTube API key via environment variable:

export YOUTUBE_API_KEY="your-youtube-api-key"

Or add to your shell profile (~/.zshrc, ~/.bashrc):

echo 'export YOUTUBE_API_KEY="your-key"' >> ~/.zshrc

Optional Langfuse Tracing:

export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_HOST="https://cloud.langfuse.com"

Using with Claude Desktop

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "youtube": {
      "command": "uv",
      "args": ["--directory", "/path/to/yt-mcp", "run", "yt-mcp", "stdio"],
      "env": {
        "YOUTUBE_API_KEY": "your-api-key-here"
      }
    }
  }
}

Using with Zed

Add to your Zed settings (.zed/settings.json or global settings):

{
  "context_servers": {
    "youtube-mcp": {
      "command": {
        "path": "uv",
        "args": ["--directory", "/path/to/yt-mcp", "run", "yt-mcp", "stdio"],
        "env": {
          "YOUTUBE_API_KEY": "your-api-key-here"
        }
      }
    }
  }
}

Using with Docker

Production (docker-compose)

# Create .env file with your API key
echo "YOUTUBE_API_KEY=your-api-key" > .env

# Run production server
docker compose up

# Run in background
docker compose up -d

# View logs
docker compose logs -f

# Stop server
docker compose down

Development (with hot reload)

# Run development server with code volume mount
docker compose --profile dev up

Direct Docker Run

# Build the image
docker build -f docker/Dockerfile -t yt-mcp:latest .

# Run the container
docker run -p 8000:8000 \
  -e YOUTUBE_API_KEY="your-api-key" \
  yt-mcp:latest

# With Langfuse tracing
docker run -p 8000:8000 \
  -e YOUTUBE_API_KEY="your-api-key" \
  -e LANGFUSE_PUBLIC_KEY="pk-lf-..." \
  -e LANGFUSE_SECRET_KEY="sk-lf-..." \
  yt-mcp:latest

Available Tools

🔍 Search Tools

search_videos(query: str, max_results: int = 5)

Search for YouTube videos matching a query.

Parameters:

  • query (string, required) - Search term (e.g., "NixOS tutorials", "vimjoyer nix")

  • max_results (integer, optional) - Number of results, 1-50, default: 5

Returns:

[
  {
    "video_id": "abc123",
    "title": "Video Title",
    "description": "Video description...",
    "url": "https://www.youtube.com/watch?v=abc123",
    "thumbnail": "https://i.ytimg.com/vi/abc123/default.jpg",
    "channel_title": "Channel Name",
    "published_at": "2024-01-15T10:30:00Z"
  }
]

Caching: 6 hours (youtube.search namespace) Quota Cost: 100 units per request

Example:

Search for videos about "Nix flakes tutorial"

search_channels(query: str, max_results: int = 5)

Search for YouTube channels matching a query.

Parameters:

  • query (string, required) - Channel search term

  • max_results (integer, optional) - Number of results, 1-50, default: 5

Returns:

[
  {
    "channel_id": "UCxyz123",
    "title": "Channel Name",
    "description": "Channel description...",
    "url": "https://www.youtube.com/channel/UCxyz123",
    "thumbnail": "https://yt3.ggpht.com/...",
    "published_at": "2020-05-10T08:00:00Z"
  }
]

Caching: 6 hours (youtube.search namespace) Quota Cost: 100 units per request


search_live_videos(query: str, max_results: int = 5)

Search for currently live YouTube videos.

Parameters:

  • query (string, required) - Search query (e.g., "gaming live", "news live")

  • max_results (integer, optional) - Number of results, 1-50, default: 5

Returns:

[
  {
    "video_id": "live123",
    "title": "Live Stream Title",
    "description": "Stream description...",
    "url": "https://www.youtube.com/watch?v=live123",
    "thumbnail": "https://i.ytimg.com/vi/live123/default.jpg",
    "channel_title": "Streamer Name",
    "published_at": "2024-01-20T15:00:00Z"
  }
]

Caching: 6 hours (youtube.search namespace) Quota Cost: 100 units per request


📊 Metadata & Status Tools

get_video_details(video_id: str)

Get detailed information about a specific video.

Parameters:

  • video_id (string, required) - YouTube video ID (e.g., "dQw4w9WgXcQ")

Returns:

{
  "video_id": "abc123",
  "title": "Video Title",
  "description": "Full description...",
  "url": "https://www.youtube.com/watch?v=abc123",
  "thumbnail": "https://i.ytimg.com/vi/abc123/maxresdefault.jpg",
  "channel_title": "Channel Name",
  "published_at": "2024-01-15T10:30:00Z",
  "view_count": "150000",
  "like_count": "5000",
  "comment_count": "300",
  "duration": "PT15M30S",
  "tags": ["nix", "linux", "tutorial"]
}

Caching: 24 hours (youtube.api namespace) Quota Cost: 1 unit per request


get_channel_info(channel_id: str)

Get detailed information about a YouTube channel.

Parameters:

  • channel_id (string, required) - YouTube channel ID (e.g., "UCuAXFkgsw1L7xaCfnd5JJOw")

Returns:

{
  "channel_id": "UCxyz123",
  "title": "Channel Name",
  "description": "Channel description...",
  "url": "https://www.youtube.com/channel/UCxyz123",
  "thumbnail": "https://yt3.ggpht.com/...",
  "subscriber_count": "50000",
  "video_count": "200",
  "view_count": "5000000",
  "published_at": "2020-05-10T08:00:00Z"
}

Caching: 24 hours (youtube.api namespace) Quota Cost: 1 unit per request


is_live(video_id: str)

Check if a YouTube video is currently live streaming.

Parameters:

  • video_id (string, required) - YouTube video ID to check

Returns:

{
  "video_id": "live123",
  "is_live": true,
  "viewer_count": 1234,
  "scheduled_start_time": "2024-01-20T15:00:00Z",
  "actual_start_time": "2024-01-20T15:02:00Z",
  "active_live_chat_id": "Cg0KC2xpdmUxMjM..."
}

Caching: 30 seconds (youtube.api namespace) Quota Cost: 1 unit per request

Note: Use this to check status before accessing live chat.


📝 Transcript Tools

list_available_transcripts(video_id: str)

List all available transcript languages for a video.

Parameters:

  • video_id (string, required) - YouTube video ID

Returns:

{
  "video_id": "abc123",
  "available_languages": ["en", "es", "fr", "de"],
  "transcript_info": [
    {
      "language": "en",
      "language_code": "en",
      "is_generated": false,
      "is_translatable": true
    },
    {
      "language": "es",
      "language_code": "es",
      "is_generated": true,
      "is_translatable": false
    }
  ]
}

Caching: Permanent (youtube.content namespace) Quota Cost: 0 (uses youtube-transcript-api, not YouTube Data API)

Note: Always check this first before requesting transcripts.


get_video_transcript_preview(video_id: str, language: str = "en", max_chars: int = 2000)

Get a preview of the video transcript (first N characters).

Parameters:

  • video_id (string, required) - YouTube video ID

  • language (string, optional) - Language code (default: "en")

  • max_chars (integer, optional) - Maximum characters to return (default: 2000)

Returns:

{
  "video_id": "abc123",
  "language": "en",
  "preview": "First 2000 characters of transcript...",
  "total_length": 50000,
  "is_truncated": true
}

Caching: Permanent (youtube.content namespace) Quota Cost: 0

Note: Use this for quick context before fetching full transcript.


get_full_transcript(video_id: str, language: str = "en")

Get the complete transcript of a video with timestamps.

Parameters:

  • video_id (string, required) - YouTube video ID

  • language (string, optional) - Language code (default: "en")

Returns:

{
  "video_id": "abc123",
  "language": "en",
  "transcript": [
    {
      "text": "Hello everyone, welcome to this tutorial...",
      "start": 0.0,
      "duration": 3.5
    },
    {
      "text": "Today we're going to learn about...",
      "start": 3.5,
      "duration": 4.2
    }
  ],
  "full_text": "Hello everyone, welcome to this tutorial. Today we're going to learn about..."
}

Caching: Permanent (youtube.content namespace) Quota Cost: 0

Note: Large transcripts return a RefCache reference. Use get_cached_result to paginate or retrieve full data.


get_transcript_chunk(video_id: str, start_index: int = 0, chunk_size: int = 50, language: str = "en")

Get a specific chunk of transcript entries (for pagination).

Parameters:

  • video_id (string, required) - YouTube video ID

  • start_index (integer, optional) - Starting entry index, 0-based (default: 0)

  • chunk_size (integer, optional) - Number of entries to return (default: 50)

  • language (string, optional) - Language code (default: "en")

Returns:

{
  "video_id": "abc123",
  "language": "en",
  "start_index": 0,
  "chunk_size": 50,
  "entries": [
    {"text": "...", "start": 0.0, "duration": 3.5}
  ],
  "total_entries": 250,
  "has_more": true
}

Caching: Permanent (youtube.content namespace) Quota Cost: 0


💬 Engagement & Live Chat Tools

get_video_comments(video_id: str, max_results: int = 20)

Get top comments from a video with engagement metrics.

Parameters:

  • video_id (string, required) - YouTube video ID

  • max_results (integer, optional) - Number of comments, 1-100 (default: 20)

Returns:

{
  "video_id": "abc123",
  "comments": [
    {
      "author": "Username",
      "text": "Great video! This really helped me understand...",
      "like_count": 42,
      "published_at": "2024-01-20T15:30:00Z",
      "reply_count": 3
    }
  ],
  "total_returned": 20
}

Caching: 5 minutes (youtube.comments namespace) Quota Cost: 1 unit per request

Note: Returns empty list if comments are disabled (not an error). Only top-level comments, no replies.


get_live_chat_id(video_id: str)

Get the live chat ID for a currently streaming video.

Parameters:

  • video_id (string, required) - YouTube video ID of the live stream

Returns:

{
  "video_id": "live123",
  "live_chat_id": "Cg0KC2xpdmUxMjM...",
  "is_live": true
}

Caching: 5 minutes (youtube.api namespace) Quota Cost: 1 unit per request

Note: Use is_live first to verify video is streaming. Chat ID remains constant during stream.


get_live_chat_messages(video_id: str, max_results: int = 200, page_token: str | None = None)

Get recent live chat messages from a streaming video with pagination.

Parameters:

  • video_id (string, required) - YouTube video ID of the live stream

  • max_results (integer, optional) - Maximum messages to return, 1-2000 (default: 200)

  • page_token (string, optional) - Pagination token from previous call (None for first call)

Returns:

{
  "video_id": "live123",
  "messages": [
    {
      "author": "ViewerName",
      "text": "Great stream!",
      "published_at": "2024-01-20T16:45:30Z",
      "author_channel_id": "UCxyz..."
    }
  ],
  "total_returned": 50,
  "next_page_token": "GgkKBxIFMTIzNDU",
  "polling_interval_millis": 30000
}

Caching: 30 seconds (youtube.comments namespace) Quota Cost: 1 unit per request

Polling Pattern:

  1. First call: No page_token → Get latest messages + next_page_token

  2. Store next_page_token

  3. Wait 30-60 seconds (respect polling_interval_millis)

  4. Subsequent calls: Pass page_token → Get only NEW messages

  5. Repeat steps 2-4 for continuous monitoring

Note: MCP is request/response (not true streaming). Agent must manually poll this tool repeatedly to see new messages.


🗂️ Cache Management Tools

get_cached_result(ref_id: str, page: int | None = None, page_size: int | None = None, max_size: int | None = None)

Retrieve and paginate through cached results.

Parameters:

  • ref_id (string, required) - Reference ID from cached tool (e.g., from large transcript)

  • page (integer, optional) - Page number, 1-indexed

  • page_size (integer, optional) - Items per page, 1-100

  • max_size (integer, optional) - Maximum preview size in tokens

Returns:

{
  "ref_id": "youtube.content:transcript_abc123_en",
  "preview": [...],
  "total_items": 250,
  "page": 2,
  "total_pages": 5
}

Note: Use this when a tool returns a ref_id instead of full data (for large results).


Example Use Cases

Finding a Specific Video

Goal: Find Vimjoyer's video about Nix garbage collection that keeps only the last N generations

Workflow:

1. Search: "Search for videos by Vimjoyer about Nix garbage collection generations"
   → Returns list of videos with IDs

2. Preview: "Get transcript preview for video abc123"
   → Returns first 2000 characters to check relevance

3. Analyze: "Get full transcript for video abc123 and find the section about keeping last N generations"
   → Returns complete transcript with timestamps

4. Extract: AI analyzes transcript and returns relevant section with timestamp

Channel Analysis

Goal: Analyze a channel's recent content and engagement

Workflow:

1. Search: "Find the NixOS channel"
   → Returns channel ID

2. Info: "Get channel info for UC[channel-id]"
   → Returns subscriber count, video count, total views

3. Videos: "Search for recent videos from NixOS channel"
   → Returns latest video list

4. Engagement: "Get comments for video abc123"
   → Returns top comments with like counts

Live Stream Monitoring

Goal: Monitor a live stream and track chat activity

Workflow:

1. Find: "Search for live videos about Python programming"
   → Returns currently live streams

2. Check: "Is video live123 currently streaming?"
   → Confirms live status and viewer count

3. Connect: "Get live chat ID for video live123"
   → Returns chat ID needed for messages

4. Monitor: "Get live chat messages for video live123"
   → Returns recent messages + next_page_token

5. Poll: "Get live chat messages for video live123 with page_token=XYZ"
   → Returns only new messages since last call

6. Repeat: Wait 30-60 seconds, then repeat step 5

Transcript Analysis Across Languages

Goal: Find and compare transcripts in multiple languages

Workflow:

1. Search: "Search for videos about 'machine learning basics'"
   → Returns video IDs

2. Check: "List available transcripts for video abc123"
   → Returns ["en", "es", "fr", "de", "auto-generated"]

3. Compare: "Get transcript preview for abc123 in English"
   → Preview English version

4. Compare: "Get transcript preview for abc123 in Spanish"
   → Preview Spanish version

5. Analyze: AI compares content across languages

Caching Strategy

The server uses a 4-tier caching architecture optimized for different data volatility levels:

Tier 1: Search Results (6 hours)

  • Namespace: youtube.search

  • TTL: 6 hours (21,600 seconds)

  • Size: 300 entries

  • Use: Video search, channel search, live video search

  • Rationale: Search rankings change throughout the day; 6h balances freshness with quota savings

Tier 2: API Metadata (24 hours)

  • Namespace: youtube.api

  • TTL: 24 hours (86,400 seconds)

  • Size: 1000 entries

  • Use: Video details, channel info

  • Rationale: Video stats change daily but not hourly; 24h cache reduces quota by 24x

Tier 3: Comments & Engagement (5 minutes)

  • Namespace: youtube.comments

  • TTL: 5 minutes (300 seconds)

  • Size: 500 entries

  • Use: Video comments

  • Rationale: Comments can change rapidly on viral videos; 5m balances real-time with quota

Tier 4: Immutable Content (Permanent)

  • Namespace: youtube.content

  • TTL: Permanent (no expiration)

  • Size: 5000 entries

  • Use: Video transcripts (all transcript tools)

  • Rationale: Transcripts never change once published; permanent cache eliminates redundant fetches

Tier 5: Live Streaming (30 seconds - 5 minutes)

  • Namespaces: youtube.api (live status), youtube.comments (chat messages)

  • TTL: 30 seconds (live status/chat), 5 minutes (chat ID)

  • Use: Live stream status, chat messages, chat IDs

  • Rationale: Real-time data needs frequent updates but excessive polling wastes quota

RefCache Integration

Large results (transcripts, long comment lists) are automatically handled by RefCache:

  1. Small Results (≤2048 tokens): Returned inline directly to agent

  2. Large Results (>2048 tokens): Cached with ref_id + preview returned

  3. Pagination: Use get_cached_result(ref_id, page=N) to access specific pages

  4. Sample Previews: Large lists show representative samples in preview

Benefits:

  • Minimizes context window pollution for agents

  • Enables efficient pagination without re-fetching

  • Preserves full data for detailed analysis when needed


API Quota Management

Understanding Quotas

YouTube Data API v3 has daily quotas measured in "units":

  • Default Quota: 10,000 units/day (free tier)

  • Search Operation: 100 units each

  • Metadata Operation: 1 unit each (video details, channel info, comments)

  • Live Chat Messages: 1 unit per request

  • Transcript Operations: 0 units (uses youtube-transcript-api, not YouTube Data API)

Quota Calculation Examples

Without Caching:

  • 100 video searches = 10,000 units = entire daily quota

  • 10,000 video detail requests = 10,000 units = entire daily quota

With Caching (6h TTL for search, 24h for metadata):

  • Same 100 searches (6h cache) = 400 units/day (~75% savings)

  • Same 10,000 metadata requests (24h cache) = ~420 units/day (~96% savings)

Best Practices

  1. Use transcript tools first - They cost 0 quota

  2. Search broadly, then get details - Search costs 100x more than metadata

  3. Cache effectively - Let the built-in caching do its job

  4. Batch operations - Group related requests in single session

  5. Monitor usage - Server returns quota errors with clear messages

Increasing Quota

If you need higher quota:

  1. Go to Google Cloud Console

  2. Navigate to your project → APIs & Services → YouTube Data API v3

  3. Click "Quotas" tab

  4. Request quota increase (requires billing account, but API is still free)

  5. Typical increases: 50,000 to 1,000,000 units/day


Docker Details

Image Sizes

  • Base Image: 290MB (ghcr.io/l4b4r4b4b4/fastmcp-base:latest)

    • Python 3.12-slim + uv + dependencies

    • Shared across all FastMCP projects

  • Production Image: 229MB (ghcr.io/l4b4r4b4b4/yt-mcp:latest)

    • Base + application code

    • Optimized for size and startup speed

Container Features

  • Non-root user: Runs as appuser for security

  • Health checks: Built-in health endpoint at /health

  • Environment config: All settings via environment variables

  • Multi-arch: Supports amd64 and arm64 (M1/M2 Macs)

  • Streamable HTTP: Uses HTTP transport (recommended for Docker/remote)

Docker Compose Configuration

The docker-compose.yml includes three profiles:

  1. Production (default): docker compose up

    • Port 8000 exposed

    • Optimized production image

    • Auto-restart on failure

  2. Development: docker compose --profile dev up

    • Port 8000 exposed

    • Volume mount for hot reload

    • Development dependencies included

  3. Build: docker compose --profile build up base

    • Builds base image for publishing

    • Only used for releases


Troubleshooting

"Invalid API Key" Error

Symptoms:

Error: API key not valid. Please pass a valid API key.

Solutions:

  1. Verify key is set: echo $YOUTUBE_API_KEY

  2. Check for typos or extra spaces in key

  3. Verify key has YouTube Data API v3 enabled in Google Cloud Console

  4. Make sure key restrictions (if any) allow YouTube Data API v3


"Quota Exceeded" Error

Symptoms:

Error: The request cannot be completed because you have exceeded your quota.

Solutions:

  1. Wait until quota resets (midnight Pacific Time)

  2. Enable billing in Google Cloud Console for higher quota

  3. Use caching effectively (it's automatic, but check get_cached_result for large operations)

  4. Use transcript tools (0 quota cost) instead of search when possible

  5. Request quota increase from Google Cloud Console


"No Transcript Available" Error

Symptoms:

Error: No transcript found for this video

Solutions:

  1. Use list_available_transcripts first to check availability

  2. Try auto-generated transcripts: often available even without manual captions

  3. Some videos genuinely don't have transcripts (creator didn't enable)

  4. Check if video is age-restricted or private


"Comments Disabled" (Empty Result)

Symptoms:

{"video_id": "abc123", "comments": [], "total_returned": 0}

This is NOT an error - the video has comments disabled by the creator. The tool returns an empty list as expected behavior.


Docker: "Cannot connect to server"

Symptoms:

Error: Failed to connect to localhost:8000

Solutions:

  1. Verify container is running: docker compose ps

  2. Check container logs: docker compose logs -f

  3. Ensure port 8000 is not in use: lsof -i :8000 (macOS/Linux)

  4. Verify API key is set in .env file or docker-compose environment

  5. Check health: curl http://localhost:8000/health


Docker: "Rate limiting" or slow responses

Symptoms:

  • Slow API responses

  • Timeout errors

Solutions:

  1. YouTube API has rate limits - this is normal behavior

  2. Caching will improve performance after first requests

  3. For local development, use stdio mode instead of HTTP: uv run yt-mcp stdio

  4. Check your network connection

  5. Verify Docker has sufficient resources (memory, CPU)


Development

Setup Development Environment

# Using Nix (recommended)
nix develop

# Or install dependencies manually with uv
uv sync

Running Tests

# Run all tests
uv run pytest

# With coverage report
uv run pytest --cov

# Run specific test file
uv run pytest tests/test_server.py

# Watch mode (requires pytest-watch)
uv run ptw

Current Test Status: 178 tests passing, 76% code coverage

Linting and Formatting

# Check and fix linting issues
uv run ruff check . --fix

# Format code
uv run ruff format .

# Type checking
uv run mypy app

Project Structure

yt-mcp/
├── app/
│   ├── __init__.py
│   ├── __main__.py          # CLI entry point
│   ├── server.py            # Main MCP server with all tools
│   ├── tools/
│   │   ├── __init__.py
│   │   ├── youtube.py       # YouTube API integration
│   │   └── ...              # Other tool modules
│   ├── tracing.py           # Langfuse tracing integration
│   └── prompts.py           # MCP prompts
├── tests/
│   ├── conftest.py          # Pytest configuration
│   ├── test_server.py       # Server tests
│   └── test_youtube.py      # YouTube tool tests
├── docker/
│   ├── Dockerfile           # Production image
│   ├── Dockerfile.base      # Base image with dependencies
│   └── Dockerfile.dev       # Development image
├── .agent/                  # Development notes and planning
├── pyproject.toml           # Dependencies and configuration
├── docker-compose.yml       # Container orchestration
├── flake.nix                # Nix development environment
└── README.md                # This file

Version 0.0.0 Release Notes

This is the first experimental release of the YouTube MCP server. It's published to test both the implementation and the release workflow.

What Works

  • ✅ All 16 YouTube tools implemented and tested

  • ✅ Comprehensive test suite (178 tests, 76% coverage)

  • ✅ Multi-tier caching with RefCache integration

  • ✅ Docker support (production + development)

  • ✅ Langfuse tracing for observability

  • ✅ Claude Desktop and Zed integration

Known Limitations

  • This is version 0.0.0 - expect issues

  • Limited real-world validation (this tests the release process)

  • Documentation may have gaps or inaccuracies

  • Docker images published but not battle-tested

Next Steps

  • 0.0.1: Bug fixes and improvements from 0.0.0 feedback

  • 0.0.x: Continued iteration and refinement

  • 0.1.0: After 5-10 patch releases and proven stability

  • 1.0.0: Production-ready after 6+ months of 0.x usage

We encourage feedback! Open issues on GitHub with any problems or suggestions.


Environment Variables Reference

Variable

Description

Required

Default

YOUTUBE_API_KEY

YouTube Data API v3 key

Yes

None

LANGFUSE_PUBLIC_KEY

Langfuse tracing public key

No

None

LANGFUSE_SECRET_KEY

Langfuse tracing secret key

No

None

LANGFUSE_HOST

Langfuse host URL

No

https://cloud.langfuse.com

FASTMCP_PORT

Server port (HTTP mode)

No

8000

FASTMCP_HOST

Server host (HTTP mode)

No

0.0.0.0


Contributing

See CONTRIBUTING.md for development guidelines and how to submit pull requests.


License

MIT License - see LICENSE for details.



Acknowledgments

  • Built on FastMCP and mcp-refcache libraries

  • Uses Google's YouTube Data API v3

  • Uses youtube-transcript-api for quota-free transcript access

  • Langfuse for observability and tracing

  • Docker for containerization


Questions or Issues? Open an issue on GitHub

Available Tools

31 tools
admin_clear_namespaceA

Clear all references in a namespace.

⚠️ ADMIN ONLY - Requires elevated permissions. ⚠️ DESTRUCTIVE - This action cannot be undone.

Args: namespace: The namespace to clear (e.g., 'user:alice'). include_children: Also clear child namespaces (default: True).

Returns: Confirmation with count of deleted references.

Inputs: namespace (required), include_children. Returns: object

admin_delete_referenceA

Delete a specific cached reference.

⚠️ ADMIN ONLY - Requires elevated permissions. ⚠️ DESTRUCTIVE - This action cannot be undone.

Args: ref_id: The reference ID to delete.

Returns: Confirmation of deletion or error.

Inputs: ref_id (required). Returns: object

admin_get_cache_statsA

Get detailed cache statistics.

⚠️ ADMIN ONLY - Requires elevated permissions.

Returns: Dictionary with cache statistics including: - Total references and counts by namespace - Active vs expired reference counts - Value type breakdown - Cache configuration

Inputs: no named parameters. Returns: object

admin_get_reference_infoA

Get detailed information about a cached reference.

⚠️ ADMIN ONLY - Requires elevated permissions.

Args: ref_id: The reference ID to look up.

Returns: Dictionary with detailed reference information (value not included).

Inputs: ref_id (required). Returns: object

admin_list_referencesA

List cached references with optional filtering.

⚠️ ADMIN ONLY - Requires elevated permissions.

Args: namespace: Filter by namespace (e.g., 'public', 'user:alice'). include_expired: Include expired references in results. include_preview: Include value previews in results. limit: Maximum number of results (default: 50, max: 100). offset: Offset for pagination.

Returns: Dictionary with references list and pagination info.

Inputs: limit, offset, namespace, include_expired, +1 more. Returns: object

delete_indexed_videoA

Delete a video's content from the semantic search index.

Removes indexed content (transcripts, comments, or both) for a specific video. Useful for re-indexing or cleaning up the index.

Args: video_id: YouTube video ID to remove from the index. content_type: Optional content type to delete ("transcript" or "comment"). If None, deletes all content types for the video.

Returns: Dictionary with: - video_id: The deleted video ID - transcripts_deleted: Number of transcript chunks removed - comments_deleted: Number of comment chunks removed - total_deleted: Total chunks removed - success: Whether the deletion was successful

Inputs: video_id (required), content_type. Returns: object

enable_test_contextA

Enable or disable test context mode for Langfuse attribution demos.

When enabled, all traces will include user_id, session_id, and metadata from the MockContext. This allows testing Langfuse filtering and aggregation without a real FastMCP authentication setup.

Args: enabled: Whether to enable test context mode (default: True).

Returns: Status dict with current test mode state and context values.

Inputs: enabled. Returns: object

get_cached_resultA

Retrieve a cached result, optionally with pagination.

Use this to:

  • Get a preview of a cached value

  • Paginate through large lists

  • Access the full value of a cached result

All cache operations are traced to Langfuse with hit/miss status.

Args: ref_id: Reference ID to look up. page: Page number (1-indexed). page_size: Items per page. max_size: Maximum preview size (overrides defaults). full: If True, return the complete cached value without preview truncation. Bypasses all preview generation. Use when you need the entire value (e.g. full transcripts).

Returns: The cached value or a preview with pagination info.

Caching: Large results are returned as references with previews.

Pagination: Use page and page_size to navigate results.

Full retrieval: Use full=True to get the complete value.

References: This tool accepts ref_id from previous tool calls.

Inputs: ref_id (required), full, page, max_size, +1 more. Returns: object

get_channel_infoA

Get detailed information about a YouTube channel.

Retrieves channel metadata including title, description, statistics
(subscribers, videos, total views), and branding information.
Cached for 24 hours to minimize API quota usage.

Args:
    channel_id: YouTube channel ID (from search results, e.g., "UCuAXFkgsw1L7xaCfnd5JJOw")

Returns:
    Channel info dictionary with:
    - title, description, channel_id, url, thumbnail
    - subscriber_count, video_count, view_count
    - published_at

Example:
    >>> info = _get_channel_info("UCuAXFkgsw1L7xaCfnd5JJOw")
    >>> print(info["title"])
    "Vimjoyer"

Note:
    - Costs 1 quota unit per request (100x cheaper than search)
    - Cached for 24h in youtube.api namespace
    - Use after channel search to get full details

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: channel_id (required). Returns: object

get_full_transcriptA

Get the complete transcript for a YouTube video.

Retrieves the full transcript with all entries and timestamps.
For large transcripts (>2KB), RefCache automatically returns a preview
with a reference that can be paginated using get_cached_result.
Cached permanently as transcript content doesn't change.

Args:
    video_id: YouTube video ID (e.g., "dQw4w9WgXcQ")
    language: Language code (e.g., "en"). If empty, uses first available

Returns:
    FullTranscript dictionary with:
    - video_id, language
    - transcript: List of entries with text, start time, duration
    - full_text: Complete transcript as plain text

Example:
    >>> full = get_full_transcript("nLwbNhSxLd4", language="en")
    >>> print(len(full["transcript"]))
    150
    >>> print(full["full_text"][:100])

Note:
    - Uses no YouTube API quota
    - Cached permanently in youtube.content namespace
    - RefCache may return preview + reference for large transcripts
    - Use get_transcript_chunk for entry-by-entry pagination

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: video_id (required), language. Returns: object

get_indexed_videosA

Get list of videos that have been indexed for semantic search.

Retrieves all indexed video IDs with optional filtering by channel and/or content type. Useful for understanding what content is available.

Args: channel_id: Optional filter by YouTube channel ID. content_type: Optional filter by content type ("transcript" or "comment").

Returns: Dictionary with: - video_ids: List of indexed video IDs - total_count: Total number of indexed videos - channel_filter: Channel ID filter if applied - content_type_filter: Content type filter if applied

Inputs: channel_id, content_type. Returns: object

get_live_chat_idA

Get the live chat ID for a currently streaming video.

Retrieves the active live chat ID required for fetching chat messages.
This ID remains constant throughout the stream's duration.
Cached for 5 minutes since chat ID doesn't change during stream.

Args:
    video_id: YouTube video ID of the live stream.

Returns:
    Dictionary with:
    - video_id: YouTube video ID
    - live_chat_id: Active live chat ID
    - is_live: Boolean confirming video is live

Example:
    >>> result = get_live_chat_id("dQw4w9WgXcQ")
    >>> chat_id = result["live_chat_id"]

Note:
    - Costs 1 quota unit per request
    - Cached for 5 minutes in youtube.api namespace
    - Raises error if video is not live or chat disabled
    - Use is_live() first to check if video is broadcasting

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: video_id (required). Returns: object

get_live_chat_messagesA

Get recent live chat messages from a streaming video.

Fetches live chat messages with pagination support for efficient polling.
Use the returned next_page_token in subsequent calls to get only new messages.
Cached for 30 seconds for near real-time monitoring.

Args:
    video_id: YouTube video ID of the live stream.
    max_results: Maximum messages to return (1-2000, default 200).
    page_token: Pagination token from previous call (None for first call).

Returns:
    Dictionary with:
    - video_id: YouTube video ID
    - messages: List of messages with author, text, published_at, author_channel_id
    - total_returned: Number of messages in this response
    - next_page_token: Token for next page (None if no more)
    - polling_interval_millis: YouTube's recommended polling interval

Example:
    >>> # First call - get latest messages
    >>> result = get_live_chat_messages("dQw4w9WgXcQ", max_results=50)
    >>> print(f"Got {result['total_returned']} messages")
    >>>
    >>> # Second call - get only new messages since first call
    >>> result2 = get_live_chat_messages(
    ...     "dQw4w9WgXcQ",
    ...     max_results=50,
    ...     page_token=result["next_page_token"]
    ... )

Note:
    - Costs 1 quota unit per request
    - Cached for 30 seconds in youtube.comments namespace
    - Polling Pattern:
      1. First call: No page_token → Get latest messages + next_page_token
      2. Store next_page_token
      3. Subsequent calls: Pass page_token → Get only NEW messages
      4. Repeat step 3 every 30-60 seconds for continuous monitoring
    - MCP Limitation: Agent must manually call this tool repeatedly to see new messages

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: video_id (required), page_token, max_results. Returns: object

get_trace_infoA

Get information about the current Langfuse trace and context.

Returns metadata about Langfuse tracing status and current context values for debugging.

Returns: Dict with Langfuse configuration and current context.

Inputs: no named parameters. Returns: object

get_transcript_chunkA

Get a chunk of transcript entries for pagination.

Retrieves a subset of transcript entries for large transcripts.
Useful for iterating through transcripts entry-by-entry.
Cached permanently as transcript content doesn't change.

Args:
    video_id: YouTube video ID (e.g., "dQw4w9WgXcQ")
    start_index: Starting entry index (0-based, default: 0)
    chunk_size: Number of entries to return (default: 50)
    language: Language code (e.g., "en"). If empty, uses first available

Returns:
    TranscriptChunk dictionary with:
    - video_id, language, start_index, chunk_size
    - entries: List of transcript entries in this chunk
    - total_entries: Total entries in full transcript
    - has_more: Whether more entries available after this chunk

Example:
    >>> chunk = get_transcript_chunk("nLwbNhSxLd4", start_index=0, chunk_size=10)
    >>> print(len(chunk["entries"]))
    10
    >>> print(chunk["has_more"])
    True
    >>> # Get next chunk
    >>> chunk2 = get_transcript_chunk("nLwbNhSxLd4", start_index=10, chunk_size=10)

Note:
    - Uses no YouTube API quota
    - Cached permanently in youtube.content namespace
    - Use for iterating through large transcripts

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: video_id (required), language, chunk_size, start_index. Returns: object

get_video_commentsA

Get top comments for a YouTube video with engagement metrics.

Retrieves top-level comments (no replies) sorted by relevance.
Comments are cached for 5 minutes. Returns empty list if comments
are disabled for the video.

Args:
    video_id: YouTube video ID (e.g., "dQw4w9WgXcQ")
    max_results: Maximum comments to return (1-100, default: 20)

Returns:
    Dictionary with video_id, comments list, and total_returned.
    Each comment includes author, text, like_count, published_at.

Example:
    >>> comments = get_video_comments("nLwbNhSxLd4", max_results=10)
    >>> print(comments["comments"][0]["author"])

Note:
    - Costs 1 quota unit per request
    - Cached for 5 minutes in youtube.comments namespace
    - Returns empty list if comments disabled (not an error)

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: video_id (required), max_results. Returns: object

get_video_detailsA

Get detailed information about a YouTube video.

Retrieves comprehensive video metadata including title, description,
statistics (views, likes, comments), duration, tags, and channel info.
Cached for 24 hours to minimize API quota usage.

Args:
    video_id: YouTube video ID (from URL or search results, e.g., "dQw4w9WgXcQ")

Returns:
    Video details dictionary with:
    - title, description, video_id, url, thumbnail
    - view_count, like_count, comment_count
    - duration (ISO 8601 format like "PT15M30S")
    - tags, channel_title, published_at

Example:
    >>> details = _get_video_details("nLwbNhSxLd4")
    >>> print(details["title"])
    "Full NixOS Guide"

Note:
    - Costs 1 quota unit per request (100x cheaper than search)
    - Cached for 24h in youtube.api namespace
    - Use after search to get full details

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: video_id (required). Returns: object

get_video_transcript_previewA

Get a preview of a YouTube video transcript.

Retrieves the first N characters of a video transcript for quick preview.
Useful for deciding if you need the full transcript.
Cached permanently as transcript content doesn't change.

Args:
    video_id: YouTube video ID (e.g., "dQw4w9WgXcQ")
    language: Language code (e.g., "en"). If empty, uses first available
    max_chars: Maximum characters to return (default: 2000)

Returns:
    TranscriptPreview dictionary with:
    - video_id, language, preview text
    - total_length: Total characters in full transcript
    - is_truncated: Whether preview is truncated

Example:
    >>> preview = get_video_transcript_preview("nLwbNhSxLd4", max_chars=500)
    >>> print(preview["preview"][:50])
    "Welcome to this NixOS tutorial..."

Note:
    - Uses no YouTube API quota
    - Cached permanently in youtube.content namespace
    - Use list_available_transcripts first to see language options

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: video_id (required), language, max_chars. Returns: object

health_checkA

Check server health status.

Returns: Health status information including Langfuse tracing status.

Inputs: no named parameters. Returns: object

index_channel_transcriptsA

Pre-index all video transcripts from a YouTube channel.

This is an optional tool for pre-warming the semantic search index. You don't need to call this before searching - semantic_search_transcripts automatically indexes missing videos. Use this only if you want to explicitly prepare a channel's content for faster first searches.

Args: channel_id: YouTube channel ID (e.g., "UCuAXFkgsw1L7xaCfnd5JJOw"). max_videos: Maximum number of videos to index (default: 50). language: Preferred transcript language code (default: "en"). force_reindex: If True, re-index videos even if already indexed.

Returns: Dictionary with indexing results: - indexed_count: Number of videos successfully indexed - chunk_count: Total chunks created - skipped_count: Videos skipped (already indexed or no transcript) - error_count: Number of failed videos - errors: List of error messages - video_ids: List of indexed video IDs

Note: - Indexing 50 videos takes ~1-2 minutes - Uses ~1 API quota unit per video (transcripts are free) - Subsequent semantic searches on this channel will be fast

Inputs: channel_id (required), language, max_videos, force_reindex. Returns: object

is_liveA

Check if a YouTube video is currently live.

Queries the YouTube Data API to determine if a video is currently
broadcasting live. Returns live status with viewer count and timing information.
Cached for 30 seconds since live status changes quickly.

Args:
    video_id: YouTube video ID to check (e.g., "dQw4w9WgXcQ").

Returns:
    Dictionary with:
    - video_id: YouTube video ID
    - is_live: Boolean indicating if video is currently live
    - viewer_count: Current concurrent viewers (None if not live)
    - scheduled_start_time: ISO 8601 scheduled start time (None if not scheduled)
    - actual_start_time: ISO 8601 actual start time (None if not started)
    - active_live_chat_id: Live chat ID (None if no chat or not live)

Example:
    >>> status = is_live("dQw4w9WgXcQ")
    >>> if status["is_live"]:
    ...     print(f"Live now with {status['viewer_count']} viewers!")

Note:
    - Costs 1 quota unit per request
    - Cached for 30 seconds in youtube.api namespace
    - Use search_live_videos() to find live streams

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: video_id (required). Returns: object

list_available_transcriptsA

List all available transcript languages for a YouTube video.

Discovers which transcript languages are available for a video,
including both manual and auto-generated transcripts.
Cached permanently as available transcripts don't change.

Args:
    video_id: YouTube video ID (from URL or search, e.g., "dQw4w9WgXcQ")

Returns:
    AvailableTranscripts dictionary with:
    - video_id: The video ID
    - available_languages: List of language codes (e.g., ["en", "es", "fr"])
    - transcript_info: Detailed info for each (language, is_generated, etc.)

Example:
    >>> transcripts = list_available_transcripts("nLwbNhSxLd4")
    >>> print(transcripts["available_languages"])
    ["en", "de", "es"]

Note:
    - Uses no YouTube API quota (third-party transcript API)
    - Cached permanently in youtube.content namespace
    - Call this first before requesting specific transcript

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: video_id (required). Returns: object

reset_test_contextB

Reset test context to default demo values.

Returns: Reset context state.

Inputs: no named parameters. Returns: object

search_channelsA

Search for YouTube channels by query string.

Searches YouTube and returns channel results with names, descriptions,
thumbnails, and URLs. Results are cached for 6 hours to minimize
API quota usage.

Args:
    query: Search query (e.g., "Vimjoyer", "NixOS channels").
    max_results: Maximum results to return (1-50, default 5).

Returns:
    List of channel results with channel_id, title, description,
    url, thumbnail, and published_at.

Example:
    >>> results = _search_channels("vimjoyer", 5)
    >>> print(results[0]["title"])

Note:
    - Search costs 100 quota units per request
    - Results cached for 6 hours in youtube.search namespace
    - Use get_cached_result() to paginate large result sets

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: query (required), max_results. Returns: object

search_live_videosA

Search for currently live YouTube videos.

Searches for videos that are currently streaming live, filtering results
to only active broadcasts. Results are cached for 6 hours.

Args:
    query: Search query (e.g., "gaming live", "news live now").
    max_results: Maximum results to return (1-50, default 5).

Returns:
    List of live video results with video_id, title, description, url,
    thumbnail, channel_title, and published_at.

Example:
    >>> results = search_live_videos("gaming", max_results=10)
    >>> print(results[0]["title"])
    'Live Gaming Stream - Fortnite'

Note:
    - Search costs 100 quota units per request
    - Results cached for 6 hours in youtube.search namespace
    - Use is_live() to check if a specific video is currently live
    - Use get_live_chat_messages() to monitor chat

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: query (required), max_results. Returns: object

search_videosA

Search for YouTube videos by query string.

Searches YouTube and returns video results with titles, descriptions,
thumbnails, channels, and URLs. Results are cached for 6 hours to
minimize API quota usage.

Args:
    query: Search query (e.g., "NixOS tutorials", "vimjoyer nix").
    max_results: Maximum results to return (1-50, default 5).

Returns:
    List of video results with video_id, title, description, url,
    thumbnail, channel_title, and published_at.

Example:
    >>> results = _search_videos("vimjoyer garbage collection", 10)
    >>> print(results[0]["title"])

Note:
    - Search costs 100 quota units per request
    - Results cached for 6 hours in youtube.search namespace
    - Use get_cached_result() to paginate large result sets

Caching Behavior:

  • Parameters that accept reference strings can accept a ref_id from a previous tool call

  • Large results return ref_id + preview; use get_cached_result to paginate

  • All responses include ref_id for future reference

Ref input compatibility: Support depends on the tool's input schema/validation. Some strictly typed parameters may reject string ref_ids before resolution.

Full retrieval: Use get_cached_result(ref_id, full=True) to get the complete value.

Preview Size: server default. Override per-call with get_cached_result(ref_id, max_size=...).

Inputs: query (required), max_results. Returns: object

semantic_search_allA

Search across all content types (transcripts and comments).

Performs unified semantic search over both video transcripts and comments. Automatically indexes any missing content before searching.

Args: query: Natural language search query (e.g., "Nix garbage collection"). content_types: List of content types to search: ["transcript", "comment"]. If None, searches all types. channel_ids: Optional list of YouTube channel IDs to scope the search. video_ids: Optional list of specific video IDs to scope the search. k: Number of results to return (default: 10). language: Preferred transcript language code (default: "en"). max_comments_per_video: Maximum comments to index per video (default: 100). max_videos_per_channel: Maximum videos to fetch per channel (default: 50). min_score: Optional minimum similarity score threshold (lower is better).

Returns: Dictionary with search results including: - query: The original search query - results: List of matches with content_type field indicating source - total_results: Number of results returned - indexing_stats: Statistics for both transcripts and comments - content_types_searched: List of content types that were searched

Note: - Results are sorted by relevance score across all content types - Each result includes content_type field ("transcript" or "comment") - Transcript results include timestamp_url, comment results include author

Inputs: query (required), k, language, min_score, +5 more. Returns: object

semantic_search_commentsA

Search comments using natural language with automatic indexing.

Performs semantic similarity search over video comments. Automatically indexes any missing comments before searching, providing a seamless experience without requiring explicit indexing calls.

Args: query: Natural language search query (e.g., "questions about flakes"). channel_ids: Optional list of YouTube channel IDs to scope the search. video_ids: Optional list of specific video IDs to scope the search. k: Number of results to return (default: 10). max_comments_per_video: Maximum comments to index per video (default: 100). max_videos_per_channel: Maximum videos to fetch per channel (default: 50). min_score: Optional minimum similarity score threshold (lower is better).

Returns: Dictionary with search results including: - query: The original search query - results: List of matches with video info, text, author, like_count, scores - total_results: Number of results returned - indexing_stats: Statistics about auto-indexing performed - scope: Description of search scope applied

Note: - First search on new content will be slower due to indexing - Subsequent searches are fast (already indexed) - If neither channel_ids nor video_ids provided, searches all indexed comments

Inputs: query (required), k, min_score, video_ids, +3 more. Returns: object

semantic_search_transcriptsA

Search transcripts using natural language with automatic indexing.

Performs semantic similarity search over video transcripts. Automatically indexes any missing transcripts before searching, providing a seamless experience without requiring explicit indexing calls.

Args: query: Natural language search query (e.g., "Nix garbage collection generations"). channel_ids: Optional list of YouTube channel IDs to scope the search. Videos from these channels will be auto-indexed if not already indexed. video_ids: Optional list of specific video IDs to scope the search. These videos will be auto-indexed if not already indexed. k: Number of results to return (default: 10). language: Preferred transcript language code (default: "en"). max_videos_per_channel: Maximum videos to fetch per channel (default: 50). min_score: Optional minimum similarity score threshold (lower is better).

Returns: Dictionary with search results including: - query: The original search query - results: List of matches with video info, text, timestamps, and scores - total_results: Number of results returned - indexing_stats: Statistics about auto-indexing performed - scope: Description of search scope applied

Note: - First search on new content will be slower due to indexing (~1-2 min for 50 videos) - Subsequent searches are fast (already indexed) - If neither channel_ids nor video_ids provided, searches all indexed content - Results include timestamp URLs for direct playback at matching segments

Inputs: query (required), k, language, min_score, +3 more. Returns: object

set_test_contextA

Set test context values for Langfuse attribution demos.

Changes here affect what user_id, session_id, and metadata are sent to Langfuse traces. Use this to test filtering by different users or sessions in the Langfuse dashboard.

Args: user_id: User identity (e.g., "alice", "bob"). org_id: Organization identity (e.g., "acme", "globex"). session_id: Session identifier for grouping traces. agent_id: Agent identity (e.g., "claude", "gpt4").

Returns: Updated context state and example of Langfuse attributes.

Inputs: org_id, user_id, agent_id, session_id. Returns: object

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A4/5.0

    Scored across 31 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose. Transcript-related tools (get_full_transcript, get_transcript_chunk, get_video_transcript_preview) are differentiated by scope and use case. Semantic search tools are separated by content type. Admin and cache tools are prefixed and clearly separated from user-facing tools. No two tools appear to do the same thing.

    Naming Consistency5/5

    All tool names follow a consistent snake_case convention with a verb_noun pattern (e.g., get_channel_info, search_videos, index_channel_transcripts). Even tools like health_check and is_live fit the pattern. No mixing of camelCase or other styles.

    Tool Count4/5

    31 tools is somewhat high, but each tool serves a distinct and necessary function for a feature-rich YouTube MCP server. The count covers search, details, transcripts, comments, live streaming, semantic search, caching, admin, and testing utilities. A few tools like admin tools could be considered optional, but they are well-integrated.

    Completeness4/5

    The tool surface thoroughly covers read operations and semantic search for YouTube content. Missing are write operations (posting comments, etc.) and nested replies for comments, but these may be out of scope. For the stated purpose, the set is nearly complete, with only minor gaps like playlist retrieval or reply threads.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      D
      maintenance
      An MCP server that enables interaction with the YouTube Data API, allowing users to search videos, get video and channel details, analyze trends, and fetch video transcripts.
      -
    • A
      license
      Not graded
      quality
      Not graded
      maintenance
      An MCP server that provides YouTube data access without API keys or quotas. It enables agents to search videos, retrieve transcripts and metadata, and perform full-text search across cached content for AI context retrieval.
      3 npm
      -