# GSC SEO MCP Connect Google Search Console to Cursor, Claude, or Gemini. Ask questions in plain English and get real SEO data back. [![npm](https://img.shields.io/npm/v/gsc-seo-mcp)](https://www.npmjs.com/package/gsc-seo-mcp) [![MCP](https://img.shields.io/badge/MCP-Server-blue)](https://modelcontextprotocol.io/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) --- ## What you can ask your AI once it's set up ``` Show me the biggest SEO opportunities for my site. Which pages are losing clicks? Find keywords ranking positions 4–15 that I can push to page 1. Split branded vs non-branded traffic for the last 90 days. Which pages have bad CTR for their ranking position? Inspect these URLs and tell me what's wrong with indexing. Generate a Markdown SEO report for the last 28 days. ``` --- ## Setup There are two parts: 1. **Google** — give the MCP access to your Search Console data 2. **Your AI app** — tell Cursor / Claude / Gemini how to run it Pick your Google auth method first: | | Service Account | OAuth | |---|---|---| | Best for | Agencies, client sites, teams | Personal sites, your own account | | How it works | JSON key file, no browser login | Signs in via browser once | | Recommended? | Yes, simpler for MCP | Works too | --- ## Part 1 — Google Setup ### Step 1: Create a Google Cloud project This is just a container for API access. It is not your website. 1. Go to [console.cloud.google.com](https://console.cloud.google.com/) 2. Click the project dropdown at the top → **New Project** 3. Name it `GSC SEO MCP` and click **Create** 4. Make sure it's selected in the top dropdown after creation ### Step 2: Enable the Search Console API 1. Go to **APIs & Services → Library** 2. Search **Google Search Console API** → click it → click **Enable** 3. Optional: also enable **Indexing API** if you want the `indexing_*` tools (only useful for JobPosting/livestream pages) --- ### Option A: Service Account (recommended) #### 1. Create the service account 1. Go to **IAM & Admin → Service Accounts** 2. Click **Create service account** 3. Name: `gsc-seo-mcp` → click **Create and continue** 4. Skip the role assignment → click **Continue** → click **Done** 5. Copy the service account email — looks like: ``` gsc-seo-mcp@your-project-id.iam.gserviceaccount.com ``` #### 2. Download the key file 1. Click the service account you just created 2. Go to the **Keys** tab → **Add key → Create new key → JSON → Create** 3. Google downloads a `.json` file — save it somewhere safe, like: - Mac/Linux: `/Users/your-name/keys/gsc-seo-mcp.json` - Windows: `C:/Users/your-name/keys/gsc-seo-mcp.json` Don't commit this file to GitHub. Treat it like a password. #### 3. Add it to Search Console 1. Open [search.google.com/search-console](https://search.google.com/search-console) 2. Select your property 3. Go to **Settings → Users and permissions → Add user** 4. Paste the service account email, set permission to **Full**, click **Add** You need to be a property owner to do this. #### 4. Your MCP config ```json { "mcpServers": { "gsc-seo": { "command": "npx", "args": ["-y", "gsc-seo-mcp"], "env": { "GSC_AUTH_MODE": "service_account", "GSC_KEY_FILE": "/absolute/path/to/gsc-seo-mcp.json", "GSC_SITE_URL": "sc-domain:example.com" } } } } ``` Windows path tip — use forward slashes or double backslashes: ```json "GSC_KEY_FILE": "C:/Users/your-name/keys/gsc-seo-mcp.json" ``` --- ### Option B: OAuth (sign in with Google) Use this if you want to connect with your own Google account via browser login. #### 1. Set up the OAuth consent screen 1. Go to **APIs & Services → OAuth consent screen** 2. Choose **External** (works for Gmail accounts) → fill in app name, email → save 3. If the app is in testing mode, add your Gmail under **Test users** #### 2. Create the OAuth client 1. Go to **APIs & Services → Credentials → Create credentials → OAuth client ID** 2. Application type: **Desktop app** → name it `GSC SEO MCP Desktop` → click **Create** 3. Click **Download JSON** — save it like: - Mac/Linux: `/Users/your-name/keys/gsc-oauth-client.json` - Windows: `C:/Users/your-name/keys/gsc-oauth-client.json` #### 3. Your MCP config ```json { "mcpServers": { "gsc-seo": { "command": "npx", "args": ["-y", "gsc-seo-mcp"], "env": { "GSC_AUTH_MODE": "oauth", "GSC_OAUTH_SECRETS_FILE": "/absolute/path/to/gsc-oauth-client.json", "GSC_TOKEN_FILE": "/absolute/path/to/gsc-oauth-token.json", "GSC_SITE_URL": "sc-domain:example.com" } } } } ``` `GSC_TOKEN_FILE` is where the MCP saves your login token after the first browser sign-in. If you leave it out, it saves to `~/.gsc-seo-mcp/token.json` by default. #### 4. First run Restart your MCP client, then ask it to run `server_health` or `list_properties`. A browser window will open — sign in with Google and approve access. That's it, no repeat login needed. If Google shows an "unverified app" warning, click **Advanced → Continue** — this is your own OAuth app, it's fine. --- ## Part 2 — Add to your AI app Node.js 20+ is required. [Download here](https://nodejs.org/) if you don't have it. ### Cursor Create `.cursor/mcp.json` in your project folder (or use global MCP settings): ```json { "mcpServers": { "gsc-seo": { "command": "npx", "args": ["-y", "gsc-seo-mcp"], "env": { "GSC_AUTH_MODE": "service_account", "GSC_KEY_FILE": "/absolute/path/to/service-account.json", "GSC_SITE_URL": "sc-domain:example.com", "GSC_BRAND_TERMS": "mybrand,mybrand.com" } } } } ``` ### Claude Desktop Edit `claude_desktop_config.json`: - Mac: `~/Library/Application Support/Claude/claude_desktop_config.json` - Windows: `%APPDATA%\Claude\claude_desktop_config.json` ```json { "mcpServers": { "gsc-seo": { "command": "npx", "args": ["-y", "gsc-seo-mcp"], "env": { "GSC_AUTH_MODE": "service_account", "GSC_KEY_FILE": "/absolute/path/to/service-account.json", "GSC_SITE_URL": "sc-domain:example.com" } } } } ``` Restart Claude Desktop after saving. ### Claude Code Create `.mcp.json` in your project: ```json { "mcpServers": { "gsc-seo": { "command": "npx", "args": ["-y", "gsc-seo-mcp"], "env": { "GSC_AUTH_MODE": "service_account", "GSC_KEY_FILE": "/absolute/path/to/service-account.json", "GSC_SITE_URL": "sc-domain:example.com" } } } } ``` Or via CLI: ```bash claude mcp add --transport stdio \ --env GSC_AUTH_MODE=service_account \ --env GSC_KEY_FILE=/absolute/path/to/service-account.json \ --env GSC_SITE_URL=sc-domain:example.com \ gsc-seo -- npx -y gsc-seo-mcp ``` ### Gemini CLI Edit `~/.gemini/settings.json` (or `.gemini/settings.json` in your project): ```json { "mcpServers": { "gsc-seo": { "command": "npx", "args": ["-y", "gsc-seo-mcp"], "env": { "GSC_AUTH_MODE": "service_account", "GSC_KEY_FILE": "/absolute/path/to/service-account.json", "GSC_SITE_URL": "sc-domain:example.com" }, "timeout": 120000, "trust": false } } } ``` --- ## Property URL format Use the exact format from Search Console: ``` sc-domain:example.com ← domain property (recommended) https://www.example.com/ ← URL-prefix property (include the trailing slash) ``` --- ## All config variables | Variable | Required | What it does | |---|---|---| | `GSC_SITE_URL` | Recommended | Default property. Example: `sc-domain:example.com` | | `GSC_SITE_URLS` | Optional | Comma-separated properties for multi-site dashboards | | `GSC_AUTH_MODE` | Optional | `service_account` or `oauth`. Auto-detected when possible | | `GSC_KEY_FILE` | Service account | Path to service account JSON key | | `GOOGLE_APPLICATION_CREDENTIALS` | Service account | Alternative path variable | | `GSC_OAUTH_SECRETS_FILE` | OAuth | Path to OAuth client secret JSON | | `GSC_OAUTH_CLIENT_ID` | OAuth alternative | Client ID if not using a secrets file | | `GSC_OAUTH_CLIENT_SECRET` | OAuth alternative | Client secret if not using a secrets file | | `GSC_TOKEN_FILE` | Optional | Where OAuth token is saved after login | | `GSC_BRAND_TERMS` | Optional | Comma-separated brand terms for `brand_nonbrand_split` | | `GSC_REPORT_DIR` | Optional | Folder for Markdown reports. Defaults to `./reports` | | `GSC_DATA_STATE` | Optional | `all`, `final`, or `hourly_all`. Defaults to `all` | --- ## Tools ### Core | Tool | What it does | |---|---| | `server_health` | Shows config status, auth mode, and tool count | | `list_properties` | Lists all Search Console properties you have access to | | `get_site` | Gets permission details for one property | | `add_site` | Adds a site to your account | | `delete_site` | Removes a site from your account | ### Search Analytics | Tool | What it does | |---|---| | `search_analytics` | Full query with dimensions, filters, search type, and data state | | `advanced_filter_query` | Pulls up to 50,000 rows for deeper audits | | `top_queries` | Top queries, optionally filtered by page | | `top_pages` | Top pages, optionally filtered by query | | `performance_overview` | Site snapshot with period comparison, daily trend, devices | | `compare_periods` | Current vs previous period by page, query, country, or device | | `dimension_breakdown` | Performance by one dimension | | `page_query_matrix` | Maps pages to the queries driving them | ### SEO Analysis | Tool | What it answers | |---|---| | `quick_wins` | Which keywords are close enough to improve fast? | | `ctr_opportunities` | Which snippets underperform for their ranking position? | | `content_decay` | Which pages are declining across multiple periods? | | `traffic_drop_diagnosis` | Was the drop rankings, CTR, demand, coverage, or mixed? | | `cannibalization_check` | Which queries are split across competing pages? | | `brand_nonbrand_split` | How much traffic is brand vs non-brand? | | `search_intent_breakdown` | How do queries split across informational, commercial, transactional, navigational, local? | | `device_country_opportunities` | Which device/country/page segments have weak CTR or ranking? | | `long_tail_questions` | Which question queries deserve content expansion? | | `page_refresh_priorities` | Which pages should be updated first? | | `internal_link_opportunities` | Which strong pages can support weaker pages? | | `query_page_fit` | What does one page rank for, and does the content match? | | `title_meta_brief` | Which queries should inform title/meta refreshes? | | `anomaly_alerts` | Which pages had abnormal losses recently? | ### Indexing, Sitemaps, URLs | Tool | What it does | |---|---| | `inspect_url` | Checks one URL for index status, canonical, crawl, coverage | | `batch_inspect_urls` | Inspects multiple URLs | | `index_coverage_summary` | Summarizes inspection results across a URL list | | `list_sitemaps` | Lists submitted sitemaps with errors and indexed counts | | `get_sitemap` | Details for one sitemap | | `submit_sitemap` | Submits or refreshes a sitemap | | `delete_sitemap` | Deletes a submitted sitemap | | `indexing_publish_url` | Sends an Indexing API notification for an eligible URL | | `indexing_batch_publish` | Sends multiple Indexing API notifications | | `indexing_get_metadata` | Checks latest Indexing API notification status for a URL | ### Reporting | Tool | What it does | |---|---| | `multi_site_dashboard` | Compares multiple properties in one view | | `generate_markdown_report` | Saves a Markdown SEO report to disk | | `verify_claim` | Re-queries GSC to check a number before you report it to a client | --- ## Troubleshooting **Tools don't show up in my AI app** Make sure Node.js 20+ is installed. Check your MCP config uses `npx -y gsc-seo-mcp` exactly. All file paths must be absolute (not `~/` or relative). **Service account shows no properties** You need to add the service account email to Search Console under **Settings → Users and permissions**. **URL Inspection fails** The URL must belong to the property in `GSC_SITE_URL`. For URL-prefix properties, use the exact prefix with protocol and trailing slash. **OAuth doesn't open the browser** Set `GSC_OAUTH_PORT=0` to let it pick a free port. If you're on a remote machine, you'll need to run this locally instead. --- ## Data notes - Search Analytics rows are sorted by clicks. The API has internal row limits, so not every possible row is included. - `GSC_DATA_STATE=all` includes fresh data. Use `final` for finalized reporting numbers. - URL Inspection shows Google's index state, not a live crawl. - The Indexing API is for JobPosting and BroadcastEvent pages only — it's not a general indexing shortcut. --- ## Security - Never commit service account keys, OAuth secrets, or token files to Git. - Use read-only Search Console permissions if you don't need write tools. - Review `delete_site`, `delete_sitemap`, `submit_sitemap`, and `indexing_publish_url` calls before approving them. --- ## Official docs - [Create a Google Cloud project](https://cloud.google.com/resource-manager/docs/creating-managing-projects) - [Enable APIs](https://developers.google.com/workspace/guides/enable-apis) - [Create credentials](https://developers.google.com/workspace/guides/create-credentials) - [Search Console users and permissions](https://support.google.com/webmasters/answer/7687615) - [Search Analytics API](https://developers.google.com/webmaster-tools/v1/searchanalytics/query) - [URL Inspection API](https://developers.google.com/webmaster-tools/v1/urlInspection.index/inspect) - [Indexing API](https://developers.google.com/search/apis/indexing-api/v3/using-api) - [Model Context Protocol](https://modelcontextprotocol.io/) --- ## License MIT. If this saves you time, star the repo.