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.
- SEO AgentProperty and period selection, interpretation, PostgreSQL history
- GSC MCP · GoFour tools, schemas, argument validation and request limits
- 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
list_sitesreturns accessible properties and permission levels. The agent uses the returnedsiteUrl:sc-domain:example.comand a URL-prefix property represent different scopes.query_analyticsretrieves impressions, clicks, CTR and average position for an explicit period, grouped by page or query.inspect_urlprovides Google’s information about a selected page, including its verdict, crawl state and canonicals.list_sitemapsadds 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.