Skip to content
Google Search Console MCP Server

Google Search Console MCP Server
MCP (Model Context Protocol) server exposing Google Search Console data to AI agents - 4 tools (sites, analytics, sitemaps, inspect) with Service Account JWT auth, caching, and production readiness.

CLIENTPersonal Project
TERM2026-08
ROLESystem Architect / Full-Stack Developer
STATUSIn Progress

"Google Search Console MCP Server gives an AI agent direct access to GSC data - the agent pulls data and forms hypotheses, while the human decides and plans, without tedious panel browsing."

Google Search Console MCP Server connects AI clients (Windsurf, Devin, Factory Droid) to the Google Search Console API. An agent can conversationally ask about traffic, sitemaps, properties, and URL indexing status - the server returns raw GSC data enriched with contextual observations (hints).

Built on the streamable-mcp-server-template by Adam Gospodarczyk (AI_DEVS, overment) and extended into a complete, deployment-ready MCP server across five epics.

📋 Project metrics

  • Start: July 2026
  • Status: MVP v1 complete and deployment-ready (experimental project, further development as v2)
  • Role: System Architect / Full-Stack Developer
  • Goal: Expose Google Search Console data to LLM agents through typed MCP tools
  • Validation: 753 tests (0 fail), lint + typecheck clean, CI 17 s, Docker smoke (cold start 0.418 s, RAM 27 MB idle, volume persistence)

🚀 Product journey

  1. Architecture: Layered architecture with Tool Registry (AD-1..AD-14) - brownfield ratification of the template, consistent rules for 4 tools.
  2. Foundation: MCP SDK upgrade to ^1.29.0 (Streamable HTTP), full Cloudflare Workers cleanup, migration from better-sqlite3 to bun:sqlite + drizzle-orm.
  3. Auth: GscAuthService - Service Account JWT RS256 (RFC 7523), token exchange, 1h cache with auto-renew and fail-fast startup.
  4. API client: GscApiClient - single interface to GSC, siteUrl encoding, smart retry (exponential backoff, daily-limit aware), unified error model.
  5. Tools: Four gsc__ tools with actions as a discriminated union - sites (list/get/add/delete), analytics (query with auto-pagination), sitemaps (list/get/submit/delete), inspect (URL Inspection). Write Operations guarded by an elicitation gate.
  6. Caching: UrlInspectionCache - SQLite 24h TTL protecting the 2,000 daily URL Inspection quota, with graceful degradation.
  7. Production: Multi-stage Dockerfile (pure bundle, USER bun, HEALTHCHECK), GitHub Actions CI, graceful shutdown with drain phase (bounded cleanup, deterministic exit 0/1).

🎯 Business problem

Google Search Console data is available, but the barrier between the data and the ability to analyze it is high. A person with years of SEO experience has intuition, but manually browsing the GSC UI is tedious enough that analyses simply never get done. An LLM agent can sift through large amounts of data, but has no access to GSC.

The MCP server closes this gap: the agent becomes the analyst, the human the strategist.

❌ Pain points and operational challenges

  • Tedious UI: Browsing the GSC panel across 4-6 properties is repetitive manual work.
  • API quotas: URL Inspection allows 2,000 queries/day/property, Search Analytics 1,200/minute - easy to exhaust.
  • siteUrl formats: sc-domain:example.com and https://example.com/ require correct path encoding.
  • Write Operations: Adding/removing properties and sitemaps is destructive - the API has no granular permission control.
  • Delayed data: Search Analytics lags 2-3 days, which without context leads to wrong conclusions.
  • Diagnostics: Checking the indexing status of a specific URL requires a separate tool and tedious navigation.

