@vmandic/searchconsole-mcp 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -29
- package/dist/server.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Search Console MCP
|
|
2
2
|
|
|
3
3
|
[](https://github.com/vmandic/searchconsole-mcp/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/vmandic/searchconsole-mcp/releases/latest)
|
|
5
|
+
[](https://www.npmjs.com/package/@vmandic/searchconsole-mcp)
|
|
4
6
|
[](LICENSE)
|
|
5
7
|
[](package.json)
|
|
6
8
|
[](https://modelcontextprotocol.io)
|
|
@@ -33,6 +35,7 @@ Connect Cursor, Claude Desktop, or any MCP client to your GSC properties: search
|
|
|
33
35
|
- [Configuration](#configuration)
|
|
34
36
|
- [Troubleshooting](#troubleshooting)
|
|
35
37
|
- [Development](#development)
|
|
38
|
+
- [Releases and npm package](#releases-and-npm-package)
|
|
36
39
|
- [License](#license)
|
|
37
40
|
|
|
38
41
|
---
|
|
@@ -135,6 +138,8 @@ When finished, summarize: clone path, GCP project ID, config file edited, and th
|
|
|
135
138
|
|
|
136
139
|
Use this if you prefer to run commands yourself.
|
|
137
140
|
|
|
141
|
+
**Fastest path (npm):** install from [@vmandic/searchconsole-mcp](https://www.npmjs.com/package/@vmandic/searchconsole-mcp), complete [Google authentication](#google-authentication), then [connect your MCP client](#connect-your-mcp-client) with `npx` (see [Option A — Install from npm](#option-a--install-from-npm-recommended)).
|
|
142
|
+
|
|
138
143
|
**1. Install and build** (from source):
|
|
139
144
|
|
|
140
145
|
```bash
|
|
@@ -197,7 +202,44 @@ Optional: [Google Cloud SDK](https://cloud.google.com/sdk) (`gcloud`) for the in
|
|
|
197
202
|
|
|
198
203
|
## Installation
|
|
199
204
|
|
|
200
|
-
|
|
205
|
+
Published on npm as [**`@vmandic/searchconsole-mcp`**](https://www.npmjs.com/package/@vmandic/searchconsole-mcp). The name is scoped because npm rejects unscoped `searchconsole-mcp` as too similar to [`search-console-mcp`](https://www.npmjs.com/package/search-console-mcp) (a different package).
|
|
206
|
+
|
|
207
|
+
### Option A — Install from npm (recommended)
|
|
208
|
+
|
|
209
|
+
No clone required. You still need [Google authentication](#google-authentication) on the machine.
|
|
210
|
+
|
|
211
|
+
**Run once (smoke test):**
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
npx -y @vmandic/searchconsole-mcp --help
|
|
215
|
+
npx -y @vmandic/searchconsole-mcp --version
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Global CLI (optional):**
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
npm install -g @vmandic/searchconsole-mcp
|
|
222
|
+
searchconsole-mcp --help
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**MCP client (stdio via `npx`)** — works in Cursor, Claude Code, Copilot, Codex, Claude Desktop. Example for **Cursor** (`~/.cursor/mcp.json`):
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
{
|
|
229
|
+
"mcpServers": {
|
|
230
|
+
"searchconsole-mcp": {
|
|
231
|
+
"command": "npx",
|
|
232
|
+
"args": ["-y", "@vmandic/searchconsole-mcp"]
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
After `npm install -g`, you can use `"command": "searchconsole-mcp"` and `"args": []` instead.
|
|
239
|
+
|
|
240
|
+
Restart the MCP client, then try *“List my Search Console properties”* (`gsc_list_sites`).
|
|
241
|
+
|
|
242
|
+
### Option B — Run from a clone (development)
|
|
201
243
|
|
|
202
244
|
```bash
|
|
203
245
|
git clone https://github.com/vmandic/searchconsole-mcp.git
|
|
@@ -214,24 +256,18 @@ node dist/server.js --help
|
|
|
214
256
|
node dist/server.js --version
|
|
215
257
|
```
|
|
216
258
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
```bash
|
|
220
|
-
npm link -g
|
|
221
|
-
searchconsole-mcp --help
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
Then point your MCP client at `searchconsole-mcp` instead of `node …/dist/server.js`.
|
|
259
|
+
Point your MCP client at `node /absolute/path/to/searchconsole-mcp/dist/server.js` (see [Connect your MCP client](#connect-your-mcp-client)).
|
|
225
260
|
|
|
226
|
-
### Option C —
|
|
261
|
+
### Option C — Global CLI from a local build
|
|
227
262
|
|
|
228
|
-
|
|
263
|
+
From a clone after `npm run build`:
|
|
229
264
|
|
|
230
265
|
```bash
|
|
231
|
-
|
|
266
|
+
npm link -g
|
|
267
|
+
searchconsole-mcp --help
|
|
232
268
|
```
|
|
233
269
|
|
|
234
|
-
|
|
270
|
+
Then use `"command": "searchconsole-mcp"` in MCP config instead of `node …/dist/server.js`.
|
|
235
271
|
|
|
236
272
|
---
|
|
237
273
|
|
|
@@ -309,9 +345,10 @@ Every client runs the **same local Node.js MCP server** (`searchconsole-mcp`). T
|
|
|
309
345
|
|
|
310
346
|
**Before you connect any client**
|
|
311
347
|
|
|
312
|
-
1.
|
|
313
|
-
2.
|
|
314
|
-
|
|
348
|
+
1. Complete [Google authentication](#google-authentication) (ADC) once on the machine.
|
|
349
|
+
2. Choose how to start the server:
|
|
350
|
+
- **npm:** [Option A](#option-a--install-from-npm-recommended) — `npx -y @vmandic/searchconsole-mcp` or global `searchconsole-mcp`
|
|
351
|
+
- **Clone:** run `npm run build` so `dist/server.js` exists, then use an **absolute path** in config (or `npm link -g` / Option C)
|
|
315
352
|
|
|
316
353
|
**If you use more than one client**, set up **Claude Code first**. You will reuse the same binary and credentials; doing auth and paths once avoids confusion when you add Cursor, Copilot, or Codex.
|
|
317
354
|
|
|
@@ -377,7 +414,20 @@ Edit **`~/.cursor/mcp.json`** (or MCP settings in the project):
|
|
|
377
414
|
}
|
|
378
415
|
```
|
|
379
416
|
|
|
380
|
-
|
|
417
|
+
**From npm (`npx`, no clone):**
|
|
418
|
+
|
|
419
|
+
```json
|
|
420
|
+
{
|
|
421
|
+
"mcpServers": {
|
|
422
|
+
"searchconsole-mcp": {
|
|
423
|
+
"command": "npx",
|
|
424
|
+
"args": ["-y", "@vmandic/searchconsole-mcp"]
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**After `npm link -g` or `npm install -g @vmandic/searchconsole-mcp`:**
|
|
381
431
|
|
|
382
432
|
```json
|
|
383
433
|
"command": "searchconsole-mcp",
|
|
@@ -578,18 +628,20 @@ This server can access **your** Search Console data using **your** Google creden
|
|
|
578
628
|
|
|
579
629
|
## Transports: stdio vs HTTP
|
|
580
630
|
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
631
|
+
```mermaid
|
|
632
|
+
flowchart LR
|
|
633
|
+
subgraph clients [MCP clients]
|
|
634
|
+
C["MCP client (Cursor, Claude, …)"]
|
|
635
|
+
H["MCP client (optional)"]
|
|
636
|
+
end
|
|
637
|
+
S["searchconsole-mcp\nNode process"]
|
|
638
|
+
G["Google Search\nConsole API"]
|
|
639
|
+
A["ADC / service account"]
|
|
640
|
+
|
|
641
|
+
C <-->|"stdio: stdin/stdout JSON-RPC (default)"| S
|
|
642
|
+
H <-->|"HTTP: POST/GET /mcp (--transport http)"| S
|
|
643
|
+
S --> G
|
|
644
|
+
A -.->|credentials| S
|
|
593
645
|
```
|
|
594
646
|
|
|
595
647
|
### Stdio (default, recommended)
|
|
@@ -692,6 +744,25 @@ Contributions welcome via [issues](https://github.com/vmandic/searchconsole-mcp/
|
|
|
692
744
|
|
|
693
745
|
---
|
|
694
746
|
|
|
747
|
+
## Releases and npm package
|
|
748
|
+
|
|
749
|
+
| What | Where |
|
|
750
|
+
|------|--------|
|
|
751
|
+
| **Version history** | [CHANGELOG.md](CHANGELOG.md) |
|
|
752
|
+
| **GitHub Releases** (tags, notes) | [github.com/vmandic/searchconsole-mcp/releases](https://github.com/vmandic/searchconsole-mcp/releases) |
|
|
753
|
+
| **Latest release** | [releases/latest](https://github.com/vmandic/searchconsole-mcp/releases/latest) |
|
|
754
|
+
| **npm package** (install) | [@vmandic/searchconsole-mcp](https://www.npmjs.com/package/@vmandic/searchconsole-mcp) |
|
|
755
|
+
|
|
756
|
+
Install the published build:
|
|
757
|
+
|
|
758
|
+
```bash
|
|
759
|
+
npx -y @vmandic/searchconsole-mcp
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
**GitHub Packages** ([packages](https://github.com/vmandic/searchconsole-mcp/packages)) is not used for distribution; this project publishes to the public npm registry. See [docs/RELEASES.md](docs/RELEASES.md) for maintainer release steps and version alignment.
|
|
763
|
+
|
|
764
|
+
---
|
|
765
|
+
|
|
695
766
|
## License
|
|
696
767
|
|
|
697
768
|
[MIT](LICENSE) — Copyright (c) Vedran Mandić and contributors.
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var ut=Object.defineProperty;var u=(t,e)=>()=>(t&&(e=t(t=0)),e);var dt=(t,e)=>{for(var o in e)ut(t,o,{get:e[o],enumerable:!0})};var F,A,R,$,N,G=u(()=>{"use strict";F="searchconsole-mcp",A="https://www.googleapis.com/auth/webmasters.readonly",R=A,$="https://www.googleapis.com/auth/analytics.readonly,https://www.googleapis.com/auth/cloud-platform,"+A,N="1.0.
|
|
2
|
+
var ut=Object.defineProperty;var u=(t,e)=>()=>(t&&(e=t(t=0)),e);var dt=(t,e)=>{for(var o in e)ut(t,o,{get:e[o],enumerable:!0})};var F,A,R,$,N,G=u(()=>{"use strict";F="searchconsole-mcp",A="https://www.googleapis.com/auth/webmasters.readonly",R=A,$="https://www.googleapis.com/auth/analytics.readonly,https://www.googleapis.com/auth/cloud-platform,"+A,N="1.0.1"});function mt(t){if(!(t instanceof Error))return;let e=t,o=e.response?.data?.error?.status;if(typeof o=="string")return o;if(typeof e.code=="string")return e.code}function b(t){if(!(t instanceof Error))return"An unexpected error occurred.";let e=mt(t),o=t.message;return e==="UNAUTHENTICATED"||o.includes("UNAUTHENTICATED")||o.includes("Could not load the default credentials")||o.includes("insufficient authentication scopes")?`Authentication failed. Run: gcloud auth application-default login --scopes=${R}`:e==="PERMISSION_DENIED"||o.includes("PERMISSION_DENIED")||o.includes("Forbidden")?"Permission denied. Ensure your Google account has access to this Search Console property.":e==="NOT_FOUND"||o.includes("NOT_FOUND")?'Site or resource not found. Check site_url matches GSC (e.g. "https://example.com/" with trailing slash).':e==="RESOURCE_EXHAUSTED"||o.includes("RESOURCE_EXHAUSTED")||o.includes("quota")?"API quota exceeded. Please wait a moment and try again.":e==="INVALID_ARGUMENT"||o.includes("INVALID_ARGUMENT")?"Invalid request parameters. Check site_url, dates, and dimension names.":o.replace(/projects\/[^\s/]+/g,"projects/***").replace(/\/home\/[^\s/]+/g,"/home/***").replace(/\/Users\/[^\s/]+/g,"/Users/***").replace(/at\s+.+\(.+:\d+:\d+\)/g,"").trim()||"An unexpected error occurred."}function S(t){return b(t)}var O=u(()=>{"use strict";G()});import{searchconsole as St}from"@googleapis/searchconsole";function g(t){return K||(M||(M=St({version:"v1",auth:t})),M)}var M,K,x=u(()=>{"use strict";M=null,K=null});async function Q(t,e){return(await g(t).searchanalytics.query({siteUrl:e.site_url,requestBody:{startDate:e.start_date,endDate:e.end_date,dimensions:e.dimensions,type:e.type,rowLimit:e.row_limit,startRow:e.start_row,dimensionFilterGroups:e.dimension_filter_groups,aggregationType:e.aggregation_type,dataState:e.data_state}})).data}var Z=u(()=>{"use strict";x()});async function tt(t,e){return(await g(t).urlInspection.index.inspect({requestBody:{siteUrl:e.site_url,inspectionUrl:e.inspection_url,languageCode:e.language_code??"en-US"}})).data}var et=u(()=>{"use strict";x()});async function ot(t,e){return(await g(t).sitemaps.list({siteUrl:e})).data}var rt=u(()=>{"use strict";x()});async function st(t){return(await g(t).sites.list({})).data}var nt=u(()=>{"use strict";x()});import{z as s}from"zod";var it,k,yt,wt,Tt,xt,p,E,U,at=u(()=>{"use strict";it=s.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Expected YYYY-MM-DD"),k=s.string().min(1).max(2048).refine(t=>t.startsWith("sc-domain:")||/^https?:\/\//i.test(t),{message:"site_url must start with https:// or sc-domain:"}),yt=s.enum(["query","page","country","device","searchAppearance","date"]),wt=s.enum(["web","image","video","news","discover","googleNews"]),Tt=s.object({dimension:s.string().min(1).max(64),operator:s.string().min(1).max(32),expression:s.string().min(1).max(512)}),xt=s.object({groupType:s.string().max(32).optional(),filters:s.array(Tt).max(20).optional()}),p=s.object({site_url:k,start_date:it,end_date:it,dimensions:s.array(yt).max(5).optional(),type:wt.optional(),row_limit:s.number().int().min(1).max(25e3).optional(),start_row:s.number().int().min(0).max(24999).optional(),dimension_filter_groups:s.array(xt).max(5).optional(),aggregation_type:s.enum(["auto","byProperty","byPage"]).optional(),data_state:s.enum(["final","all"]).optional()}),E=s.object({site_url:k,inspection_url:s.string().url().max(2048),language_code:s.string().min(2).max(16).optional()}),U=s.object({site_url:k})});var ct={};dt(ct,{registerGscTools:()=>Ct});function I(t){return{content:[{type:"text",text:JSON.stringify(t,null,2)}]}}function Et(t){return{content:[{type:"text",text:t}],isError:!0}}function D(t,e){return async o=>{let r=t.safeParse(o);if(!r.success)return Et(`Invalid request parameters. ${JSON.stringify(r.error.flatten(),null,2)}`);try{return await e(r.data)}catch(i){return{content:[{type:"text",text:b(i)}],isError:!0}}}}function Ct(t,e){t.tool("gsc_mcp_server_ping","Liveness check for this MCP server process (local Node.js). Returns pong. Does not call Google Search Console.",{},async()=>({content:[{type:"text",text:"pong"}]})),t.tool("gsc_list_sites","Lists all sites (properties) the authenticated user has access to in Google Search Console.",{},async()=>{try{return I(await st(e))}catch(o){return{content:[{type:"text",text:b(o)}],isError:!0}}}),t.tool("gsc_search_analytics","Queries Google Search Console search analytics data \u2014 impressions, clicks, CTR, and position for queries, pages, countries, and devices.",{site_url:p.shape.site_url,start_date:p.shape.start_date,end_date:p.shape.end_date,dimensions:p.shape.dimensions,type:p.shape.type,row_limit:p.shape.row_limit,start_row:p.shape.start_row,dimension_filter_groups:p.shape.dimension_filter_groups,aggregation_type:p.shape.aggregation_type,data_state:p.shape.data_state},D(p,async o=>I(await Q(e,o)))),t.tool("gsc_inspect_url","Inspects a URL in Google Search Console \u2014 index status, crawl info, mobile usability, and rich results.",{site_url:E.shape.site_url,inspection_url:E.shape.inspection_url,language_code:E.shape.language_code},D(E,async o=>I(await tt(e,o)))),t.tool("gsc_list_sitemaps","Lists all sitemaps submitted for a site in Google Search Console.",{site_url:U.shape.site_url},D(U,async({site_url:o})=>I(await ot(e,o))))}var pt=u(()=>{"use strict";O();Z();et();rt();nt();at()});function V(){let t=process.stdout.write.bind(process.stdout),e=process.stderr.write.bind(process.stderr);return console.log=(...o)=>{e(Buffer.from(o.join(" ")+`
|
|
3
3
|
`))},console.info=console.log,console.debug=console.log,console.warn=(...o)=>{e(Buffer.from("[WARN] "+o.join(" ")+`
|
|
4
4
|
`))},process.stdout.write=((o,r,i)=>(typeof o=="string"?o:o?.toString?.()??"").includes('"jsonrpc"')?t(o,r,i):e(o,r,i)),{writeStdout:t,writeStderr:e}}G();var _="127.0.0.1";var Y=["stdio","http"];function H(t,e,o){let r=t.indexOf(e);if(r!==-1&&t[r+1])return t[r+1];if(o)return process.env[o]}function J(t){t(`searchconsole-mcp \u2014 Google Search Console MCP server (read-only)
|
|
5
5
|
|