UNPKG

youtube-data-mcp

Version:

MCP server for YouTube data extraction - transcripts, comments, and search

92 lines 4.48 kB
import { z } from "zod"; import { getVideoId, createToolResponse, createErrorResponse } from "../utils/helpers.js"; import * as serpapi from "../services/serpapi.js"; import * as youtube from "../services/youtube.js"; export function registerTools(server) { server.tool("getTranscript", "Extract transcript/subtitles from a YouTube video. Returns full text with video metadata. Supports multiple languages and optional timestamps.", { url: z.string().describe("YouTube video URL or 11-character video ID"), lang: z.string().default("en").describe("Language code (en, ko, ja, es, etc.)"), includeTimestamps: z.boolean().default(false).describe("Include start time and duration for each segment"), }, async ({ url, lang, includeTimestamps }) => { try { const videoId = getVideoId(url); if (!videoId) { throw new Error("Invalid YouTube URL or video ID"); } const result = includeTimestamps ? await youtube.getTranscriptWithTimestamps(videoId, lang) : await youtube.getTranscript(videoId, lang); return createToolResponse(result); } catch (error) { return createErrorResponse(error); } }); server.tool("getVideoInfo", "Get YouTube video metadata: title, views, publish date, channel, comment count, and pagination tokens for comments.", { url: z.string().describe("YouTube video URL or video ID"), }, async ({ url }) => { try { const videoId = getVideoId(url); if (!videoId) { throw new Error("Invalid YouTube URL or video ID"); } const result = await serpapi.getVideoInfo(videoId); return createToolResponse(result); } catch (error) { return createErrorResponse(error); } }); server.tool("getComments", "Fetch YouTube video comments with pagination. Supports sorting by relevance or time. Use nextPageToken for pagination.", { url: z.string().optional().describe("YouTube video URL or ID (required for first page)"), limit: z.number().default(100).describe("Max comments to return (1-100)"), sort: z.enum(["relevance", "time"]).default("relevance").describe("Sort: relevance or time"), pageToken: z.string().optional().describe("Pagination token from previous response"), }, async ({ url, limit, sort, pageToken }) => { try { if (!url && !pageToken) { throw new Error("Either url or pageToken required"); } let videoId; if (url) { videoId = getVideoId(url) || undefined; if (!videoId) { throw new Error("Invalid YouTube URL or video ID"); } } const result = await serpapi.getComments(videoId, limit, sort, pageToken); return createToolResponse(result); } catch (error) { return createErrorResponse(error); } }); server.tool("getCommentReplies", "Fetch replies to a specific YouTube comment. Use repliesToken from getComments response.", { pageToken: z.string().describe("repliesToken from a comment object"), }, async ({ pageToken }) => { try { const result = await serpapi.getReplies(pageToken); return createToolResponse(result); } catch (error) { return createErrorResponse(error); } }); server.tool("searchYoutube", "Search YouTube for videos, channels, and playlists. Returns results with thumbnails, views, and channel info.", { query: z.string().describe("Search query"), limit: z.number().default(10).describe("Max results (1-50)"), gl: z.string().optional().describe("Country code (us, kr, jp)"), hl: z.string().optional().describe("Language code (en, ko, ja)"), sp: z.string().optional().describe("Filter parameter for duration/date"), pageToken: z.string().optional().describe("Pagination token"), }, async ({ query, limit, gl, hl, sp, pageToken }) => { try { const result = await serpapi.searchYouTube(query, limit, gl, hl, sp, pageToken); return createToolResponse(result); } catch (error) { return createErrorResponse(error); } }); } //# sourceMappingURL=index.js.map