Skip to main content
Glama
Vrealmatic

Google Search Console MCP Server

by Vrealmatic
README.md
# Google Search Console MCP Server

An [MCP](https://modelcontextprotocol.io) server that gives any MCP-compatible
AI client (Claude Desktop, Claude Code, Cursor, …) read-only access to your
**Google Search Console** data. Ask questions in plain language — _"why did my
traffic drop last week?"_ — and the assistant pulls the numbers, compares
periods, and surfaces SEO opportunities for you.

> Read-only. The server only ever **reads** Search Analytics data; it cannot
> change anything in your Search Console property.

## What it does

It exposes six tools to the AI client:

| Tool | What it answers |
| --- | --- |
| `search_analytics` | Raw clicks / impressions / CTR / position for a date range, grouped by query, page, country, device, or date. |
| `compare_periods` | Which pages or queries gained or lost the most clicks/impressions between two date ranges. Great for diagnosing traffic drops. |
| `top_opportunities` | "Low-hanging fruit" — pages/queries ranking 4–20, or high-impression pages with low CTR that are worth optimizing. |
| `page_details` | Deep dive on one page: its top queries and day-by-day trend. |
| `query_details` | For one query: which of your pages rank for it and how. |
| `list_sites` | Lists the configured properties — used when you have several sites and haven't said which one to analyze. |

## Requirements

- **Node.js 18+**
- A Google account with access to a **Search Console** property
- A **Google Cloud OAuth client** (free — steps below)

## Quick start

```bash
# 1. Get an OAuth refresh token (interactive, one-time)
npx github:Vrealmatic/gsc-mcp-server get-token

# 2. Save the printed JSON as config.json, then point your MCP client at the server (see below)
```

That's it — the assistant can now query your Search Console.

## Getting credentials

You need four values: `CLIENT_ID`, `CLIENT_SECRET`, `REFRESH_TOKEN`, and
`SITE_URL`. Step 1 creates the OAuth client (the `CLIENT_ID` / `CLIENT_SECRET`);
in step 2 you exchange those for a `REFRESH_TOKEN` — pick **either** method, both
produce the same result.

### Step 1 — Create an OAuth client

1. Open the [Google Cloud Console](https://console.cloud.google.com/) and create
   (or pick) a project.
2. Enable the **Google Search Console API**:
   APIs & Services → Library → search "Search Console API" → **Enable**.
3. Configure the **OAuth consent screen** (External is fine). Add yourself as a
   **Test user** so you can authorize without app verification.
4. APIs & Services → **Credentials** → Create credentials → **OAuth client ID**.
   - Application type: **Web application**
   - Add **both** of these as Authorized redirect URIs (so either method below
     works):
     - `http://localhost:5858/oauth2callback` — for the helper script
     - `https://developers.google.com/oauthplayground` — for the OAuth Playground
5. Copy the generated **Client ID** and **Client secret**.

### Step 2 — Get a refresh token (pick one method)

#### Method A — Helper script (recommended)

```bash
npx github:Vrealmatic/gsc-mcp-server get-token
```

It asks for your Client ID, Client secret, and site URL, opens a browser for you
to grant access, then prints a ready-to-paste `config.json`. Uses the
`http://localhost:5858/oauth2callback` redirect URI.

#### Method B — Google OAuth Playground (no local helper)

Handy if you can't or don't want to run the script — everything happens in the
browser:

1. Open the [OAuth Playground](https://developers.google.com/oauthplayground/).
2. Click the **⚙️ gear** (top right) → check **Use your own OAuth credentials**
   → paste your **Client ID** and **Client secret**.
3. In the left panel, scroll to the bottom field "Input your own scopes" and
   enter: `https://www.googleapis.com/auth/webmasters.readonly`
4. Click **Authorize APIs**, sign in, and grant access.
5. Click **Exchange authorization code for tokens** — copy the **Refresh token**.

Then assemble `config.json` by hand (next step) with that refresh token.

> **`SITE_URL`** (needed by both methods) must match the property exactly as it
> appears in Search Console:
> - URL-prefix property: `https://example.com/` (note the trailing slash)
> - Domain property: `sc-domain:example.com`

### Step 3 — Save config.json

```json
{
  "CLIENT_ID": "…",
  "CLIENT_SECRET": "…",
  "REFRESH_TOKEN": "…",
  "SITE_URL": "https://example.com/"
}
```

Save it **anywhere outside the repo** and point the server at it with `--config`
(e.g. `~/.gsc/config.json`). Keep it private — it grants read access to your
Search Console data. If you do keep it inside the project folder, it's already
covered by `.gitignore`.

## Multiple sites

One config can hold several properties. Replace `SITE_URL` with a `SITES` array
(the OAuth account must have access to each one):

```json
{
  "CLIENT_ID": "…",
  "CLIENT_SECRET": "…",
  "REFRESH_TOKEN": "…",
  "SITES": ["https://example.com/", "sc-domain:another-site.com"]
}
```

How site selection works:

- Every tool takes an optional **`siteUrl`** argument. Just name the site in your
  question — _"compare last month for **another-site.com**"_ — and the assistant
  passes it through. A partial match is enough (`another-site` resolves to
  `sc-domain:another-site.com`).
- If you **don't** specify a site and several are configured, the tool returns
  the list of available sites and the assistant will **ask you which one** to
  use. It never silently picks one.
- The **`list_sites`** tool lets the assistant enumerate the configured
  properties at any time.
- With only one site configured (`SITE_URL` or a single-entry `SITES`),
  `siteUrl` is optional and that site is always used.

To keep properties fully isolated instead (separate tokens, separate clients),
register multiple MCP server entries, each with its own `--config`.

## Connecting your MCP client

The server speaks MCP over stdio. Pass your credentials with `--config`:

### Claude Desktop

Edit `claude_desktop_config.json`
(macOS: `~/Library/Application Support/Claude/`,
Windows: `%APPDATA%\Claude\`):

```json
{
  "mcpServers": {
    "search-console": {
      "command": "npx",
      "args": [
        "-y",
        "github:Vrealmatic/gsc-mcp-server",
        "--config",
        "/absolute/path/to/config.json"
      ]
    }
  }
}
```

### Claude Code

```bash
claude mcp add search-console -- npx -y github:Vrealmatic/gsc-mcp-server --config /absolute/path/to/config.json
```

### Local clone

```bash
git clone https://github.com/Vrealmatic/gsc-mcp-server.git
cd gsc-mcp-server
npm install
node index.js --config ./config.json
```

You can also pass credentials via environment variables (`CLIENT_ID`,
`CLIENT_SECRET`, `REFRESH_TOKEN`, `SITE_URL`) instead of `--config`.

## Example

Once connected, just talk to your assistant:

> **You:** My organic traffic feels lower this month. What dropped between
> May and June?

The assistant calls `compare_periods` and replies:

> Comparing **2026-05-01 → 2026-05-31** vs **2026-06-01 → 2026-06-23**, the
> biggest click losses are:
>
> | Page | May clicks | June clicks | Δ |
> | --- | --- | --- | --- |
> | `/guides/onboarding` | 1,240 | 410 | **−830** |
> | `/pricing` | 980 | 720 | −260 |
> | `/blog/seo-basics` | 540 | 360 | −180 |
>
> `/guides/onboarding` lost two-thirds of its clicks and its average position
> slipped from 3.1 to 7.8 — that single page explains most of the drop. Want me
> to pull `page_details` for it to see which queries fell?

> **You:** Yes, and show me where the easy wins are.

It then runs `page_details` and `top_opportunities` to point you at queries
sitting at positions 4–20 (a small ranking gain there yields a big click jump)
and high-impression pages with weak CTR.

## How it works

- Built on the official [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk).
- Authenticates to Google with the [`googleapis`](https://www.npmjs.com/package/googleapis)
  OAuth2 client and a long-lived refresh token, scoped to
  `webmasters.readonly`.
- One or more properties per server instance (`SITE_URL` or `SITES`); see
  [Multiple sites](#multiple-sites) above.

## Security

- The OAuth scope is **read-only** (`webmasters.readonly`).
- Your `config.json` / refresh token are stored locally and never leave your
  machine except to talk to Google's API. Do not commit them.
- Revoke access anytime at
  [Google Account → Security → Third-party access](https://myaccount.google.com/permissions).

## License

[MIT](LICENSE) © [Vrealmatic.com](https://vrealmatic.com)