@orellbuehler/search-console-mcp
v0.1.0
Published
Model Context Protocol server for Google Search Console: query search analytics (clicks, impressions, CTR, position), manage sitemaps and properties, and inspect URL index status over the official Search Console API.
Maintainers
Readme
search-console-mcp
MCP server for Google Search Console that exposes the official Search Console API as tools for AI agents.
Its focus is search performance and index health — querying clicks, impressions, CTR and position by query, page, country, device or date, checking whether a URL is indexed and why not, and managing the sitemaps and properties of an account.
What it deliberately does not do: no requesting (re)indexing of URLs — the separate Indexing API only supports job posting and livestream pages — no property ownership verification (an owner must add the service account to each property), and no Google Analytics data (that is the unrelated Analytics Data API).
Deletes are opt-in.
delete_sitemapanddelete_siteare only registered whenGOOGLE_SEARCH_CONSOLE_ALLOW_DESTRUCTIVEis set — see Configuration.
Install
claude mcp add search-console \
-e GOOGLE_SERVICE_ACCOUNT_KEY_PATH=/path/to/service-account.json \
-e GOOGLE_SEARCH_CONSOLE_SITE_URL=https://example.com/ \
-- npx -y @orellbuehler/search-console-mcpThe -e flags must come before the -- separator; anything after -- is passed to the server
process instead of being read as configuration.
Getting a service account key
- In the Google Cloud console, select or create a project and enable the Google Search Console API.
- Go to IAM & Admin → Service accounts → Create service account. You can skip the optional "grant access" steps — Search Console permissions are granted separately, not via Cloud IAM roles.
- Open the new service account, go to the Keys tab, and choose Add key → Create new key → JSON. The file downloads once and cannot be retrieved again.
- In Search Console, open the property, go to
Settings → Users and permissions → Add user, and paste the service account's email address
(
[email protected]). Grant:- Restricted or Full for the read tools (analytics, sitemaps, URL inspection)
- Full for
submit_sitemapanddelete_sitemap
- Repeat step 4 for every property the server should see — a service account cannot verify properties itself.
- Point
GOOGLE_SERVICE_ACCOUNT_KEY_PATHat the downloaded JSON file.
Treat the JSON key like a password — it carries whatever permissions you granted, with no second
factor in front of it. Keep it outside the repository and consider chmod 600.
Configuration
| Variable | Required | Description |
| ----------------------------------------- | -------- | -------------------------------------------------------------------------- |
| GOOGLE_SERVICE_ACCOUNT_KEY_PATH | one of | Path to the downloaded service account JSON key |
| GOOGLE_SERVICE_ACCOUNT_KEY | one of | The service account JSON key inline, as a raw JSON string |
| GOOGLE_SEARCH_CONSOLE_SITE_URL | no | Default property, so tools can omit site_url |
| GOOGLE_SEARCH_CONSOLE_ALLOW_DESTRUCTIVE | no | Set to 1, true or yes to register delete_sitemap and delete_site |
A property is identified either as a URL-prefix property like https://example.com/ (protocol
and trailing slash matter — https://example.com/ and http://example.com/ are different
properties) or as a domain property like sc-domain:example.com, which covers all subdomains
and protocols. Use whichever form the property was added to Search Console with; list_sites shows
the exact strings.
Usage with Claude Code
{
"mcpServers": {
"search-console": {
"command": "npx",
"args": ["-y", "@orellbuehler/search-console-mcp"],
"env": {
"GOOGLE_SERVICE_ACCOUNT_KEY_PATH": "/path/to/service-account.json",
"GOOGLE_SEARCH_CONSOLE_SITE_URL": "https://example.com/"
}
}
}
}Example prompts
- "What are my top search queries this month?"
- "Which pages get the most clicks from Google, and how did that change vs the previous 28 days?"
- "Show queries containing 'pricing' where we rank below position 10 — quick-win candidates."
- "How much of our traffic is mobile vs desktop?"
- "Plot our daily clicks and impressions over the last three months."
- "Which countries do we get impressions from but almost no clicks?"
- "Is https://example.com/blog/launch indexed? If not, why?"
- "List our sitemaps and tell me if any have errors or warnings."
- "Resubmit the sitemap after yesterday's site restructure."
- "Which pages ranking for 'mcp server' compete with each other?"
- "Compare our Discover traffic to web search traffic this quarter."
Tools
Search analytics
| Tool | Description |
| ------------------------ | ---------------------------------------------------------------------------------------------------- |
| query_search_analytics | Full-power performance query: any dimensions, filters, regex, search type, pagination up to 25k rows |
| top_queries | Top search queries by clicks, optionally narrowed to a page, country or device |
| top_pages | Top pages by clicks, optionally narrowed to a query substring, country or device |
Sitemaps
| Tool | Description |
| ---------------- | ---------------------------------------------------------------------------- |
| list_sitemaps | List submitted sitemaps with status, errors, warnings and indexed URL counts |
| get_sitemap | Get one sitemap's processing status and contents |
| submit_sitemap | Submit a new sitemap or resubmit an existing one for reprocessing |
| delete_sitemap | Delete a sitemap from Search Console (opt-in via ..._ALLOW_DESTRUCTIVE) |
Sites
| Tool | Description |
| ------------- | ------------------------------------------------------------------------------ |
| list_sites | List all properties the service account can access, with permission levels |
| get_site | Get one property's permission level |
| add_site | Add an already-verified property to the account |
| delete_site | Remove a property from the account's view (opt-in via ..._ALLOW_DESTRUCTIVE) |
URL inspection
| Tool | Description |
| ------------- | --------------------------------------------------------------------------------------------- |
| inspect_url | Google index status of a URL: verdict, coverage, canonicals, last crawl, rich results, robots |
Notes & caveats
- Performance data lags ~2–3 days. The convenience tools default their date range to end 3 days
ago;
data_state: "all"includes fresh but possibly incomplete data. - 16-month retention. Queries older than that return no rows.
- Privacy filtering. Rows for rare queries are withheld, so summing per-query rows undercounts the true totals; query without dimensions for exact totals.
- 25,000 rows per call. Paginate with
start_row; a response with fewer rows thanrow_limitis the last page. - URL inspection quota is about 2,000 calls/day per property and 600/minute — inspect selectively, not in bulk.
- The
hourdimension requiresdata_state: "hourly_all"and only covers the last ~10 days. - Your search data goes to the LLM. Everything a tool returns becomes model context; don't connect properties whose data must not leave your environment.
Development
npm install
npm run build # tsc -p tsconfig.build.json -> dist/
npm test # vitest run
npm run lint # eslint src
npm run typecheck # tsc --noEmit
npm run format # prettier --write .Smoke-test the built server against a real property:
GOOGLE_SERVICE_ACCOUNT_KEY_PATH=/path/to/service-account.json \
GOOGLE_SEARCH_CONSOLE_SITE_URL=https://example.com/ \
npx @modelcontextprotocol/inspector node dist/index.jsCI / Releasing
CI runs format:check, lint, typecheck, test and build on Node 20 and 22. Publishing happens
on GitHub release via npm trusted publishing (OIDC, no tokens):
npm version patch
git push --follow-tags
gh release create "v$(node -p "require('./package.json').version")" --generate-notesLicense
MIT © Orell Bühler
