gsc_search_performance
Retrieve Google Search Console search performance data with clicks, impressions, CTR, and position. Filter by query, page, device, or country, and group by multiple dimensions.
Instructions
Query Google Search Console search performance data. Returns clicks, impressions, CTR, and position for a site. Supports filtering by query, page, device, or country and grouping by multiple dimensions.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| site_url | No | Site URL in GSC format, e.g. 'sc-domain:example.com' or 'https://example.com/'. Uses config default if omitted. | |
| start_date | Yes | Start date in YYYY-MM-DD format. | |
| end_date | Yes | End date in YYYY-MM-DD format. | |
| dimensions | No | Dimensions to group results by. Default: ['query']. | |
| filter_query | No | Filter results to queries containing this string. | |
| filter_page | No | Filter results to this page URL (exact match). | |
| filter_device | No | Filter results to this device type. | |
| filter_country | No | Filter results to this country (ISO 3166-1 alpha-3, e.g. 'USA'). | |
| row_limit | No | Max rows to return. Default 100, max 25000. |
Implementation Reference
- Zod schema for gsc_search_performance tool, defining all input parameters: site_url, start_date, end_date, dimensions, filter_*, and row_limit.
const schema = z.object({ site_url: z.string().optional().describe( "Site URL in GSC format, e.g. 'sc-domain:example.com' or 'https://example.com/'. Uses config default if omitted." ), start_date: z.string().describe("Start date in YYYY-MM-DD format."), end_date: z.string().describe("End date in YYYY-MM-DD format."), dimensions: z .array(z.enum(["query", "page", "country", "device", "date"])) .optional() .describe("Dimensions to group results by. Default: ['query']."), filter_query: z.string().optional().describe("Filter results to queries containing this string."), filter_page: z.string().optional().describe("Filter results to this page URL (exact match)."), filter_device: z .enum(["DESKTOP", "MOBILE", "TABLET"]) .optional() .describe("Filter results to this device type."), filter_country: z .string() .optional() .describe("Filter results to this country (ISO 3166-1 alpha-3, e.g. 'USA')."), row_limit: z.number().optional().describe("Max rows to return. Default 100, max 25000."), }); - Full tool definition including name, description, schema, and handler. The handler authenticates via GSC OAuth2, calls the Search Analytics query API, applies filters, and returns tab-separated results.
export const gscSearchPerformance: ToolDefinition<typeof schema> = { name: "gsc_search_performance", description: "Query Google Search Console search performance data. Returns clicks, impressions, CTR, and position for a site. Supports filtering by query, page, device, or country and grouping by multiple dimensions.", schema, handler: async (args, config) => { const auth = getOAuth2Client(); const sc = google.searchconsole({ version: "v1", auth }); const siteUrl = args.site_url ?? config.gsc?.default_site; if (!siteUrl) { throw new Error( "site_url is required. Pass it as an argument or set gsc.default_site in ~/.seo-mcp/config.json" ); } const dimensions = args.dimensions ?? ["query"]; const rowLimit = args.row_limit ?? 100; const filterGroups: Record<string, unknown>[] = []; if (args.filter_query) { filterGroups.push({ filters: [{ dimension: "query", operator: "contains", expression: args.filter_query }] }); } if (args.filter_page) { filterGroups.push({ filters: [{ dimension: "page", operator: "equals", expression: args.filter_page }] }); } if (args.filter_device) { filterGroups.push({ filters: [{ dimension: "device", operator: "equals", expression: args.filter_device }] }); } if (args.filter_country) { filterGroups.push({ filters: [{ dimension: "country", operator: "equals", expression: args.filter_country }] }); } const res = await sc.searchanalytics.query({ siteUrl, requestBody: { startDate: args.start_date, endDate: args.end_date, dimensions, rowLimit, dimensionFilterGroups: filterGroups.length > 0 ? filterGroups : undefined, }, }); const rows = res.data.rows ?? []; if (rows.length === 0) { return { content: [{ type: "text", text: "No data returned for the specified parameters." }] }; } const header = [...dimensions, "clicks", "impressions", "ctr", "position"].join("\t"); const lines = rows.map((r) => { const keys = (r.keys ?? []).join("\t"); const ctr = ((r.ctr ?? 0) * 100).toFixed(2) + "%"; const pos = r.position?.toFixed(1) ?? "—"; return `${keys}\t${r.clicks ?? 0}\t${r.impressions ?? 0}\t${ctr}\t${pos}`; }); return { content: [{ type: "text", text: [header, ...lines].join("\n") }] }; }, }; - src/tools/gsc/index.ts:1-16 (registration)Imports and registers gscSearchPerformance in the gscTools array, making it available as a tool definition.
import { gscSearchPerformance } from "./search-performance.js"; import { gscStrikingDistance } from "./striking-distance.js"; import { gscTrafficDrop } from "./traffic-drop.js"; import { gscUrlInspection } from "./url-inspection.js"; import { gscSitemapList } from "./sitemap-list.js"; import { gscBrandNonbrand } from "./brand-nonbrand.js"; import type { ToolDefinition } from "../../types/tool.js"; export const gscTools: ToolDefinition[] = [ gscSearchPerformance as unknown as ToolDefinition, gscStrikingDistance as unknown as ToolDefinition, gscTrafficDrop as unknown as ToolDefinition, gscUrlInspection as unknown as ToolDefinition, gscSitemapList as unknown as ToolDefinition, gscBrandNonbrand as unknown as ToolDefinition, ]; - src/auth/gsc.ts:12-39 (helper)getOAuth2Client helper used by the handler to authenticate with Google Search Console API.
export function getOAuth2Client() { const clientId = process.env.GSC_CLIENT_ID; const clientSecret = process.env.GSC_CLIENT_SECRET; if (!clientId || !clientSecret) { throw new Error( "GSC_CLIENT_ID and GSC_CLIENT_SECRET must be set.\n" + "Run: npx @patchwindow/seo-mcp auth gsc\n" + "See README for Google Cloud Console setup instructions." ); } const oauth2 = new google.auth.OAuth2(clientId, clientSecret, GSC_REDIRECT_URI); const tokens = readTokens(); if (!tokens) { throw new Error( "GSC not authenticated. Run: npx @patchwindow/seo-mcp auth gsc" ); } oauth2.setCredentials(tokens); oauth2.on("tokens", (newTokens) => { writeTokens({ ...tokens, ...newTokens }); }); return oauth2; } - src/types/tool.ts:12-18 (helper)ToolDefinition type that provides the interface contract for the tool definition, ensuring it has name, description, schema, and handler.
export interface ToolDefinition<T extends AnyZodObject = AnyZodObject> { name: string; description: string; schema: T; handler: (args: z.infer<T>, config: Config) => Promise<ToolResult>; }