npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@infinitnet/google-search-console-gsc-mcp-server

v1.1.1

Published

Infinitnet Google Search Console (GSC) MCP Server for Search Console operations and SEO analysis workflows.

Readme

Infinitnet Google Search Console (GSC) MCP Server

Infinitnet Google Search Console (GSC) MCP Server is a local stdio MCP server that lets AI assistants work with Google Search Console data safely and consistently. It provides property discovery, Search Analytics queries, URL Inspection, sitemap operations, Indexing API notifications, and higher-level SEO analysis workflows such as traffic-loss diagnosis, CTR gaps, content decay, query overlap, and prioritized action plans.

Contents

What this server does

The server exposes 26 MCP tools grouped into five areas:

  1. Setup and discovery — server guide, auth status, and Search Console property listing.
  2. Search Analytics — flexible GSC performance queries, period comparisons, and page-level query breakdowns.
  3. Technical SEO — URL Inspection API, batch inspection, indexing issue scans, and sitemap operations.
  4. SEO analysis — site health, rank-lift opportunities, CTR gaps, uncovered queries, traffic losses, content decay, query overlap, section performance, alerts, action plans, and claim checks.
  5. Indexing API notifications — single and batch URL update/delete notifications.

Every tool returns a structured JSON response envelope so the assistant can distinguish successful data, errors, input echo, and metadata.

Requirements

  • Node.js 20 or newer.
  • A Google Cloud project with the relevant APIs enabled:
    • Google Search Console API for Search Analytics, properties, sitemaps, and URL Inspection.
    • Indexing API only if you use gsc_index_notify or gsc_index_notify_batch.
  • Access to at least one Google Search Console property.
  • Either service-account credentials or OAuth client credentials.

Install from npm

The npm package is the recommended way to run this MCP server. You can start it directly with npx without cloning the repository:

npx -y @infinitnet/google-search-console-gsc-mcp-server

For a persistent local install, install it globally and run the short binary name:

npm install -g @infinitnet/google-search-console-gsc-mcp-server
gsc-mcp

Install from source

git clone <this-repository-url>
cd google-search-console-gsc-mcp
npm install
npm run build

Start the server manually for a smoke test:

node dist/index.js

When launched manually, the process waits for MCP JSON-RPC messages on stdin. In normal use, your MCP client starts it for you.

Authentication

The server supports two auth modes. Both can list accessible properties with gsc_properties_list; follow-up tool calls should pass the chosen property as site_url.

Before configuring either mode:

  1. Create or select a Google Cloud project.
  2. In Google Cloud APIs & Services > Library, enable Google Search Console API (searchconsole.googleapis.com).
  3. Enable Indexing API (indexing.googleapis.com) only if you plan to use gsc_index_notify or gsc_index_notify_batch; write tools can be disabled globally with GSC_ENABLE_WRITE_TOOLS=false.
  4. Make sure the Google identity you will use can access the relevant Search Console property. Search Console property strings must match exactly, for example sc-domain:example.com or https://www.example.com/.

Service-account mode

Use this when the MCP server should authenticate as a Google Cloud service account. This is a good fit for server/agency workflows where you can explicitly grant the service-account email access to the Search Console properties it should read.

  1. In Google Cloud, go to IAM & Admin > Service Accounts and create a service account.
    • The service account does not need a broad Google Cloud IAM role just to read Search Console data. Search Console access is granted in Search Console, not by project IAM.
  2. Create a JSON key for the service account: open the service account, go to Keys > Add key > Create new key > JSON, and download it. Store it securely and never commit it. Google only gives you the private key file at creation time.
  3. In Search Console, open the property as a verified owner and grant the service-account email access:
    • For read-only analytics/inspection workflows, add the service-account email under Settings > Users and permissions with the least privilege that works for your use case.
    • For Indexing API usage, Google documents adding the service account as a site owner.
    • For sitemap submission or other write-like operations, grant sufficient Search Console permission for that action. Set GSC_ENABLE_WRITE_TOOLS=false if you want a read-only deployment.
  4. Set one of these env vars in your MCP client config:
    • GSC_KEY_FILE=/absolute/path/to/service-account.json
    • GSC_CREDENTIALS_PATH=/absolute/path/to/service-account.json
    • GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json
  5. Leave property selection dynamic: call gsc_properties_list, then pass the selected property as site_url.

OAuth mode

Use this when the MCP server should act as a specific Google user. The Google user who completes the browser consent flow must already have access to the target Search Console property. You do not add the OAuth client ID to Search Console; Search Console permissions come from the signed-in Google user.

  1. In Google Cloud, configure the Google Auth Platform / OAuth consent screen for the project. For personal/internal testing, keep the app in testing and add your Google account as a test user if required by Google.
  2. Create an OAuth client:
    • Recommended: Desktop app client. This server uses a local loopback callback at http://127.0.0.1:3847/oauth2callback; Google's desktop OAuth flow supports loopback redirects on macOS, Linux, and Windows desktop.
    • Alternative: Web application client with the exact authorized redirect URI http://127.0.0.1:3847/oauth2callback or your custom port/path if you set GSC_OAUTH_CALLBACK_PORT.
  3. Download the OAuth client JSON immediately and store it securely. New Google OAuth client secrets might only be fully visible/downloadable at creation time.
  4. Set OAuth env vars in your MCP client config:
GSC_AUTH_MODE=oauth
GSC_OAUTH_SECRETS_FILE=/absolute/path/to/client_secret.json

Alternative OAuth env vars:

GSC_AUTH_MODE=oauth
GSC_OAUTH_CLIENT_ID=your-client-id
GSC_OAUTH_CLIENT_SECRET=your-client-secret

On first use, the server opens your browser, receives the callback on 127.0.0.1, and stores refresh tokens locally. The default token cache is now branded to this package:

~/.config/infinitnet-google-search-console-gsc-mcp/oauth-token.json

Override it with GSC_OAUTH_TOKEN_FILE or set the base directory with GSC_CONFIG_DIR.

OAuth scopes used by this server:

  • https://www.googleapis.com/auth/webmasters for Search Console API tools. Google documents this as read/write scope; set GSC_ENABLE_WRITE_TOOLS=false for a read-only deployment.
  • https://www.googleapis.com/auth/indexing for Indexing API tools when write tools and Indexing API are enabled. Indexing uses a separate scope-aware token cache file.

Configure your MCP client

Recommended MCP client key: infinitnet-gsc-mcp. The server advertises the MCP server name infinitnet-google-search-console-gsc-mcp-server, matching the npm package; gsc-mcp remains a short binary alias for local command use.

npm package config examples

If you installed from npm, point your MCP client at the published binary instead of a local dist/index.js path. For one-off npx execution:

{
  "mcpServers": {
    "infinitnet-gsc-mcp": {
      "command": "npx",
      "args": ["-y", "@infinitnet/google-search-console-gsc-mcp-server"],
      "env": {
        "GSC_KEY_FILE": "/absolute/path/to/service-account.json",
        "GSC_DATA_STATE": "all"
      }
    }
  }
}

If you installed globally with npm install -g @infinitnet/google-search-console-gsc-mcp-server, use the short binary:

{
  "mcpServers": {
    "infinitnet-gsc-mcp": {
      "command": "gsc-mcp",
      "env": {
        "GSC_KEY_FILE": "/absolute/path/to/service-account.json",
        "GSC_DATA_STATE": "all"
      }
    }
  }
}

Claude Desktop / Claude Code style config: service account

{
  "mcpServers": {
    "infinitnet-gsc-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/google-search-console-gsc-mcp/dist/index.js"],
      "env": {
        "GSC_KEY_FILE": "/absolute/path/to/service-account.json",
        "GSC_DATA_STATE": "all"
      }
    }
  }
}

