Skip to main content
Glama

site-indexer

A local MCP server (stdio) that takes a newly deployed website from just deployed to verified in Google Search Console, sitemap submitted, indexing monitored, with no per-site clicking. The only manual step is a one-time Google sign-in, shared by all your sites.

deploy ─▶ setup_site ─▶ get token ─▶ agent commits file / DNS record ─▶ deploy
                ▲                                                         │
                └──────────── setup_site again (verify w/ backoff) ◀──────┘
                     ─▶ sites.add ─▶ sitemaps.submit ─▶ URL inspection ─▶ schedule re-check
  • Uses the Site Verification API (to get and trigger verification) and the Search Console API (properties, sitemaps, URL Inspection). Existing GSC MCP servers have only the second.

  • Properties land in your own Search Console account (OAuth installed-app flow).

  • Ships a Claude Code skill, /index-site <url>, that drives the whole loop in a site's repo.

  • Generic: one install and one sign-in serve every site you publish, on any host (Netlify, Vercel, Cloudflare Pages, GitHub Pages, self-hosted). Nothing is tied to one project. See docs/hosting-recipes.md.

Tools

Tool

What it does

auth_status

Signed in? Which mode? What to do if not. Never returns secrets.

auth_login / auth_logout

One-time loopback OAuth on 127.0.0.1 (PKCE). Returns the consent URL and tries to open your browser.

get_verification_token

Exact thing to place: FILE → fileName + fileContent; META → tag; DNS_TXT / DNS_CNAME → record.

verify_site

Checks locally that the token is live (file / meta / DNS), then calls webResource.insert, retrying with backoff (5s, 10s, 20s, 30s…) up to maxWaitSeconds. Idempotent.

create_dns_record

For sc-domain: properties: creates the TXT/CNAME via Netlify DNS or Cloudflare. Skips if it already exists.

list_sites / add_site

Search Console properties; sites.add (after verification).

check_sitemap

Fetches the live sitemap (no Google call): URL count, samples, wrong-host / HTML-fallback problems.

submit_sitemap / list_sitemaps

Probes, then sitemaps.submit; Google's status (pending, errors, last download).

inspect_url / inspect_urls

URL Inspection (read-only): verdict, coverage, last crawl, canonicals; batch from the sitemap.

setup_site

Orchestrator. Idempotent; stops at the first step needing action and returns nextAction.

indexnow_key / indexnow_ping

Optional. IndexNow for Bing/Yandex/Seznam/Naver. Not Google.

delete_site, delete_sitemap, unverify_site, set_owners

Destructive. Not registered unless SITE_INDEXER_ENABLE_DESTRUCTIVE=1; each needs confirm = the exact property id.

setup_site output (abridged) for a site whose file is not deployed yet:

{
  "site": "https://my-site.netlify.app/",
  "complete": false,
  "steps": [
    { "step": "auth", "status": "done" },
    { "step": "verification", "status": "action_required", "detail": "Token not in place yet: HTTP 404; the file is not deployed yet." }
  ],
  "nextAction": {
    "who": "agent",
    "do": "Create \"google1234abcd.html\" in the directory that is published at https://my-site.netlify.app/ ... commit, deploy, then call verify_site. Then call setup_site again.",
    "placement": { "method": "FILE", "fileName": "google1234abcd.html", "fileContent": "google-site-verification: google1234abcd.html", "url": "https://my-site.netlify.app/google1234abcd.html" }
  }
}

Who does what with FILE verification