💡 Why it works (product approach)

  • 4 tools instead of 10 endpoints: Consolidated into gsc__sites, gsc__analytics, gsc__sitemaps, gsc__inspect - fewer schemas in the LLM context, fewer mistakes, lower token usage.
  • Hints as observations, not directives: The server describes the data (e.g., "7 queries at positions 5-10 with CTR < 3% - optimization potential"), the agent forms its own hypothesis.
  • Auto-discovery fan-out: When the agent omits siteUrl, the server finds the properties itself, fans out with rate limiting, and labels results per property.
  • Smart retry: Distinguishes per-minute limits (retry with backoff) from daily limits (immediate error with recovery hints) - no wasted API calls.
  • Protective caching: URL Inspection cache with 24h TTL eliminates repeated queries for the same URL (2,000 QPD quota).
  • Elicitation gate: Write Operations require user confirmation (kill switch WRITE_OPS_ENABLED + elicitation) - the only protection against unauthorized changes.
  • Zero-interaction auth: Service Account JWT works headless - no OAuth popups, token auto-renews every 5 minutes.
  • Graceful shutdown with drain phase: Safe redeploys - in-flight requests finish, data (sessions, cache, tokens) is flushed before exit.

📈 Impact on work (ROI)

AreaBefore Google Search Console MCPWith Google Search Console MCPEffect
GSC data analysisManual panel browsingConversational agent queriesLess context switching
Finding striking-distance queriesManual CSV export and sortingQuery with query/page dimensions + hintsReady candidates for content plan
SEO problem diagnosisManual panel digginggsc__inspect with 24h cacheFaster indexing diagnosis
Write OperationsRisk of costly mistakesElicitation gate + kill switchSafe change management

„Instead of drowning in the GSC panel, you can simply ask the agent: what is going on with domain X? You get the data with context for making decisions.”

🛠️ Architecture and tech stack

  • Runtime: Bun 1.3.0 (strict TypeScript, ESM)
  • Protocol: MCP Streamable HTTP (@modelcontextprotocol/sdk ^1.29.0)
  • HTTP: Hono + @hono/node-server
  • Schema: Zod ^3.23 (JSON Schema for MCP, .describe() on every field)
  • JWT/JWS: jose (Service Account RS256)
  • Storage: bun:sqlite (sessions + cache), drizzle-orm/bun-sqlite, encrypted token store (AES-256-GCM)
  • Tests: bun test (753 tests, 17 files)
  • CI/CD: GitHub Actions (lint + typecheck + test, 17 s, bun 1.3.0 pin)
  • Deployment: Multi-stage Docker (oven/bun:1.3.0-alpine, pure bundle 111 MB, USER bun) + Dokploy/Traefik

🔒 Security and operational decisions

  • Service Account JSON only in env/Docker secrets - never in git.
  • Server access protected by Bearer token (AUTH_STRATEGY: none/bearer/oauth/api_key/custom).
  • Client tokens encrypted with AES-256-GCM (RS_TOKENS_ENC_KEY).
  • Logger sanitizes sensitive values - secrets never reach logs.
  • Fail-fast startup in production: no valid SA JSON = no server start.
  • Write Operations blocked by elicitation gate + WRITE_OPS_ENABLED kill switch.
  • Graceful shutdown: drain (30 s) + force-close grace (2 s) + cleanup bound (15 s), deterministic exit 0/1, tokenStore.flush() awaited before exit.
  • Container runs as non-root (USER bun), persistent data in VOLUME /app/.data.

✅ Validation

The project includes:

  • 753 unit and integration tests (0 fail, 1,718 expect)
  • lint (Biome) + typecheck (tsc) clean, GitHub Actions CI green in 17 s
  • drain phase tests (single-close, timeout, resilience, re-entry guard, exit policy)
  • cache tests (TTL, graceful degradation, corrupted-row resilience)
  • Docker smoke: build, /health 200, cold start 0.418 s (< 2 s NFR), RAM 27 MB idle (< 80 MB NFR), volume persistence across redeploys
  • graceful shutdown smoke: SIGTERM → Graceful shutdown complete + tokens.json written + exit 0
  • E2E flow through MCP Inspector against real GSC data

🚀 Next steps

  • Triage ~20 deferred debt items from deferred-work.md (fix vs consciously keep).
  • OAuth user flow / multi-user - many users with their own properties (oauth4webapi already in deps).
  • Production hardening: atomic token write, volume monitoring, .data backup.
  • Extending the analytics toolkit - more MCP servers per the PRD vision.
  • Public distribution - the project is marked experimental, not all roadmap features are implemented yet.

Artifacts

Contact

Have a similar challenge? Write to me — I will come back with a proposal for next steps.

Send message