Claude Desktop / Claude Code style config: OAuth

{
  "mcpServers": {
    "infinitnet-gsc-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/google-search-console-gsc-mcp/dist/index.js"],
      "env": {
        "GSC_AUTH_MODE": "oauth",
        "GSC_OAUTH_SECRETS_FILE": "/absolute/path/to/client_secret.json",
        "GSC_DATA_STATE": "all"
      }
    }
  }
}

Optional fallback property

GSC_SITE_URL and GSC_SITE_URLS exist only as fallbacks. They are intentionally omitted from the main MCP config examples because agents should normally choose the property dynamically: call gsc_properties_list, match the user's requested site, and pass the exact property as site_url in the tool call.

Important: property selection workflow

Do not assume a property string. Search Console property identifiers must match exactly.

A good AI-agent workflow is:

  1. Call gsc_server_guide to check auth mode and available tool groups.
  2. Call gsc_properties_list.
  3. Pick the property that matches the user's requested site.
    • Domain property format: sc-domain:example.com
    • URL-prefix property format: https://www.example.com/
  4. Pass that exact value as site_url to each follow-up tool.
  5. If a tool returns a 404/property error, call gsc_properties_list again and use the exact returned property.

Example property discovery response shape:

{
  "ok": true,
  "tool": "gsc_properties_list",
  "data": {
    "count": 2,
    "properties": [
      { "siteUrl": "sc-domain:example.com", "permissionLevel": "siteOwner" },
      { "siteUrl": "https://www.example.com/", "permissionLevel": "siteFullUser" }
    ]
  }
}

Usage examples

The examples below show MCP tool arguments. Your AI client will issue these as tool calls; you normally do not run them in a shell.

1. Discover server capabilities

Tool: gsc_server_guide

{}

Use this to confirm auth mode, configured fallback sites, and available tool groups.

2. List GSC properties

Tool: gsc_properties_list

{}

Use the returned siteUrl exactly in later calls.

3. Run a custom Search Analytics query

Tool: gsc_search_query

{
  "site_url": "sc-domain:example.com",
  "days": 28,
  "dimensions": ["query", "page"],
  "filters": [
    { "dimension": "country", "operator": "equals", "expression": "usa" }
  ],
  "row_limit": 100,
  "sort_by": "clicks",
  "sort_direction": "desc"
}

4. Compare performance with the previous period

Tool: gsc_period_compare

{
  "site_url": "sc-domain:example.com",
  "days": 28,
  "dimensions": ["page"],
  "row_limit": 250
}

5. Find queries for one page

Tool: gsc_page_queries

{
  "site_url": "sc-domain:example.com",
  "page_url": "https://www.example.com/blog/example-page/",
  "days": 90,
  "row_limit": 50
}

6. Inspect one URL

Tool: gsc_url_inspect

{
  "site_url": "sc-domain:example.com",
  "url": "https://www.example.com/blog/example-page/"
}

Returns normalized index status, crawl status, canonical information, robots state, rich result information, and detected issues.

7. Inspect a batch of URLs

Tool: gsc_url_inspect_batch

{
  "site_url": "sc-domain:example.com",
  "urls": [
    "https://www.example.com/",
    "https://www.example.com/blog/example-page/"
  ]
}

Batch inspection is capped at 10 URLs per call.

8. Find indexing problems in a URL set

Tool: gsc_indexing_issue_scan

{
  "site_url": "sc-domain:example.com",
  "urls": [
    "https://www.example.com/",
    "https://www.example.com/blog/example-page/"
  ]
}

This calls URL Inspection and returns a problemUrls subset.

9. List and submit sitemaps

Tool: gsc_sitemaps_list

{
  "site_url": "https://www.example.com/"
}

Tool: gsc_sitemap_get

{
  "site_url": "https://www.example.com/",
  "sitemap_url": "https://www.example.com/sitemap.xml"
}

Tool: gsc_sitemap_submit

