youtube-research-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| YT_DLP_COOKIEFILE | No | Path to a cookies.txt file exported from your browser, used when YouTube requires sign-in to confirm you're not a bot. | |
| YT_DLP_COOKIES_FROM_BROWSER | No | Browser name to use for YouTube cookies (e.g., 'chrome', 'firefox', 'edge'). Note: this fails if the specified browser is currently running. |
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 |
|---|---|
| list_channel_videosA | List a YouTube channel's uploads, newest first, without an API key. Use this to survey what a channel has published before deciding which videos are worth transcribing. Also accepts playlist URLs. Args: channel_url: A handle ('@mwganson'), a bare name ('mwganson'), a channel ID ('UCxxxx...'), any youtube.com channel URL (with or without a /videos, /shorts or /streams tab), or a playlist URL. max_results: How many videos to return, newest first (1-1000, default 50). resolve_all_dates: False (default) fills upload dates for roughly the 15 most recent videos from the channel's RSS feed, which is one extra cheap request. True fetches every listed video's metadata to date the whole list - accurate but roughly one request per video, so only use it on small max_results. Returns: { "channel": str | None, # display name "channel_id": str | None, # UC... id "channel_url": str, # URL actually listed "total_videos": int | None, # total on the channel/playlist, if known "count": int, # videos in this response "videos": [ { "video_id": str, # e.g. "Tbiu_rMJolk" "title": str, "url": str, # watch URL, feed straight to get_video_transcript "duration_seconds": int | None, "duration": str | None, # "44:19" "view_count": int | None, "upload_date": str | None # "2022-08-14", None if not resolved } ] } Errors: Raises ValueError for an unparseable channel reference and RuntimeError with an actionable message if YouTube refuses the listing. |
| get_video_transcriptA | Fetch a video's transcript as clean plain text. No download, no API key. Prefers a human-written caption track and falls back to YouTube's auto-generated one. Nothing is written to disk - the caption track is read straight into memory. Args: video_url_or_id: An 11-character video ID, or any watch/youtu.be/shorts/ live/embed URL. language: Preferred caption language code (default 'en'). Regional variants match too ('en' will accept 'en-US'); if the language is missing entirely, the first available track is used. include_timestamps: True prefixes each paragraph with [H:MM:SS], which is what you want when you intend to cite a moment in the video. max_chars: Truncate the transcript at this many characters (0 = no limit). Set it when scanning many videos, since a long tutorial can run tens of thousands of characters. Returns: { "video_id": str, "title": str | None, "channel": str | None, "url": str, "duration_seconds": int | None, "duration": str | None, "upload_date": str | None, # "2022-08-14" "transcript_kind": str, # "manual" or "automatic" "language": str, # track actually used, e.g. "en" "char_count": int, "truncated": bool, "transcript": str # blank-line separated ~30s paragraphs } Errors: Raises ValueError for an unparseable video reference, and RuntimeError when the video is unavailable or has no caption track at all (some videos genuinely have none - listen for that message rather than retrying). |
| search_youtubeA | Search YouTube by keyword when you do not yet know the channel or video. The entry point for research that starts from a topic rather than a URL: find candidate videos here, then feed their channel or URL to list_channel_videos or get_video_transcript. Args: query: Free-text search, e.g. "FreeCAD sketcher constraints tutorial". max_results: How many results to return (1-100, default 20). Returns: { "query": str, "count": int, "videos": [ {video_id, title, url, duration_seconds, duration, view_count, channel} ] } Search results carry no upload date; call get_video_transcript or list_channel_videos if you need one. Errors: Raises ValueError on an empty query and RuntimeError if the search fails. |
| get_video_framesA | See what a video actually shows at chosen moments. Returns real images. Transcripts cannot capture a screen-based tutorial. "Click this, then drag it here" has no referent in text, toolbar clicks are usually silent, typed dialog values are rarely spoken, and auto-captions mangle exactly the technical terms you need. Use this to look at the moments that matter. The intended workflow is two steps, and doing it in this order is what keeps it cheap:
The video-only stream is fetched to a temp file first, then every frame comes off it locally. That sounds expensive and is not: video-only means no audio track, so a 31 minute 720p tutorial is about 32 MB and lands in under 10 seconds, and further calls on the same video are instant because the file is kept for the life of the server process (3 videos max, deleted on exit). Asking for many timestamps in ONE call is therefore much cheaper than many calls, and vastly cheaper than one call per frame on different videos. Args: video_url_or_id: An 11-character video ID or any YouTube video URL. timestamps: The moments to capture, as 'S', 'M:SS' or 'H:MM:SS' strings (e.g. ["4:12", "11:38", "1:02:05"]). Take these from a timestamped transcript. every_seconds: Instead of explicit timestamps, sample evenly this many seconds apart. Use only when surveying an unfamiliar video; explicit timestamps are far cheaper. Ignored if timestamps is given. max_frames: Hard cap on frames returned (1-20, default 6). Every frame costs context, so keep this tight. width: Output width in pixels (320-1920, default 1280). Do not go below about 960 if you need to read menu labels or dialog values. max_height: Source stream height to fetch (default 720, which is enough to read a CAD toolbar and keeps the fetch small). Raise to 1080 only if 720 proves too coarse. quality: JPEG quality, 2 is best and 31 is worst (default 4). Returns: A list whose first item is a text summary (video title, duration, and the timestamp of each frame in order), followed by one image per timestamp. Frames that could not be captured are reported in the summary text rather than failing the whole call. Errors: Raises ValueError for bad arguments or unparseable timestamps, and RuntimeError if ffmpeg is missing or the video has no playable stream. |
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
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/Diterex/youtube-research-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server