Skip to main content
Glama

mcp-youtube

by kirbah
getVideoDetails.ts4.82 kB
import { z } from "zod"; import { YoutubeService } from "../../services/youtube.service.js"; import { formatError } from "../../utils/errorHandler.js"; import { formatSuccess } from "../../utils/responseFormatter.js"; import { videoIdSchema } from "../../utils/validation.js"; import { calculateLikeToViewRatio, calculateCommentToViewRatio, } from "../../utils/engagementCalculator.js"; import { parseYouTubeNumber } from "../../utils/numberParser.js"; import { formatDescription } from "../../utils/textUtils.js"; import type { VideoDetailsParams } from "../../types/tools.js"; import type { LeanVideoDetails } from "../../types/youtube.js"; import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; export const getVideoDetailsSchema = z.object({ videoIds: z .array(videoIdSchema) .describe("Array of YouTube video IDs to get details for"), includeTags: z .boolean() .optional() .default(false) .describe( "Specify 'true' to include the video's 'tags' array in the response, which is useful for extracting niche keywords. The 'tags' are omitted by default to conserve tokens." ), descriptionDetail: z .enum(["NONE", "SNIPPET", "LONG"]) .optional() .default("NONE") .describe( "Controls video description detail to manage token cost. Options: 'NONE' (default, no text), 'SNIPPET' (a brief preview for broad scans), 'LONG' (a 500-char text for deep analysis of specific targets)." ), }); export const getVideoDetailsConfig = { name: "getVideoDetails", description: "Get detailed information about multiple YouTube videos. Returns comprehensive data including video metadata, statistics, and content details. Use this when you need complete information about specific videos.", inputSchema: getVideoDetailsSchema, }; export const getVideoDetailsHandler = async ( params: VideoDetailsParams, youtubeService: YoutubeService ): Promise<CallToolResult> => { try { const validatedParams = getVideoDetailsSchema.parse(params); const videoPromises = validatedParams.videoIds.map(async (videoId) => { // 1. Call the service. Caching is now transparent and handled inside youtubeService. const fullVideoDetails = await youtubeService.getVideo({ videoId, parts: ["snippet", "statistics", "contentDetails"], }); // 2. The transformation logic remains here. It operates on the data // whether it came from the cache or a live API call. if (!fullVideoDetails) { // Handle case where video is not found return { [videoId]: null }; } // ... all your existing logic to parse counts and create the 'leanDetails' object ... const viewCount = parseYouTubeNumber( fullVideoDetails.statistics?.viewCount ); const likeCount = parseYouTubeNumber( fullVideoDetails.statistics?.likeCount ); const commentCount = parseYouTubeNumber( fullVideoDetails.statistics?.commentCount ); const formattedDescription = formatDescription( fullVideoDetails.snippet?.description, validatedParams.descriptionDetail ); const baseLeanDetails = { id: fullVideoDetails.id ?? null, title: fullVideoDetails.snippet?.title ?? null, channelId: fullVideoDetails.snippet?.channelId ?? null, channelTitle: fullVideoDetails.snippet?.channelTitle ?? null, publishedAt: fullVideoDetails.snippet?.publishedAt ?? null, duration: fullVideoDetails.contentDetails?.duration ?? null, viewCount: viewCount, likeCount: likeCount, commentCount: commentCount, likeToViewRatio: calculateLikeToViewRatio(viewCount, likeCount), commentToViewRatio: calculateCommentToViewRatio( viewCount, commentCount ), categoryId: fullVideoDetails.snippet?.categoryId ?? null, defaultLanguage: fullVideoDetails.snippet?.defaultLanguage ?? null, }; const detailsWithDescription = formattedDescription !== undefined ? { ...baseLeanDetails, description: formattedDescription } : baseLeanDetails; const leanDetails: LeanVideoDetails = validatedParams.includeTags ? { ...detailsWithDescription, tags: fullVideoDetails.snippet?.tags ?? [], } : detailsWithDescription; // Return the final transformed object for this video return { [videoId]: leanDetails }; }); const results = await Promise.all(videoPromises); const finalOutput = results.reduce( (acc, current) => ({ ...acc, ...current }), {} as Record<string, LeanVideoDetails | null> ); return formatSuccess(finalOutput); } catch (error: any) { return formatError(error); } };

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/kirbah/mcp-youtube'

If you have feedback or need assistance with the MCP directory API, please join our Discord server