Skip to main content
Glama
gsc-mcp

gsc-mcp

by yan-labs
README.md
# gsc-mcp

![gsc-mcp cover](docs/cover.png)

Read your Google Search Console data locally from Claude Code, Codex, Cursor, or any MCP client.

让 Claude Code、Codex、Cursor 或任何 MCP 客户端在本地读取你的 Google Search Console 数据。

[English](#english) | [中文](#中文)

## English

### 1. Why

Google does not provide an official Search Console MCP. `gsc-mcp` lets your AI agent read the Search Console properties your Google account can access, using credentials stored on your machine. It is read-only by default and includes built-in SEO insights.

### 2. Features

- Search analytics, URL inspection, and sitemap listing.
- Built-in insights for striking-distance queries, low CTR, query cannibalization, and movers.
- CLI and MCP server in one install; stdio and loopback-only Streamable HTTP modes.
- Read-only by default. Sitemap submission is an opt-in write operation.

![Example insights](docs/insights.png)

| MCP tool name | CLI equivalent | What it does |
| --- | --- | --- |
| `list_sites` | `gsc sites` | List properties accessible to your Google account. |
| `search_analytics` | `gsc query <site>` | Query Search Console performance rows; optionally compare with the equal preceding period. |
| `inspect_url` | `gsc inspect <site> <url>` | Inspect Google's indexed URL status; this is not a live test. |
| `list_sitemaps` | `gsc sitemaps <site>` | List submitted sitemaps. |
| `submit_sitemap` | `gsc submit-sitemap <site> <url>` | Submit a sitemap. Registered only with `GSC_ALLOW_WRITE=1`; requires a write-scoped OAuth token and property permission. |
| `striking_distance` | `gsc insights striking_distance <site>` | Find queries ranking in positions 6–20. |
| `low_ctr` | `gsc insights low_ctr <site>` | Find queries with low CTR and enough impressions. |
| `cannibalization` | `gsc insights cannibalization <site>` | Find queries returning multiple pages. |
| `movers` | `gsc insights movers <site>` | Compare query performance with the equal preceding period. |

### 3. Requirements

- Node.js 20 or newer
- npm
- git
- A Google account with access to Search Console properties

### 4. Install

```sh
git clone https://github.com/yan-labs/gsc-mcp.git
cd gsc-mcp
npm install
npm run build
npm link
gsc --help
```

If you do not want to run `npm link`, invoke the CLI directly:

```sh
node /path/to/gsc-mcp/dist/cli.js --help
```

### 5. Google Cloud setup

1. Create a project at [Google Cloud Console](https://console.cloud.google.com/).
2. Open **APIs & Services > Library**, find **Google Search Console API**, and enable it.
3. Open **Google Auth Platform** (or **OAuth consent screen**) and configure the consent screen:
   - Set **User type** to **External**.
   - Enter an app name and the required support and developer email addresses.
   - Set **Audience** to **Testing** and add your Google account as a test user.
4. Open **Clients > Create client**. Set **Application type** to **Desktop app**.
5. Copy the **Client ID** and **Client secret**. Downloading the JSON file is optional.

While the app is in Testing, Google-issued refresh tokens expire after 7 days. Re-run `gsc auth` weekly, or set the publishing status to **In production**. For personal use with the read-only `webmasters` scope, Google may show an “unverified app” warning; continue via **Advanced**. Verification is only needed for public distribution.

### 6. Authenticate

Set the desktop OAuth client credentials and start the local authorization flow:

```sh
GSC_CLIENT_ID='your-client-id' GSC_CLIENT_SECRET='your-client-secret' gsc auth
```

The command prints a Google URL. Open it in a browser and approve access. A temporary callback server listens on `127.0.0.1` at a random port. The token is saved to `~/.config/gsc-mcp/token.json` with file mode `600`. Set `GSC_TOKEN_FILE` to use a different path.

For a headless or remote machine, run `gsc auth` on a machine with a browser and copy the token file securely, or use SSH port forwarding to reach the callback.

To grant sitemap-submission scope, authenticate with:

```sh
GSC_CLIENT_ID='your-client-id' GSC_CLIENT_SECRET='your-client-secret' gsc auth --write
```

Verify access and copy the exact property name from the output:

```sh
gsc sites
```

### 7. Service account alternative

1. Create a service account in Google Cloud and create a JSON key for it.
2. In Search Console, open **Settings > Users and permissions > Add user** and add the service account email. **Restricted** permission is enough for read access.
3. Point the environment variable to the JSON key:

```sh
export GOOGLE_APPLICATION_CREDENTIALS='/path/to/key.json'
gsc sites
```

### 8. CLI usage

Use the property name exactly as printed by `gsc sites`. A Domain property looks like `sc-domain:example.com`; a URL-prefix property looks like `https://example.com/`.

```sh
# List accessible properties
gsc sites

# Query search analytics by query and page for 28 days, with a comparison
gsc query 'sc-domain:example.com' --dims query,page --days 28 --compare

# Supply explicit dates and dimensions
gsc query 'https://example.com/' --start-date 2026-09-01 --end-date 2026-09-28 --dims query,page,country

# Filter using a JSON dimensionFilterGroups array
gsc query 'sc-domain:example.com' --filters '[{"groupType":"and","filters":[{"dimension":"query","operator":"contains","expression":"shoes"}]}]'

# Inspect a URL (indexed status, not a live test)
gsc inspect 'sc-domain:example.com' 'https://example.com/page'

# List or submit sitemaps
gsc sitemaps 'sc-domain:example.com'
GSC_ALLOW_WRITE=1 gsc submit-sitemap 'sc-domain:example.com' 'https://example.com/sitemap.xml'

# Run each built-in insight
gsc insights striking_distance 'sc-domain:example.com' --days 28
gsc insights low_ctr 'sc-domain:example.com' --min-impressions 100 --max-ctr 0.02
gsc insights cannibalization 'sc-domain:example.com'
gsc insights movers 'sc-domain:example.com' --days 28

# Machine-readable JSON
gsc --json sites
gsc query 'sc-domain:example.com' --days 28 --json
```

`gsc query` supports `--dims` (default `query,page`), `--days` (default `28`), `--start-date`, `--end-date`, `--filters`, `--limit` (default `1000`, maximum `25000`), `--compare`, and `--json`. If `--start-date` is supplied, `--end-date` is required. `--days` periods end three days ago because Search Console data typically lags by 2–3 days.

Insights support `--min-impressions` (default `100`; small sites can try `10`), `--max-ctr` (default `0.02`, a fraction), and the same date options. `--max-ctr` affects `low_ctr`.

Example shape from `gsc insights striking_distance 'sc-domain:example.com'` (illustrative data):

```json
{
  "type": "striking_distance",
  "period": { "startDate": "2026-10-05", "endDate": "2026-11-01" },
  "sampleLimit": 100000,
  "note": "Top rows only; API omissions and sampling may affect conclusions.",
  "result": [
    {
      "keys": ["example running shoes"],
      "clicks": 42,
      "impressions": 1800,
      "ctr": 0.0233,
      "position": 11.4
    }
  ]
}
```

Compare a period with the equal preceding period:

```sh
gsc query 'sc-domain:example.com' --dims query,page --days 28 --compare
```

The response contains `current`, `previous`, `previousPeriod`, and `changes` (including click change and position improvement).

### 9. Use with AI clients

The stdio MCP server runs as `gsc mcp`.

**Claude Code**

```sh
claude mcp add gsc -- gsc mcp
```

To pass a custom token path:

```sh
claude mcp add gsc -e GSC_TOKEN_FILE=/path/to/token.json -- gsc mcp
```

**Codex**

```sh
codex mcp add gsc -- gsc mcp
```

Equivalent `~/.codex/config.toml` configuration:

```toml
[mcp_servers.gsc]
command = "gsc"
args = ["mcp"]
```

**Cursor**

Add this to `.cursor/mcp.json` or `~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "gsc": {
      "command": "gsc",
      "args": ["mcp"]
    }
  }
}
```

**Any other MCP client**

Configure the client's stdio command as `gsc mcp`.

For Streamable HTTP on the local machine:

```sh
gsc mcp --http 8787
```

The endpoint is `http://127.0.0.1:8787/mcp`, and the server binds to loopback only. For remote access, put an authenticated TLS reverse proxy in front of it.

**Use as an agent skill**

Copy `SKILL.md` into `~/.claude/skills/gsc/` or `~/.codex/skills/gsc/`. The agent can then use the `gsc` CLI.

### 10. Troubleshooting

- **403**: Confirm your Google account has access to the property, the Search Console API is enabled, and the property name exactly matches `gsc sites` (`sc-domain:example.com` versus `https://example.com/`).
- **Empty results**: Check the property, date range, 2–3 day data lag, and insight thresholds. Try `--min-impressions 10` for a small site.
- **“Token refresh failed” / `invalid_grant`**: A Testing-mode refresh token may have expired after 7 days, or access may have been revoked. Run `gsc auth` again.
- **“No refresh token returned”**: Remove the app from [Google Account permissions](https://myaccount.google.com/permissions), then authenticate again.
- **ENOENT for token file**: Run `gsc auth`, or set `GSC_TOKEN_FILE` to the correct token path.
- **Port 8787 is in use**: Choose another port, such as `gsc mcp --http 8788`.
- **`gsc: command not found`**: Run `npm link`, check that npm's bin directory is on `PATH`, or use `node /path/to/gsc-mcp/dist/cli.js`.
- **Results seem incomplete**: Search analytics and insights return top rows, not a complete export. Insights sample at most 100,000 rows; Google may omit rows.

### 11. Security

- OAuth requests the read-only Search Console scope by default.
- The token stays on your machine at `~/.config/gsc-mcp/token.json` with mode `600`; override with `GSC_TOKEN_FILE`.
- Never commit tokens or credentials. `.gitignore` covers `token*.json`, `credentials*.json`, and `.env`.
- Write operations are disabled unless `GSC_ALLOW_WRITE=1`; sitemap submission also requires a write-scoped token and property permission.
- HTTP mode binds to `127.0.0.1`.
- Errors do not echo upstream response bodies.
- Revoke OAuth access at [Google Account permissions](https://myaccount.google.com/permissions).

### 12. Development and license

```sh
npm test
npm run build
```

Licensed under the MIT License. See [LICENSE](LICENSE).

## 中文

### 1. 为什么使用

Google 没有官方的 Search Console MCP。`gsc-mcp` 让你的 AI Agent 使用保存在本机的凭据,读取 Google 账号有权访问的 Search Console 资源。默认只读,并内置 SEO 数据洞察。

### 2. 功能

- 查询搜索表现、检查 URL,以及查看已提交的站点地图。
- 内置排名机会、低点击率、查询词页面竞争和表现变化洞察。
- CLI 与 MCP 服务集成在同一安装中,支持 stdio 和仅监听本机回环地址的 Streamable HTTP。
- 默认只读;提交站点地图属于需要主动开启的写入操作。

![洞察示例](docs/insights.png)

| MCP 工具名 | 对应 CLI 命令 | 功能 |
| --- | --- | --- |
| `list_sites` | `gsc sites` | 列出 Google 账号可访问的资源。 |
| `search_analytics` | `gsc query <site>` | 查询 Search Console 表现数据,可选与等长的前一时段比较。 |
| `inspect_url` | `gsc inspect <site> <url>` | 检查 Google 已收录的 URL 状态;这不是实时测试。 |
| `list_sitemaps` | `gsc sitemaps <site>` | 列出已提交的站点地图。 |
| `submit_sitemap` | `gsc submit-sitemap <site> <url>` | 提交站点地图。仅在设置 `GSC_ALLOW_WRITE=1` 后注册;需要写入授权范围的 OAuth 令牌和资源权限。 |
| `striking_distance` | `gsc insights striking_distance <site>` | 找出排名在第 6–20 位的查询词。 |
| `low_ctr` | `gsc insights low_ctr <site>` | 找出展示量达到门槛但点击率较低的查询词。 |
| `cannibalization` | `gsc insights cannibalization <site>` | 找出对应多个页面的查询词。 |
| `movers` | `gsc insights movers <site>` | 将查询词表现与等长的前一时段比较。 |

### 3. 环境要求

- Node.js 20 或更高版本
- npm
- git
- 一个有权访问 Search Console 资源的 Google 账号

### 4. 安装

```sh
git clone https://github.com/yan-labs/gsc-mcp.git
cd gsc-mcp
npm install
npm run build
npm link
gsc --help
```

如果不想执行 `npm link`,可以直接运行 CLI:

```sh
node /path/to/gsc-mcp/dist/cli.js --help
```

### 5. Google Cloud 设置

1. 在 [Google Cloud Console](https://console.cloud.google.com/) 创建项目。
2. 打开 **APIs & Services > Library**,找到 **Google Search Console API** 并启用。
3. 打开 **Google Auth Platform**(或 **OAuth consent screen**)并配置授权同意页面:
   - **User type** 选择 **External**。
   - 填写应用名称,以及要求的支持邮箱和开发者邮箱。
   - **Audience** 设为 **Testing**,并将自己的 Google 账号添加为测试用户。
4. 打开 **Clients > Create client**,将 **Application type** 设为 **Desktop app**。
5. 复制 **Client ID** 和 **Client secret**。下载 JSON 文件是可选的。

应用处于 Testing 状态时,Google 签发的 refresh token 会在 7 天后过期。每周重新运行 `gsc auth`,或将发布状态设为 **In production**。个人使用只读 `webmasters` scope 时,Google 可能显示“应用未验证”警告;可通过 **Advanced** 继续。只有公开分发时才需要验证。

### 6. 授权

设置桌面 OAuth 客户端凭据并启动本地授权流程:

```sh
GSC_CLIENT_ID='your-client-id' GSC_CLIENT_SECRET='your-client-secret' gsc auth
```

命令会打印一个 Google 链接。用浏览器打开并批准访问。临时回调服务器会在 `127.0.0.1` 的随机端口监听。令牌默认保存到 `~/.config/gsc-mcp/token.json`,文件权限为 `600`。设置 `GSC_TOKEN_FILE` 可更改路径。

如果机器没有图形界面或位于远程,可在有浏览器的机器上运行 `gsc auth` 并安全复制令牌文件,或通过 SSH 端口转发访问回调。

如需站点地图提交权限,使用以下命令授权:

```sh
GSC_CLIENT_ID='your-client-id' GSC_CLIENT_SECRET='your-client-secret' gsc auth --write
```

检查访问权限,并从输出中复制完全一致的资源名称:

```sh
gsc sites
```

### 7. 服务账号方式

1. 在 Google Cloud 创建服务账号,并为其创建 JSON 密钥。
2. 在 Search Console 打开 **Settings > Users and permissions > Add user**,添加服务账号邮箱。只读访问使用 **Restricted** 权限即可。
3. 将环境变量指向 JSON 密钥:

```sh
export GOOGLE_APPLICATION_CREDENTIALS='/path/to/key.json'
gsc sites
```

### 8. CLI 用法

资源名称必须与 `gsc sites` 输出完全一致。Domain 资源格式如 `sc-domain:example.com`;URL-prefix 资源格式如 `https://example.com/`。

```sh
# 列出可访问的资源
gsc sites

# 查询 28 天内按查询词和页面统计的表现,并进行对比
gsc query 'sc-domain:example.com' --dims query,page --days 28 --compare

# 指定日期和维度
gsc query 'https://example.com/' --start-date 2026-09-01 --end-date 2026-09-28 --dims query,page,country

# 使用 JSON dimensionFilterGroups 数组筛选
gsc query 'sc-domain:example.com' --filters '[{"groupType":"and","filters":[{"dimension":"query","operator":"contains","expression":"shoes"}]}]'

# 检查 URL(检查收录状态,不是实时测试)
gsc inspect 'sc-domain:example.com' 'https://example.com/page'

# 查看或提交站点地图
gsc sitemaps 'sc-domain:example.com'
GSC_ALLOW_WRITE=1 gsc submit-sitemap 'sc-domain:example.com' 'https://example.com/sitemap.xml'

# 运行各项内置洞察
gsc insights striking_distance 'sc-domain:example.com' --days 28
gsc insights low_ctr 'sc-domain:example.com' --min-impressions 100 --max-ctr 0.02
gsc insights cannibalization 'sc-domain:example.com'
gsc insights movers 'sc-domain:example.com' --days 28

# 输出机器可读的 JSON
gsc --json sites
gsc query 'sc-domain:example.com' --days 28 --json
```

`gsc query` 支持 `--dims`(默认 `query,page`)、`--days`(默认 `28`)、`--start-date`、`--end-date`、`--filters`、`--limit`(默认 `1000`,最大 `25000`)、`--compare` 和 `--json`。指定 `--start-date` 时必须同时指定 `--end-date`。由于 Search Console 数据通常延迟 2–3 天,`--days` 时段的结束日期是三天前。

洞察命令支持 `--min-impressions`(默认 `100`;小站点可尝试 `10`)、`--max-ctr`(默认 `0.02`,按比例填写)以及相同的日期选项。`--max-ctr` 仅影响 `low_ctr`。

`gsc insights striking_distance 'sc-domain:example.com'` 的输出结构示例(数据为示意):

```json
{
  "type": "striking_distance",
  "period": { "startDate": "2026-10-05", "endDate": "2026-11-01" },
  "sampleLimit": 100000,
  "note": "Top rows only; API omissions and sampling may affect conclusions.",
  "result": [
    {
      "keys": ["example running shoes"],
      "clicks": 42,
      "impressions": 1800,
      "ctr": 0.0233,
      "position": 11.4
    }
  ]
}
```

将某一时段与等长的前一时段比较:

```sh
gsc query 'sc-domain:example.com' --dims query,page --days 28 --compare
```

响应包含 `current`、`previous`、`previousPeriod` 和 `changes`(包括点击变化量和排名提升幅度)。

### 9. 与 AI 客户端配合使用

stdio MCP 服务命令为 `gsc mcp`。

**Claude Code**

```sh
claude mcp add gsc -- gsc mcp
```

指定令牌路径:

```sh
claude mcp add gsc -e GSC_TOKEN_FILE=/path/to/token.json -- gsc mcp
```

**Codex**

```sh
codex mcp add gsc -- gsc mcp
```

等效的 `~/.codex/config.toml` 配置:

```toml
[mcp_servers.gsc]
command = "gsc"
args = ["mcp"]
```

**Cursor**

将以下内容添加到 `.cursor/mcp.json` 或 `~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "gsc": {
      "command": "gsc",
      "args": ["mcp"]
    }
  }
}
```

**其他 MCP 客户端**

将客户端的 stdio 命令设为 `gsc mcp`。

在本机启动 Streamable HTTP:

```sh
gsc mcp --http 8787
```

端点为 `http://127.0.0.1:8787/mcp`,服务只绑定本机回环地址。需要远程访问时,请在前方配置经过身份验证的 TLS 反向代理。

**作为 Agent Skill 使用**

将 `SKILL.md` 复制到 `~/.claude/skills/gsc/` 或 `~/.codex/skills/gsc/`。之后 Agent 就可以使用 `gsc` CLI。

### 10. 故障排查

- **403**:确认 Google 账号有该资源的访问权限、Search Console API 已启用,且资源名与 `gsc sites` 完全一致(`sc-domain:example.com` 和 `https://example.com/` 是不同格式)。
- **结果为空**:检查资源、日期范围、2–3 天的数据延迟和洞察阈值。小站点可尝试 `--min-impressions 10`。
- **“Token refresh failed” / `invalid_grant`**:Testing 状态下的 refresh token 可能已在 7 天后过期,也可能已撤销。重新运行 `gsc auth`。
- **“No refresh token returned”**:在 [Google 账号权限](https://myaccount.google.com/permissions)中移除该应用,然后重新授权。
- **令牌文件报 ENOENT**:运行 `gsc auth`,或将 `GSC_TOKEN_FILE` 设为正确的令牌路径。
- **8787 端口已占用**:换一个端口,例如 `gsc mcp --http 8788`。
- **`gsc: command not found`**:运行 `npm link`,检查 npm 的 bin 目录是否在 `PATH` 中,或使用 `node /path/to/gsc-mcp/dist/cli.js`。
- **结果看起来不完整**:搜索分析和洞察返回的是排名靠前的数据行,不是完整导出。洞察最多抽样 100,000 行;Google 也可能省略部分行。

### 11. 安全

- OAuth 默认请求 Search Console 只读 scope。
- 令牌保存在本机 `~/.config/gsc-mcp/token.json`,权限为 `600`;可用 `GSC_TOKEN_FILE` 更改路径。
- 不要提交令牌或凭据。`.gitignore` 已覆盖 `token*.json`、`credentials*.json` 和 `.env`。
- 除非设置 `GSC_ALLOW_WRITE=1`,否则写入操作不可用;提交站点地图还需要写入 scope 的令牌和资源权限。
- HTTP 模式只绑定 `127.0.0.1`。
- 错误信息不会回显上游响应正文。
- 可在 [Google 账号权限](https://myaccount.google.com/permissions)撤销 OAuth 授权。

### 12. 开发与许可证

```sh
npm test
npm run build
```

本项目采用 MIT License,详见 [LICENSE](LICENSE)。

TDQS

C2.5/5.0

Scored across 8 tools

Disambiguation3/5

The core tools (list_sites, search_analytics, inspect_url, list_sitemaps) are clearly distinct, but the four insight tools have tautological descriptions ("Search Console insight: striking_distance") that give no real explanation, forcing the agent to infer meaning from names. All five analytics-related tools draw from the same underlying Search Console data, so the boundary between search_analytics and striking_distance/low_ctr/movers/cannibalization is unclear.

Naming Consistency3/5

Four tools follow a clean verb_noun convention (list_sites, search_analytics, inspect_url, list_sitemaps) while the four insight tools are bare noun phrases (striking_distance, low_ctr, cannibalization, movers). The style split is systematic but still breaks predictability about whether a tool is an action or a report.

Tool Count5/5

Eight tools is a well-scoped size for a Search Console analytics server, with room for site/sitemap listing, querying, inspection, and canned insights. Nothing feels padded or missing at the count level.

Completeness3/5

The surface covers discovery (sites, sitemaps), reporting (search_analytics), and inspection, but sitemaps are read-only — no submit or delete operation — and sites cannot be added or removed. For a diagnostics-oriented server this is workable, but sitemap submission is a standard Search Console operation that agents will hit as a dead end.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues