Back to News & Insights
Artificial Intelligence October 11, 2026 · 6 min read

Google Search Console + MCP: 3 ways to give Claude your search data (and how I built one)

Search Console is the most useful SEO data most developers never open. It tells you which queries...

Google Search Console + MCP: 3 ways to give Claude your search data (and how I built one)

Search Console is the most useful SEO data most developers never open. It tells you which queries show your pages, how often people click and where you rank. Turning that into "fix these three things this week" is tedious table work, which is exactly what agents are good at.

The missing piece is access. Google doesn't ship an official Search Console MCP server, so you have to wire one up. This post covers: What the API gives you (and its quirks) Three ways to expose it over MCP How I built the hosted one in my product, and the bug I shipped in it Prompts that turn the data into work

Disclosure: route C below is my product, Blogizi. Routes A and B don't involve it. The API in two minutes Nearly everything useful comes from one endpoint, searchanalytics.query:

The quirks that matter for agents: Two property formats. Domain properties are sc-domain:example.com. URL-prefix properties are https://example.com/, with the trailing slash. Normalize both or you'll get 403s that look like auth bugs. Data lags about 2–3 days. If the agent compares "last 7 days" without accounting for that, it will tell you traffic is collapsing. Rows are sorted by clicks. Keep this in mind. It's the bug in section 3. Position is an average, weighted by impressions. To aggregate across rows, weight by impressions; don't average the averages. The scope you want is webmasters.readonly. An agent reading your data has no reason to hold write access to your properties. Three ways to expose it over MCP

There are several on GitHub. The setup is roughly the same for all of them: Create a Google Cloud project. Enable the Search Console API. Create an OAuth client, or a service account. With a service account, add its email as a user on the property in Search Console. Point the server at the credentials JSON and register it with your client:

Good: free, full API access (URL inspection, any dimension, many sites), and your data stays on your machine. Less good: about 20 minutes of Cloud Console setup. It runs as a local process, so it won't work in hosted agents that can't spawn one.

Several marketing-data platforms offer a hosted MCP endpoint that already handles the Google OAuth, often bundled with GA4 and ads data. They're paid and multi-source, which makes them good for agencies.

This is the one I built. The reasoning: an SEO agent's loop is read performance → decide what to change → change the post. If reading and writing live on different MCP servers, the agent has to stitch identities together (which GSC page is which post?). If they live on the same server, getsearchperformance and updatepost share a project and URL space.

You click "Connect Google" in the dashboard once and pick the property. No Cloud project. Next, how it works. Building the hosted version

The refresh token is encrypted at rest. If Google doesn't return one (the user consented before), the callback tells them to remove the app from their Google account permissions and retry. Users will hit this, so the error message has to say exactly that.

The MCP tool does not call Google live. A daily cron syncs each bound property into snapshots, and the tool reads those:

The sync runs date, query and page dimensions in parallel, for 7-, 28- and 90-day windows. A manual refresh has a 5-minute cooldown.

Why cache: Agents call tools a lot. One "analyze my SEO" session might call getsearchperformance 5–10 times with different windows. That shouldn't be 30 Google API calls. Latency. Snapshot reads are milliseconds; the live API is not. The data is 2+ days old anyway. Real-time buys nothing.

Design notes: days is a union of literals, not a number. Agents will happily ask for 30 or 45 days. A literal union makes the schema say exactly which windows exist, so the model picks one instead of getting an error. Return range and lastSyncedAt. The agent can then say "data through Oct 8" instead of implying it's live. 25 rows, not 1,000. Tool output goes into the context window. 25 queries plus 25 pages is enough to find the near-wins without burying the model.

While taking screenshots for an article, I noticed my own dashboard's top-queries list was alphabetical: "astro app", "nanoclaw", "surfer seo"... The query responsible for a quarter of my impressions wasn't in it.

The sync requested rowLimit: 50 and stored the rows in API order. The API sorts by clicks. On a young site nearly every query has 0 clicks, so everything ties, and the tie order I got was alphabetical. The cut to 50 (and then 25) kept the alphabetically-first queries instead of the most-seen ones. Worse, this is what the MCP tool returns, so agents were analyzing an alphabetical sample.

". Delete this comment. --> General lesson for anyone wrapping an API in an MCP tool: truncation is a product decision. Whatever you cut is invisible to the model, and it won't know to ask for it. Prompts that make it worth it

Get my search performance for the last 28 days. Which pages have 200+ impressions but a CTR clearly below pages at a similar position? For each, suggest a new title and meta description based on its top query.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation