search_channels
Search for YouTube channels using keywords to discover content creators, filter results by relevance or metrics, and retrieve channel statistics for analysis.
Instructions
Find and analyze YouTube channels
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| includeStats | No | Whether to include channel statistics | |
| maxResults | No | Maximum number of channels to return | |
| order | No | Sort order for channels | relevance |
| query | Yes | Search query for YouTube channels |
Implementation Reference
- src/tools/channels.ts:20-127 (handler)The main handler method of ChannelSearchTool class that executes the 'search_channels' tool logic: validates input with schema, manages cache and quota, calls YouTubeClient.searchChannels, enhances results with analysis (engagement scores, categorization, growth assessment), and returns enriched response with metadata.async execute(args: unknown): Promise<ChannelSearchResult & { metadata?: { quotaUsed: number; cached: boolean; analysis?: { categoryDistribution: Record<string, number>; subscriberRanges: Record<string, number>; avgVideosPerChannel: number; topPerformers: Array<{ name: string; subscribers: number; videos: number; }>; }; }; }> { // Validate input parameters const params = SearchChannelsSchema.parse(args); this.logger.info(`Searching channels for: "${params.query}"`); // Generate cache key const cacheKey = `channels:${Buffer.from(JSON.stringify(params)).toString('base64')}`; // Check cache first const cached = await this.cache.get<ChannelSearchResult>(cacheKey); if (cached) { this.logger.info(`Returning cached channel search results for: "${params.query}"`); return { ...cached, metadata: { quotaUsed: 0, cached: true } }; } // Check quota before making API call const operationCost = QuotaManager.getOperationCost('channel_search'); if (!this.quotaManager.canPerformOperation(operationCost)) { throw new QuotaExceededError('Insufficient quota for channel search operation'); } // Optimize operation based on quota availability const optimizedMaxResults = this.quotaManager.optimizeOperation('channel_search', params.maxResults); if (optimizedMaxResults === 0) { throw new QuotaExceededError('Cannot perform channel search due to quota constraints'); } const optimizedParams: SearchChannelsParams = { ...params, maxResults: optimizedMaxResults }; try { // Perform the channel search const result = await this.youtubeClient.searchChannels(optimizedParams); // Record quota usage await this.quotaManager.recordUsage(operationCost, 'channel_search'); // Add additional cost if we fetched detailed stats if (params.includeStats) { const additionalCost = Math.ceil(result.channels.length / 50); // 1 unit per 50 channels await this.quotaManager.recordUsage(additionalCost, 'channel_details'); } // Enhance the result with analysis const enhancedResult = await this.enhanceChannelResults(result); // Cache the result await this.cache.set(cacheKey, enhancedResult); this.logger.info( `Channel search completed for "${params.query}": ${result.channels.length} channels found` ); return { ...enhancedResult, metadata: { quotaUsed: operationCost + (params.includeStats ? Math.ceil(result.channels.length / 50) : 0), cached: false, analysis: this.analyzeChannelData(result.channels) } }; } catch (error) { this.logger.error(`Channel search failed for "${params.query}":`, error); // Try fallback strategies if quota exceeded if (error instanceof QuotaExceededError) { const fallbackResults = await this.getFallbackChannelData(params.query); if (fallbackResults) { this.logger.warn('Returning fallback channel data due to quota limits'); return { ...fallbackResults, metadata: { quotaUsed: 0, cached: true, fallback: true } } as any; } } throw error; } }
- src/types.ts:92-97 (schema)Zod schema definition for SearchChannelsParams used for input validation in the handler.export const SearchChannelsSchema = z.object({ query: z.string().describe('Search query for YouTube channels'), maxResults: z.number().min(1).max(50).default(10).describe('Maximum number of channels to return'), includeStats: z.boolean().default(true).describe('Whether to include channel statistics'), order: z.enum(['relevance', 'date', 'viewCount', 'videoCount']).default('relevance').describe('Sort order for channels'), });
- src/index.ts:350-380 (registration)Tool registration in the listTools handler, defining name, description, and input schema matching the Zod schema.name: 'search_channels', description: 'Find and analyze YouTube channels', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query for YouTube channels' }, maxResults: { type: 'number', minimum: 1, maximum: 50, default: 10, description: 'Maximum number of channels to return' }, includeStats: { type: 'boolean', default: true, description: 'Whether to include channel statistics' }, order: { type: 'string', enum: ['relevance', 'date', 'viewCount', 'videoCount'], default: 'relevance', description: 'Sort order for channels' } }, required: ['query'] } },
- src/index.ts:575-577 (registration)Dispatch registration in the CallToolRequestSchema handler switch statement, routing 'search_channels' calls to channelTool.execute()case 'search_channels': result = await this.channelTool.execute(args); break;
- src/youtube-client.ts:182-236 (helper)Low-level YouTube API client method that performs the actual channel search.list and channels.list calls, handling quota checks and response mapping.async searchChannels(params: SearchChannelsParams): Promise<ChannelSearchResult> { try { this.checkQuota(100); // Search costs 100 quota units const searchResponse = await this.youtube.search.list({ part: ['snippet'], q: params.query, type: ['channel'], maxResults: params.maxResults, order: params.order }); this.quotaUsed += 100; if (!searchResponse.data.items) { return { channels: [], totalResults: 0 }; } const channelIds = searchResponse.data.items .map(item => item.id?.channelId) .filter(Boolean) as string[]; let channels: YouTubeChannel[] = []; if (params.includeStats && channelIds.length > 0) { this.checkQuota(1); // Channels.list costs 1 quota unit const channelsResponse = await this.youtube.channels.list({ part: ['snippet', 'statistics'], id: channelIds }); this.quotaUsed += 1; channels = this.mapChannelsResponse(channelsResponse.data.items || []); } else { channels = searchResponse.data.items.map(item => ({ id: item.id?.channelId || '', title: item.snippet?.title || '', description: item.snippet?.description || '', publishedAt: item.snippet?.publishedAt || '', thumbnails: item.snippet?.thumbnails || {} })); } return { channels, totalResults: searchResponse.data.pageInfo?.totalResults || 0, nextPageToken: searchResponse.data.nextPageToken }; } catch (error) { this.handleError(error); throw error; } }