Skip to main content
Glama

searchVideos

Find YouTube videos by query with filters for duration, recency, channel, and region to get relevant results with metadata.

Instructions

Searches for videos based on a query string. Returns a list of videos matching the search criteria, including titles, descriptions, and metadata. Use this when you need to find videos related to specific topics or keywords.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
channelIdNoRestrict search to specific channel ID
maxResultsNoMaximum number of results to return (1-500, default: 10)
orderNoSort order for results (default: relevance)
queryYesSearch query string to find videos
recencyNoFilter by recency. Possible values: 'any', 'pastHour', 'pastDay', 'pastWeek', 'pastMonth', 'pastQuarter', 'pastYear'.
regionCodeNo2-letter country code to restrict results
typeNoType of content to search for (default: video)
videoDurationNoFilter by video duration. 'any' (default): no duration filter. 'short': videos less than 4 minutes. 'medium': videos 4 to 20 minutes. 'long': videos longer than 20 minutes.

Implementation Reference

  • The main handler function for the 'searchVideos' MCP tool. It validates input parameters using the schema, calls the youtubeService to perform the search, maps the results to a lean format, and formats the response.
    export const searchVideosHandler = async ( params: SearchParams, youtubeService: YoutubeService ): Promise<CallToolResult> => { try { const validatedParams = searchVideosSchema.parse(params); const rawResults = await youtubeService.searchVideos(validatedParams); const leanResults: LeanVideoSearchResult[] = rawResults.map( (result: youtube_v3.Schema$SearchResult) => ({ videoId: result.id?.videoId ?? null, title: result.snippet?.title ?? null, descriptionSnippet: result.snippet?.description ?? null, channelId: result.snippet?.channelId ?? null, channelTitle: result.snippet?.channelTitle ?? null, publishedAt: result.snippet?.publishedAt ?? null, }) ); return formatSuccess(leanResults); } catch (error: unknown) { return formatError(error); } };
  • Zod schema defining the input parameters for the searchVideos tool, including query, maxResults, order, type, filters etc.
    export const searchVideosSchema = z.object({ query: querySchema.describe("Search query string to find videos"), maxResults: maxResultsSchema .optional() .default(10) .describe("Maximum number of results to return (1-500, default: 10)"), order: z .enum(["relevance", "date", "viewCount"]) .optional() .describe("Sort order for results (default: relevance)"), type: z .enum(["video", "channel"]) .optional() .describe("Type of content to search for (default: video)"), channelId: z .string() .optional() .describe("Restrict search to specific channel ID"), videoDuration: z .enum(["any", "short", "medium", "long"]) .optional() .describe( "Filter by video duration. 'any' (default): no duration filter. 'short': videos less than 4 minutes. 'medium': videos 4 to 20 minutes. 'long': videos longer than 20 minutes." ), recency: z .enum([ "any", "pastHour", "pastDay", "pastWeek", "pastMonth", "pastQuarter", "pastYear", ]) .optional() .describe( "Filter by recency. Possible values: 'any', 'pastHour', 'pastDay', 'pastWeek', 'pastMonth', 'pastQuarter', 'pastYear'." ), regionCode: z .string() .length(2) .optional() .describe("2-letter country code to restrict results"), });
  • Registration of the searchVideos tool in the allTools function, using the exported config and handler, injecting youtubeService.
    { config: searchVideosConfig, handler: (params) => searchVideosHandler(params as unknown as SearchParams, youtubeService), },
  • Supporting method in YoutubeService that performs the actual paginated YouTube API search.list calls, handles caching, pagination, and parameter mapping for recency filters.
    async searchVideos( options: SearchOptions ): Promise<youtube_v3.Schema$SearchResult[]> { const cacheKey = this.cacheService.createOperationKey( "searchVideos", options ); const operation = async (): Promise<youtube_v3.Schema$SearchResult[]> => { try { const { query, maxResults = 10, order = "relevance", type = "video", channelId, videoDuration, publishedAfter, recency, regionCode, } = options; const results: youtube_v3.Schema$SearchResult[] = []; let nextPageToken: string | undefined = undefined; const targetResults = Math.min(maxResults, this.ABSOLUTE_MAX_RESULTS); let calculatedPublishedAfter = publishedAfter; if (recency && recency !== "any") { calculatedPublishedAfter = this.calculatePublishedAfter(recency); } while (results.length < targetResults) { const searchParams: youtube_v3.Params$Resource$Search$List = { part: ["snippet"], q: query, maxResults: Math.min( this.MAX_RESULTS_PER_PAGE, targetResults - results.length ), type: [type], order: order, pageToken: nextPageToken, }; if (channelId) { searchParams.channelId = channelId; } if (videoDuration && videoDuration !== "any") { searchParams.videoDuration = videoDuration; } if (calculatedPublishedAfter) { searchParams.publishedAfter = calculatedPublishedAfter; } if (regionCode) { searchParams.regionCode = regionCode; } const response = await this.trackCost( () => this.youtube.search.list(searchParams), API_COSTS["search.list"] ); const searchResponse: youtube_v3.Schema$SearchListResponse = response.data; if (!searchResponse.items?.length) { break; } results.push(...searchResponse.items); nextPageToken = searchResponse.nextPageToken || undefined; if (!nextPageToken) { break; } } return results.slice(0, targetResults); } catch (error) { throw new YouTubeApiError( `YouTube API call for searchVideos failed`, error ); } }; return this.cacheService.getOrSet( cacheKey, operation, CACHE_TTLS.STANDARD, CACHE_COLLECTIONS.VIDEO_DETAILS, options, ["snippet.thumbnails"] ); }

Latest Blog Posts

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