{
  "site_url": "https://www.example.com/",
  "sitemap_url": "https://www.example.com/sitemap.xml"
}

Sitemap operations are Search Console write operations. gsc_sitemap_submit is intended to be safe/idempotent, but it still notifies Google about the sitemap. Set GSC_ENABLE_WRITE_TOOLS=false to block all write tools, or GSC_ENABLE_SITEMAP_SUBMIT=false to block only sitemap submission.

10. Get site health

Tool: gsc_site_health

{
  "site_url": "sc-domain:example.com",
  "days": 28
}

Returns current/prior totals and changes for clicks, impressions, CTR, and average position.

11. Find rank-lift opportunities

Tool: gsc_rank_lift_opportunities

{
  "site_url": "sc-domain:example.com",
  "days": 28,
  "min_impressions": 100,
  "max_position": 15,
  "limit": 25
}

Returns the same opportunities array as before; sampling metadata is exposed under response meta.sampling. Use this for query-page pairs that rank near page one and may benefit from content improvements, internal links, or snippet refinement.

12. Find CTR gap pages

Tool: gsc_ctr_gap_pages

{
  "site_url": "sc-domain:example.com",
  "days": 28,
  "min_impressions": 300,
  "limit": 25
}

Returns the same pages array as before; sampling metadata is exposed under response meta.sampling. CTR benchmarks are heuristics based on average position. Treat estimated extra clicks as prioritization guidance, not a guarantee.

13. Find uncovered query demand

Tool: gsc_uncovered_queries

{
  "site_url": "sc-domain:example.com",
  "days": 90,
  "min_impressions": 50,
  "min_position": 20,
  "limit": 50
}

Returns the same queries array as before; sampling metadata is exposed under response meta.sampling. Use this to discover high-impression queries where the site appears but ranks poorly.

14. Diagnose traffic losses

Tool: gsc_traffic_loss

{
  "site_url": "sc-domain:example.com",
  "days": 28,
  "min_prior_clicks": 5,
  "limit": 50
}

Includes current/prior sampling metadata and classifies likely causes as ranking decline, CTR decline, demand/SERP visibility decline, disappearance from returned rows, or mixed signal.

15. Detect content decay

Tool: gsc_content_decay

{
  "site_url": "sc-domain:example.com",
  "min_oldest_clicks": 10,
  "limit": 50
}

Returns the same decaying-pages array as before; sampling metadata is exposed under response meta.sampling. Looks for pages with three consecutive 30-day click declines.

16. Find query overlap between pages

Tool: gsc_query_overlap

{
  "site_url": "sc-domain:example.com",
  "days": 28,
  "min_impressions": 50,
  "min_pages": 2,
  "min_overlap_impressions": 10,
  "min_overlap_percent": 1,
  "limit": 50
}

Use this for cannibalization, consolidation, or intent-separation reviews.

The default output focuses on two-page comparisons in pagePairs. Each pair reports overlapping query counts, query-overlap percentages, shared impressions, and overlappingImpressions.balanced, which uses 2 × min(page impressions) per shared query. This discounts lopsided cases where one page receives almost all impressions for a shared query. cannibalizationScore and severity are relative: they combine query-overlap share with balanced-impression-overlap share. attentionScore combines that relative severity with absolute balanced-overlap volume for prioritization. By default, min_overlap_impressions and min_overlap_percent only remove tiny/noisy pairs; min_impressions continues to filter query-level groups by total query impressions. Query-level groups remain available in queries for consolidation context.

SEO sampling and data coverage metadata

SEO analysis tools include sampling metadata so clients can see how much Search Analytics data the recommendation used. Google's Search Analytics query reference documents that rows are grouped by requested dimensions, non-date results are sorted by clicks descending, date-grouped results are sorted by date ascending, rowLimit accepts 1-25,000 rows per request, and the API can return top rows rather than every matching row under internal limits. Search Console Help also documents a performance-data export cap of 50K rows per day per type per property.

