@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.
Files changed (3) hide show
  1. package/README.md +100 -29
  2. package/dist/server.js +1 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Search Console MCP
2
2
 
3
3
  [![CI](https://github.com/vmandic/searchconsole-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/vmandic/searchconsole-mcp/actions/workflows/ci.yml)
4
+ [![GitHub release](https://img.shields.io/github/v/release/vmandic/searchconsole-mcp?include_prereleases)](https://github.com/vmandic/searchconsole-mcp/releases/latest)
5
+ [![npm version](https://img.shields.io/npm/v/@vmandic/searchconsole-mcp.svg)](https://www.npmjs.com/package/@vmandic/searchconsole-mcp)
4
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
7
  [![Node](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](package.json)
6
8
  [![MCP](https://img.shields.io/badge/MCP-Model%20Context%20Protocol-6366f1)](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
- ### Option A Run from a clone (recommended for development)
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
- ### Option B Global CLI after build
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 — `npx` (when published to npm)
261
+ ### Option C — Global CLI from a local build
227
262
 
228
- The package is published under the **`@vmandic`** scope because npm blocks the unscoped name as too similar to [`search-console-mcp`](https://www.npmjs.com/package/search-console-mcp).
263
+ From a clone after `npm run build`:
229
264
 
230
265
  ```bash
231
- npx -y @vmandic/searchconsole-mcp
266
+ npm link -g
267
+ searchconsole-mcp --help
232
268
  ```
233
269
 
234
- Until the package is on npm, use Option A or B from a local clone.
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. Run `npm run build` so `dist/server.js` exists.
313
- 2. Complete [Google authentication](#google-authentication) (ADC) once on the machine.
314
- 3. Use an **absolute path** to `dist/server.js` in config (or `searchconsole-mcp` after `npm link -g`).
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
- After `npm link -g`:
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
- ┌─────────────┐ stdin/stdout (JSON-RPC) ┌──────────────┐
583
- MCP client │ ◄──────────────────────────────► │ searchconsole-mcp │
584
- (Cursor) │ default: stdio │ + Google │
585
- └─────────────┘ │ Search │
586
- │ Console API│
587
- ┌─────────────┐ HTTP POST/GET /mcp └──────────────┘
588
- MCP client │ ◄──────────────────────────────► ▲
589
- │ (optional) │ --transport http │
590
- └─────────────┘ │
591
- ADC /
592
- service account
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.0"});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(" ")+`
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vmandic/searchconsole-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Read-only Google Search Console MCP server for Cursor and other MCP clients.",
5
5
  "type": "module",
6
6
  "bin": {