google_ads
Extract Google Ads search results for any query, location, and device type with automatic parsing.
Instructions
Scrape Google Ads search results with automatic parsing
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query for Google Ads (e.g., "laptop") | |
| geo | No | Geolocation of the desired request, expressed as a country name | |
| locale | No | Locale of the desired request | |
| jsRender | No | Should the request be opened in a headless browser, false by default | |
| deviceType | No | Device type to emulate for the request | |
| pageFrom | No | Starting page number for pagination |
Implementation Reference
- The GoogleAdsTool class extends Tool and contains the full handler logic. The register method (lines 26-65) defines the tool 'google_ads', sets up the input schema, and implements the async handler that sends scraping params (with target=GOOGLE_ADS) to the Scraper API and transforms the response by removing 'url' fields.
export class GoogleAdsTool extends Tool { toolset = TOOLSET.SEARCH; private static FIELDS_WITH_HIGH_CHAR_COUNT = ['url']; transformResponse = ({ data }: { data: object }) => { for (const fieldToRemove of GoogleAdsTool.FIELDS_WITH_HIGH_CHAR_COUNT) { data = removeKeyFromNestedObject({ obj: data, keyToRemove: fieldToRemove }); } return { data: JSON.stringify(data) }; }; register = ({ server, sapiClient, auth }: ToolRegistrationArgs) => { server.registerTool( 'google_ads', { description: 'Scrape Google Ads search results with automatic parsing', inputSchema: { query: z.string().describe('Search query for Google Ads (e.g., "laptop")'), geo: zodGeo, locale: zodLocale, jsRender: zodJsRender, deviceType: zodDeviceType, pageFrom: zodPageFrom, }, annotations: { readOnlyHint: true, openWorldHint: true, }, }, async (scrapingParams: ScrapingMCPParams, extra: ProgressExtra) => { const params = { ...scrapingParams, target: SCRAPER_API_TARGETS.GOOGLE_ADS, parse: true, } satisfies ScraperAPIParams; const { data } = await sapiClient.scrape<object>({ auth, scrapingParams: params, extra }); const { data: text } = this.transformResponse({ data }); return { content: [ { type: 'text', text, }, ], }; } ); }; } - Input schema for the google_ads tool: 'query' (string), 'geo', 'locale', 'jsRender', 'deviceType' (imported from zod-types), and 'pageFrom' (optional number for pagination).
const zodPageFrom = z .number() .describe('Starting page number for pagination') .optional(); - src/server/sapi-base-server.ts:66-117 (registration)GoogleAdsTool is instantiated in the allTools array (line 70) and registered via registerAllTools/registerTools methods (lines 99-117) which call tool.register() on each tool, ultimately registering 'google_ads' with the MCP server.
static allTools: Tool[] = [ new ScrapeAsMarkdownTool(), new ScreenshotTool(), new GoogleSearchTool(), new GoogleAdsTool(), new GoogleLensTool(), new GoogleAiModeTool(), new GoogleTravelHotelsTool(), new AmazonSearchTool(), new AmazonProductTool(), new AmazonPricingTool(), new AmazonSellersTool(), new AmazonBestsellersTool(), new WalmartSearchTool(), new WalmartProductTool(), new TargetSearchTool(), new TargetProductTool(), new TiktokPostTool(), new TiktokShopSearchTool(), new TiktokShopProductTool(), new TiktokShopUrlTool(), new YoutubeMetadataTool(), new YoutubeChannelTool(), new YoutubeSubtitlesTool(), new YoutubeSearchTool(), new RedditPostTool(), new RedditSubredditTool(), new RedditUserTool(), new BingSearchTool(), new ChatGPTTool(), new PerplexityTool(), ]; registerTools({ toolsets }: { toolsets: TOOLSET[] }) { if (toolsets.length === 0) { this.registerAllTools(); return; } for (const toolset of toolsets) { const tools = ScraperAPIBaseServer.allTools.filter(tool => tool.toolset === toolset); for (const tool of tools) { tool.register({ server: this.server, sapiClient: this.sapiClient, auth: this.auth }); } } } registerAllTools() { for (const tool of ScraperAPIBaseServer.allTools) { tool.register({ server: this.server, sapiClient: this.sapiClient, auth: this.auth }); } } - The transformResponse helper method (lines 18-24) post-processes scraped data by removing 'url' fields (FIELDS_WITH_HIGH_CHAR_COUNT) from nested objects to reduce character count, then stringifies the result.
private static FIELDS_WITH_HIGH_CHAR_COUNT = ['url']; transformResponse = ({ data }: { data: object }) => { for (const fieldToRemove of GoogleAdsTool.FIELDS_WITH_HIGH_CHAR_COUNT) { data = removeKeyFromNestedObject({ obj: data, keyToRemove: fieldToRemove }); } return { data: JSON.stringify(data) }; };