Google Search Console MCP Server
This server provides an MCP interface to Google Search Console, enabling AI agents to:
List and manage Search Console properties.
Diagnose setup issues with automated checks for OAuth, tokens, configuration, and browsers.
Inspect URL indexing status via the URL Inspection API.
Monitor API quotas (Request-Indexing and URL Inspection budgets) per property.
Retrieve Search Analytics performance data (clicks, impressions, CTR, position) with flexible dimensions.
Submit or resubmit sitemaps.
Walk through setup and authentication steps.
Detect installed Chromium browsers and profiles for browser-driven actions.
Provides tools for interacting with Google Search Console, enabling URL index status checks, indexing requests, sitemap submission, search analytics retrieval, and quota monitoring.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Google Search Console MCP ServerCan you check if https://example.com/landing-page is indexed?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Google Search Console MCP Server
An MCP server that gives Claude and other AI agents real control over Google Search Console — list your properties, check whether a URL is indexed, find the pages Google left out, run URL inspection in bulk, submit sitemaps, request indexing, and pull search analytics, all from a conversation.
Built for SEO practitioners tired of checking index status and submitting sitemaps by hand, one property at a time, and for the AI agents that can do it for them.
shahidali.co/tools/gsc-mcp is the project page: the same install lines, the tool list, and what the quota rules actually are, written for people who have not opened this repo.
Add it to your agent — one-liners for Claude Code, Cursor, VS Code, LM Studio
Project status — what is verified, and on how many platforms
Tools — the fifteen tools this server registers
Install · The OAuth client is handled for you · Using your own OAuth client instead
Getting started — first run, sign-in, the browser extension
Privacy — what leaves your machine, and what does not
Known gaps — read this before trusting it with a client property
Add it to your agent
Claude Code, in one command:
claude mcp add gsc -- uvx gsc-indexer-mcpAnything else that speaks MCP, by hand — this is the whole config:
{
"mcpServers": {
"gsc": { "command": "uvx", "args": ["gsc-indexer-mcp"] }
}
}uvx fetches and runs the published package with nothing installed first, which
is why every button above is a one-liner. A .mcp.json with exactly
that content sits in this repo, so cloning it is also enough.
No API key goes in any of these. Sign-in happens once, in your browser, when you
first call gsc_setup() — see The OAuth client is handled for you.
Related MCP server: ga4-mcp
Project status
Beta. The whole surface is wired up, and it has now met a real Google account — on one operating system, driven by one person.
0.1.0 drops the pre-release suffix so that pip install finds it without
--pre. That is a decision about reach, not a claim of maturity: this project
needs bug reports from people who are not its author, and a package pip refuses
to install by default does not get them. Read the Known issues in
CHANGELOG.md before pointing it at a property you care about —
in particular, a transient rate-limit from Google currently ends the whole
batch. Bug reports are the point; please file them.
Fifteen tools are registered on the server and covered by a wire-level smoke test that connects a real MCP client session and confirms every tool answers with a description. Storage, quota accounting, OAuth, and config are the foundation underneath them. Sign-in has been walked for real, on Windows against a live Google account — see docs/manual-smoke.md, which is also where the defects that run found are recorded. Submission has since driven a real browser and had Google confirm real Request Indexing calls, in Chrome and in Brave, against live properties. That is one platform and one operator, and every automated assertion about it is still made against a fake; see Known gaps for what that does and does not buy you.
Milestone | Scope | State |
1. Foundation | Paths, logging, SQLite store, quota engine, OAuth + PKCE, config | Done |
2. MCP surface | The tools below, exposed over MCP | Done |
3A. Onboarding | Guided sign-in, browser/profile detection, the bridge extension | Done |
3B. Submission | Browser-driven Request Indexing, job control | Verified live on Windows |
4. Reporting | Indexation discovery and audits | Verified live on Windows |
Released versions and what changed in them are in CHANGELOG.md. Watch or star the repo if you want to know when the milestones above are verified on a platform other than Windows.
Tools
Shipped and registered on the MCP server today:
Tool | What it does |
| List every Search Console property the account can reach |
| Diagnose auth, config and environment problems |
| Index status for one or more URLs via the URL Inspection API (read-only, spends no Request-Indexing slot) |
| Request-Indexing and URL Inspection budget remaining today, per property |
| Clicks, impressions, CTR and position from Search Analytics |
| Submit or resubmit sitemaps to a property |
| Walk through sign-in and setup; idempotent, returns the single next step |
| Locate installed browsers and profiles for browser-driven submission |
| Pin the browser profile to drive, overriding the detector's recommendation |
| Submit up to five URLs for indexing, one at a time. Blocks for minutes — see Submitting URLs |
| Queue a background submission run over any number of URLs; returns at once |
| Progress and state for one submission job, or the most recent |
| Ask a running submission job to stop after the URL in flight |
| Find which of a property's URLs are not indexed, and why — see Finding what is not indexed |
| The current indexation position for a property, read from the local store; spends no quota |
Why quota accounting is the hard part
Most tools in this space get Google's limits wrong, then get throttled and blame detection. Both limits that matter are per property, not per account:
Limit | Value | Mechanic |
Request Indexing | ~11 slots per property | Rolling — each slot frees 24h + 1 min after its own use |
URL Inspection | 2,000 per day per property | Daily reset |
URL Inspection | 600 per minute per property | Rate limit |
Properties are independent, so eight properties means eight independent budgets. This server tracks slots individually rather than counting a daily total, so it knows the exact minute the next slot opens — and it deliberately over-counts rather than under-counts when a race is possible, because a short wait is cheaper than a hard Quota Exceeded.
Finding what is not indexed
gsc_find_unindexed collects candidate URLs — from the property's registered sitemaps, from URLs already in the local store, or both — inspects the ones whose last inspection has gone stale, and reports each unindexed URL with a reason. limit caps how many URLs are inspected, not how many come back: an inspection spends budget, and a cap that only trimmed the output would pay full price for an answer it discarded. Which URLs a capped run reaches follows the store's own URL ordering (alphabetical), not staleness, so a capped run is a sample rather than a worst-first sweep.
gsc_audit answers the same question from the store alone — no HTTP inspection, no budget spent. It is point-in-time: it reports what the last inspection found, and carries as_at and a stale count so you can tell how old that picture is. There are deliberately no movement numbers.
Reason codes
There are ten of them. submitting_helps on each row is the one to act on before calling gsc_request_indexing:
Reason |
| What it means |
| yes | Google knows the URL but has not crawled it |
| yes | Google has never seen the URL |
| yes | Google crawled it and chose not to index it — improve it, then submit |
| no | The URL returns not-found |
| no | The URL redirects elsewhere |
| no | A noindex directive on the page or its response |
| no | Returns 200 but reads as an error or empty page |
| no | robots.txt blocks the URL |
| no | Google chose a different canonical |
| no | An alternate page pointing at its own canonical — no action |
If you have read the eight-code list in the design notes and counted ten here, the extra two are discovered-not-indexed and unknown-to-google, kept separate from crawled-not-indexed on purpose. All three answer yes to "can a quota slot move this", but not to "what do I do first", and that is the part you act on. Discovered and unknown are pages Google has not judged — it has not fetched them yet, so submitting is the whole remedy. Crawled-not-indexed is a page it fetched and passed on; a fresh crawl can reverse that verdict, but resubmitting byte-identical content re-crawls to the same one. Improve the page, then submit it.
Slots are roughly eleven per property per rolling day and unrecoverable, and crawled-not-indexed is usually the biggest bucket on a real site. submitting_helps: true means the slot can work, not that today is the day to spend it.
A URL whose state could not be established — a failed inspection, or a result a re-check could not confirm — is reported as undetermined, never as unindexed. Absence of evidence is not a finding.
Submitting URLs
Google has no API for Request Indexing that a tool like this can use, so submission goes through your own browser: the bridge extension, loaded into the profile you paired during gsc_setup, clicks Request Indexing in a real Search Console session. That has three consequences worth knowing before you spend anything.
It is slow, and the slowness is the feature. Submissions are paced 130–180 seconds apart. That gap is not a placeholder and not a bug report — it is the interval proven not to draw a throttle over long runs. Five URLs is therefore up to fifteen minutes of wall clock, and the tool that does it blocks for all of it.
Quota is per property and small. Roughly eleven slots per property, on a rolling 24-hour window — each slot frees 24 hours and a minute after its own use, not at midnight. Properties are independent budgets. Call gsc_quota first and act on spendable_free, not free: spendable_free subtracts the daily_reserve you set aside in config. A spent slot is unrecoverable; there is no undo.
One run at a time. The bridge drives a single browser tab in your real profile and listens on one fixed local port, so a second run while one is going is refused outright rather than queued. That covers both directions: gsc_start_indexing_job while a job or a gsc_request_indexing call is in flight, and gsc_request_indexing while a job is running.
Which tool
You have | Use | Because |
One to five URLs, and you can wait |
| Synchronous. Returns the outcome of every URL. Hard-capped at five — |
More than five, or you want your session back |
| Returns a |
A job in flight |
| Progress, per-URL results, and whether a worker is still on it. Called with no argument it reports the most recent job. |
A job you want to end |
| Stops after the URL in flight, never mid-URL: a submission already sent has spent its slot and its ledger row has to settle with the real outcome. |
What a run does when things go wrong
A run stops early rather than burning the rest of the batch against a server that is already refusing: a quota_exceeded, a captcha, a rate limit, or a signed-out session ends it. stopped_early and stop_reason in the result say so, and the URLs never attempted keep their slots. A job that ended this way lands in state stopped_throttled; one you stopped by hand lands in stopped_user.
URLs that could not be routed to any known property come back as no_property, and ones that found no spendable slot as no_quota. Neither reached the browser and neither cost anything — they are reported apart from failures on purpose, because the fixes are different: run gsc_list_sites for the first, wait for the second.
If the server is restarted while a job is running, that job's row is closed out as failed at the next startup, and any submission row left open is settled against the property's ledger. Nothing is silently resumed — a background worker does not survive the process that owns it.
Before your first submission
The extension must be loaded in the browser profile you paired, and the browser must be one this server can drive. gsc_setup walks both; gsc_doctor re-checks them. If the browser is closed, auto_launch_browser (on by default) opens it. The first run of all pairs the extension to the bridge, which needs the browser window in front of you.
Requirements
Python 3.11 or newer
A Google account with Search Console properties
A Chromium browser — Chrome, Brave, Edge, Vivaldi, Opera or Chromium.
gsc_setuploads a browser extension into one of your existing profiles, and there is no way to complete setup without one. Firefox and Safari are not Chromium and will not work.No Google Cloud setup.
gsc_setupfetches the OAuth client this project ships. You can still supply your own — see Install below.
Install
The distribution is gsc-indexer-mcp. Note the indexer: plain gsc-mcp
on PyPI is an unrelated project by another author, so installing that name gets
you someone else's server. Everything inside this one is still gsc_mcp — the
import package, the console script, the config directory.
pip install gsc-indexer-mcpVersions up to and including 0.1.0a6 were pre-releases and needed --pre.
From 0.1.0 they do not.
Or skip installing entirely and let uvx gsc-indexer-mcp fetch it on demand,
which is what the buttons at the top of this page do.
You can also take the wheel from the latest release — that one differs in one way, described below: it carries the OAuth client, where the PyPI build downloads it at first setup.
Or from a checkout, which is what you want if you intend to change anything:
git clone https://github.com/Mrshahidali420/google-search-console-mcp.git
cd google-search-console-mcp
python -m venv .venv
.venv/Scripts/python -m pip install -e . # POSIX: .venv/bin/pythonThe OAuth client is handled for you
You do not need a Google Cloud project. gsc_setup() finds a client in
this order — environment variables, the client baked into a release wheel,
then a one-time download of the client this project ships, cached in your
config directory. A source checkout takes the third path; everything after
the first run is offline.
The tracked source deliberately contains no client. A secret committed to a public repository is permanent in git history, and GitHub reports Google client secrets to Google, which can revoke them — breaking every user at once. So it is delivered as a release asset and a build-time injection instead; docs/google-cloud-oauth.md has the mechanism. To be plain about it: that asset is public and anyone can read it, exactly like the wheel. What it buys is rotation, not secrecy — an installed app's security comes from PKCE, which this uses.
Using your own OAuth client instead
Optional. Worth doing if you want the consent screen to carry your own
app name, or your organisation requires its own client. Set
GSC_MCP_CLIENT_ID and GSC_MCP_CLIENT_SECRET and they override
everything above, in a release build or a source checkout alike.
All of this happens in Google Cloud Console, free, and takes about five minutes. Do the steps in order — step 4 is the one people skip, and skipping it fails at the very end.
Create a project. Use the project dropdown in the top bar → New project. Any name. Wait for it to be created, then make sure it is the project selected in that dropdown; everything below applies to the selected project only.
Enable the Search Console API. Search "Search Console API" in the console's search bar, open it, and click Enable. Without this, every call returns a 403 that mentions the API being disabled.
Configure the OAuth consent screen. In the left menu: APIs & Services → OAuth consent screen.
User type: External. ("Internal" only exists on Workspace accounts and restricts the app to your own organisation.)
App name: anything — you are the only user who will see it.
User support email and developer contact email: your own address.
You do not need to add scopes here. This server requests its scope at sign-in time, and adding it on this screen does not change what you are granted.
Save through to the end.
Publish the app — or add yourself as a Test user. Either works; publishing is better, and this is the step people skip.
Every new app starts in Testing status, where Google lets only listed test users sign in. Everyone else gets
403: access_deniedon the consent screen — after creating the project, enabling the API, creating the client, setting the environment variables and runninggsc_setup. Nothing earlier warns you. A Testing app also expires its refresh token every 7 days, so sign-in breaks a week later in a way that looks like a bug here and is not.Both Search Console scopes are classed non-sensitive by Google, so publishing costs nothing: no verification, no security assessment, no user cap. Audience → Publishing status → Publish app, and both problems above disappear.
If you would rather stay in Testing, find Test users (on newer consoles: Audience → Test users) and add the Google address that owns your Search Console properties. That works indefinitely for your own account, at the cost of signing in again every 7 days.
Create the OAuth client. APIs & Services → Credentials → Create credentials → OAuth client ID, application type Desktop app. Copy the client ID and client secret it shows you — the secret is shown once, though you can always create another client.
Desktop app is the right type: this server signs you in over a loopback redirect on
127.0.0.1, which is what that type allows. Do not pick "Web application" and do not add a redirect URI by hand.Set the two environment variables below before starting the server. Without them, any tool that needs to talk to Google returns
{"ok": false, "error": "not_configured", ...}rather than doing anything —gsc_list_sites,gsc_check_status,gsc_performance, andgsc_submit_sitemapsall behave this way.gsc_doctorandgsc_quotaare the two exceptions:gsc_doctorstill runs and reportsoauth_client: not okas one line in its checks list rather than failing outright, which makes it the right first tool to run when something is stuck;gsc_quotais local-only and returns[]on an empty store regardless of OAuth configuration.
export GSC_MCP_CLIENT_ID="your-client-id.apps.googleusercontent.com"
export GSC_MCP_CLIENT_SECRET="your-client-secret"
# Windows PowerShell:
# $env:GSC_MCP_CLIENT_ID = "your-client-id.apps.googleusercontent.com"
# $env:GSC_MCP_CLIENT_SECRET = "your-client-secret"Connect it to an MCP client
Point your MCP client at the installed console script. For Claude
Desktop, add to its claude_desktop_config.json:
{
"mcpServers": {
"gsc-mcp": {
"command": "C:\\path\\to\\google-search-console-mcp\\.venv\\Scripts\\gsc-mcp.exe",
"env": {
"GSC_MCP_CLIENT_ID": "your-client-id.apps.googleusercontent.com",
"GSC_MCP_CLIENT_SECRET": "your-client-secret"
}
}
}
}On POSIX, use .venv/bin/gsc-mcp as the command instead. Any other
MCP-speaking client that can launch a stdio server works the same way —
the entry point is the gsc-mcp console script installed above, and the
server talks the standard MCP stdio transport (gsc_mcp.server:main).
This has been exercised against a real Google account through a real MCP client session on Windows; it has not been run against Claude Desktop specifically, nor on macOS or Linux. See Known gaps.
Getting started
Once the server is installed and connected, the whole of setup is one tool
called repeatedly. gsc_setup() is idempotent: it never resumes a session,
it re-reads the whole state on every call, and it hands back the single
next thing to do. Call it in a loop until it returns ok: true.
1. Install and connect — see Install above.
2. Nothing. The OAuth client is handled for you — gsc_setup()
downloads it on the first run and caches it. Set GSC_MCP_CLIENT_ID and
GSC_MCP_CLIENT_SECRET only if you want to
use your own.
3. Run gsc_setup(). It opens a Google consent screen in your browser
and returns the URL as well, so a headless machine can still complete it by
hand. Approve it, then call gsc_setup() again — the second call collects
the redirect, stores the token, and moves on. Nothing about your sign-in is
returned to the caller: not the token, not the authorization code, not the
PKCE verifier.
4. Load the bridge extension. gsc_setup() will tell you where it
extracted the extension to and which browser profile to load it into. In
that browser: open its extensions page (chrome://extensions,
brave://extensions, edge://extensions, and so on — gsc_setup() gives
you the exact URL for your browser), turn on Developer mode, choose
Load unpacked, and select the folder it named.
You will see a warning banner, and it is expected. The extension asks for the
debuggerpermission, so Chromium shows a prominent bar saying an extension is debugging your browser, and may warn you when you enable Developer mode. That permission is not incidental. Search Console applies a soft throttle to Request Indexing clicks that did not come from a real pointer, and synthetic DOM clicks trip it. The extension therefore issues trusted input events through the Chrome DevTools Protocol instead, which is whatdebuggergrants and the only way to grant it. The banner is Chromium correctly reporting a real capability — read it as "yes, this is the extension you just installed", not as malware. It only ever attaches tosearch.google.com, the one host in itshost_permissions.
5. Run gsc_doctor(). Seven checks, in order: oauth_client, token,
config, store, properties, browser, extension. Every failing one
carries a concrete fix. Sample output, on a machine where everything is
working:
{
"ok": true,
"checks": [
{"name": "oauth_client", "ok": true, "detail": "configured", "fix": ""},
{"name": "token", "ok": true, "detail": "token file present", "fix": ""},
{"name": "config", "ok": true, "detail": "config valid", "fix": ""},
{"name": "store", "ok": true, "detail": "schema version 2", "fix": ""},
{"name": "properties", "ok": true, "detail": "2 properties", "fix": ""},
{"name": "browser", "ok": true,
"detail": "Google Chrome / Default is the profile to use", "fix": ""},
{"name": "extension", "ok": true,
"detail": "the gsc-mcp bridge extension is installed in Google Chrome / Default at version 1.10.0; whether its background service worker is running is not checked in this milestone",
"fix": ""}
]
}Reading the browser and extension checks
These two are about your local machine rather than your Google account, and they are worded carefully because the failure modes are easy to misread.
"Could not be checked" never means "not installed." The extension check
reads your browser's own preferences files. Those files are frequently
locked, mid-write, cloud-synced, or held open by antivirus. When a read
does not happen, the check says the question could not be checked and
that the extension may already be there. That is not a polite way of saying
it is missing, and the fix is to run gsc_doctor() again (closing the
browser first if it is running) — not to reinstall an extension that is
sitting right where you put it. The same distinction runs through
gsc_detect_browsers, whose has_extension field is three-valued: true
present, false every preferences file was read and it was not among them,
null the check could not be performed.
Microsoft Edge can report a Microsoft account where a Google one is expected. Edge stores signed-in account addresses in the same file and the same key Chrome uses for Google accounts, but by default it signs profiles in to Microsoft identities. Nothing on disk tells the two apart. So for an Edge profile, an address found is not evidence of a Google sign-in — and if your Microsoft address happens to be the same as your Google one, what looks like a confirmed match is not confirmed at all. The tools hedge this rather than assert it: an Edge profile is reported with "this profile's Google sign-in could not be confirmed". Check it yourself before relying on it. Brave, Vivaldi, Opera and plain Chromium record no Google account at all and are hedged for the different reason that there is nothing to read.
A changed extension ID means re-pairing, not breakage. The extension
ships with no manifest key, so Chromium derives its ID by hashing the
absolute path it was loaded from. That ID is stable for as long as the
extraction directory is stable — and it changes if that directory moves:
an upgrade that relocates the config directory, a different GSC_MCP_HOME,
a migration to a new machine. When it changes, the extension check stops
recognising the loaded copy and reports it as not installed. Nothing is
broken and nothing is corrupted; the fix is to load the unpacked extension
again from the new folder, exactly as in step 4.
A green extension check means registered, not running. It says the
extension is loaded into that profile at that version. Whether its MV3
background service worker is alive is a separate question, and only the
bridge can answer it: at submission time it waits for a connection, wakes
an evicted worker if none arrives, and fails with extension_not_connected
if that does not work either. gsc_doctor still reports registration only.
Development
.venv/Scripts/python -m pip install -e ".[dev]" # POSIX: .venv/bin/python
.venv/Scripts/python -m pytest -vArchitecture
gsc_core is a standalone engine with no MCP dependency, so it can be driven by the MCP server, a CLI, or a future desktop app without change.
Module | Responsibility |
| Where files live, per platform |
| Logging to stderr and file — never stdout, which MCP reserves for JSON-RPC |
| SQLite: sites, urls, submissions, jobs, quota slots |
| Per-property rolling slot accounting |
| OAuth 2.0 with PKCE S256, hardened token storage, refresh |
| User-tunable settings with validation |
| Which Chromium browsers are installed, and where they keep their state |
| Which profiles each browser has, and which Google account is signed into each |
| Where the bridge extension is extracted to, and what ID Chromium gave it |
| The localhost WebSocket server the browser extension connects back to |
| The per-URL submission loop: routing, atomic quota reservation, outcomes |
Privacy
To tell you which browser profile to use, this tool reads the profile list and the signed-in account address out of the browser's own files on your machine — Local State and each profile's Preferences / Secure Preferences. The same files are read a second time, for a different reason, to find out whether the bridge extension is loaded in that profile and at what version.
That read is entirely local. The address is used in memory to show you which profile is signed into which account, and:
it is never transmitted anywhere,
it is never written to disk by this tool,
it is never written to the log, at any level — failures reading these files are logged by exception type name only, precisely so that neither an address nor a path containing your Windows username can end up in a log file you might attach to a bug report.
Nothing in the tool opens these files for writing. No address is ever returned by a tool either, in either direction — not one found in a profile, and not your own authorised address. A tool result is rendered into a transcript and retained by whatever MCP client is driving the server, none of which this project controls, so a profile is identified by browser and profile directory and nothing else.
One path is the exception, and it is deliberate. When gsc_setup finds the bridge extension is not loaded yet, its result carries the directory the extension was unpacked to — on Windows, C:\Users\<your username>\AppData\Roaming\gsc-mcp\extension. On most machines that path contains your operating-system account name. It is returned because "Load unpacked" in Chrome asks you to pick that exact folder, and a set-up instruction you cannot follow is not a privacy win. It is the only path any tool returns, it appears only in the one step that needs it, and it is never written to the log. If your account name is something you would rather not have in a transcript, run that step, then clear the transcript.
Known gaps
Stated plainly, because they are the things a reviewer should look at first:
No test proves
icaclsactually applied an ACL on Windows — the Windows test only observes that the call was made, so_hardencould no-op there and the suite would stay green. The POSIX equivalents now execute on Linux and macOS on every push, so this gap is Windows-only.The submission path has now submitted real URLs, but the test suite still cannot prove it. As of 2026-08-05 it has driven a real browser, clicked Request Indexing, and had Google confirm the request — on Windows 11, in both Chrome and Brave, across several days and several properties, including running the quota ledger up against a real refusal from Google. What the automated suite exercises is still fakes only: every assertion about the extension bridge, the pacing, the quota reservation, the run loop and the job worker is made against a stand-in. So "it submits URLs" is now supported by a manual log rather than by CI, and the states a fake cannot reach remain the submission pass in docs/manual-smoke.md. Live running has found defects the suite missed at a steady rate; assume it has not run out of them.
The sign-in path has now been walked for real — once, on one machine (Windows 11, Chrome, Python 3.13, 2026-08-04), against an account with nine properties. Steps 1-8 of docs/manual-smoke.md pass. One run on one platform is not coverage: it found two defects that the whole automated suite had missed, which is the argument for running it again on macOS and Linux rather than for trusting it.
The doctor cannot detect a stale extension build, and no longer pretends to. Chromium records no manifest snapshot for an unpacked extension — and unpacked is the only way this bridge is installed — so the version the browser is actually running cannot be read from disk at all. The check now reports the version on disk and says the loaded one is unreadable, rather than passing the first off as the second. Closing this needs the extension to report
chrome.runtime.getManifest().versionover the bridge, which is a protocol change and is deferred until the bridge has been exercised against a real submission.The bridge port defaults to 8765, and two runs cannot share it. A second
gsc-mcpprocess, or anything else already on that port, fails to bind — the run now fails within seconds naming the port and the remedy, rather than blaming the extension after the full connect timeout. Moving the port (bridge_portin config) requires setting the same port in the extension's options page; the two are paired, not discovered.macOS and Linux browser detection has only ever run against fixtures, never on real hardware, here or in CI. The first person to run the smoke checklist on a Mac or a Linux box is performing that test.
gsc_detect_browsersreportsmatches_authorised_accountasnullon every real machine today. The flag reads anaccount_emailkey from the stored token, and nothing writes it: the current scope set returns no identity claim and the consent step does not record the authorising account. The plumbing is correct and inert. Treat the field as "unknown", not as "does not match".The
extensioncheck reports whether the extension is registered, not whether it is working. Only the bridge learns whether the MV3 worker is alive, and only at submission time.The published package is on PyPI as
gsc-indexer-mcp, notgsc-mcp— that name belongs to an unrelated project by another author, and installing it gets you their server, not this one. The two distribution channels also differ in one substantive way: the GitHub release wheel embeds this project's OAuth client, while the PyPI wheel deliberately does not (a secret on a public index is a revoked secret), so a PyPI install downloads the client from theclientrelease asset at firstgsc_setup(). Both paths have been exercised, but they are not the same path, and a bug in one would not show up in the other.mcpis pinned>=2.0,<3. The server is written against mcp 2.0'sMCPServerAPI — 1.x spelled itFastMCPand the two shapes are mutually exclusive, so this package now hard-conflicts with anything still requiringmcp<2(the mirror image of the conflict the old<2.0cap created).
Contributing
Contributions are genuinely welcome — issues, pull requests, bug reports, docs fixes, all of it. Start with CONTRIBUTING.md. Good first issues are the CI legs listed under Known gaps.
The single most useful thing you can contribute right now is a bug report from a machine that is not Windows. Everything here has been exercised by hand on one operating system, by one person; see Known gaps.
Security policy — please report anything involving tokens, OAuth or the local bridge privately
License
Functional Source License 1.1 with an Apache 2.0 future grant (FSL-1.1-ALv2).
In plain terms: use it, modify it, contribute to it, run it on client work — just don't sell a competing product built from it. Every release converts to Apache 2.0 two years after publication, so nothing here is locked away permanently.
Available Tools
15 toolsgsc_auditA
The current indexation position for one property, as structured data.
Reads the local store only: no network call, no quota spent. It
reports what the last inspection found, which is why the payload
carries as_at — run gsc_find_unindexed first if the picture is
stale, and check the stale count to see how much of it is.
Point-in-time by design. There are no movement numbers — nothing
"moved to indexed", nothing "de-indexed" — because the store keeps no
status history, and a zero in a field like that would read as a
measurement that found no change rather than as an absence of data.
basis says so in the payload.
Returns counts (total_known, checked, indexed, unindexed,
undetermined, never_checked, stale), indexed_pct (null when
nothing has been checked), a by_reason histogram over the ten reason
codes, and three action counts: submittable, needs_site_access and
no_action_needed. Every reason code is in exactly one of the three,
so they sum to unindexed. submittable counts URLs a quota slot can
move, not URLs to submit right now: it includes crawled-not-indexed,
usually the largest bucket, where Google has already fetched the page
and passed — a re-crawl can reverse that, but only after the page
changes. Read each row's action before spending slots. Rendering all
this — prose, table, chart — is yours to do.
| Name | Required | Description | Default |
|---|---|---|---|
| site | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full transparency burden. It thoroughly discloses behavioral traits: no network call, no quota usage, point-in-time snapshot, no movement numbers due to no status history, and explains how to interpret zeros (absence of data). It also reveals the `basis` field and the meaning of `stale`.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and front-loaded with the most critical information, but it is somewhat verbose. Each sentence conveys relevant detail, yet some redundancy exists (e.g., repeating local-only nature). Overall, it is appropriately sized for the complexity and manages to stay organized.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with one parameter and no output schema, the description is remarkably complete. It explains all return fields, edge cases (e.g., null indexed_pct when nothing checked), the meaning of action counts, and how to interpret the data. It also situates the tool among siblings for stale-vs-fresh scenarios.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description refers to 'one property' and implies the `site` parameter is that property identifier, but it does not explicitly describe the parameter's format, allowed values, or how to obtain it. With schema description coverage at 0%, the description should compensate more, but it adds only minimal meaning beyond the schema's title.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool's function: reporting the current indexation position for one property from the local store. It uses specific verbs and resource scope, and distinguishes itself from sibling tools by explicitly naming gsc_find_unindexed as an alternative for stale data.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage guidance: it states this is a local read-only operation with no quota cost, and instructs to run gsc_find_unindexed first if the picture is stale. It also cautions about the correct interpretation of 'submittable' and urges reading each row's 'action' before spending quota slots.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_check_statusA
Check whether each URL is indexed by Google Search, via the URL Inspection API.
READ-ONLY: this tool inspects current index status and submits NOTHING. It never requests indexing and never spends a Request-Indexing slot. No tool here does yet — requesting indexing is not built, so an assistant asked to get a URL indexed should say so rather than reaching for this one, which answers a different question and spends a different budget doing it. This tool DOES spend URL Inspection quota, a separate per-property budget of 2,000 calls a day and roughly 600 a minute (see gsc_quota) — one call per URL inspected.
concurrency defaults to the configured inspect_concurrency
(config.load()["inspect_concurrency"]) when omitted.
Properties come from the local store, the same one gsc_list_sites populates. If the store has never been synced — e.g. this is the very first call this install has ever made — it is synced automatically first, so a first-ever gsc_check_status call does not fail with "no property matches" purely because nothing has been synced yet.
Returns {"rows": [...], "checked": int, "skipped_quota": [...], "quota": {...}}. "quota" is per property, and its
daily_free_at_gate/minute_free_at_gate are the headroom measured
BEFORE this call reserved its own budget — they are a record of what
the gate saw, not current headroom, and are already stale by the size
of this batch by the time you read them. gsc_quota's similarly-shaped
daily_free/minute_free are the ones measured now; do not compare
the two pairs or plan a second batch against these. binding_at_gate
(here and on each "skipped_quota" entry) carries the suffix for the
same reason: it names only the exhausted INSPECTION window as seen at
the gate, where gsc_quota's binding covers the submission budget too
and is read now. Each row is
{"url", "status", "detail", "unverified"}. status is one of: indexed, crawled_not_indexed,
discovered_not_indexed, unknown_to_google, redirect, noindex,
duplicate, alternate_canonical, not_found, soft_404, blocked_robots,
no_property, error. no_property means no Search Console property in
this account covers that URL's host. unverified is True when a
concurrent burst produced a suspect result (unknown_to_google or
error) that a sequential re-check could not confirm before quota or
time ran out — treat such a row as UNKNOWN, not as a confirmed
"not indexed".
On a missing, expired, or rejected token, returns {"ok": False, "error": "auth_required", "fix": ...} instead of raising; if no
OAuth client is configured at all, returns {"ok": False, "error": "not_configured", "fix": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| urls | Yes | ||
| concurrency | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It extensively discloses behavioral traits: read-only nature, that it spends URL Inspection quota with specific limits, the concurrency default, automatic local-store sync, exact return format including stale quota field semantics, the meaning of 'unverified' status, and auth error return patterns. This goes far beyond minimal disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Although lengthy, every paragraph addresses a distinct concern: purpose, budget/quota, concurrency, store sync, return schema, and error handling. The core purpose is front-loaded in one sentence, and the complex quota timing caveats justify the additional detail. There is no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, but the description fully details the return structure, including a full list of status enum values, the 'no_property' and 'unverified' edge cases, and auth error return objects. It also explains quota measurement timing issues that could otherwise lead to misuse. For a complex tool, this is comprehensive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% description coverage, so the description must compensate. It explicitly explains the concurrency parameter's default via config.load() and the per-URL quota implication, and implies urls semantics with 'each URL' and 'one call per URL inspected'. However, it doesn't specify URL format requirements (e.g., absolute vs. relative, scheme), so it's not fully exhaustive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states precisely what the tool does: 'Check whether each URL is indexed by Google Search, via the URL Inspection API.' It clearly distinguishes itself from requesting indexing ('answers a different question and spends a different budget doing it') and references sibling tools like gsc_quota, making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says when NOT to use it, stating an assistant asked to get a URL indexed 'should say so rather than reaching for this one'. It also references gsc_quota for quota details and gsc_list_sites for the property store, with added context about automatic first-call syncing, providing clear guidance on use vs. alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_detect_browsersA
List the Chromium browser profiles on this machine and recommend one.
Local-only: reads the browsers' own state files, makes no network call, spends no quota, and needs no token — safe to call before signing in. Answers "which browser profile should I drive?", nothing else; it opens no browser and changes no setting.
PRIVACY: no email address is returned, in either direction. Not the account signed in to a profile, not the account that authorised this server, and not a profile display name that is itself an address. No filesystem path is returned either — a profile path carries the operator's account name. What identifies a profile here is its browser and its profile directory.
Returns {"ok": True, "profiles": [...], "recommended": <one of them or None>, "reasons": [...]}. profiles is a FLAT list across every
browser, ranked-flag included, not grouped by browser — the question is
which single profile to use, so each entry carries its own brand
context (browser, browser_key, extensions_url) and stands alone.
Each profile is {"browser", "browser_key", "extensions_url", "profile", "display_name", "account_on_disk", "account_discoverable", "matches_authorised_account", "has_extension", "recommended"}.
extensions_url is where that browser's extensions page lives
(chrome://extensions, brave://extensions, ...). Use the value given;
do not build one from the browser key, since Chromium registers no
chromium:// scheme and uses chrome://extensions.
has_extension is TRI-STATE: true means the pairing extension is
installed in that profile, false means every preferences file was read
and it was not among them, and null means the check could not be
PERFORMED — an unreadable preferences file, or no unpacked extension
directory to match against. Read null as "not detected", never as "not
installed"; telling a user with a working install to reinstall it is
the one wrong answer this flag exists to avoid.
account_on_disk says an account address was found in that profile's
files — found, not validated: no token is checked and nobody's live
session is inspected, and on Microsoft Edge the same file records
Microsoft accounts, so treat it as a hint rather than a login check.
account_discoverable is a fact about the BRAND: Brave, Vivaldi, Opera
and plain Chromium record no Google account at all, so account_on_disk: false there means "not discoverable", NOT "nobody is signed in".
matches_authorised_account is true, false, or NULL — null means the
question could not be asked (nothing has authorised yet, or the brand
records nothing), and must not be read as "no". reasons explains the
recommendation in plain sentences.
A machine with no Chromium browser installed returns ok: true with an
empty profiles list, recommended: null, and a note saying what to
install; that is an ordinary state, not a failure. Only an unexpected
fault returns {"ok": False, "error": "unexpected", "detail": <exception type>, "fix": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses local-only operation, no network/quota/token usage, no filesystem paths returned, privacy guarantees about email addresses, and the exact meaning of tri-state flags (has_extension, matches_authorised_account). It also explains error states. This exceeds typical expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but front-loaded with a one-sentence summary and purpose. Each paragraph adds essential caveats (privacy, tri-state semantics, edge cases). While not terse, every section is necessary given the tool's complexity, so it earns its length without being bloated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description must document the return structure, and it does so exhaustively: the flat list format, each field's meaning, tri-state behavior, empty-list case, and error format. It also explains the 'recommended' field and reasons. This makes the description fully self-contained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters, so there are no parameter semantics to explain. Per the rubric, a baseline of 4 is appropriate because there is nothing to add; the description focuses on output semantics instead.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence 'List the Chromium browser profiles on this machine and recommend one' clearly states the action and scope. It also explicitly distinguishes itself by saying 'Answers "which browser profile should I drive?", nothing else', setting it apart from sibling tools like gsc_use_browser.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states when it is safe to call ('safe to call before signing in') and defines its boundary relative to other tools ('opens no browser and changes no setting'). It does not explicitly name alternative tools, but the context signals (sibling gsc_use_browser) make the guidance clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_doctorA
Diagnose whether gsc-mcp is set up to talk to Search Console.
Runs seven checks in order — oauth_client, token, config, store,
properties, browser, extension — and reports all of them even if one
raises. A check that raises is recorded as ok: False with the
exception's TYPE NAME only in detail; the message is never included,
because it can carry a bearer token, a credentialed URL, a raw response
body, or a filesystem path holding your account name. Every failing
check carries a non-empty fix string with a concrete next step; this
tool diagnoses, it does not repair anything itself.
The last two are the local setup for browser-driven submission, and
they come last because they cost nothing and the first five establish
whether anything works at all. browser names the profile to use;
extension reports whether the bridge extension is REGISTERED in that
profile — a green check does not mean its background worker is
running, which needs a live connection and arrives with Milestone 3B.
"Could not be checked" is reported as such, never as "not installed".
Costs at most one Search Console API call (sites.list, for the
properties check); the browser and extension checks are local file
reads and make none.
Returns {"ok": bool, "checks": [{"name", "ok", "detail", "fix"}, ...]};
ok is true only when every check passed.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it excels: it reveals that error messages are deliberately omitted for security, that all checks run even if one fails, that 'could not be checked' is distinct from 'not installed', and that at most one API call is made. It also discloses the exact return contract.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with a one-sentence purpose, then organized into focused paragraphs covering checks, security, order rationale, cost, and return value. Every sentence adds substantive detail without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity and the absence of an output schema, the description is remarkably complete. It explains the seven checks, failure handling, security constraints, fix strings, local vs API costs, ordering rationale, and the exact return shape — leaving little ambiguity for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and the input schema has 100% coverage by being empty. Per the baseline rule for parameterless tools, this scores 4; the description adds no parameter-specific meaning because none is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Diagnose whether gsc-mcp is set up to talk to Search Console.' It further clarifies the tool's scope by listing the seven checks, clearly distinguishing it from sibling tools like gsc_setup or gsc_check_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context for when to use the tool — to verify setup health — and explicitly states it only diagnoses, not repairs. However, it does not name specific alternatives or state when not to use it, stopping short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_find_unindexedA
Which of a property's URLs are not in Google's index, and why.
source chooses where candidate URLs come from: "sitemap" fetches and
parses the property's registered sitemaps fresh, "store" uses only
URLs already seen, "both" (the default) unions them.
limit caps how many URLs are INSPECTED, not how many are returned —
inspection spends a daily budget, so a cap that only trimmed the
output would pay full price for an answer it threw away. Which URLs a
capped run reaches follows the store's url ordering (alphabetical),
not staleness: a capped run is a sample, not a worst-first sweep. The
result reports candidates_total, inspected and limited so you
can tell a truncated answer from a complete one.
limit is not the only thing that can cut a run short. Inspection
quota is per property and roughly eleven slots a day, so on any site
larger than that the run reaches the gate and stops: inspected is
what was handed to the API, checked is what actually reached it,
and skipped_quota lists the URLs accounting for the difference.
Report both numbers rather than inspected alone — a run that
answered for three of forty URLs is not a survey of the property, and
the remaining URLs are answerable tomorrow at no extra cost.
Only URLs whose last inspection is older than inspection_ttl_days
are re-inspected; the rest are reported from their stored status. A
second call the same day therefore costs no budget and still answers
in full. "fresh": true on a row means only that THIS run did not
inspect it — usually because it was within the TTL, but also when
limit cut the run short before reaching it. It is not a promise
that the stored status is within the TTL.
Each unindexed row carries reason (one of ten codes), action,
submitting_helps and needs_site_access. Act on
submitting_helps before calling gsc_request_indexing: submitting a
404, a redirect, a noindex, or a page Google crawled and declined
wastes an unrecoverable quota slot.
URLs whose state this run did not establish are in undetermined,
never in unindexed. Read each one's status before wording the
answer: it separates two cases a reader acts on differently. "We
looked and could not tell" covers a failed inspection and a result
the burst re-verify pass could not confirm. "skipped_quota" is the
other case and means the opposite: we never got to look, because the
property's daily budget ran out first. That is not a problem with the
URL, needs no investigation, and is answered by running again
tomorrow — say so rather than reporting it as a fault.
A refusal is {"ok": false, "error": <code>, "fix": <what to do>},
plus status when Search Console refused the call and detail (an
exception type name) when the failure was unexpected.
| Name | Required | Description | Default |
|---|---|---|---|
| site | Yes | ||
| limit | No | ||
| source | No | both |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It richly discloses many non-obvious behaviors: `limit` caps inspected URLs not returned, quota is ~11 inspections per day per property, `fresh: true` only means this run didn't inspect the URL, and the distinction between `undetermined` and `skipped_quota`. It also details the error response format. This far exceeds typical tool descriptions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every sentence earns its place by explaining a nuance or an edge case that affects the agent's decision-making. It is well-structured: starts with a one-sentence purpose, then parameter semantics, then behavioral caveats, then output and error formats. No filler or redundancy; the length is justified by the complexity of the tool's behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must explain return values and it does so comprehensively: `candidates_total`, `inspected`, `limited`, `fresh`, `reason`, `action`, `submitting_helps`, `undetermined`, `status`, `skipped_quota`, and the error response format. It also places the tool in context with sibling tools (e.g., `gsc_request_indexing`) and addresses quota/timing implications, making it complete for an AI agent to invoke and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains `source` (sitemap vs store vs both) and `limit` (caps inspections, not output, affects sampling) in depth. Although `site` is not explicitly described, the description repeatedly references 'the property' and 'registered sitemaps', making it clear that `site` identifies the property. This is sufficient semantic clarification for all parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first line states precisely what the tool does: finding which URLs of a property are not in Google's index and why. It specifies the resource (property URLs) and the action (identifying unindexed ones), clearly distinguishing it from sibling tools like gsc_request_indexing (which requests indexing) and gsc_performance (which measures performance).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on using the tool's output: it advises acting on `submitting_helps` before calling `gsc_request_indexing` and discusses when submission is a waste. It also explains the `source` parameter choices and the meaning of `limit`, including when a run is a sample rather than a full survey. This directly addresses when to use the tool and how to interpret its results vs. alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_job_statusA
Progress and state for one submission job, or the most recent one.
States: pending, running, completed, stopped_user, stopped_throttled,
failed. results holds one entry per URL attempted so far, and live
says whether a worker is still on it in this process.
stop_reason says why a run ended early — "quota_exceeded", "no_quota",
"stopped_by_user". It is the only trace of a run refused at the gate,
which attempts nothing and so leaves results and error both empty.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description takes on full responsibility for behavioral disclosure. It does this admirably by enumerating all possible states, explaining the meaning of `results` and `live`, detailing `stop_reason` values, and even covering the edge case of a run refused at the gate with empty `results` and `error`. This is rich, exact, and goes far beyond what a simple status check would imply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise but packed with useful information: a clear opening statement, a list of states, definitions of key fields, and an edge case explanation. Each sentence contributes meaning, and the structure is logical. It is not overly verbose, though the density of terms might require careful reading.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the lack of an output schema, the description explains the meaningful return fields (`results`, `live`, `stop_reason`) and provides context on how to interpret them. It covers common states and the special case of a gated run. However, it does not describe error handling, timeouts, or how to distinguish between a yet-to-start job and a failed one, leaving some gaps for a complete operational picture.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has one optional parameter `job_id` with default null, but the schema description coverage is 0%. The description compensates partially by stating that the tool returns progress for 'one submission job, or the most recent one', implying that omitting job_id selects the most recent. However, it never explicitly names `job_id` or explains the parameter's format or null behavior, leaving ambiguity for the agent.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Progress and state for one submission job, or the most recent one.' It names the resource and the kind of information returned (progress, state), making it easy to understand. However, it does not explicitly differentiate itself from similar sibling tools like gsc_check_status, which could also be interpreted as a status check.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The usage context is implied: you use this tool to inspect the progress or state of a submission job. It does not provide explicit 'when to use' or 'when not to use' guidance, nor does it mention alternatives like gsc_check_status. The presence of optional job_id suggests checking a specific job or the most recent, but no explicit conditions are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_list_sitesA
List every Search Console property this account can see.
Costs one Search Console API call (sites.list) — no per-property
quota is spent. Persists each property into the local store (upserted
by property URL) so other tools can route a page URL to its property
without another network round trip; an existing row's sitemaps are
left untouched here, since this call does not fetch or change them.
Returns [{"property", "host", "permission"}, ...] sorted by
property. On a missing, expired, or rejected token, returns
{"ok": False, "error": "auth_required", "fix": ...} instead of
raising; if no OAuth client is configured at all, returns
{"ok": False, "error": "not_configured", "fix": ...} instead — in
either case the caller can surface fix directly rather than parsing
an exception. A Search Console error returns {"ok": False, "error": "api_error", "status": <http status>, "fix": ...}, and anything else
{"ok": False, "error": "unexpected", "detail": <exception type>, "fix": ...}. An EMPTY LIST therefore means what it says — this
account really has no properties — and never a call that was refused.
Does not fetch sitemaps, index status, or search analytics; see gsc_doctor, gsc_check_status, and gsc_performance for those. A property already known to the store keeps whatever sitemaps a prior gsc_submit_sitemaps() call recorded against it — this call never fetches or clears that list, so a routine refresh cannot erase it.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full burden. It discloses persistence behavior (upsert by URL), no-side-effect on sitemaps, exact return format, detailed error handling for token missing/expired/rejected, not_configured, api_error, and unexpected, and importantly clarifies that an empty list means the account has no properties, not a refused call.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured into clear paragraphs: a summary, cost/persistence behavior, return and error formats, and explicit non-scope exclusions. Every sentence provides valuable information; no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (listing, persistence, error cases), the description covers all important aspects: API cost, side effects, return schema, error contract, and alternative tools. Output schema exists but description independently explains return values and error objects, making it self-sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema is trivially 100% covered. The description correctly adds no parameter details because there are none. Baseline for 0 params is 4, and the description appropriately focuses on behavior and return semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'List' with a clear resource: 'every Search Console property this account can see.' It clearly scopes the operation and differentiates from siblings by explicitly stating what it does not do (fetch sitemaps, index status, analytics).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides explicit guidance on when to use this tool: mentions the one API call cost, persistence of properties to the local store, and contrast with sibling tools via 'see gsc_doctor, gsc_check_status, and gsc_performance for those.' It also notes a routine refresh won't erase sitemaps, clarifying a common concern.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_performanceA
Search Analytics performance: clicks, impressions, ctr, position.
Three shapes, chosen by what is passed:
No
site-> one row per property the store knows about (scope: "portfolio",sites,totalsaggregated across all of them).site, nodim-> a single aggregate for that site (scope: "site", plusclicks/impressions/ctr/position).siteanddim-> per-dimrows for that site, sorted by clicks descending (scope: <dim>,rows,totalsaggregated acrossrows).dimmust be one of perf.VALID_DIMENSIONS ("query", "page", "country", "device", "date", "searchAppearance").
Date window: pass start_date AND end_date (both "YYYY-MM-DD") for an
explicit range, or leave both unset and get the trailing days calendar
days ending yesterday. start_date without end_date is refused
outright -- {"ok": False, "note": "start_date needs end_date (both YYYY-MM-DD)"} -- rather than guessing an end.
IMPORTANT -- data_state defaults to "all", not Google's own API default
of "final". Passing data_state="final" attaches a warning string
explaining why: data_state='final' silently omits the most recent
~perf.FINAL_LAG_DAYS (3) day(s) of data -- Google has not finished
processing them yet, and nothing in the response marks the gap. The
Search Console web UI has no such restriction and shows those days
immediately, so a 'final' query compared against what a human sees in
the UI right now will look like a discrepancy or a missed traffic
change when both are simply answering different questions. Prefer
data_state='all' (the default here) unless you specifically need
finalized-only rows; its trade-off is that the last day or two may
still revise upward on a later query.
On a missing, expired, or rejected token, returns {"ok": False, "error": "auth_required", "fix": ...}; if no OAuth client is configured at all,
{"ok": False, "error": "not_configured", "fix": ...}. Any other failure
-- a bad dimension, an unroutable site, a Search Console API error --
comes back as {"ok": False, "start", "end", "note": str(exc)} rather
than raising.
| Name | Required | Description | Default |
|---|---|---|---|
| dim | No | ||
| days | No | ||
| site | No | ||
| limit | No | ||
| end_date | No | ||
| data_state | No | all | |
| start_date | No | ||
| search_type | No | web |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses behavioral traits: the non-standard default of data_state='all', the 3-day lag warning for 'final', the exact error response formats (auth_required, not_configured, and generic failure with start/end/note), and the refusal of incomplete date ranges. This goes well beyond basic expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with a clear summary, bulleted shapes, separate sections for date windows, data_state, and error handling. Each sentence adds necessary operational detail, and the organization aids quick comprehension.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema or annotations, the description covers input modes, output shapes, date logic, data_state semantics, and error handling, making it highly complete for the tool's complexity. The only minor gaps are limit and search_type, but these do not undermine overall completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Given 0% schema description coverage, the description explains most parameters (site, dim, start_date, end_date, days, data_state) in detail, including valid dim values and date defaults. However, 'limit' and 'search_type' are not described, leaving their behavior ambiguous.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as retrieving Search Analytics performance metrics (clicks, impressions, CTR, position) and details three output shapes based on parameters. This makes it distinct from sibling tools like gsc_list_sites (site listing) and gsc_quota (quota checks).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage guidance for parameter combinations (e.g., no site → portfolio aggregate, site+dim → per-dimension rows) and date window behavior, including the refusal of start_date without end_date. It does not explicitly contrast with sibling tools or state when not to use this tool, but the context is clear enough to select it appropriately.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_quotaA
Report Request-Indexing and URL Inspection budget for every property the store currently knows about.
Local-only: reads the store and the config file, makes no Search Console API call, and needs no OAuth token — safe to call at any time, including before signing in. An empty store (nothing synced yet via gsc_list_sites or gsc_check_status) returns [].
One entry per property: {"property", "submission", "inspection", "binding"}.
THESE NUMBERS ARE AN ESTIMATE, NOT A MEASUREMENT, and the estimate is
biased in one direction. The store counts only the slots THIS TOOL
spent: a URL submitted by hand in Search Console, from a phone, or on
another machine never reaches it. So used is a lower bound and free
an upper bound — a property reported with headroom can still be refused
by Google, and that is expected behaviour rather than a defect. Do not
tell a user "you have N submissions left" without that caveat, and do
not conclude anything about Google's own rules from these counts.
counts and free_is_upper_bound restate this in the payload so it
survives being read without the docstring.
"submission" is the Request-Indexing slot budget: {"free", "spendable_free", "used", "slots", "daily_reserve", "next_free_at", "counts", "free_is_upper_bound", "last_refusal_at"}.
last_refusal_at is the last time Google actually said Quota Exceeded
for this property (ISO-8601, or None) — the only figure in the block
that came from Google rather than from local arithmetic.
free is the RAW free-slot count and ignores daily_reserve.
spendable_free is computed against the RESERVE-ADJUSTED ceiling —
max(0, (slots - daily_reserve) - used) — NOT simply free minus
daily_reserve: that arithmetic breaks at the clamp (slots=11,
daily_reserve=2, used=10 gives free=1, but spendable_free is 0, not
-1). ACT ON spendable_free, NOT free: daily_reserve exists to hold
slots back from every tool, and a caller that submits up to free
instead will be refused once spendable_free runs out. next_free_at
is an ISO-8601 string, or None when a slot is free right now — it is
already computed against the reserve-adjusted ceiling too, so it can
report a wait even while free (the raw count) is nonzero.
"inspection" is the URL Inspection API budget: {"daily_free", "minute_free", "daily_limit", "minute_limit"} (2000/day, 600/minute,
per property — the same quota gsc_check_status spends).
"binding" names whichever budget is exhausted for that property right
now — "submission" (the Request-Indexing ceiling, reserve applied),
"refused" (Google said Quota Exceeded recently and a short cooldown is
running), "inspection_daily", or "inspection_minute" — or None when
every budget has headroom. On "refused", spendable_free may be
nonzero: the local estimate is being overruled by what Google actually
answered, and next_free_at is when to ask again rather than a moment
a slot is known to exist.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and excels. It discloses that numbers are an estimate, biased as lower/upper bounds, explains that `used` is a lower bound and `free` an upper bound, and details the origin of `last_refusal_at` as the only figure from Google. It also explains the difference between `free` and `spendable_free` and the reserve-adjusted arithmetic, providing deep behavioral insight beyond a simple operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured, using clear section breaks and a logical flow from overall purpose to local-only nature to detailed field semantics. It is front-loaded with the key caveat ('THESE NUMBERS ARE AN ESTIMATE') early on. While every sentence is informative, the length is considerable; it could be trimmed without losing critical information, but the complexity of the quota semantics justifies most of the detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity and the presence of an output schema, the description is thoroughly complete. It covers return values for all scenarios (empty store, per-property entries, `free` vs `spendable_free`), explains edge cases like `bounding` being 'refused' or `None`, and clarifies relationships to sibling tools like gsc_list_sites. The description ensures an agent can correctly interpret and act on the results, even without additional documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters, so there is nothing to document. The description goes beyond by explaining the output structure in detail (e.g., `submission`, `inspection`, `binding` blocks and their sub-fields). Since there are no parameters, a baseline of 4 is appropriate; the description adds significant semantic value to the tool's output, even if not to parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Report Request-Indexing and URL Inspection budget for every property the store currently knows about.' It identifies a specific verb ('Report') and resource ('budget'), and distinguishes itself by emphasizing it is local-only and makes no Search Console API call, which separates it from siblings like gsc_check_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage context: 'safe to call at any time, including before signing in' and clarifies that an empty store (nothing synced via gsc_list_sites or gsc_check_status) returns []. It also advises against telling users 'you have N submissions left' without the estimate caveat, effectively providing when-to-use and when-to-caution guidance. It lacks an explicit statement of when *not* to use this tool in favor of an alternative, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_request_indexingA
Submit up to five URLs to Google's Request Indexing, one at a time, through the browser extension in your own signed-in profile.
BLOCKING and slow by design: submissions are paced 130-180 seconds apart, so five URLs can take fifteen minutes. Use gsc_start_indexing_job for anything larger.
Quota is per property — roughly eleven slots per property on a rolling
24-hour window, and properties are independent. Call gsc_quota first to
see what is spendable; act on spendable_free, not free.
Returns {"ok", "submitted", "skipped", "failed", "stopped_early", "stop_reason", "notes", "results"}, with one entry per URL in
results. A run stops early on the first throttle, captcha, or
signed-out session rather than burning the rest of the batch against a
refusing server. A refusal is {"ok": False, "error", "detail", "fix"}.
| Name | Required | Description | Default |
|---|---|---|---|
| urls | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so admirably. It discloses the BLOCKING nature, pacing (130-180 seconds), quota per property (roughly eleven slots), early-stop on throttle/captcha/signed-out, and details the return structure including error format. This goes well beyond a simple tool summary.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact yet information-dense. Every sentence adds distinct value: purpose, pacing, alternative tool, quota, call order, return shape, early-stop condition, and error shape. It is structured logically, front-loading the core purpose and moving to caveats and outputs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description compensates by clearly listing the return keys and explaining the early-stop behavior and refusal format. It also covers operational context (quota, pacing, browser profile) that integrates well with sibling tools like gsc_quota and gsc_start_indexing_job. This is a fully specified tool from the agent's perspective.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% coverage—the description doesn't explain the format of each URL string. However, it does add a meaningful constraint: 'up to five URLs' and the behavioral nuance 'one at a time.' For a single, self-evident parameter named 'urls' this is adequate, but it leaves room for more detail (e.g., URL validation, required protocol).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-resource pair: 'Submit up to five URLs to Google's Request Indexing.' It further clarifies the method ('through the browser extension in your own signed-in profile') and even distinguishes itself from a sibling tool ('Use gsc_start_indexing_job for anything larger'). This fully clarifies the tool's purpose and scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool vs. the alternative ('Use gsc_start_indexing_job for anything larger') and provides a critical prerequisite ('Call gsc_quota first to see what is spendable; act on spendable_free, not free'). It also implicitly warns about blocking/slowness, setting user expectations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_setupA
Set this server up, one step at a time. Call it, do what it says,
call it again — repeat until ok is true.
IDEMPOTENT and SAFE TO CALL REPEATEDLY. It spends no Search Console indexing quota and makes at most one API call (verifying the stored sign-in still works). Every call re-reports the whole state from scratch, so there is no session to resume and no order to get wrong: if you have lost track of where setup got to, just call it again.
There are four steps, checked in order: oauth_client (credentials to
sign in with), consent (the user approves Google's consent screen),
browser (a Chromium browser with a profile exists), extension (the
gsc-mcp bridge extension is loaded in the profile this server
recommends). The FIRST unsatisfied step is returned as next and the
call stops there — later steps are meaningless until it is done.
Returns {"ok": bool, "done": [step], "pending": [step], "next": {"step", "action", "url"?, "path"?} | None}. ok is true, and next
is null, only when all four steps are satisfied. next.action is a
plain-English instruction to relay to the user. next.url, when
present, is the Google consent URL to open. next.path, when present,
is the folder to choose in the browser's "Load unpacked" dialog.
open_browser (default true) opens the consent URL in the user's
default browser when a NEW consent is started. A repeat call while one
is already pending returns the SAME url and opens nothing — the pending
consent screen is the only one whose redirect will be accepted, so
never assume a second call means a second link.
PRIVACY: no email address, no token field, no PKCE verifier and no
authorization code is ever returned. The only filesystem path returned
is next.path, which is this server's own extension directory.
Never raises. An unexpected fault comes back as next.step: "unexpected" with an action to retry.
| Name | Required | Description | Default |
|---|---|---|---|
| open_browser | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It thoroughly discloses idempotency, safety, that it spends no Search Console indexing quota, makes at most one API call, re-reports entire state, returns the same URL for pending consent, never raises, and gives privacy guarantees. This goes beyond basic expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy but every sentence serves a purpose: usage pattern, idempotency, step enumeration, return format, parameter semantics, privacy, and error behavior. It is well-structured with clear paragraphs and no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given there is no output schema, the description fully explains the return object structure, including ok, done, pending, next, and the meaning of null next. It also covers edge cases like unexpected faults. All necessary behavioral and operational details are present for the agent to use the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema only lists open_browser as a boolean with a default, with 0% description coverage. The description fully compensates by explaining exactly what open_browser does: opens the consent URL when a new consent starts, and that a repeat call while pending returns the same URL and opens nothing. This adds critical meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Set this server up, one step at a time' and enumerates the four specific steps (oauth_client, consent, browser, extension), distinguishing it from sibling tools that handle jobs, status, performance, etc. The resource and action are specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit iterative usage guidance: 'Call it, do what it says, call it again — repeat until ok is true' and explains that if you lose track, just call again. It also covers open_browser behavior on repeat calls. However, it does not explicitly mention when not to use it or contrast with alternative tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_start_indexing_jobA
Queue a background submission run over any number of URLs.
Returns immediately with {"ok", "job_id", "total", "note"}. Poll
gsc_job_status for progress and gsc_stop_job to end it early. One
submission job runs at a time: the bridge drives a single browser tab
in your real profile, so a second job is refused rather than queued.
| Name | Required | Description | Default |
|---|---|---|---|
| urls | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses the asynchronous return immediately, the response shape, the concurrency limitation (second job refused), and the underlying browser-tab mechanism. These are significant behavioral traits beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three compact sentences, each adding distinct value: what it does, what to do after, and a key limitation. It is front-loaded and free of redundant wording.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with no output schema, the description covers the essential operational context: return behavior, follow-up actions, and concurrency policy. It could mention prerequisites (e.g., browser setup) or error scenarios, but given the simplicity, it is quite complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema only names the 'urls' parameter as an array of strings, and the description adds only 'any number' — a minor clarification. It does not explain URL format, length limits, or any constraints, leaving the parameter semantics largely underspecified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's action (queue a background submission run) and the resource (URLs). It distinguishes itself from sibling tools like gsc_request_indexing (single submission) and gsc_job_status (polling) by emphasizing the background, batch nature.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description mentions related tools for tracking and stopping (gsc_job_status, gsc_stop_job), and notes the one-at-a-time concurrency constraint. However, it does not explicitly say when to use this tool versus alternatives like gsc_request_indexing, nor does it mention prerequisites or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_stop_jobA
Ask a running submission job to stop.
It stops after the URL currently in flight, never mid-URL: a submission already sent has spent its quota slot and its ledger row must settle with the real outcome.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and does an excellent job. It discloses a non-obvious and important behavioral trait: the stop happens after the URL currently in flight, not mid-URL, and explains the rationale (quota slot and ledger row must settle). This is exactly the kind of side-effect transparency an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no fluff. The first sentence front-loads the primary purpose, and the second adds an essential caveat. Every word earns its place, making it an ideal concise description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter tool with no output schema, the description covers the core behavior and its rationale well. It could be more complete by mentioning edge cases (e.g., what happens if the job is already stopped, or what the return value is), but it is sufficient for typical use and provides the most critical contextual detail (the no-mid-URL guarantee).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has one parameter, job_id, with 0% description coverage. The description does not add specific meaning to job_id (e.g., where to obtain it, format, or that it comes from a start-job call). It only refers generically to 'a running submission job,' leaving the agent to infer the job_id's role from the schema property name alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Ask a running submission job to stop.' It uses a specific verb ('stop') and resource ('running submission job'), and it distinguishes itself from sibling tools like gsc_start_indexing_job and gsc_job_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool (when a submission job is running and needs stopping) and provides a critical context clue by explaining the stopping behavior ('never mid-URL'). However, it does not explicitly mention alternative tools or when not to use it, so it stops short of full exclusionary guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_submit_sitemapsA
Submit one or more sitemaps to Search Console (PUT, idempotent -- safe to resubmit an already-known sitemap).
sitemaps is an optional list of sitemap URLs; each is routed to its
covering property via the same host-matching gsc_check_status
uses. Omit it to resubmit every sitemap already on
record for every property (the same list gsc_list_sites carries
forward on refresh).
REFUSES TO GUESS: when sitemaps is omitted and the store has no
sitemap recorded for any property, this returns {"ok": False, "note": "No sitemaps known. Pass sitemaps=[...] explicitly."} rather than
trying /sitemap.xml -- submitting a URL nobody named is an
outward-facing action against the caller's Search Console property, and
a wrong guess leaves a permanent failed submission in their sitemap
list for no reason.
Returns a list of {"site", "sitemap", "http_status", "ok", "note"}
(api.submit_sitemap's shape) -- one entry per sitemap attempted, plus one
{"site": None, "sitemap", "http_status": None, "ok": False, "note"}
entry for any URL that matched no known property. Every successful
submission is recorded back onto its property's row (merged with,
never replacing, whatever sitemaps were already there), so a later bare
call resubmits it too.
On a missing, expired, or rejected token, returns {"ok": False, "error": "auth_required", "fix": ...} instead of raising, once real
work is about to start (nothing has been submitted yet at that point);
if no OAuth client is configured at all, {"ok": False, "error": "not_configured", "fix": ...}. Any other failure comes back as
{"ok": False, "error": "unexpected", "detail": <exception type>, "fix": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| sitemaps | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so outstandingly. It discloses idempotency, host-matching routing, persistence behavior, the refusal-to-guess safeguard, return shapes, and all auth/error handling (auth_required, not_configured, unexpected). No behavioral blind spots remain.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy but every sentence earns its place. It is front-loaded with the core action, then organizes complex behavioral details into logical sections covering parameter use, refusal behavior, return shape, and error handling. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite the tool's complexity and the presence of an output schema, the description fully specifies input semantics, expected return entries, persistence side effects, and every failure mode. It is complete enough for an agent to invoke the tool correctly and interpret results without additional context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema only defines an optional nullable 'sitemaps' array with no description. The description compensates fully by explaining that it is a list of sitemap URLs routed via host-matching, that omitting it resubmits all recorded sitemaps, and that if no sitemaps are known it will return a specific error rather than guessing. This adds substantial meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific action: 'Submit one or more sitemaps to Search Console (PUT, idempotent -- safe to resubmit an already-known sitemap).' It clearly identifies the verb, resource, and core operation, and distinguishes itself from siblings like gsc_list_sites and gsc_check_status, which are about listing or checking status rather than submitting.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context on when to use the tool and how to use the optional 'sitemaps' parameter: omit it to resubmit every sitemap already on record, or provide a list to target specific sitemaps. It also explains the refusal-to-guess behavior when no sitemaps are known. However, it does not explicitly name sibling tools or state when not to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gsc_use_browserA
Choose which browser profile this server drives, overriding detection.
Local-only: writes one preference to this server's config file, makes no network call, spends no quota, needs no token, and opens no browser. Use it when gsc_detect_browsers recommends a profile that is not the one holding your Search Console account — the detector can rank the profiles it finds, but it cannot know which browser you work in.
browser is the browser_key from gsc_detect_browsers ("chrome",
"brave", "edge", "vivaldi", "opera", "chromium") — the key, not the
display label. profile is the profile field from the same entry
(the profile DIRECTORY, e.g. "Default" or "Profile 3"); omit it to take
that browser's default profile. clear=True removes the pin and
returns to the detector's recommendation, and ignores the other two.
The pair is checked against the profiles that actually exist BEFORE it
is saved. A pair that matches nothing is refused with {"ok": False, "error": "browser_not_found", ...} whose fix lists the pairs that
would work, so a typo is answered immediately rather than becoming a
browser that silently never opens.
Once pinned, the choice is absolute: gsc_setup, gsc_doctor and every tool that drives the browser use it, and the ranking is not consulted. If the pinned profile later disappears — browser uninstalled, profile deleted — nothing falls back to a different one. Every affected tool stops and says the pin is dangling, because driving the wrong profile would submit URLs from whichever account happens to be signed in there.
The pin survives restarts. Returns {"ok": True, "pinned": "<browser> / <profile>" or null, "note": ...}.
| Name | Required | Description | Default |
|---|---|---|---|
| clear | No | ||
| browser | No | ||
| profile | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations, so description carries full burden. It discloses local-only writes, no network/quota/token, validation-before-save, absolute pin behavior, dangling-pin failure, and persistence. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with one-line purpose, then structured paragraphs for constraints, usage, params, validation, and edge cases. Every sentence adds operational knowledge.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Without output schema, it describes return shape and error response. Covers all parameters and non-happy-path behavior, making it complete for reliable invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has no descriptions, but description fully explains browser as key from gsc_detect_browsers, profile as directory string with omit behavior, and clear as override that ignores other params.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States verb 'Choose' and resource 'browser profile', and explicitly frames as overriding detection. Distinguishes itself from gsc_detect_browsers by explaining it selects rather than detects.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells when to use: when detection recommends a profile that doesn't hold the account. It also contrasts with gsc_detect_browsers, clarifying that detection can rank but cannot know user's browser.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Each tool has a clearly defined primary purpose, and the descriptions are thorough in distinguishing them. However, a few pairs (gsc_check_status vs gsc_find_unindexed, gsc_request_indexing vs gsc_start_indexing_job) operate in the same domain and could be confused without careful reading.
All tools share the gsc_ prefix and snake_case, which provides a consistent feel, but the structural pattern is mixed. Most use verb_noun (list_sites, check_status, submit_sitemaps), while several are plain nouns (doctor, quota, performance, setup, audit) or noun_noun (job_status). This is readable but not fully consistent.
At 15 tools, the server is on the higher end of the ideal range, but the broad domain of Search Console management justifies it. Each tool covers a distinct aspect (setup, properties, inspection, analytics, quota, sitemaps, indexing jobs), and none feel redundant or unnecessary.
The tool set covers the core Search Console workflows: setup, property listing, index status inspection, performance analytics, quota estimation, sitemap submission, and indexing jobs. Minor gaps exist, such as no standalone tool to list or remove sitemaps and no property creation/removal, but agents can work around these limitations.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
SEO MCP server: crawl your site, find AI-visibility gaps, and ship the fix from your coding agent.
MCP server for building and testing AI agents with multi-model experimentation and insights.
SEO MCP server for keyword research, SERP analysis, audits, and Search Console workflows.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Related MCP Servers
- AlicenseAqualityCmaintenanceMCP server for querying Google Search Console data — search analytics, URL inspection, sitemap monitoring, and more — read-only tools for any MCP-compatible AI client.7Apache 2.0
- AlicenseBqualityDmaintenanceAn MCP server integrating Google Analytics 4, Search Console, and Indexing API, enabling AI agents to run reports, inspect URLs, manage properties, and request indexing.16155MIT
- AlicenseNot gradedqualityDmaintenanceMCP server that exposes the Google Search Console API, allowing LLMs to query SEO data, inspect URLs, manage sitemaps, and analyze search performance via natural language.63MIT
- AlicenseAqualityBmaintenanceMCP server for Google Search Console, enabling querying search performance, listing properties, and inspecting URL indexing status from MCP-compatible clients.4221MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mrshahidali420/google-search-console-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server