get_video_metadata
Retrieve detailed metadata from any YouTube video including title, description, channel, duration, and chapters. Provide a video URL or ID to get structured information.
Instructions
Fetch metadata (title, description, channel, upload date, duration, views, chapters, etc.) for a YouTube video.
Args: url: YouTube video URL or video ID
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- main.py:367-421 (handler)The main tool handler function for 'get_video_metadata'. It extracts the video ID, fetches metadata via _fetch_metadata, and formats the output (title, channel, publish date, duration, views, likes, tags, chapters, description, etc.). Decorated with @mcp.tool().
@mcp.tool() def get_video_metadata(url: str) -> str: """Fetch metadata (title, description, channel, upload date, duration, views, chapters, etc.) for a YouTube video. Args: url: YouTube video URL or video ID """ try: video_id = extract_video_id(url) except ValueError as e: return f"Error: {e}" meta = _fetch_metadata(video_id) if meta is None: return f"Error: Failed to fetch metadata for video '{video_id}'." lines = [f"Metadata for video '{video_id}':", ""] if meta.get("title"): lines.append(f"Title: {meta['title']}") if meta.get("channel"): ch = meta["channel"] if meta.get("channel_url"): ch = f"{ch} ({meta['channel_url']})" lines.append(f"Channel: {ch}") pub = _format_upload_date(meta.get("upload_date")) if pub: lines.append(f"Published: {pub}") if meta.get("duration_seconds") is not None: lines.append(f"Duration: {_format_hms(meta['duration_seconds'])}") if meta.get("view_count") is not None: lines.append(f"Views: {meta['view_count']:,}") if meta.get("like_count") is not None: lines.append(f"Likes: {meta['like_count']:,}") if meta.get("age_limit"): lines.append(f"Age limit: {meta['age_limit']}") if meta.get("is_live"): lines.append("Live: yes") if meta.get("categories"): lines.append(f"Categories: {', '.join(meta['categories'])}") if meta.get("tags"): tags = meta["tags"][:20] suffix = "" if len(meta["tags"]) <= 20 else f" (+{len(meta['tags']) - 20} more)" lines.append(f"Tags: {', '.join(tags)}{suffix}") if meta.get("webpage_url"): lines.append(f"URL: {meta['webpage_url']}") if meta.get("thumbnail_url"): lines.append(f"Thumbnail: {meta['thumbnail_url']}") if meta.get("chapters"): lines.extend(["", "Chapters:"]) for ch in meta["chapters"]: start = ch.get("start_time") or 0 lines.append(f" {_format_hms(start)} {ch.get('title', '')}") if meta.get("description"): lines.extend(["", "Description:", meta["description"]]) return "\n".join(lines) - main.py:129-166 (helper)The _fetch_metadata helper function that does the actual data fetching using yt-dlp's YoutubeDL. Returns a dict with title, description, channel, duration, views, likes, tags, chapters, etc., or None on failure.
def _fetch_metadata(video_id: str) -> dict | None: """Fetch video metadata via yt-dlp. Returns None on any failure.""" try: from yt_dlp import YoutubeDL opts = { "quiet": True, "no_warnings": True, "skip_download": True, "logger": _SilentLogger(), } with YoutubeDL(opts) as ydl: info = ydl.extract_info( f"https://www.youtube.com/watch?v={video_id}", download=False, ) if not info: return None return { "title": info.get("title"), "description": info.get("description"), "channel": info.get("channel") or info.get("uploader"), "channel_id": info.get("channel_id"), "channel_url": info.get("channel_url") or info.get("uploader_url"), "upload_date": info.get("upload_date"), "duration_seconds": info.get("duration"), "view_count": info.get("view_count"), "like_count": info.get("like_count"), "tags": info.get("tags") or [], "categories": info.get("categories") or [], "thumbnail_url": info.get("thumbnail"), "chapters": info.get("chapters") or [], "age_limit": info.get("age_limit"), "is_live": info.get("is_live"), "webpage_url": info.get("webpage_url"), } except Exception: return None - main.py:226-229 (helper)Helper to format upload date from YYYYMMDD to YYYY-MM-DD.
def _format_upload_date(yyyymmdd: str | None) -> str | None: if not yyyymmdd or len(yyyymmdd) != 8: return yyyymmdd return f"{yyyymmdd[0:4]}-{yyyymmdd[4:6]}-{yyyymmdd[6:8]}" - main.py:169-174 (helper)Helper to format seconds into HH:MM:SS string.
def _format_hms(seconds: float | int) -> str: """Format seconds as HH:MM:SS (no brackets).""" total = int(seconds) h, rem = divmod(total, 3600) m, s = divmod(rem, 60) return f"{h:02d}:{m:02d}:{s:02d}" - main.py:40-50 (helper)Helper to extract a YouTube video ID from a URL or bare ID string. Used by get_video_metadata to parse the input 'url' argument.
def extract_video_id(url_or_id: str) -> str: """Extract a YouTube video ID from a URL or bare ID string.""" url_or_id = url_or_id.strip() if BARE_ID_REGEX.match(url_or_id): return url_or_id match = VIDEO_ID_REGEX.search(url_or_id) if match: return match.group(1) raise ValueError( f"Could not extract a YouTube video ID from: {url_or_id}" )