Array-returning tools keep their data arrays for compatibility and put sampling in envelope meta.sampling; object-returning SEO tools include sampling inside data.sampling. A single sampling object looks like:

{
  "coverageLabel": "top_returned_rows",
  "dateRange": { "startDate": "2026-04-29", "endDate": "2026-05-26" },
  "dimensions": ["query", "page"],
  "filtersApplied": [],
  "dataState": "all",
  "requestedRowLimit": 5000,
  "requestedStartRow": 0,
  "rowsFetched": 5000,
  "pageSize": 5000,
  "pagesFetched": 1,
  "responseRowCounts": [5000],
  "fetchAllWithinRequestedLimit": true,
  "limitReached": true,
  "requestedLimitReached": true,
  "possiblyTruncated": true,
  "apiMayOmitRows": true,
  "sortBasis": "clicks_descending_with_arbitrary_tie_order",
  "apiLimits": {
    "maxRowsPerRequest": 25000,
    "performanceRowsPerDayPerTypePerProperty": 50000
  },
  "completeness": "capped_at_requested_limit",
  "note": "The requested row limit was reached..."
}

requestedLimitReached is true when rowsFetched reaches the requested row limit; possiblyTruncated mirrors that value for compatibility. apiMayOmitRows remains true because Google documents that Search Analytics can return top rows rather than every matching row. Google does not return a total available row count for searchanalytics.query, so this metadata avoids claiming exhaustive coverage.

17. Analyze a site section

Tool: gsc_section_performance

{
  "site_url": "sc-domain:example.com",
  "path_contains": "/blog/",
  "days": 28,
  "limit": 10
}

Returns aggregate section metrics, top pages, top queries, and separate page/query sampling metadata for URLs containing the path fragment.

18. Scan for recent alerts

Tool: gsc_alert_scan

{
  "site_url": "sc-domain:example.com",
  "days": 7,
  "position_drop": 10,
  "ctr_drop_percent": 30,
  "click_drop_percent": 30
}

Use this for quick monitoring of material click, CTR, and position drops.

19. Generate an SEO action plan

Tool: gsc_action_plan

{
  "site_url": "sc-domain:example.com",
  "days": 28,
  "limit": 15
}

Combines multiple signals into prioritized recommendations and includes per-source sampling metadata under data.sampling. Treat recommendations as deterministic analysis output that still needs human SEO judgment before implementation.

20. Verify a numeric claim

Tool: gsc_claim_check

{
  "site_url": "sc-domain:example.com",
  "claim": "The blog generated about 1,000 clicks in the last 28 days.",
  "metric": "clicks",
  "expected": 1000,
  "days": 28,
  "page_url": "https://www.example.com/blog/"
}

Use this before reporting important numbers to users.

21. Compare multiple properties

Tool: gsc_multi_property_health

{
  "site_urls": ["sc-domain:example.com", "https://www.example.com/"],
  "days": 28
}

If site_urls is omitted, the tool uses GSC_SITE_URLS or GSC_SITE_URL fallback configuration.

22. Notify the Indexing API

Tool: gsc_index_notify

{
  "url": "https://www.example.com/job/example-role/",
  "action": "URL_UPDATED"
}

Tool: gsc_index_notify_batch

{
  "urls": [
    "https://www.example.com/job/example-role/",
    "https://www.example.com/job/another-role/"
  ],
  "action": "URL_UPDATED"
}

Google documents the Indexing API primarily for JobPosting and BroadcastEvent-in-VideoObject pages. A successful notification does not guarantee crawling, indexing, or ranking changes. Set GSC_ENABLE_WRITE_TOOLS=false to block all write tools, or GSC_ENABLE_INDEXING_API=false to block only Indexing API notification tools.

Tool reference

