MARTECH

Google Search Console MCP

Connecting Google search analytics to SEO Agent while retaining dates, incomplete-data boundaries and access errors.

A Go MCP server for reading Google Search Console: four tools, explicit analytics contracts, service-account access and a reproducible demo.

Go · MCP · Google Search Console · Docker

Role

Project author: architecture, Go, Google API and MCP integration, data contracts, tests and Docker.

Open source · September 2026. This case covers version 1.0.0 at published commit ab9a7ba0. Implementation links are pinned to that revision.

The problem: give SEO Agent access to Google data

For my SEO Agent, I collect a history of search metrics and page changes. Google Search Console is one source: it reports impressions, clicks, queries and how Google sees a URL. I built a separate Go MCP server so the agent can retrieve those reports on demand.

The integration needs to do more than forward an HTTP response. The agent must select the right property, retain the reporting period and grouping, distinguish incomplete data from zeros and show the evidence behind a recommendation. Scheduling and historical storage remain in SEO Agent; GSC MCP handles access to Search Console.

From a question to source data
  1. SEO AgentProperty and period selection, interpretation, PostgreSQL history
  2. GSC MCP · GoFour tools, schemas, argument validation and request limits
  3. Google Search ConsoleSearch analytics, URL information and sitemaps

The agent sends an MCP bearer token. The Google service-account key stays on the server. The adapter has no persistent application database.

Workflow: choose pages for further investigation

  1. list_sites returns accessible properties and permission levels. The agent uses the returned siteUrl: sc-domain:example.com and a URL-prefix property represent different scopes.
  2. query_analytics retrieves impressions, clicks, CTR and average position for an explicit period, grouped by page or query.
  3. inspect_url provides Google’s information about a selected page, including its verdict, crawl state and canonicals. list_sitemaps adds sitemap information.

A useful request is: “Choose a property from list_sites. Compare two equally long completed periods with identical filters. Show pages whose impressions and clicks changed, and list the limitations of the data separately.” This produces candidates for inspection. A CTR change alone does not explain why traffic changed.

Decision 1: four read operations with explicit contracts

The MCP catalog has four tools: property discovery, analytics, URL inspection and sitemaps. Each publishes input and output schemas and read-only annotations. The server exposes no tool for deleting a property or submitting a URL for indexing. This matches the scheduled collector’s role.

MCP handlers depend on the small gsc.Console interface. The real client and synthetic demo implement the same boundary. Argument and protocol behavior can therefore be checked without a Google key, while external API mapping is tested separately. Tool registration and handlers.

Decision 2: retain the calendar and data incompleteness

Search Analytics dates use Pacific Time, including daylight saving transitions. The server computes defaults in that calendar: 28 days ending yesterday, with dataState=final. Results retain effective dates, dimensions and data state. When Google supplies incomplete-data metadata for recent reports, the adapter preserves it.

Pagination uses startRow with mayHaveMore/nextStartRow hints. Google does not guarantee every row will be returned, so following pagination does not create an exhaustive export. The Search Analytics API contract describes those limits.

Dedicated tests cover midnight and daylight saving boundaries, preservation of firstIncompleteDate, the next-page offset and rejection of incompatible parameters before an upstream call. Calendar and analytics contract tests.

Decision 3: bound the entire request path

The default Google request budget is 30 seconds, including queueing, OAuth and retries. One process allows eight concurrent operations by default, and Google responses are limited to 8 MiB. Cancellation covers waiting for a slot and the upstream request.

Transient read errors may be retried within that shared budget. A permanent access error requires a configuration change. Clients receive a classified error and retry information, without raw Google error messages or key material. Retry, cancellation, OAuth and response-size tests.

What was verified

While preparing this case, the internal/gsc, internal/mcpserver and cmd/mcp-server package tests passed at the cited revision. An isolated native demo passed the built-in smoke checks for list_sites, query_analytics, inspect_url and list_sitemaps. An additional HTTP tool call confirmed the response shown above.

The integration test uses the real MCP SDK and HTTP with a substituted external API. These checks cover transport, access and data mapping. This case does not measure search-traffic growth or service throughput.

Boundaries of the solution

Each installation uses one service account. There is no multi-user OAuth login or isolation between users inside the process. Unrelated site owners need separate installations. Concurrency limits are local, so additional replicas increase aggregate pressure on Google’s quotas.

inspect_url reads Google’s stored index information; it does not perform a live crawl. The MCP server stores no history, runs no schedule and cannot guarantee recent finalized rows exist. Alongside Webmaster MCP and ahref, each source keeps its own data semantics.

Try it

The Docker demo needs no Google account. This example uses port 18088 so it can run alongside another MCP:

git clone https://github.com/tenqz/google-search-console-mcp.git
cd google-search-console-mcp
HTTP_PORT=18088 docker compose -f compose.demo.yml up -d --build
docker compose -f compose.demo.yml exec mcp /mcp-server --smoke http://127.0.0.1:8080/mcp

Connect an HTTP client to http://localhost:18088/mcp with Authorization: Bearer demo-token. Stop with HTTP_PORT=18088 docker compose -f compose.demo.yml down. Live access requires a service-account key, permission on the specific Search Console property and a separate MCP token. See the installation and usage guide and Google access setup.

GitHub Setup guide

Let's make the complex understandable.

Architecture, engineering leadership, and AI in development — when the system is too important to simplify, and too expensive not to own.

LinkedIn Telegram Email