list_captions
List caption tracks for a YouTube video, showing language, name, status, and draft status. Provide the video ID to retrieve available captions.
Instructions
List caption tracks on a video with their language, name, status, and whether they are drafts.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| video_id | Yes | Video ID to list captions for. |
Implementation Reference
- src/tools/captions.ts:38-40 (schema)Schema for list_captions, defining video_id as a required string input.
const listCaptionsSchema = { video_id: z.string().describe("Video ID to list captions for."), }; - src/tools/captions.ts:50-77 (handler)Handler for the list_captions tool. Calls client.listCaptions(video_id) and formats the output listing each caption track's id, language, name, trackKind, status, and draft status.
server.tool( "list_captions", "List caption tracks on a video with their language, name, status, and whether they are drafts.", listCaptionsSchema, async (args) => { const res = await client.listCaptions(args.video_id); if (res.items.length === 0) { return { content: [ { type: "text" as const, text: `Video ${args.video_id} has no caption tracks.`, }, ], }; } const lines = [ `Found ${res.items.length} caption track(s):`, ...res.items.map((c) => { const s = c.snippet ?? {}; const draft = s.isDraft ? " [draft]" : ""; const kind = s.trackKind ? ` (${s.trackKind})` : ""; return ` ${c.id} — ${s.language ?? "?"} "${s.name ?? ""}"${kind} [${s.status ?? "?"}]${draft}`; }), ]; return { content: [{ type: "text" as const, text: lines.join("\n") }] }; }, ); - src/tools/captions.ts:46-135 (registration)Registration function registerCaptionTools that calls server.tool("list_captions", ...) along with upload_caption and delete_caption on the MCP server.
export function registerCaptionTools( server: McpServer, client: YouTubeClient, ): void { server.tool( "list_captions", "List caption tracks on a video with their language, name, status, and whether they are drafts.", listCaptionsSchema, async (args) => { const res = await client.listCaptions(args.video_id); if (res.items.length === 0) { return { content: [ { type: "text" as const, text: `Video ${args.video_id} has no caption tracks.`, }, ], }; } const lines = [ `Found ${res.items.length} caption track(s):`, ...res.items.map((c) => { const s = c.snippet ?? {}; const draft = s.isDraft ? " [draft]" : ""; const kind = s.trackKind ? ` (${s.trackKind})` : ""; return ` ${c.id} — ${s.language ?? "?"} "${s.name ?? ""}"${kind} [${s.status ?? "?"}]${draft}`; }), ]; return { content: [{ type: "text" as const, text: lines.join("\n") }] }; }, ); server.tool( "upload_caption", "Upload a caption track (SRT or WebVTT) to a video. Creates a new track — use a distinct `name` per language/track, or `is_draft=true` while iterating.", uploadCaptionSchema, async (args) => { const contentType = args.format === "vtt" ? "text/vtt" : "application/x-subrip"; const bytes = new Uint8Array(Buffer.from(args.caption_text, "utf-8")); const result = (await client.insertCaption({ videoId: args.video_id, language: args.language, name: args.name, isDraft: args.is_draft, body: bytes, captionContentType: contentType, })) as { id?: string; snippet?: { status?: string }; }; return { content: [ { type: "text" as const, text: [ `Uploaded caption track: ${result.id ?? "(unknown id)"}`, ` video: ${args.video_id}`, ` language: ${args.language}`, ` name: "${args.name}"`, ` format: ${args.format}`, ` status: ${result.snippet?.status ?? "?"}`, args.is_draft ? " (draft — not visible to viewers)" : "", ] .filter(Boolean) .join("\n"), }, ], }; }, ); server.tool( "delete_caption", "Delete a caption track by ID. Use list_captions to find the track ID first.", deleteCaptionSchema, async (args) => { await client.deleteCaption(args.caption_id); return { content: [ { type: "text" as const, text: `Deleted caption track ${args.caption_id}.`, }, ], }; }, ); } - src/server.ts:17-17 (registration)Import of registerCaptionTools from the captions module.
import { registerCaptionTools } from "./tools/captions.js"; - src/youtube/client.ts:276-290 (helper)YouTubeClient.listCaptions method that calls the YouTube Data API /captions endpoint with part=snippet and videoId.
listCaptions(videoId: string): Promise<{ items: Array<{ id: string; snippet?: { name?: string; language?: string; status?: string; isDraft?: boolean; lastUpdated?: string; trackKind?: string; }; }>; }> { return this.dataGet("/captions", { part: "snippet", videoId }); }