search_people_also_ask
Discover related questions from Google's People Also Ask feature to enhance SEO research and content planning by analyzing search term hierarchies.
Instructions
Search for "People Also Ask" questions related to search terms. Returns hierarchical question data from Google PAA.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| terms | Yes | Array of search terms to query | |
| language | No | Language code (e.g., "en", "es", "fr") | en |
| region | No | Region code (e.g., "us", "uk", "ca") | us |
| latitude | No | Latitude for geographic targeting (e.g., 40.7128 for NYC, 31.9686 for Texas) | |
| longitude | No | Longitude for geographic targeting (e.g., -74.0060 for NYC, -99.9018 for Texas) | |
| depth | No | Depth of question hierarchy (1-3) | |
| fresh | No | Whether to fetch fresh results or use cached data | |
| async | No | Whether to process request asynchronously |
Implementation Reference
- src/index.ts:289-341 (handler)The main handler function that validates input, makes the API request to AlsoAsked /search endpoint, processes the hierarchical PAA results, formats them, and returns structured JSON content via MCP tool response.private async handleSearch(options: SearchRequestOptions) { const searchData: SearchRequestOptions = { terms: options.terms, language: options.language || 'en', region: options.region || 'us', latitude: options.latitude, longitude: options.longitude, depth: options.depth || 2, fresh: options.fresh || false, async: options.async || false, notifyWebhooks: options.notifyWebhooks || false, }; // Remove undefined values to avoid sending them to the API Object.keys(searchData).forEach(key => { if (searchData[key as keyof SearchRequestOptions] === undefined) { delete searchData[key as keyof SearchRequestOptions]; } }); const response: SearchResponse = await this.makeApiRequest('/search', { method: 'POST', body: JSON.stringify(searchData), }); if (response.status !== 'success') { throw new Error(`Search failed: ${response.message || 'Unknown error'}`); } // Format results for better readability const formattedResults = response.queries.map(query => ({ searchTerm: query.term, totalQuestions: this.countTotalQuestions(query.results), questions: this.formatQuestionHierarchy(query.results), })); return { content: [ { type: 'text', text: JSON.stringify({ status: response.status, searchId: response.id, results: formattedResults, summary: { totalSearchTerms: response.queries.length, totalQuestions: formattedResults.reduce((sum, result) => sum + result.totalQuestions, 0), } }, null, 2), }, ], }; }
- src/index.ts:115-164 (registration)MCP tool registration in the ListTools handler, defining the tool name, description, and detailed input schema with properties, defaults, and requirements.{ name: 'search_people_also_ask', description: 'Search for "People Also Ask" questions related to search terms. Returns hierarchical question data from Google PAA.', inputSchema: { type: 'object', properties: { terms: { type: 'array', items: { type: 'string' }, description: 'Array of search terms to query', }, language: { type: 'string', description: 'Language code (e.g., "en", "es", "fr")', default: 'en', }, region: { type: 'string', description: 'Region code (e.g., "us", "uk", "ca")', default: 'us', }, latitude: { type: 'number', description: 'Latitude for geographic targeting (e.g., 40.7128 for NYC, 31.9686 for Texas)', }, longitude: { type: 'number', description: 'Longitude for geographic targeting (e.g., -74.0060 for NYC, -99.9018 for Texas)', }, depth: { type: 'integer', description: 'Depth of question hierarchy (1-3)', default: 2, minimum: 1, maximum: 3, }, fresh: { type: 'boolean', description: 'Whether to fetch fresh results or use cached data', default: false, }, async: { type: 'boolean', description: 'Whether to process request asynchronously', default: false, }, }, required: ['terms'], }, },
- src/index.ts:14-42 (schema)TypeScript interfaces defining the structure for search requests, results, queries, and responses used by the search_people_also_ask tool.interface SearchRequestOptions { terms: string[]; language?: string; region?: string; latitude?: number; longitude?: number; depth?: number; fresh?: boolean; async?: boolean; notifyWebhooks?: boolean; } interface SearchResult { question: string; results?: SearchResult[]; } interface SearchQuery { term: string; results: SearchResult[]; } interface SearchResponse { status: string; queries: SearchQuery[]; id?: string; message?: string; }
- src/index.ts:221-222 (handler)Dispatch case in the CallToolRequestSchema handler that routes calls to search_people_also_ask to the handleSearch method after validation.case 'search_people_also_ask': return await this.handleSearch(this.validateSearchArgs(args));
- src/index.ts:245-265 (helper)Helper function to validate and normalize input arguments against the tool schema, providing defaults and type checks.private validateSearchArgs(args: Record<string, unknown> | undefined): SearchRequestOptions { if (!args || typeof args !== 'object') { throw new Error('Invalid arguments provided'); } if (!args.terms || !Array.isArray(args.terms)) { throw new Error('terms parameter is required and must be an array'); } return { terms: args.terms as string[], language: typeof args.language === 'string' ? args.language : 'en', region: typeof args.region === 'string' ? args.region : 'us', latitude: typeof args.latitude === 'number' ? args.latitude : undefined, longitude: typeof args.longitude === 'number' ? args.longitude : undefined, depth: typeof args.depth === 'number' ? args.depth : 2, fresh: typeof args.fresh === 'boolean' ? args.fresh : false, async: typeof args.async === 'boolean' ? args.async : false, notifyWebhooks: typeof args.notifyWebhooks === 'boolean' ? args.notifyWebhooks : false, }; }