mcp-google-gsc 1.1.2 → 1.1.4
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/dist/build-info.json +3 -3
- package/dist/embedded-secrets.js +2 -2
- package/dist/embedded-secrets.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +2 -2
- package/package.json +4 -3
package/dist/build-info.json
CHANGED
package/dist/embedded-secrets.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const EMBEDDED_CLIENT_ID = "
|
|
2
|
-
const EMBEDDED_CLIENT_SECRET = "
|
|
1
|
+
const EMBEDDED_CLIENT_ID = "";
|
|
2
|
+
const EMBEDDED_CLIENT_SECRET = "";
|
|
3
3
|
function hasEmbeddedSecrets() {
|
|
4
4
|
return EMBEDDED_CLIENT_ID.length > 10 && EMBEDDED_CLIENT_SECRET.length > 10;
|
|
5
5
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/embedded-secrets.ts"],
|
|
4
4
|
"sourcesContent": ["// ============================================\n// BUILD-TIME INJECTED SECRETS\n// ============================================\n// Replaced by esbuild --define at build time. In dev mode (tsx),\n// falls back to runtime env vars via credentials.ts.\n//\n// GSC only needs client_id + client_secret (no developer token).\n// Google Desktop OAuth client ID/secret are NOT true secrets per Google docs.\n\nexport const EMBEDDED_CLIENT_ID: string = process.env.EMBEDDED_CLIENT_ID || \"\";\nexport const EMBEDDED_CLIENT_SECRET: string = process.env.EMBEDDED_CLIENT_SECRET || \"\";\n\nexport function hasEmbeddedSecrets(): boolean {\n return EMBEDDED_CLIENT_ID.length > 10 && EMBEDDED_CLIENT_SECRET.length > 10;\n}\n"],
|
|
5
|
-
"mappings": "AASO,MAAM,
|
|
5
|
+
"mappings": "AASO,MAAM,qBAA+D;AACrE,MAAM,yBAAuE;AAE7E,SAAS,qBAA8B;AAC5C,SAAO,mBAAmB,SAAS,MAAM,uBAAuB,SAAS;AAC3E;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.js
CHANGED
|
@@ -68,7 +68,8 @@ if (heapLimit < 256 * 1024 * 1024) {
|
|
|
68
68
|
}
|
|
69
69
|
const envTrimmed = (key) => (process.env[key] || "").trim().replace(/^["']|["']$/g, "");
|
|
70
70
|
function loadConfig() {
|
|
71
|
-
const
|
|
71
|
+
const defaultConfigPath = join(dirname(new URL(import.meta.url).pathname), "..", "config.json");
|
|
72
|
+
const configPath = envTrimmed("MCP_GSC_CONFIG_PATH") || defaultConfigPath;
|
|
72
73
|
if (existsSync(configPath)) {
|
|
73
74
|
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
74
75
|
const rawCf = raw.credentials_file || envTrimmed("GOOGLE_APPLICATION_CREDENTIALS");
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { readFileSync, existsSync } from \"fs\";\nimport { join, dirname, resolve, isAbsolute } from \"path\";\nimport { google, searchconsole_v1 } from \"googleapis\";\nimport { GoogleAuth, OAuth2Client } from \"googleapis-common\";\nimport {\n GscAuthError,\n GscRateLimitError,\n GscServiceError,\n classifyError,\n validateCredentials,\n} from \"./errors.js\";\nimport { resolveOAuthCredentials } from \"./credentials.js\";\nimport { EMBEDDED_CLIENT_ID, EMBEDDED_CLIENT_SECRET } from \"./embedded-secrets.js\";\nimport { tools } from \"./tools.js\";\nimport { withResilience, safeResponse, logger } from \"./resilience.js\";\nimport { checkForUpdate } from \"./updateNotifier.js\";\nimport v8 from \"v8\";\n\n// CLI package info\nconst __cliPkg = JSON.parse(readFileSync(join(dirname(new URL(import.meta.url).pathname), \"..\", \"package.json\"), \"utf-8\"));\n\n// Log build fingerprint at startup\ntry {\n const __buildInfoDir = dirname(new URL(import.meta.url).pathname);\n const buildInfo = JSON.parse(readFileSync(join(__buildInfoDir, \"build-info.json\"), \"utf-8\"));\n console.error(`[build] SHA: ${buildInfo.sha} (${buildInfo.builtAt})`);\n} catch {\n console.error(`[build] ${__cliPkg.name}@${__cliPkg.version} (dev mode)`);\n}\n\n// Version safety: warn if running a deprecated or dangerously old version\nconst __minimumSafeVersion = \"1.0.5\"; // minimum version with input sanitization\nconst __semverLt = (a: string, b: string) => { const pa = a.split(\".\").map(Number), pb = b.split(\".\").map(Number); for (let i = 0; i < 3; i++) { if ((pa[i] || 0) < (pb[i] || 0)) return true; if ((pa[i] || 0) > (pb[i] || 0)) return false; } return false; };\nif (__semverLt(__cliPkg.version, __minimumSafeVersion)) {\n console.error(`[WARNING] Running deprecated version ${__cliPkg.version}. Minimum safe version is ${__minimumSafeVersion}. Please upgrade.`);\n}\n\n// Fire-and-forget npm outdated check. Non-blocking; any error is swallowed.\nvoid checkForUpdate(__cliPkg.name, __cliPkg.version).catch(() => {});\n\n// CLI flags\nif (process.argv.includes(\"--help\") || process.argv.includes(\"-h\")) {\n console.error(`${__cliPkg.name} v${__cliPkg.version}\\n`);\n console.error(`Usage: ${__cliPkg.name} [options]\\n`);\n console.error(\"MCP server communicating via stdio. Configure in your .mcp.json.\\n\");\n console.error(\"Options:\");\n console.error(\" --help, -h Show this help message\");\n console.error(\" --version, -v Show version number\");\n console.error(`\\nDocumentation: https://github.com/mharnett/mcp-search-console`);\n process.exit(0);\n}\nif (process.argv.includes(\"--version\") || process.argv.includes(\"-v\")) {\n console.error(__cliPkg.version);\n process.exit(0);\n}\n\n// Startup: detect npx vs direct node\nif (process.argv[1]?.includes('.npm/_npx')) {\n console.error(\"[startup] Running via npx -- first run may be slow due to package resolution\");\n}\n\n// Startup: check heap size\nconst heapLimit = v8.getHeapStatistics().heap_size_limit;\nif (heapLimit < 256 * 1024 * 1024) {\n console.error(`[startup] WARNING: Heap limit is ${Math.round(heapLimit / 1024 / 1024)}MB`);\n}\n\n// ============================================\n// ENV VAR TRIMMING\n// ============================================\n\nconst envTrimmed = (key: string): string => (process.env[key] || \"\").trim().replace(/^[\"']|[\"']$/g, \"\");\n\n// ============================================\n// CONFIGURATION\n// ============================================\n\ninterface ClientConfig {\n name: string;\n folder: string;\n site_url: string;\n}\n\ninterface Config {\n credentials_file: string;\n clients: Record<string, ClientConfig>;\n}\n\nfunction loadConfig(): Config {\n // Try config.json (for multi-client setups)\n const configPath = join(dirname(new URL(import.meta.url).pathname), \"..\", \"config.json\");\n if (existsSync(configPath)) {\n const raw = JSON.parse(readFileSync(configPath, \"utf-8\"));\n const rawCf = raw.credentials_file || envTrimmed(\"GOOGLE_APPLICATION_CREDENTIALS\");\n return {\n credentials_file: rawCf && !isAbsolute(rawCf) ? resolve(rawCf) : rawCf,\n clients: raw.clients || {},\n };\n }\n\n // Fall back to env vars for service account\n const rawCredsFile = envTrimmed(\"GOOGLE_APPLICATION_CREDENTIALS\");\n const credsFile = rawCredsFile && !isAbsolute(rawCredsFile) ? resolve(rawCredsFile) : rawCredsFile;\n if (credsFile) {\n return {\n credentials_file: credsFile,\n clients: {},\n };\n }\n\n // Fall back to OAuth credentials (from mcp-gsc-auth or env vars)\n // Return empty credentials_file to signal OAuth mode\n return {\n credentials_file: \"\",\n clients: {},\n };\n}\n\nfunction getClientFromWorkingDir(config: Config, cwd: string): ClientConfig | null {\n for (const [key, client] of Object.entries(config.clients)) {\n if (cwd.startsWith(client.folder) || cwd.includes(key)) {\n return client;\n }\n }\n return null;\n}\n\nfunction getDefaultSiteUrl(config: Config): string | null {\n const clients = Object.values(config.clients);\n return clients.length > 0 ? clients[0].site_url : null;\n}\n\n// ============================================\n// DATE HELPERS\n// ============================================\n\n// Note: resolveDate uses UTC dates via toISOString(). GSC data is in the property's timezone.\n// At 11PM PT, \"today\" resolves to tomorrow in UTC. Users should be aware of this timezone behavior.\nfunction resolveDate(dateStr: string): string {\n const today = new Date();\n if (dateStr === \"today\") {\n return today.toISOString().slice(0, 10);\n }\n const match = dateStr.match(/^(\\d+)daysAgo$/);\n if (match) {\n const days = parseInt(match[1], 10);\n const d = new Date(today);\n d.setDate(d.getDate() - days);\n return d.toISOString().slice(0, 10);\n }\n return dateStr; // assume YYYY-MM-DD\n}\n\n// ============================================\n// DIMENSION FILTER PARSING\n// ============================================\n\ninterface DimensionFilter {\n dimension: string;\n operator: string;\n expression: string;\n}\n\nfunction parseDimensionFilter(filterStr: string): DimensionFilter | null {\n if (!filterStr) return null;\n\n const operators = [\n \"includingRegex\", \"excludingRegex\",\n \"notContains\", \"notEquals\",\n \"contains\", \"equals\",\n ];\n\n for (const op of operators) {\n const parts = filterStr.split(` ${op} `, 2);\n if (parts.length === 2) {\n return {\n dimension: parts[0].trim(),\n operator: op,\n expression: parts[1].trim(),\n };\n }\n }\n\n return null;\n}\n\n// ============================================\n// GOOGLE SEARCH CONSOLE API CLIENT\n// ============================================\n\nclass GscManager {\n private config: Config;\n private service: searchconsole_v1.Searchconsole | null = null;\n private authMode: \"service_account\" | \"oauth\" = \"service_account\";\n\n constructor(config: Config) {\n this.config = config;\n\n if (config.credentials_file) {\n // Service account mode\n const creds = validateCredentials(config.credentials_file);\n if (!creds.valid) {\n const msg = `[STARTUP ERROR] Missing required credentials: ${creds.missing.join(\", \")}. MCP will not function.`;\n console.error(msg);\n throw new GscAuthError(msg);\n }\n this.authMode = \"service_account\";\n } else {\n // OAuth mode -- resolve will throw with helpful message if no credentials found\n resolveOAuthCredentials(); // validates credentials exist\n this.authMode = \"oauth\";\n }\n }\n\n private getService(): searchconsole_v1.Searchconsole {\n if (!this.service) {\n if (this.authMode === \"service_account\") {\n const auth = new google.auth.GoogleAuth({\n keyFile: this.config.credentials_file,\n scopes: [\"https://www.googleapis.com/auth/webmasters.readonly\"],\n });\n this.service = google.searchconsole({ version: \"v1\", auth });\n console.error(`[startup] Service account loaded from: ${this.config.credentials_file}`);\n } else {\n const resolved = resolveOAuthCredentials();\n const oauth2Client = new google.auth.OAuth2(\n resolved.client_id,\n resolved.client_secret,\n );\n oauth2Client.setCredentials({ refresh_token: resolved.refresh_token });\n this.service = google.searchconsole({ version: \"v1\", auth: oauth2Client });\n console.error(`[startup] OAuth credentials loaded (source: ${resolved.source})`);\n }\n }\n return this.service;\n }\n\n async listSites(): Promise<any> {\n const svc = this.getService();\n return withResilience(async () => {\n const resp = await svc.sites.list();\n const sites = (resp.data.siteEntry || []).map((entry) => ({\n site_url: entry.siteUrl || \"\",\n permission_level: entry.permissionLevel || \"\",\n }));\n return { sites, count: sites.length };\n }, \"gsc_list_sites\");\n }\n\n async searchAnalytics(options: {\n startDate: string;\n endDate: string;\n dimensions: string[];\n searchType: string;\n dimensionFilter: string;\n rowLimit: number;\n aggregationType: string;\n siteUrl: string;\n }): Promise<any> {\n const svc = this.getService();\n const siteUrl = options.siteUrl || getDefaultSiteUrl(this.config);\n if (!siteUrl) {\n return { error: \"No site_url provided and none found in config\" };\n }\n\n const rowLimit = Math.min(Math.max(1, options.rowLimit), 25000);\n const startDate = resolveDate(options.startDate);\n const endDate = resolveDate(options.endDate);\n\n // Future date validation (skip relative dates like \"90daysAgo\")\n const today_gsc = new Date().toISOString().slice(0, 10);\n if (startDate && !options.startDate.includes(\"daysAgo\") && !options.startDate.includes(\"yesterday\") && !options.startDate.includes(\"today\") && startDate > today_gsc) {\n return { error: `start_date \"${startDate}\" is in the future. Reports only cover historical data.` };\n }\n\n const requestBody: any = {\n startDate,\n endDate,\n dimensions: options.dimensions,\n type: options.searchType,\n rowLimit,\n aggregationType: options.aggregationType,\n };\n\n const parsed = parseDimensionFilter(options.dimensionFilter);\n if (parsed) {\n requestBody.dimensionFilterGroups = [{\n filters: [{\n dimension: parsed.dimension,\n operator: parsed.operator,\n expression: parsed.expression,\n }],\n }];\n }\n\n return withResilience(async () => {\n const resp = await svc.searchanalytics.query({\n siteUrl,\n requestBody,\n });\n\n const rows = (resp.data.rows || []).map((row) => {\n const r: Record<string, any> = {};\n for (let i = 0; i < options.dimensions.length; i++) {\n if (row.keys && i < row.keys.length) {\n r[options.dimensions[i]] = row.keys[i];\n }\n }\n r.clicks = row.clicks || 0;\n r.impressions = row.impressions || 0;\n r.ctr = Math.round((row.ctr || 0) * 10000) / 10000;\n r.position = Math.round((row.position || 0) * 10) / 10;\n return r;\n });\n\n return {\n rows,\n row_count: rows.length,\n date_range: `${startDate} to ${endDate}`,\n site_url: siteUrl,\n };\n }, \"gsc_search_analytics\");\n }\n\n async inspection(url: string, siteUrl: string): Promise<any> {\n const svc = this.getService();\n const resolvedSiteUrl = siteUrl || getDefaultSiteUrl(this.config);\n if (!resolvedSiteUrl) {\n return { error: \"No site_url provided and none found in config\" };\n }\n\n return withResilience(async () => {\n try {\n const resp = await svc.urlInspection.index.inspect({\n requestBody: {\n inspectionUrl: url,\n siteUrl: resolvedSiteUrl,\n },\n });\n\n const result = resp.data.inspectionResult || {};\n const indexStatus = result.indexStatusResult || {};\n const mobile = result.mobileUsabilityResult || {};\n const rich = result.richResultsResult || {};\n\n return {\n url,\n site_url: resolvedSiteUrl,\n index_status: {\n verdict: indexStatus.verdict || \"UNKNOWN\",\n coverage_state: indexStatus.coverageState || \"\",\n indexing_state: indexStatus.indexingState || \"\",\n last_crawl_time: indexStatus.lastCrawlTime || \"\",\n page_fetch_state: indexStatus.pageFetchState || \"\",\n robots_txt_state: indexStatus.robotsTxtState || \"\",\n crawled_as: indexStatus.crawledAs || \"\",\n referring_urls: indexStatus.referringUrls || [],\n },\n mobile_usability: {\n verdict: mobile.verdict || \"UNKNOWN\",\n issues: (mobile.issues || []).map((i: any) => i.issueType || \"\"),\n },\n rich_results: {\n verdict: rich.verdict || \"UNKNOWN\",\n },\n };\n } catch (err) {\n return { error: String(err), url, site_url: resolvedSiteUrl };\n }\n }, \"gsc_inspection\");\n }\n}\n\n// ============================================\n// MCP SERVER\n// ============================================\n\nconst config = loadConfig();\nconst gscManager = new GscManager(config);\n\nconst server = new Server(\n {\n name: __cliPkg.name,\n version: __cliPkg.version,\n },\n {\n capabilities: {\n tools: {},\n },\n }\n);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\n return { tools };\n});\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n switch (name) {\n case \"gsc_get_client_context\": {\n const cwd = args?.working_directory as string;\n const client = getClientFromWorkingDir(config, cwd);\n if (!client) {\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify({\n error: \"No client found for working directory\",\n working_directory: cwd,\n available_clients: Object.entries(config.clients).map(([k, v]) => ({\n key: k,\n name: v.name,\n folder: v.folder,\n })),\n }, null, 2),\n }],\n };\n }\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify({\n client_name: client.name,\n site_url: client.site_url,\n folder: client.folder,\n }, null, 2),\n }],\n };\n }\n\n case \"gsc_list_sites\": {\n const result = await gscManager.listSites();\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify(safeResponse(result, \"listSites\"), null, 2),\n }],\n };\n }\n\n case \"gsc_search_analytics\": {\n const dimensions = ((args?.dimensions as string) || \"query\")\n .split(\",\")\n .map((d: string) => d.trim())\n .filter(Boolean);\n\n const result = await gscManager.searchAnalytics({\n startDate: (args?.start_date as string) || \"90daysAgo\",\n endDate: (args?.end_date as string) || \"today\",\n dimensions,\n searchType: (args?.search_type as string) || \"web\",\n dimensionFilter: (args?.dimension_filter as string) || \"\",\n rowLimit: (args?.row_limit as number) || 100,\n aggregationType: (args?.aggregation_type as string) || \"auto\",\n siteUrl: (args?.site_url as string) || \"\",\n });\n\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify(safeResponse(result, \"searchAnalytics\"), null, 2),\n }],\n };\n }\n\n case \"gsc_inspection\": {\n const result = await gscManager.inspection(\n args?.url as string,\n (args?.site_url as string) || \"\",\n );\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n }],\n };\n }\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (rawError: any) {\n const error = classifyError(rawError);\n logger.error({ error_type: error.name, message: error.message }, \"Tool call failed\");\n\n const response: Record<string, unknown> = {\n error: true,\n error_type: error.name,\n message: error.message,\n server: __cliPkg.name,\n };\n\n if (error instanceof GscAuthError) {\n response.action_required = \"Check credentials (service account or OAuth) and Search Console permissions. If using OAuth, re-run: npx mcp-gsc-auth\";\n } else if (error instanceof GscRateLimitError) {\n response.retry_after_ms = error.retryAfterMs;\n response.action_required = `Rate limited. Retry after ${Math.ceil(error.retryAfterMs / 1000)} seconds.`;\n } else if (error instanceof GscServiceError) {\n response.action_required = \"Google Search Console API server error. This is transient - retry in a few minutes.\";\n } else {\n response.details = rawError.stack;\n }\n\n // Size-limit error responses through safeResponse to prevent oversized payloads\n const safeErrorResponse = safeResponse(response, \"error\");\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: JSON.stringify(safeErrorResponse, null, 2),\n }],\n };\n }\n});\n\n// Start server\nasync function main() {\n try {\n await gscManager.listSites();\n console.error(\"[startup] Auth verified: GSC API call succeeded\");\n } catch (err: any) {\n console.error(`[STARTUP WARNING] Auth check FAILED: ${err.message}`);\n console.error(`[STARTUP WARNING] MCP will start but API calls may fail until auth is fixed.`);\n }\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"[startup] MCP GSC server running\");\n}\n\nprocess.on(\"SIGTERM\", () => {\n console.error(\"[shutdown] SIGTERM received, exiting\");\n process.exit(0);\n});\n\nprocess.on(\"SIGINT\", () => {\n console.error(\"[shutdown] SIGINT received, exiting\");\n process.exit(0);\n});\n\nprocess.on(\"SIGPIPE\", () => {\n // Client disconnected -- expected during shutdown\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n console.error(\"[error] Unhandled promise rejection:\", reason);\n});\n\nmain().catch(console.error);\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { readFileSync, existsSync } from \"fs\";\nimport { join, dirname, resolve, isAbsolute } from \"path\";\nimport { google, searchconsole_v1 } from \"googleapis\";\nimport { GoogleAuth, OAuth2Client } from \"googleapis-common\";\nimport {\n GscAuthError,\n GscRateLimitError,\n GscServiceError,\n classifyError,\n validateCredentials,\n} from \"./errors.js\";\nimport { resolveOAuthCredentials } from \"./credentials.js\";\nimport { EMBEDDED_CLIENT_ID, EMBEDDED_CLIENT_SECRET } from \"./embedded-secrets.js\";\nimport { tools } from \"./tools.js\";\nimport { withResilience, safeResponse, logger } from \"./resilience.js\";\nimport { checkForUpdate } from \"./updateNotifier.js\";\nimport v8 from \"v8\";\n\n// CLI package info\nconst __cliPkg = JSON.parse(readFileSync(join(dirname(new URL(import.meta.url).pathname), \"..\", \"package.json\"), \"utf-8\"));\n\n// Log build fingerprint at startup\ntry {\n const __buildInfoDir = dirname(new URL(import.meta.url).pathname);\n const buildInfo = JSON.parse(readFileSync(join(__buildInfoDir, \"build-info.json\"), \"utf-8\"));\n console.error(`[build] SHA: ${buildInfo.sha} (${buildInfo.builtAt})`);\n} catch {\n console.error(`[build] ${__cliPkg.name}@${__cliPkg.version} (dev mode)`);\n}\n\n// Version safety: warn if running a deprecated or dangerously old version\nconst __minimumSafeVersion = \"1.0.5\"; // minimum version with input sanitization\nconst __semverLt = (a: string, b: string) => { const pa = a.split(\".\").map(Number), pb = b.split(\".\").map(Number); for (let i = 0; i < 3; i++) { if ((pa[i] || 0) < (pb[i] || 0)) return true; if ((pa[i] || 0) > (pb[i] || 0)) return false; } return false; };\nif (__semverLt(__cliPkg.version, __minimumSafeVersion)) {\n console.error(`[WARNING] Running deprecated version ${__cliPkg.version}. Minimum safe version is ${__minimumSafeVersion}. Please upgrade.`);\n}\n\n// Fire-and-forget npm outdated check. Non-blocking; any error is swallowed.\nvoid checkForUpdate(__cliPkg.name, __cliPkg.version).catch(() => {});\n\n// CLI flags\nif (process.argv.includes(\"--help\") || process.argv.includes(\"-h\")) {\n console.error(`${__cliPkg.name} v${__cliPkg.version}\\n`);\n console.error(`Usage: ${__cliPkg.name} [options]\\n`);\n console.error(\"MCP server communicating via stdio. Configure in your .mcp.json.\\n\");\n console.error(\"Options:\");\n console.error(\" --help, -h Show this help message\");\n console.error(\" --version, -v Show version number\");\n console.error(`\\nDocumentation: https://github.com/mharnett/mcp-search-console`);\n process.exit(0);\n}\nif (process.argv.includes(\"--version\") || process.argv.includes(\"-v\")) {\n console.error(__cliPkg.version);\n process.exit(0);\n}\n\n// Startup: detect npx vs direct node\nif (process.argv[1]?.includes('.npm/_npx')) {\n console.error(\"[startup] Running via npx -- first run may be slow due to package resolution\");\n}\n\n// Startup: check heap size\nconst heapLimit = v8.getHeapStatistics().heap_size_limit;\nif (heapLimit < 256 * 1024 * 1024) {\n console.error(`[startup] WARNING: Heap limit is ${Math.round(heapLimit / 1024 / 1024)}MB`);\n}\n\n// ============================================\n// ENV VAR TRIMMING\n// ============================================\n\nconst envTrimmed = (key: string): string => (process.env[key] || \"\").trim().replace(/^[\"']|[\"']$/g, \"\");\n\n// ============================================\n// CONFIGURATION\n// ============================================\n\ninterface ClientConfig {\n name: string;\n folder: string;\n site_url: string;\n}\n\ninterface Config {\n credentials_file: string;\n clients: Record<string, ClientConfig>;\n}\n\nfunction loadConfig(): Config {\n // Try config.json (for multi-client setups).\n // MCP_GSC_CONFIG_PATH env var overrides the default so multiple MCP instances\n // can run against different configs (e.g., one per client).\n const defaultConfigPath = join(dirname(new URL(import.meta.url).pathname), \"..\", \"config.json\");\n const configPath = envTrimmed(\"MCP_GSC_CONFIG_PATH\") || defaultConfigPath;\n if (existsSync(configPath)) {\n const raw = JSON.parse(readFileSync(configPath, \"utf-8\"));\n const rawCf = raw.credentials_file || envTrimmed(\"GOOGLE_APPLICATION_CREDENTIALS\");\n return {\n credentials_file: rawCf && !isAbsolute(rawCf) ? resolve(rawCf) : rawCf,\n clients: raw.clients || {},\n };\n }\n\n // Fall back to env vars for service account\n const rawCredsFile = envTrimmed(\"GOOGLE_APPLICATION_CREDENTIALS\");\n const credsFile = rawCredsFile && !isAbsolute(rawCredsFile) ? resolve(rawCredsFile) : rawCredsFile;\n if (credsFile) {\n return {\n credentials_file: credsFile,\n clients: {},\n };\n }\n\n // Fall back to OAuth credentials (from mcp-gsc-auth or env vars)\n // Return empty credentials_file to signal OAuth mode\n return {\n credentials_file: \"\",\n clients: {},\n };\n}\n\nfunction getClientFromWorkingDir(config: Config, cwd: string): ClientConfig | null {\n for (const [key, client] of Object.entries(config.clients)) {\n if (cwd.startsWith(client.folder) || cwd.includes(key)) {\n return client;\n }\n }\n return null;\n}\n\nfunction getDefaultSiteUrl(config: Config): string | null {\n const clients = Object.values(config.clients);\n return clients.length > 0 ? clients[0].site_url : null;\n}\n\n// ============================================\n// DATE HELPERS\n// ============================================\n\n// Note: resolveDate uses UTC dates via toISOString(). GSC data is in the property's timezone.\n// At 11PM PT, \"today\" resolves to tomorrow in UTC. Users should be aware of this timezone behavior.\nfunction resolveDate(dateStr: string): string {\n const today = new Date();\n if (dateStr === \"today\") {\n return today.toISOString().slice(0, 10);\n }\n const match = dateStr.match(/^(\\d+)daysAgo$/);\n if (match) {\n const days = parseInt(match[1], 10);\n const d = new Date(today);\n d.setDate(d.getDate() - days);\n return d.toISOString().slice(0, 10);\n }\n return dateStr; // assume YYYY-MM-DD\n}\n\n// ============================================\n// DIMENSION FILTER PARSING\n// ============================================\n\ninterface DimensionFilter {\n dimension: string;\n operator: string;\n expression: string;\n}\n\nfunction parseDimensionFilter(filterStr: string): DimensionFilter | null {\n if (!filterStr) return null;\n\n const operators = [\n \"includingRegex\", \"excludingRegex\",\n \"notContains\", \"notEquals\",\n \"contains\", \"equals\",\n ];\n\n for (const op of operators) {\n const parts = filterStr.split(` ${op} `, 2);\n if (parts.length === 2) {\n return {\n dimension: parts[0].trim(),\n operator: op,\n expression: parts[1].trim(),\n };\n }\n }\n\n return null;\n}\n\n// ============================================\n// GOOGLE SEARCH CONSOLE API CLIENT\n// ============================================\n\nclass GscManager {\n private config: Config;\n private service: searchconsole_v1.Searchconsole | null = null;\n private authMode: \"service_account\" | \"oauth\" = \"service_account\";\n\n constructor(config: Config) {\n this.config = config;\n\n if (config.credentials_file) {\n // Service account mode\n const creds = validateCredentials(config.credentials_file);\n if (!creds.valid) {\n const msg = `[STARTUP ERROR] Missing required credentials: ${creds.missing.join(\", \")}. MCP will not function.`;\n console.error(msg);\n throw new GscAuthError(msg);\n }\n this.authMode = \"service_account\";\n } else {\n // OAuth mode -- resolve will throw with helpful message if no credentials found\n resolveOAuthCredentials(); // validates credentials exist\n this.authMode = \"oauth\";\n }\n }\n\n private getService(): searchconsole_v1.Searchconsole {\n if (!this.service) {\n if (this.authMode === \"service_account\") {\n const auth = new google.auth.GoogleAuth({\n keyFile: this.config.credentials_file,\n scopes: [\"https://www.googleapis.com/auth/webmasters.readonly\"],\n });\n this.service = google.searchconsole({ version: \"v1\", auth });\n console.error(`[startup] Service account loaded from: ${this.config.credentials_file}`);\n } else {\n const resolved = resolveOAuthCredentials();\n const oauth2Client = new google.auth.OAuth2(\n resolved.client_id,\n resolved.client_secret,\n );\n oauth2Client.setCredentials({ refresh_token: resolved.refresh_token });\n this.service = google.searchconsole({ version: \"v1\", auth: oauth2Client });\n console.error(`[startup] OAuth credentials loaded (source: ${resolved.source})`);\n }\n }\n return this.service;\n }\n\n async listSites(): Promise<any> {\n const svc = this.getService();\n return withResilience(async () => {\n const resp = await svc.sites.list();\n const sites = (resp.data.siteEntry || []).map((entry) => ({\n site_url: entry.siteUrl || \"\",\n permission_level: entry.permissionLevel || \"\",\n }));\n return { sites, count: sites.length };\n }, \"gsc_list_sites\");\n }\n\n async searchAnalytics(options: {\n startDate: string;\n endDate: string;\n dimensions: string[];\n searchType: string;\n dimensionFilter: string;\n rowLimit: number;\n aggregationType: string;\n siteUrl: string;\n }): Promise<any> {\n const svc = this.getService();\n const siteUrl = options.siteUrl || getDefaultSiteUrl(this.config);\n if (!siteUrl) {\n return { error: \"No site_url provided and none found in config\" };\n }\n\n const rowLimit = Math.min(Math.max(1, options.rowLimit), 25000);\n const startDate = resolveDate(options.startDate);\n const endDate = resolveDate(options.endDate);\n\n // Future date validation (skip relative dates like \"90daysAgo\")\n const today_gsc = new Date().toISOString().slice(0, 10);\n if (startDate && !options.startDate.includes(\"daysAgo\") && !options.startDate.includes(\"yesterday\") && !options.startDate.includes(\"today\") && startDate > today_gsc) {\n return { error: `start_date \"${startDate}\" is in the future. Reports only cover historical data.` };\n }\n\n const requestBody: any = {\n startDate,\n endDate,\n dimensions: options.dimensions,\n type: options.searchType,\n rowLimit,\n aggregationType: options.aggregationType,\n };\n\n const parsed = parseDimensionFilter(options.dimensionFilter);\n if (parsed) {\n requestBody.dimensionFilterGroups = [{\n filters: [{\n dimension: parsed.dimension,\n operator: parsed.operator,\n expression: parsed.expression,\n }],\n }];\n }\n\n return withResilience(async () => {\n const resp = await svc.searchanalytics.query({\n siteUrl,\n requestBody,\n });\n\n const rows = (resp.data.rows || []).map((row) => {\n const r: Record<string, any> = {};\n for (let i = 0; i < options.dimensions.length; i++) {\n if (row.keys && i < row.keys.length) {\n r[options.dimensions[i]] = row.keys[i];\n }\n }\n r.clicks = row.clicks || 0;\n r.impressions = row.impressions || 0;\n r.ctr = Math.round((row.ctr || 0) * 10000) / 10000;\n r.position = Math.round((row.position || 0) * 10) / 10;\n return r;\n });\n\n return {\n rows,\n row_count: rows.length,\n date_range: `${startDate} to ${endDate}`,\n site_url: siteUrl,\n };\n }, \"gsc_search_analytics\");\n }\n\n async inspection(url: string, siteUrl: string): Promise<any> {\n const svc = this.getService();\n const resolvedSiteUrl = siteUrl || getDefaultSiteUrl(this.config);\n if (!resolvedSiteUrl) {\n return { error: \"No site_url provided and none found in config\" };\n }\n\n return withResilience(async () => {\n try {\n const resp = await svc.urlInspection.index.inspect({\n requestBody: {\n inspectionUrl: url,\n siteUrl: resolvedSiteUrl,\n },\n });\n\n const result = resp.data.inspectionResult || {};\n const indexStatus = result.indexStatusResult || {};\n const mobile = result.mobileUsabilityResult || {};\n const rich = result.richResultsResult || {};\n\n return {\n url,\n site_url: resolvedSiteUrl,\n index_status: {\n verdict: indexStatus.verdict || \"UNKNOWN\",\n coverage_state: indexStatus.coverageState || \"\",\n indexing_state: indexStatus.indexingState || \"\",\n last_crawl_time: indexStatus.lastCrawlTime || \"\",\n page_fetch_state: indexStatus.pageFetchState || \"\",\n robots_txt_state: indexStatus.robotsTxtState || \"\",\n crawled_as: indexStatus.crawledAs || \"\",\n referring_urls: indexStatus.referringUrls || [],\n },\n mobile_usability: {\n verdict: mobile.verdict || \"UNKNOWN\",\n issues: (mobile.issues || []).map((i: any) => i.issueType || \"\"),\n },\n rich_results: {\n verdict: rich.verdict || \"UNKNOWN\",\n },\n };\n } catch (err) {\n return { error: String(err), url, site_url: resolvedSiteUrl };\n }\n }, \"gsc_inspection\");\n }\n}\n\n// ============================================\n// MCP SERVER\n// ============================================\n\nconst config = loadConfig();\nconst gscManager = new GscManager(config);\n\nconst server = new Server(\n {\n name: __cliPkg.name,\n version: __cliPkg.version,\n },\n {\n capabilities: {\n tools: {},\n },\n }\n);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\n return { tools };\n});\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n switch (name) {\n case \"gsc_get_client_context\": {\n const cwd = args?.working_directory as string;\n const client = getClientFromWorkingDir(config, cwd);\n if (!client) {\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify({\n error: \"No client found for working directory\",\n working_directory: cwd,\n available_clients: Object.entries(config.clients).map(([k, v]) => ({\n key: k,\n name: v.name,\n folder: v.folder,\n })),\n }, null, 2),\n }],\n };\n }\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify({\n client_name: client.name,\n site_url: client.site_url,\n folder: client.folder,\n }, null, 2),\n }],\n };\n }\n\n case \"gsc_list_sites\": {\n const result = await gscManager.listSites();\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify(safeResponse(result, \"listSites\"), null, 2),\n }],\n };\n }\n\n case \"gsc_search_analytics\": {\n const dimensions = ((args?.dimensions as string) || \"query\")\n .split(\",\")\n .map((d: string) => d.trim())\n .filter(Boolean);\n\n const result = await gscManager.searchAnalytics({\n startDate: (args?.start_date as string) || \"90daysAgo\",\n endDate: (args?.end_date as string) || \"today\",\n dimensions,\n searchType: (args?.search_type as string) || \"web\",\n dimensionFilter: (args?.dimension_filter as string) || \"\",\n rowLimit: (args?.row_limit as number) || 100,\n aggregationType: (args?.aggregation_type as string) || \"auto\",\n siteUrl: (args?.site_url as string) || \"\",\n });\n\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify(safeResponse(result, \"searchAnalytics\"), null, 2),\n }],\n };\n }\n\n case \"gsc_inspection\": {\n const result = await gscManager.inspection(\n args?.url as string,\n (args?.site_url as string) || \"\",\n );\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify(result, null, 2),\n }],\n };\n }\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (rawError: any) {\n const error = classifyError(rawError);\n logger.error({ error_type: error.name, message: error.message }, \"Tool call failed\");\n\n const response: Record<string, unknown> = {\n error: true,\n error_type: error.name,\n message: error.message,\n server: __cliPkg.name,\n };\n\n if (error instanceof GscAuthError) {\n response.action_required = \"Check credentials (service account or OAuth) and Search Console permissions. If using OAuth, re-run: npx mcp-gsc-auth\";\n } else if (error instanceof GscRateLimitError) {\n response.retry_after_ms = error.retryAfterMs;\n response.action_required = `Rate limited. Retry after ${Math.ceil(error.retryAfterMs / 1000)} seconds.`;\n } else if (error instanceof GscServiceError) {\n response.action_required = \"Google Search Console API server error. This is transient - retry in a few minutes.\";\n } else {\n response.details = rawError.stack;\n }\n\n // Size-limit error responses through safeResponse to prevent oversized payloads\n const safeErrorResponse = safeResponse(response, \"error\");\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: JSON.stringify(safeErrorResponse, null, 2),\n }],\n };\n }\n});\n\n// Start server\nasync function main() {\n try {\n await gscManager.listSites();\n console.error(\"[startup] Auth verified: GSC API call succeeded\");\n } catch (err: any) {\n console.error(`[STARTUP WARNING] Auth check FAILED: ${err.message}`);\n console.error(`[STARTUP WARNING] MCP will start but API calls may fail until auth is fixed.`);\n }\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"[startup] MCP GSC server running\");\n}\n\nprocess.on(\"SIGTERM\", () => {\n console.error(\"[shutdown] SIGTERM received, exiting\");\n process.exit(0);\n});\n\nprocess.on(\"SIGINT\", () => {\n console.error(\"[shutdown] SIGINT received, exiting\");\n process.exit(0);\n});\n\nprocess.on(\"SIGPIPE\", () => {\n // Client disconnected -- expected during shutdown\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n console.error(\"[error] Unhandled promise rejection:\", reason);\n});\n\nmain().catch(console.error);\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["config"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-google-gsc",
|
|
3
3
|
"mcpName": "io.github.mharnett/google-gsc",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.4",
|
|
5
5
|
"description": "MCP server for Google Search Console API with multi-client support, search analytics, and URL inspection.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"dev": "tsx src/index.ts",
|
|
29
29
|
"dev:auth": "tsx src/auth-cli.ts",
|
|
30
30
|
"auth": "node dist/auth-cli.js",
|
|
31
|
-
"test": "vitest run"
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"smoke": "scripts/healthcheck.sh"
|
|
32
33
|
},
|
|
33
34
|
"author": "drak-marketing",
|
|
34
35
|
"license": "MIT",
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
"prompts": "^2.4.2"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
49
|
-
"@drak/mcp-test-harness": "file
|
|
50
|
+
"@drak/mcp-test-harness": "file:./mcp-test-harness",
|
|
50
51
|
"@types/node": "^20.10.0",
|
|
51
52
|
"@types/prompts": "^2.4.9",
|
|
52
53
|
"esbuild": "^0.25.0",
|