| Tool | Purpose | Key inputs | | --- | --- | --- | | gsc_server_guide | Capabilities, auth status, tool groups, property workflow | none | | gsc_properties_list | List accessible GSC properties | none | | gsc_property_get | Get one property's details | site_url | | gsc_search_query | Custom Search Analytics query | site_url, days or date range, dimensions, filters, row_limit | | gsc_period_compare | Compare current vs previous period | site_url, days, dimensions, filters | | gsc_page_queries | Query performance for one URL | site_url, page_url, days | | gsc_url_inspect | Inspect one URL | site_url, url | | gsc_url_inspect_batch | Inspect up to 10 URLs | site_url, urls | | gsc_indexing_issue_scan | Return only inspected URLs with issues | site_url, urls | | gsc_sitemaps_list | List sitemaps | site_url | | gsc_sitemap_get | Get one sitemap | site_url, sitemap_url | | gsc_sitemap_submit | Submit/resubmit sitemap (write tool) | site_url, sitemap_url | | gsc_site_health | Site-level current/prior health | site_url, days | | gsc_rank_lift_opportunities | Near-page-one opportunities | site_url, days, min_impressions, max_position | | gsc_ctr_gap_pages | CTR underperformance opportunities | site_url, days, min_impressions | | gsc_uncovered_queries | Poor-ranking high-impression queries | site_url, days, min_impressions, min_position | | gsc_traffic_loss | Diagnose page click losses | site_url, days, min_prior_clicks | | gsc_content_decay | Three-period page decline detection | site_url, min_oldest_clicks | | gsc_query_overlap | Two-page query/impression overlap with relative cannibalization severity | site_url, days, min_impressions, min_pages, overlap filters | | gsc_section_performance | Analyze top returned URLs containing a path fragment | site_url, path_contains, days | | gsc_alert_scan | Recent click/CTR/position alerts | site_url, days, thresholds | | gsc_action_plan | Prioritized SEO recommendations | site_url, days, limit | | gsc_claim_check | Verify a numeric claim | site_url, claim, metric, expected, optional filters | | gsc_multi_property_health | Compare up to 20 properties | site_urls, days | | gsc_index_notify | Notify one URL update/delete (write tool) | url, action | | gsc_index_notify_batch | Notify up to 200 URLs (write tool) | urls, action |

Environment variables

| Variable | Default | Purpose | | --- | --- | --- | | GSC_AUTH_MODE | service_account | Auth mode: service_account or oauth. | | GSC_KEY_FILE | unset | Service-account JSON key path. | | GSC_CREDENTIALS_PATH | unset | Alias for service-account JSON key path. | | GOOGLE_APPLICATION_CREDENTIALS | unset | Google-standard service-account key path fallback. | | GSC_OAUTH_SECRETS_FILE | unset | OAuth client secrets JSON file. | | GSC_OAUTH_CLIENT_SECRETS_FILE | unset | Alias for OAuth client secrets JSON file. | | GSC_OAUTH_CLIENT_ID | unset | OAuth client ID, if not using a secrets file. | | GSC_OAUTH_CLIENT_SECRET | unset | OAuth client secret, if not using a secrets file. | | GSC_OAUTH_TOKEN_FILE | ~/.config/infinitnet-google-search-console-gsc-mcp/oauth-token.json | OAuth token cache path. | | GSC_CONFIG_DIR | ~/.config/infinitnet-google-search-console-gsc-mcp | Base config directory for OAuth token cache. | | GSC_OAUTH_PORT | 3847 | Local OAuth callback port. | | GSC_OAUTH_CALLBACK_PORT | 3847 | Alias/override for OAuth callback port. | | GSC_SITE_URL | unset | Optional fallback property if a tool call omits site_url. | | GSC_SITE_URLS | unset | Optional comma-separated fallback list for multi-property tools. | | GSC_DATA_STATE | all | Search Analytics data state: all or final. | | GSC_ENABLE_WRITE_TOOLS | true | Set to false to block external write operations. Read-only tools still work. | | GSC_ENABLE_SITEMAP_SUBMIT | true | Set to false to keep sitemap submission disabled even when other write tools are enabled. | | GSC_ENABLE_INDEXING_API | true | Set to false to keep Indexing API notification tools disabled even when other write tools are enabled. |