The server does not touch your repo or your host. It returns the file name and content. The calling agent (Claude Code in the site's repo, driven by /index-site) writes the file into the directory that ends up at the site root (public/ for Vite/Next/Astro, static/ for Hugo/SvelteKit, the repo root for plain HTML), commits it, and deploys. setup_site / verify_site then poll the live URL until the deploy is out before asking Google. Keep the file forever: Google re-checks it.

For domain properties (sc-domain:example.com), create_dns_record (or setup_site with dnsProvider) writes the TXT record with your Netlify or Cloudflare token. Otherwise the agent gives you the exact record for your registrar.


Related MCP server: Google Search Console MCP Server

One-time Google Cloud setup (≈10 minutes, once for all sites)

  1. Create a project: https://console.cloud.google.com/projectcreate (e.g. site-indexer).

  2. Enable both APIs in that project:

  3. OAuth consent screen (Google Auth Platform → Branding / Audience): user type External, app name site-indexer, your email as support and developer contact. Under Data access, add the scopes https://www.googleapis.com/auth/siteverification and https://www.googleapis.com/auth/webmasters.

  4. Publish the app: Audience → "Publish app" → In production. In Testing mode, Google expires refresh tokens after 7 days, so you would have to sign in again every week. An unverified app in production is fine for personal use: you click through the "Google hasn't verified this app" screen once (Advanced → Go to site-indexer).

  5. Create credentials → OAuth client ID → Application type: Desktop app. Download the JSON (e.g. ~/.config/site-indexer/client_secret.json; keep it out of git).

Install

Requires Node ≥ 20.

# From GitHub (private repo: needs your normal git credentials). Builds on install.
claude mcp add site-indexer --scope user \
  -e GOOGLE_OAUTH_CLIENT_FILE=$HOME/.config/site-indexer/client_secret.json \
  -- npx -y github:yassine-codes/site-indexer-mcp

# Or from a local clone
git clone git@github.com:yassine-codes/site-indexer-mcp.git && cd site-indexer-mcp && npm ci && npm run build
claude mcp add site-indexer --scope user \
  -e GOOGLE_OAUTH_CLIENT_FILE=$HOME/.config/site-indexer/client_secret.json \
  -- node "$PWD/dist/cli.js"

Claude Desktop / other MCP clients use the same command in their config:

{
  "mcpServers": {
    "site-indexer": {
      "command": "node",
      "args": ["/abs/path/site-indexer/dist/cli.js"],
      "env": { "GOOGLE_OAUTH_CLIENT_FILE": "/abs/path/client_secret.json" }
    }
  }
}

Sign in once, from a terminal (npx site-indexer auth login, or node dist/cli.js auth login) or by asking Claude to run auth_login. The browser opens, you approve, and the token is stored. Check with auth status.

Install the skill (adds /index-site to Claude Code):

node dist/cli.js install-skill            # ~/.claude/skills/index-site
node dist/cli.js install-skill --project  # ./.claude/skills/index-site (commit it to a site repo)

Then, in any site's repo: /index-site https://my-site.netlify.app/

Environment variables

Variable

Purpose

GOOGLE_OAUTH_CLIENT_FILE

Path to the Desktop OAuth client JSON. Or:

GOOGLE_OAUTH_CLIENT_ID + GOOGLE_OAUTH_CLIENT_SECRET

Same, inline.

SITE_INDEXER_CONFIG_DIR

Override token location. Default: ~/.config/site-indexer (Linux, $XDG_CONFIG_HOME), ~/Library/Application Support/site-indexer (macOS), %APPDATA%\site-indexer (Windows).

SITE_INDEXER_DRY_RUN=1

No Google, DNS-provider or IndexNow requests; tools return wouldCall. The public site is still fetched (read-only).

SITE_INDEXER_ENABLE_DESTRUCTIVE=1

Registers delete/unverify/owner tools (still need confirm).

NETLIFY_AUTH_TOKEN

Netlify personal access token, for create_dns_record with Netlify DNS.

CLOUDFLARE_API_TOKEN

Cloudflare token with Zone → DNS → Edit on the zone.

INDEXNOW_KEY

Your IndexNow key (after publishing <key>.txt).

GOOGLE_SERVICE_ACCOUNT_FILE

Optional service-account mode (see caveat).

SITE_INDEXER_EXTRA_OWNERS

Comma-separated emails added as owners on verification (service-account mode).

Service-account mode (optional, read the caveat)

Set GOOGLE_SERVICE_ACCOUNT_FILE to a key JSON. Sources disagree on whether a service account can complete Site Verification. Where it can, the property belongs to the service account: it does not appear in your Search Console unless you are also an owner. Set SITE_INDEXER_EXTRA_OWNERS=you@gmail.com, or add the service account as a user of an existing property instead. OAuth mode is the supported path.

Security

  • Scopes: only siteverification and webmasters. No Gmail/Drive/etc.

  • Refresh token in token.json in the config dir, written atomically with mode 0600 in a 0700 directory. Access tokens live only in memory. No tool returns a secret; auth_status shows mode, scopes and file path only. Errors never include the bearer token.

  • Loopback OAuth listens on 127.0.0.1 on a random port for one request, with PKCE and a random state. The listener closes after the redirect or after 5 minutes.

  • No repo writes and no shell. The server returns file contents; the agent writes them. FILE tokens are validated against ^google[0-9a-z]+\.html$, so a hostile response cannot steer a path.

  • Destructive tools are off by default and need the exact property id as confirm.

  • Revoke any time: https://myaccount.google.com/permissions, plus site-indexer auth logout.

  • Netlify/Cloudflare tokens come from env only and are sent only to their own APIs.

Honest limits

  • There is no public API to "Request indexing." URL Inspection is read-only. Google discovers pages through the submitted sitemap and links. The Indexing API is only for JobPosting / BroadcastEvent pages, and this server deliberately does not use it. The sitemap "ping" endpoint was retired in 2023.

  • Time: verification succeeds as soon as the deploy is live (FILE/META) or DNS propagates (minutes to hours; verify_site retries up to maxWaitSeconds, so call it again later). A new site typically shows "URL is unknown to Google" for days, and first indexing often takes days to weeks.

  • Quotas (per Google docs, subject to change): URL Inspection ≈ 2,000/day and 600/min per property. inspect_urls caps at 100 per call and stops on the first 429/403. Search Console and Site Verification have per-project QPS limits, which normal use won't hit.

  • IndexNow reaches Bing, Yandex, Seznam, Naver and Yep. Not Google.

  • DNS_CNAME token parsing assumes Google's "<label> <target>" format. DNS_TXT is the recommended method for domain properties.

  • Removing the verification file or record later can unverify the site.

Development

npm ci
npm test            # vitest: unit + MCP in-memory tests, all Google HTTP mocked
npm run typecheck
npm run build
node scripts/smoke.mjs https://my-site.netlify.app/   # dry-run over real stdio against the live site

The tests never touch the network: mockFetch fails on any unmocked request.

Owner-run live verification (needs your real credentials)

export GOOGLE_OAUTH_CLIENT_FILE=~/.config/site-indexer/client_secret.json
node dist/cli.js auth login
node dist/cli.js auth status                                     # ready: true
node scripts/smoke.mjs https://uktob.app/                        # still dry-run: shows the plan
# real run, in Claude Code (interactive), from the site's repo:
#   /index-site https://uktob.app/

Validation runs: docs/validation/uktob.md (Netlify static site on a custom domain; first live run, 2026-10-20, all steps passed) and docs/validation/code2025.md (self-hosted Node app, local integration run).

License

MIT

Available Tools

16 tools
add_siteA
Idempotent

Adds a VERIFIED site to Search Console (sites.add). Run verify_site first.

Inputs: site (required).

auth_loginA

One-time Google OAuth (loopback on 127.0.0.1). Returns a consent URL immediately; the owner opens it in a browser on THIS machine. Poll auth_status until ready. The refresh token is stored in the OS config dir with 0600 permissions.

Inputs: timeoutSeconds.

auth_logoutA

Deletes the stored refresh token from this machine.

Inputs: no named parameters.

auth_statusA
Read-only

Is site-indexer signed in to Google, in which mode, and what to do if not. Never returns secrets.

Inputs: no named parameters.

check_sitemapA
Read-only

Fetches a sitemap from the live site (no Google call) and reports URL count, sample URLs and problems such as wrong host or HTML fallback.

Inputs: sitemapUrl (required), site.

create_dns_recordA
Idempotent

For sc-domain: properties: fetches the DNS token and creates the TXT (or CNAME) record via Netlify DNS (NETLIFY_AUTH_TOKEN) or Cloudflare (CLOUDFLARE_API_TOKEN). Skips if it already exists.

Inputs: site (required), provider (required), method.

get_verification_tokenA
Read-only

Gets the Google Site Verification token and returns exactly what to place: FILE -> fileName + fileContent to publish at the site root; META -> tag for ; DNS_TXT/DNS_CNAME -> the DNS record. Does not verify.

Inputs: site (required), method.

indexnow_keyA
Read-only

Generates (or echoes INDEXNOW_KEY) an IndexNow key and the key file to publish at the site root. Bing/Yandex/etc only, not Google.

Inputs: site (required).

indexnow_pingA

Submits URLs (given or from the sitemap) to IndexNow (Bing, Yandex, Seznam, Naver...). Google ignores IndexNow.

Inputs: site (required), key, urls, sitemapUrl.

inspect_urlA
Read-only

URL Inspection (read-only): verdict, coverage state, last crawl, canonical. Does NOT request indexing (no public API exists for that).

Inputs: url (required), site (required), languageCode.

inspect_urlsA
Read-only

Inspects many URLs (given, or read from the live sitemap) and summarises how many are indexed. Quota: ~2,000 inspections/day and 600/min per property.

Inputs: site (required), urls, limit, fromSitemap.

list_sitemapsB
Read-only

Sitemaps known to Search Console for a property, with last download, errors, warnings and submitted counts.

Inputs: site (required).

list_sitesA
Read-only

Search Console properties for the signed-in account, with permission level.

Inputs: no named parameters.

setup_siteA
Idempotent

Runs the whole loop idempotently: auth -> verification -> add to Search Console -> submit sitemap -> first inspection. Stops at the first step that needs action and returns nextAction (e.g. the exact file to commit and deploy). Call again after each deploy.

Inputs: site (required), method, sitemapUrl, dnsProvider, +1 more.

submit_sitemapA
Idempotent

Probes then submits a sitemap to Search Console (default /sitemap.xml) and returns Google's sitemap status.

Inputs: site (required), sitemapUrl.

verify_siteA
Idempotent

Checks locally that the token is live (file / meta / DNS), then asks Google to verify ownership, retrying with backoff for deploy/DNS propagation. Idempotent: returns alreadyVerified if the site is already yours.

Inputs: site (required), method, skipPrecheck, maxWaitSeconds.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 16 tools

    Disambiguation5/5

    Each tool targets a distinct resource and action (auth, verification, sitemaps, URL inspection, IndexNow), with clear boundary lines like check_sitemap (live fetch) vs submit_sitemap (Google submission) vs list_sitemaps (reported state). setup_site is an explicit orchestrator that wraps the individual steps rather than duplicating them, so no tool genuinely overlaps another's purpose.

    Naming Consistency4/5

    Mostly consistent snake_case with a verb_noun pattern (list_sites, add_site, check_sitemap, submit_sitemap, inspect_urls, verify_site), but a few names break the pattern: auth_status and indexnow_key are noun-first rather than verb-led. The deviations are minor and still readable, so the convention is largely predictable.

    Tool Count5/5

    16 tools is slightly above the typical 3-15 sweet spot, but every tool here earns its place: three auth tools, three verification/setup tools, three sitemap tools, two inspection tools, two IndexNow tools, and one orchestrator. There is no redundant CRUD padding or missing obvious helper, making the count well-scoped for the domain.

    Completeness4/5

    The surface covers the full lifecycle from authentication through Google verification, Search Console submission, and URL inspection, plus an alternate IndexNow path. Minor gaps exist (no remove_site/delete_sitemap operations, and no sitemap update beyond re-submission), but agents can work around them and the core workflow is complete.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI agents to manage Google Tag Manager, Google Search Console, and Google Analytics (GA4) through unified access to tags, search performance data, URL inspection, sitemaps, and analytics reporting.
      7 npm
      ISC
    • F
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to query Google Search Console data including search analytics, URL inspection, sitemap management, and site performance monitoring, with per-user OAuth authentication.
      -
    • F
      license
      Not graded
      quality
      C
      maintenance
      Enables programmatic management of Google Search Console properties and IndexNow URL submission for search indexing.
      -
    • A
      license
      A
      quality
      D
      maintenance
      Enables automation of Google Search Console tasks, including retrieving search analytics, managing sitemaps and site properties, and inspecting URLs for index status and crawl information.
      9
      MIT