MCP server for natural-language YouTube channel discovery + Gemini-powered video summaries. Zero YouTube API key required.
Server has 11 tools with mostly complete schemas and descriptions. Naming is verb-forward and clear (discover_, analyze_, add_, remove_, list_, search_, resolve_, get_). Descriptions are detailed (100-400 chars) and explain WHEN to use each tool. However, several tools lack output schema documentation, error handling guidance is minimal, and some parameter descriptions could be more precise about constraints and formats. No tool annotations (readOnlyHint/destructiveHint) despite clear risk profiles. Composition is good, tools chain well (discover → analyze → poll pattern). Security: GEMINI_API_KEY injected via environment, not exposed as parameter (correct). Overall: solid foundation with gaps in schema completeness and error guidance.
Add a channel to the MCP's registry so discover_new_videos defaults to it.
Poll for an analyze_video_start result. Blocks up to wait_seconds for a state change. Default wait_seconds=10 keeps the blocking window well under the typical 60s MCP request timeout enforced by hosts. Smaller blocking window = guaranteed return well under 60s at the cost of more poll round-trips (cheap, ~1KB per poll). Recommended pattern: call with wait_seconds=10 each poll. Cap total polling at ~90 iterations (~15 min) — most podcasts finish within 3-5 min. If a poll returns an MCP-transport error (not a `status: "error"` payload), the underlying job is likely still alive on the server — re-poll with the SAME job_id rather than starting over.
Launch Gemini video analysis as a background job. Returns in <1s with a job_id. **This is the default for both single-video and multi-video requests.** For multiple videos, fire this tool N times back-to-back (each call returns in <1s with its own job_id) — the analyses run concurrently in background threads, so wall-clock time is bounded by the slowest single video (~3-10 min), NOT N × per-video time. Then poll `analyze_video_result(job_id)` for each job_id. Use `analyze_videos_batch_start` ONLY when the user explicitly says "no rush", "overnight", or for scheduled / cron digests where minutes- to-hours latency is acceptable in exchange for 50% cost savings. Podcast-length videos take Gemini 3-15 min to analyze, which exceeds typical MCP host request timeouts (Claude Desktop, Claude Code, OpenClaw all cap individual tool calls at ~60s). This tool spawns a background thread and returns immediately; poll `analyze_video_result(job_id)` to get the finished analysis. Does NOT update discovery state. Caller is responsible for calling discover_new_videos (which manages state) beforehand.
Output schemas not documented. Tools return dicts (DiscoverResult, AnalysisResult, etc.) but LLM cannot see field structure. Forces LLM to guess what fields exist and their types.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). Tools marked 'Risk: WRITE' in metadata but LLM cannot see this. Agents may retry destructive ops (add_tracked_channel, remove_tracked_channel) without knowing they are non-idempotent.
Error handling lacks recovery guidance. No tool returns actionable error messages (e.g., 'Channel not found. Try search_youtube_channels() first'). Stack traces or bare error codes give LLM no next step.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | 2026-07-28+ | v2 |
Poll for batch analysis results. Returns results for completed jobs or current state.
Submit multiple videos for batch analysis (50% cheaper, async, up to 24h latency). Use only when the user explicitly says "no rush", "overnight", or for scheduled digests.
Discover new videos from YouTube channels since the last time this MCP saw them. Two modes for selecting channels: 1. Pass `channel_ids` explicitly (legacy behavior). 2. Omit `channel_ids` and the MCP reads from its tracked-channel registry (managed by add_tracked_channel / remove_tracked_channel). Use `tag` to filter the registry — e.g. tag="macro" returns only channels tagged macro. State is tracked per channel in a server-managed JSON file. On the FIRST call for a channel, the most recent video is returned (and state is seeded) so the caller has something to analyze without ingesting the entire backlog. Filters applied: - Livestreams (duration == 0) are skipped - Videos shorter than min_duration_seconds are skipped (default 10 minutes) - Videos older than or equal to the last-seen video are skipped
Fetch full metadata for a known channel_id. Raises ValueError for inputs that don't look like UCxxxx ids.
List all channels in the MCP's registry, optionally filtered by tag.
Remove a channel from the MCP's registry.
Resolve a handle (@x) or full channel URL to a ChannelInfo dict. Returns None for video URLs, free-text strings, or channels yt-dlp can't load.
Find YouTube channels matching a free-text query. Uses yt-dlp's ytsearchN: magic prefix to fetch video results, then groups by channel_id and ranks the unique channels by relevance. Returns the top max_results.
Parameter constraints not fully specified. 'max_per_channel' and 'max_results' lack min/max bounds. 'min_duration_seconds' default is 600 but no range stated. LLM could pass absurd values (e.g., max_per_channel=10000).
Polling pattern (analyze_video_result) lacks timeout guidance. Description says 'cap total polling at ~90 iterations (~15 min)' but tool has no built-in timeout or max_polls parameter. LLM could poll indefinitely.