Response format

Successful tools return a text content item containing JSON like:

{
  "ok": true,
  "tool": "gsc_site_health",
  "input": { "site_url": "sc-domain:example.com", "days": 28 },
  "data": {},
  "meta": {
    "generatedAt": "2026-05-26T12:00:00.000Z",
    "source": "Google Search Console API via local MCP server",
    "siteUrl": "sc-domain:example.com",
    "notes": [
      "Use only the returned API data for numeric claims; re-run gsc_claim_check before presenting important numbers.",
      "Search Console data may include fresh unfinalized rows unless GSC_DATA_STATE=final is set."
    ]
  }
}

Errors use the same envelope:

{
  "ok": false,
  "tool": "gsc_property_get",
  "input": { "site_url": "sc-domain:missing.example" },
  "error": {
    "message": "Property 'sc-domain:missing.example' was not found or is not accessible to the authenticated account.",
    "code": 404,
    "hint": "Domain properties require exact sc-domain:example.com format and explicit user/service-account access."
  },
  "meta": {}
}

Troubleshooting

Service-account mode requires GSC_KEY_FILE...

Set one of GSC_KEY_FILE, GSC_CREDENTIALS_PATH, or GOOGLE_APPLICATION_CREDENTIALS to an absolute service-account JSON path, or switch to OAuth with GSC_AUTH_MODE=oauth.

Credential file does not exist

Use an absolute path in the MCP client config. Relative paths may resolve from the MCP client's working directory rather than this repository.

No Search Console property selected

Call gsc_properties_list, choose the exact property, and pass it as site_url. Optionally set GSC_SITE_URL only as a fallback.

Property not found / 404

Common causes:

  • The site_url does not exactly match a Search Console property.
  • A domain property was passed as a URL-prefix property, or vice versa.
  • The authenticated user/service account does not have access to that property.

Fix: call gsc_properties_list and copy the exact siteUrl value.

OAuth browser flow does not open

The server prints the auth URL to stderr if opening the browser fails. Open that URL manually, complete consent, and keep the MCP server process running until the callback completes.

OAuth callback port is already in use

Set a different port:

GSC_OAUTH_PORT=3850

URL Inspection returns no data or permission errors

Check that the inspected URL belongs to the selected property and that the authenticated account has property access. Domain properties can inspect URLs across protocols/subdomains only when the property/account access is correct.

Sitemap operations fail for domain properties

Google sitemap calls are often easiest with exact URL-prefix properties such as https://www.example.com/. If a domain property fails, list properties and try the matching URL-prefix property if available.

Indexing API calls succeed but nothing changes

A successful Indexing API notification only means Google accepted the notification. It does not guarantee crawl, index, or ranking changes.

Development

Install dependencies:

npm install

Build:

npm run build

Typecheck/lint:

npm run lint

Run tests:

npm test

Run a package dry run:

npm pack --dry-run

Project layout:

src/index.ts        MCP server and tool registration
src/auth.ts         Google auth and API client creation
src/config.ts       Environment parsing and property fallback handling
src/analytics.ts    Date windows, Search Analytics fetching, metric helpers
src/gsc.ts          Direct Search Console API operations
src/seo.ts          Higher-level SEO analysis workflows
src/response.ts     Shared JSON response envelope
src/types.ts        Shared TypeScript types
src/__tests__/      Mocked unit/integration tests

Design conventions:

  • Keep stdout reserved for MCP protocol messages.
  • Use console.error only for fatal startup/runtime diagnostics.
  • Keep Google API calls in src/gsc.ts or src/analytics.ts.
  • Keep pure deterministic analysis in src/seo.ts where possible.
  • Add mocked tests for new Google API wrappers; tests must not require live credentials.
  • Preserve the shared response envelope for every MCP tool.