getTrendingVideos
Retrieves trending videos filtered by region and category to discover popular content in specific areas or categories.
Instructions
Retrieves trending videos based on region and category. Returns a list of videos that are currently popular in the specified region and category. Use this when you want to discover what's trending in specific areas or categories. To get available category IDs and their names, use the getVideoCategories tool first.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| regionCode | No | Two-letter country code (e.g., 'US', 'GB', 'JP'). Defaults to 'US' | US |
| categoryId | No | YouTube category ID to filter trending videos by category. Use getVideoCategories tool to get available category IDs. | |
| maxResults | No | Maximum number of trending videos to return (1-500, default: 10) |
Implementation Reference
- The GetTrendingVideosTool class that executes the tool logic. It extends BaseTool, defers to youtubeService.getTrendingVideos(), and formats the result via formatSuccess().
export class GetTrendingVideosTool extends BaseTool< typeof getTrendingVideosSchema > { name = "getTrendingVideos"; description = "Retrieves trending videos based on region and category. Returns a list of videos that are currently popular in the specified region and category. Use this when you want to discover what's trending in specific areas or categories. To get available category IDs and their names, use the getVideoCategories tool first."; schema = getTrendingVideosSchema; protected async executeImpl( params: z.infer<typeof getTrendingVideosSchema> ): Promise<CallToolResult> { const trendingVideos = await this.container.youtubeService.getTrendingVideos(params); return formatSuccess(trendingVideos); } } - src/services/youtube.service.ts:604-674 (handler)The core service implementation getTrendingVideos() that calls the YouTube API v3 videos.list endpoint with chart='mostPopular', handles regionCode, categoryId, maxResults parameters, and returns lean trending video data with engagement ratios.
async getTrendingVideos( options: TrendingOptions ): Promise<LeanTrendingVideo[]> { const cacheKey = this.cacheService.createOperationKey( "getTrendingVideos", options ); const operation = async (): Promise<LeanTrendingVideo[]> => { try { const { regionCode = "US", categoryId, maxResults = 10 } = options; const params: youtube_v3.Params$Resource$Videos$List = { part: ["snippet", "statistics", "contentDetails"], chart: "mostPopular", regionCode: regionCode, maxResults: maxResults, }; if (categoryId) { params.videoCategoryId = categoryId; } const response = await this.trackCost( () => this.youtube.videos.list(params), API_COSTS["videos.list"] ); return ( response.data.items?.map((video) => { const viewCount = parseYouTubeNumber(video.statistics?.viewCount); const likeCount = parseYouTubeNumber(video.statistics?.likeCount); const commentCount = parseYouTubeNumber( video.statistics?.commentCount ); return { id: video.id, title: video.snippet?.title, channelId: video.snippet?.channelId, channelTitle: video.snippet?.channelTitle, publishedAt: video.snippet?.publishedAt, duration: video.contentDetails?.duration, viewCount: viewCount, likeCount: likeCount, commentCount: commentCount, likeToViewRatio: calculateLikeToViewRatio(viewCount, likeCount), commentToViewRatio: calculateCommentToViewRatio( viewCount, commentCount ), }; }) || [] ); } catch (error) { if (error instanceof AppError) throw error; throw new YouTubeApiError( `YouTube API call for getTrendingVideos failed`, error ); } }; return this.cacheService.getOrSet( cacheKey, operation, CACHE_TTLS.DYNAMIC, CACHE_COLLECTIONS.TRENDING_VIDEOS, options ); } - Zod schema (getTrendingVideosSchema) defining input parameters: regionCode (default 'US'), categoryId (optional), maxResults (default 10).
export const getTrendingVideosSchema = z.object({ regionCode: regionCodeSchema .default("US") .describe( "Two-letter country code (e.g., 'US', 'GB', 'JP'). Defaults to 'US'" ), categoryId: categoryIdSchema.describe( "YouTube category ID to filter trending videos by category. Use getVideoCategories tool to get available category IDs." ), // categoryId is optional and has no default maxResults: maxResultsSchema .default(10) .describe( "Maximum number of trending videos to return (1-500, default: 10)" ), }); - src/types/youtube.ts:35-47 (schema)LeanTrendingVideo interface defining the output type shape: id, title, channelId, channelTitle, publishedAt, duration, viewCount, likeCount, commentCount, likeToViewRatio, commentToViewRatio.
export interface LeanTrendingVideo { id: string | null | undefined; title: string | null | undefined; channelId: string | null | undefined; channelTitle: string | null | undefined; publishedAt: string | null | undefined; duration: string | null | undefined; viewCount: number | null | undefined; likeCount: number | null | undefined; commentCount: number | null | undefined; likeToViewRatio: number | null | undefined; commentToViewRatio: number | null | undefined; } - src/tools/index.ts:14-89 (registration)Tool registration: GetTrendingVideosTool is imported (line 14), added to TOOL_CLASSES array (line 35), and registered with the MCP server via registerTools() (line 65-87).
import { GetTrendingVideosTool } from "./general/getTrendingVideos.js"; import { GetVideoCategoriesTool } from "./general/getVideoCategories.js"; import { FindConsistentOutlierChannelsTool } from "./general/findConsistentOutlierChannels.js"; interface ITool { readonly name: string; readonly description: string; readonly schema: z.ZodObject<z.ZodRawShape>; execute(args: z.infer<this["schema"]>): Promise<CallToolResult>; } type ToolConstructor = new (container: IServiceContainer) => ITool; // 1. Maintain a list of Constructors const TOOL_CLASSES = [ GetVideoDetailsTool, SearchVideosTool, GetTranscriptsTool, GetVideoCommentsTool, GetChannelStatisticsTool, GetChannelTopVideosTool, GetTrendingVideosTool, GetVideoCategoriesTool, ]; export function registerTools(server: McpServer, container: IServiceContainer) { const hasYoutubeKey = !!process.env.YOUTUBE_API_KEY; const toolsToRegister: ToolConstructor[] = []; if (hasYoutubeKey) { // Register all standard YouTube tools toolsToRegister.push(...(TOOL_CLASSES as ToolConstructor[])); // Register analytics tools if connection string is present if (process.env.MDB_MCP_CONNECTION_STRING) { toolsToRegister.push(FindConsistentOutlierChannelsTool); } } else { // Only register tools that don't require the API key toolsToRegister.push(GetTranscriptsTool); } for (const ToolClass of toolsToRegister) { // Instantiate with DI container const toolInstance = new ToolClass(container); const humanReadableTitle = toolInstance.name .replace(/([A-Z])/g, " $1") .replace(/^./, (str: string) => str.toUpperCase()); // Register with MCP Server server.registerTool( toolInstance.name, { description: toolInstance.description, inputSchema: toolInstance.schema, annotations: { title: humanReadableTitle, readOnlyHint: true, idempotentHint: true, }, }, // eslint-disable-next-line @typescript-eslint/no-unsafe-argument (async ( args: z.infer<typeof toolInstance.schema> ): Promise<CallToolResult> => { try { return await toolInstance.execute(args); } catch (err) { return formatError(err); } // eslint-disable-next-line @typescript-eslint/no-explicit-any }) as any ); } }