podcast-summarizer-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| GEMINI_API_KEY | Yes | Your Gemini API key from https://aistudio.google.com | |
| VIDEO_ANALYSIS_JOBS_PATH | No | Path to store job data | ~/.podcast-summarizer-mcp/jobs.json |
| VIDEO_ANALYSIS_STATE_PATH | No | Path to store video state | ~/.podcast-summarizer-mcp/video-state.json |
| VIDEO_ANALYSIS_PROMPT_PATH | No | Path to custom prompt file (re-read on every analysis) | |
| VIDEO_ANALYSIS_CHANNELS_PATH | No | Path to store channel registry | ~/.podcast-summarizer-mcp/channels.json |
| VIDEO_ANALYSIS_BATCH_METADATA_PATH | No | Path to store batch metadata | ~/.podcast-summarizer-mcp/batches.json |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| discover_new_videosA | Discover new videos from YouTube channels since the last time this MCP saw them. Two modes for selecting channels:
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:
Args: channel_ids: Optional list of YouTube channel IDs. If omitted, the registry is used. tag: Optional tag filter for registry-based mode (ignored if channel_ids given). max_per_channel: How many recent uploads to inspect per channel (default 5) min_duration_seconds: Minimum video length to include (default 600 = 10min) Returns: DiscoverResult with new_videos (newest first), skipped, channels_processed, and first_run_channels (channels that had no prior state). |
| analyze_video_startA | 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
Use 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 Does NOT update discovery state. Caller is responsible for calling discover_new_videos (which manages state) beforehand. Args:
video_url: Full YouTube URL (https://www.youtube.com/watch?v=...)
max_retries: How many Gemini retries on empty/short output (default 3)
prompt: Optional override for the analysis prompt. If None, the
default ships with an investment-podcast persona — set
$VIDEO_ANALYSIS_PROMPT_PATH to change the host-wide default,
or pass Returns: { job_id, video_url, status: "pending" } |
| analyze_video_resultA | 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 Args: job_id: The id returned by analyze_video_start wait_seconds: How many seconds to block waiting for completion (default 10, clamped to [0, 55] to stay safely under the MCP 60s request timeout) Returns: { job_id, status, video_url, created_at, started_at, finished_at, result?, error?, attempts }
|
| analyze_videos_batch_startA | Submit a batch of YouTube videos to Gemini Batch API for async analysis. Use this ONLY when the user explicitly says "no rush", "overnight",
"do it later", or for scheduled cron digests. Batch is 50% cheaper
than Args:
video_urls: List of full YouTube URLs (https://www.youtube.com/watch?v=...)
prompt: Optional override for the analysis prompt. If None, the
default ships with an investment-podcast persona — set
$VIDEO_ANALYSIS_PROMPT_PATH to change the host-wide default,
or pass Returns: { batch_job_name, video_count, video_urls, status: "pending", skipped: [{video_url, reason}] } |
| analyze_videos_batch_resultA | Poll the Gemini Batch API once; if done, return per-video results. Call repeatedly until status is SUCCEEDED / FAILED / CANCELLED / EXPIRED. Recommended cadence: every 30-60s. Args: batch_job_name: Name returned by analyze_videos_batch_start Returns: { status, batch_job_name, results? (on SUCCEEDED), error? (on terminal failure) }
|
| get_video_infoA | Cheap metadata-only lookup for a single YouTube video (1 YouTube API unit). Use this to inspect a video's title, duration, channel, and publish date without burning Gemini tokens. Args: video_url: Full YouTube URL or just the video ID min_duration_seconds: Threshold for the excluded_from_analysis flag (default 600) |
| get_stateA | Read-only view of the discovery state file. Returns the last-seen video_id, published_at, and analyzed_at for each channel that has been processed. Useful for answering "what's the latest video I've seen from channel X?" without re-hitting YouTube. Args: channel_ids: If provided, return only these channels. Otherwise return all. |
| search_youtube_channelsA | Search YouTube for channels matching a free-text query. Use this when the user names a channel ("Forward Guidance", "All-In podcast") or describes one ("a good macro investing channel") and you need to identify candidate channels before adding to the registry. No YouTube API key required — uses yt-dlp scraping under the hood. Args: query: Free-text search term, e.g. "Forward Guidance" or "macro investing". max_results: How many distinct channels to return, ranked by relevance (default 5). Returns: { "candidates": [ { "channel_id", "name", "channel_url", "hit_count", "confidence_score" }, ... ] } Empty list if nothing matches. Subscriber count + recent videos are NOT populated here — call get_channel_metadata(channel_id) for that. |
| resolve_youtube_channelA | Resolve a YouTube handle (@name) or channel URL to channel metadata. Use this when the user gives an exact handle or URL — skips the search step. Returns None / error for video URLs, free-text strings, or channels that can't be loaded. Args: handle_or_url: e.g. "@ForwardGuidance" or "https://www.youtube.com/@ForwardGuidance" or "https://www.youtube.com/channel/UCxxxxx". Returns: { channel_id, name, handle, description, subscriber_count, channel_url, recent_video_titles } on success. { "error": "..." } on failure. |
| get_channel_metadataA | Fetch full metadata for a known channel_id. Use after search_youtube_channels to enrich a candidate with subscriber count, description, and recent video titles before presenting to the user. Args: channel_id: YouTube channel ID (must start with "UC"). Returns: { channel_id, name, handle, description, subscriber_count, channel_url, recent_video_titles }. |
| add_tracked_channelA | Add a channel to the registry. You MUST call this tool to add a channel — claiming "I've added X" without invoking it leaves the user's registry empty and the user has no way to know until they next ask "what am I tracking" and discover the missing channels. Idempotent: re-adding the same channel_id updates name/handle/tags but preserves the original added_at timestamp. Tags are arbitrary strings — use them to group channels (e.g. ["macro"], ["semis", "podcast"]). Args: channel_id: YouTube channel ID, must start with "UC". name: Display name (the user-friendly label). handle: Optional "@handle" (cosmetic, helps users identify the channel). tags: Optional list of grouping strings (default empty). Returns:
{ added: true,
channel: {channel_id, name, handle, tags, added_at},
registry_total: ,
registry_now_contains: [name, name, ...], # alphabetical
user_facing_message: "Added X. Registry now has N channels: ..." }
Use |
| remove_tracked_channelA | Remove a channel from the registry. You MUST call this tool to remove — claiming "I've removed X" without invoking it leaves the channel still tracked and produces silently wrong state. No-op (returns removed=false) if the channel_id wasn't tracked. Does NOT clear the per-channel last-seen state, so re-adding later won't re-ingest the backlog. Args: channel_id: YouTube channel ID. Returns:
{ removed: true|false,
channel_id,
registry_total: ,
registry_now_contains: [name, name, ...],
user_facing_message: "Removed X. Registry now has N channels: ..." }
Use |
| list_tracked_channelsA | List all channels currently in the registry. Always call this tool when the user asks "what am I tracking" or similar — never answer from memory or prior conversation context, since the registry can be mutated by other clients between turns. Args: tag: If provided, return only channels carrying this tag. Returns:
{ channels: [{channel_id, name, handle, tags, added_at}, ...],
count, tag,
user_facing_message: "Tracking N channels: ..." or "No channels tracked." }
Use |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kaiding-ucb/podcast-summarizer-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server