ai_scraper
Scrape ChatGPT or Gemini search results for a keyword to analyze AI-generated local SEO insights. Costs 3 credits per query.
Instructions
Scrape ChatGPT or Gemini search results for a keyword. Budget-friendly alternative to llm_response. Costs 3 credits.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| keyword | Yes | Keyword to scrape results for (e.g. "best electrician") | |
| platform | Yes | Which platform to scrape (chat_gpt or gemini) | |
| location | No | Location for results (e.g. "Boston, MA"). Default: US |
Implementation Reference
- src/tools/ai-visibility.ts:157-165 (handler)The handler function for the 'ai_scraper' tool. It calls the '/v1/ai/scraper' API endpoint with keyword, platform, and optional location parameters, then formats the result.
withErrorHandling(async ({ keyword, platform, location }) => { const result = await callApi( "/v1/ai/scraper", { keyword, platform, ...(location && { location }) }, getAuth() ); return { content: [{ type: "text" as const, text: formatResult(result.data, result) }] }; }) ); - src/tools/ai-visibility.ts:151-155 (schema)Zod schema defining the input parameters for the ai_scraper tool: keyword (string), platform (enum: chat_gpt or gemini), and optional location (string).
{ keyword: z.string().min(1).describe('Keyword to scrape results for (e.g. "best electrician")'), platform: z.enum(["chat_gpt", "gemini"]).describe("Which platform to scrape (chat_gpt or gemini)"), location: z.string().optional().describe('Location for results (e.g. "Boston, MA"). Default: US'), }, - src/tools/ai-visibility.ts:148-165 (registration)Registration of the 'ai_scraper' tool using server.tool(), which ties the tool name, description, schema, and handler together.
server.tool( "ai_scraper", "Scrape ChatGPT or Gemini search results for a keyword. Budget-friendly alternative to llm_response. Costs 3 credits.", { keyword: z.string().min(1).describe('Keyword to scrape results for (e.g. "best electrician")'), platform: z.enum(["chat_gpt", "gemini"]).describe("Which platform to scrape (chat_gpt or gemini)"), location: z.string().optional().describe('Location for results (e.g. "Boston, MA"). Default: US'), }, READ_ONLY, withErrorHandling(async ({ keyword, platform, location }) => { const result = await callApi( "/v1/ai/scraper", { keyword, platform, ...(location && { location }) }, getAuth() ); return { content: [{ type: "text" as const, text: formatResult(result.data, result) }] }; }) ); - src/server.ts:45-51 (registration)Top-level registration: registerAIVisibilityTools is called to register all AI visibility tools including ai_scraper.
registerAIVisibilityTools(server, getAuth); registerCompetitiveTools(server, getAuth); registerLocationTools(server, getAuth); registerDiagnosticTools(server, getAuth); return server; } - src/api-client.ts:143-158 (helper)The withErrorHandling wrapper used to catch errors and return structured MCP error content for the ai_scraper tool handler.
export function withErrorHandling<T>( fn: (args: T) => Promise<ToolResult> ): (args: T) => Promise<ToolResult> { return async (args) => { try { return await fn(args); } catch (err) { const message = err instanceof Error ? err.message : String(err); console.error(`[mcp] Tool error: ${message}`); return { content: [{ type: "text" as const, text: `Error: ${message}` }], isError: true, }; } }; }