The limit to know first
If you came here thinking “I'll connect Search Console and have it index everything”, the answer belongs before the setup, not after: you can't. And it isn't a limit of the MCP — it's a limit of Google.
The Indexing API — the only API that accepts a crawl request — is restricted to two content types. The official documentation is a single line and leaves no room:
“The Indexing API can only be used to crawl pages with either
JobPostingorBroadcastEventembedded in aVideoObject.”
Job postings and livestreams. Everything else is discarded, even when the call returns 200. Be wary of any MCP server advertising “batch submit, 200 URLs a day” for ordinary pages: it is calling an endpoint that ignores those pages.
The URL Inspection API doesn't index either: it is read-only. It tells you what Google decided about a URL; it doesn't change its mind.
The real value sits elsewhere, and it is bigger: the MCP lets you read Google's verdict, URL by URL. Knowing that 900 pages are stuck on “Crawled – currently not indexed” beats a thousand “request indexing” buttons, because that verdict names the cause — and the cause is fixable in code.
What you need before you start
Three things, and it pays to check them now: each one, if missing, surfaces halfway through the OAuth setup — the worst possible moment.
- property A verified property in Search Console, and above all the Google account that owns it. The OAuth token inherits that account's permissions: authorizing with the wrong address returns an empty property list and no useful error.
- uv The server is Python and runs via
uvx, which downloads and updates the package itself: no clone, no virtualenv. - project Any Google Cloud project, the default one included. No billing required: the Search Console API sits in the free quota.
The MCP server is AminForou/mcp-gsc, open source. It is not Google's: the official list of Google MCP servers holds sixty-plus Cloud services plus Drive, Gmail and Calendar — Search Console is not among them. No official server exists, and this is how you verify that rather than assume it.
The OAuth client on Google Cloud
Five steps in the Google Cloud console. Do them in this order: postpone the third and it costs you a second round in seven days.
- 1
Enable the Search Console API
In the project's API Library, search for “Search Console API” and hit Enable. It's free: no billing needed, and the $300 trial banner can be ignored.
- 2
Fill in the consent screen
User type External, app name, support and contact email. This is the screen you yourself will see two minutes from now — not a form for Google.
- 3
Publish the app to production
The step almost everyone skips. An app left in “Testing” issues refresh tokens that die after seven days: you'd re-authenticate every week. In production the token persists.
- 4
Declare the scope
Just one: webmasters, read and write. The write half serves exactly one legitimate purpose — submitting or resubmitting the sitemap.
- 5
Create the client, type Desktop app
Not “Web application”. The MCP uses the localhost loopback flow, and only the desktop client declares it. Download the JSON: that's the credential.
At the end Google shows a yellow banner: “your app requires verification”. Ignore it. Verification only removes the warning screen and lifts the 100-user cap. You are one user, and the app is yours: at sign-in you'll click Advanced → Go to … (unsafe), and that is correct.
The two traps
Service account key creation is blocked
The “obvious” path — service account plus JSON key — runs into the iam.disableServiceAccountKeyCreation organization policy, which Google enforces by default on new projects. Turning it off requires the Organization Policy Administrator role at organization level; if your project sits in “No organization”, that organization doesn't exist and there is nothing to edit. Dead end: use OAuth.
The wrong client type fails silently
A “Web application” client downloads a JSON keyed web with no redirect_uris; the desktop one is keyed installed and carries http://localhost. The MCP accepts only the second — and the first doesn't fail at download time, it fails later, when the browser never opens. Check the file before moving on.
Put the downloaded JSON where it will live, outside the repo: it is a live credential to your Search Console.
mkdir -p ~/.config/gsc
mv ~/Downloads/client_secret_*.json ~/.config/gsc/client_secrets.json
chmod 600 ~/.config/gsc/client_secrets.json Then confirm you have the right client — thirty seconds that save twenty minutes:
python3 -c "import json,os; d=json.load(open(os.path.expanduser('~/.config/gsc/client_secrets.json'))); print(list(d.keys()))"
# -> ['installed'] correct
# -> ['web'] wrong client, do it again Wiring the MCP into Claude Code
One command. --scope local registers it for this project and for you only: it never lands in a versioned file, which is what you want for a personal credential.
claude mcp add gsc --scope local \
--env GSC_OAUTH_CLIENT_SECRETS_FILE=$HOME/.config/gsc/client_secrets.json \
-- "$(which uvx)" mcp-search-console Then restart Claude Code: MCP servers load at session start, so the running one won't see the tools yet. On the first call the browser opens, you pick the account, clear the unverified-app warning and grant access. Once only: from there the token is cached.
If the browser never opens, it is almost always the wrong client (trap number two). Re-check that the JSON is keyed installed and not web.
What to ask it on day one
Roughly twenty tools, but six do the work. Exactly one writes; every other one reads.
-
list_propertiesLists the visible properties. An empty result means you authorized with the wrong Google account: this is the first check, always. -
list_sitemaps_enhancedHow many URLs Google read from your sitemap, with errors and warnings. Comparing that to how many you emit is the first diagnosis. -
manage_sitemapsSubmits or deletes a sitemap. The one and only write action in the whole set. -
get_search_analyticsQueries, clicks, impressions, CTR, position. Filterable by page, country, device. -
compare_search_periodsTwo date ranges side by side: what separates a real drop from seasonality. -
batch_url_inspectionInspects up to 10 URLs at a time and returns Google’s verdict on each. The one that matters most.
The order that works runs from the general to the single URL. First list_properties, to be sure you're talking about the right site. Then the sitemap: how many URLs you emit versus how many Google read — if those two numbers diverge, that's the problem and nothing else needs looking at.
Only then go down to individual pages. And here is the move that changes the outcome: inspect in separate samples, not at random. Ten URLs from one section, ten from another, ten from the secondary languages. A random sample hands you an average; three per-group samples tell you which group is broken.
Read the verdict literally, because each phrasing is a different cause with a different fix: “Crawled – currently not indexed” points at content judged thin or duplicated; “Discovered – currently not indexed” at a crawl-budget problem; “Duplicate without user-selected canonical” at a canonical you are not declaring the way you think. Three diagnoses, three interventions. That is the part the MCP unlocks — and the part a “request indexing” button would never give you.
The sources (and why they matter)
This guide touches two areas where memory is routinely wrong: the limits of an API and the exact names of packages and variables. Both need checking at the source every time — so the sources are here, each with the reason it was consulted.
- AminForou/mcp-gsc
The MCP server used in this guide. Its README carries the exact package and environment-variable names — the part you cannot guess.
- Indexing API — Quickstart (Google)
The line that closes the forced-indexing question. Quoted verbatim above because the whole guide turns on it.
- Search Console API — Authorizing requests (Google)
The authorization model: which credentials the API accepts, and with which property permissions.
- Google Cloud — MCP supported products
The official list of Google MCP servers. Search Console is absent: that is how you establish the official server doesn’t exist, instead of inferring it.
One methodological note that outlives this guide: absence is proven with a list, not with a search that came back empty. “I couldn't find an official Google MCP” and “Search Console does not appear in the official list of products with an MCP” sound like the same sentence. Only the second one is a verification.