YouTube MCP Server
Provides tools for searching YouTube videos, channels, and live streams; retrieving video details, transcripts, and comments; monitoring live streams and chat; and analyzing channel statistics.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@YouTube MCP Server search for recent tech reviews"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
YouTube MCP Server
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 datayoutube.search- 6h cache for search resultsLive 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
Go to Google Cloud Console
Create a new project or select an existing one
Enable the YouTube Data API v3:
Navigate to "APIs & Services" > "Library"
Search for "YouTube Data API v3"
Click "Enable"
Create credentials:
Go to "APIs & Services" > "Credentials"
Click "Create Credentials" > "API Key"
Copy your API key
(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 stdioInstallation (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 upThe 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"' >> ~/.zshrcOptional 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 downDevelopment (with hot reload)
# Run development server with code volume mount
docker compose --profile dev upDirect 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:latestAvailable 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 termmax_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 IDlanguage(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 IDlanguage(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 IDstart_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 IDmax_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 streammax_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:
First call: No
page_token→ Get latest messages +next_page_tokenStore
next_page_tokenWait 30-60 seconds (respect
polling_interval_millis)Subsequent calls: Pass
page_token→ Get only NEW messagesRepeat 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-indexedpage_size(integer, optional) - Items per page, 1-100max_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 timestampChannel 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 countsLive 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 5Transcript 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 languagesCaching Strategy
The server uses a 4-tier caching architecture optimized for different data volatility levels:
Tier 1: Search Results (6 hours)
Namespace:
youtube.searchTTL: 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.apiTTL: 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.commentsTTL: 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.contentTTL: 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:
Small Results (≤2048 tokens): Returned inline directly to agent
Large Results (>2048 tokens): Cached with
ref_id+ preview returnedPagination: Use
get_cached_result(ref_id, page=N)to access specific pagesSample 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
Use transcript tools first - They cost 0 quota
Search broadly, then get details - Search costs 100x more than metadata
Cache effectively - Let the built-in caching do its job
Batch operations - Group related requests in single session
Monitor usage - Server returns quota errors with clear messages
Increasing Quota
If you need higher quota:
Go to Google Cloud Console
Navigate to your project → APIs & Services → YouTube Data API v3
Click "Quotas" tab
Request quota increase (requires billing account, but API is still free)
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
appuserfor securityHealth checks: Built-in health endpoint at
/healthEnvironment 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:
Production (default):
docker compose upPort 8000 exposed
Optimized production image
Auto-restart on failure
Development:
docker compose --profile dev upPort 8000 exposed
Volume mount for hot reload
Development dependencies included
Build:
docker compose --profile build up baseBuilds 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:
Verify key is set:
echo $YOUTUBE_API_KEYCheck for typos or extra spaces in key
Verify key has YouTube Data API v3 enabled in Google Cloud Console
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:
Wait until quota resets (midnight Pacific Time)
Enable billing in Google Cloud Console for higher quota
Use caching effectively (it's automatic, but check
get_cached_resultfor large operations)Use transcript tools (0 quota cost) instead of search when possible
Request quota increase from Google Cloud Console
"No Transcript Available" Error
Symptoms:
Error: No transcript found for this videoSolutions:
Use
list_available_transcriptsfirst to check availabilityTry auto-generated transcripts: often available even without manual captions
Some videos genuinely don't have transcripts (creator didn't enable)
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:8000Solutions:
Verify container is running:
docker compose psCheck container logs:
docker compose logs -fEnsure port 8000 is not in use:
lsof -i :8000(macOS/Linux)Verify API key is set in
.envfile or docker-compose environmentCheck health:
curl http://localhost:8000/health
Docker: "Rate limiting" or slow responses
Symptoms:
Slow API responses
Timeout errors
Solutions:
YouTube API has rate limits - this is normal behavior
Caching will improve performance after first requests
For local development, use stdio mode instead of HTTP:
uv run yt-mcp stdioCheck your network connection
Verify Docker has sufficient resources (memory, CPU)
Development
Setup Development Environment
# Using Nix (recommended)
nix develop
# Or install dependencies manually with uv
uv syncRunning 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 ptwCurrent 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 appProject 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 fileVersion 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 Data API v3 key | Yes | None |
| Langfuse tracing public key | No | None |
| Langfuse tracing secret key | No | None |
| Langfuse host URL | No | |
| Server port (HTTP mode) | No | 8000 |
| 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.
Related Projects
mcp-refcache - Reference-based caching for MCP servers
FastMCP - High-performance MCP server framework
Model Context Protocol - Official MCP specification
YouTube Data API v3 - YouTube API documentation
youtube-transcript-api - Transcript library
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 toolsadmin_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 detailsCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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 paginationCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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 broadcastingCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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 messagesCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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 transcriptsCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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_idfrom a previous tool callLarge 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 detailsCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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 optionsCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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 streamsCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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 transcriptCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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 setsCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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 chatCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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 setsCaching Behavior:
Parameters that accept reference strings can accept a
ref_idfrom a previous tool callLarge 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
warmup_semantic_searchA
Pre-load the embedding model and vector store for semantic search.
Call this before your first semantic search to avoid timeout. Downloads and initializes the Nomic embedding model (~270MB) and creates the vector store connection.
The warmup process:
Downloads the embedding model (if not cached)
Loads the model into memory
Runs a test embedding to warm up inference
Initializes the vector store connection
Returns: Dictionary with warmup status: - status: "ready" if successful - model: Name of the embedding model loaded - dimensionality: Embedding dimensions configured - inference_mode: How embeddings are computed (local/remote) - test_embedding_size: Size of test embedding (confirms model works) - warmup_time_seconds: Time taken to warm up
Note: - First call downloads ~270MB model (takes 30-60 seconds) - Subsequent calls are instant (model cached on disk) - Model stays in memory for fast inference after warmup
Inputs: no named parameters. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 31 tools
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.
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.
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.
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
Related MCP Connectors
Real-time YouTube transcripts, comments, channels & video search MCP. Local npx or hosted OAuth.
An MCP server that gives any LLM or agent clean YouTube transcripts on demand: a single video, a whole channel, or a playlist, plus AI cleanup of auto-generated captions. API-key auth, credit-based, same backend as the public v1 API. Get a free API key with 25 free credits at youtubetranscriptdownload.com/account.
Hosted YouTube MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
YouTube transcripts, search, channel/playlist listings and upload tracking for AI agents.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn 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.-
- AlicenseNot gradedqualityNot gradedmaintenanceAn 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-
- FlicenseNot gradedqualityDmaintenanceMCP server for YouTube that provides tools to fetch video metadata and transcripts, enabling natural language queries about YouTube videos.2-
- AlicenseNot gradedqualityBmaintenanceA comprehensive MCP server providing YouTube transcript retrieval, video search, channel browsing, playlist extraction, and upload monitoring for AI agents.13MIT