mcp-google-gsc 1.1.0 → 1.1.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/dist/auth-cli.js +5 -8
- package/dist/auth-cli.js.map +2 -2
- package/dist/build-info.json +1 -1
- package/package.json +1 -1
package/dist/auth-cli.js
CHANGED
|
@@ -276,16 +276,13 @@ function randomState() {
|
|
|
276
276
|
globalThis.crypto.getRandomValues(bytes);
|
|
277
277
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
278
278
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
const classified = classifyError(err);
|
|
283
|
-
process.stderr.write(`
|
|
279
|
+
run().catch((err) => {
|
|
280
|
+
const classified = classifyError(err);
|
|
281
|
+
process.stderr.write(`
|
|
284
282
|
${classified.message}
|
|
285
283
|
`);
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
284
|
+
process.exit(1);
|
|
285
|
+
});
|
|
289
286
|
export {
|
|
290
287
|
run
|
|
291
288
|
};
|
package/dist/auth-cli.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/auth-cli.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\n// ============================================\n// mcp-gsc-auth -- one-time OAuth + site selection\n// ============================================\n// Flow:\n// 1. Loopback HTTP listener on a free port\n// 2. Open browser to Google OAuth consent screen (webmasters.readonly scope)\n// 3. Exchange code for tokens\n// 4. Enumerate accessible GSC sites\n// 5. User picks which site to use as default\n// 6. Write credentials to ~/.config/mcp-gsc-nodejs/credentials.json\n\nimport { google } from \"googleapis\";\nimport http from \"http\";\nimport promptsImport from \"prompts\";\nimport { URL } from \"url\";\nimport { writeStoredCredentials, credentialsFilePath, CREDENTIALS_FILE_VERSION, type StoredCredentials } from \"./credentials.js\";\nimport { EMBEDDED_CLIENT_ID, EMBEDDED_CLIENT_SECRET } from \"./embedded-secrets.js\";\nimport { classifyError, GscAuthError } from \"./errors.js\";\nimport { findFreeLoopbackPort, openBrowser } from \"./platform.js\";\nimport { logger, withResilience } from \"./resilience.js\";\n\nconst prompts = (promptsImport as unknown as { default?: typeof promptsImport }).default ?? promptsImport;\n\nconst OAUTH_SCOPE = \"https://www.googleapis.com/auth/webmasters.readonly\";\nconst OAUTH_AUTH_URL = \"https://accounts.google.com/o/oauth2/v2/auth\";\nconst OAUTH_TOKEN_URL = \"https://oauth2.googleapis.com/token\";\n\ninterface CliArgs {\n siteUrl?: string;\n help: boolean;\n}\n\nfunction parseArgs(argv: string[]): CliArgs {\n const args: CliArgs = { help: false };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === \"--help\" || a === \"-h\") args.help = true;\n else if (a === \"--site-url\" && argv[i + 1]) {\n args.siteUrl = argv[++i];\n }\n }\n return args;\n}\n\nfunction printHelp(): void {\n process.stdout.write(\n [\n \"mcp-gsc-auth -- authorize Claude to access your Google Search Console data\",\n \"\",\n \"Usage:\",\n \" npx mcp-gsc-auth\",\n \" npx mcp-gsc-auth --site-url https://example.com/\",\n \"\",\n \"Options:\",\n \" --site-url <url> Skip the site picker and use this property directly\",\n \" -h, --help Show this help\",\n \"\",\n `Credentials are written to: ${credentialsFilePath}`,\n \"\",\n ].join(\"\\n\"),\n );\n}\n\n// ============================================\n// OAUTH: LOOPBACK REDIRECT FLOW\n// ============================================\n\nfunction buildAuthUrl(clientId: string, redirectUri: string, state: string): string {\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: redirectUri,\n response_type: \"code\",\n scope: OAUTH_SCOPE,\n access_type: \"offline\",\n prompt: \"consent\",\n state,\n });\n return `${OAUTH_AUTH_URL}?${params.toString()}`;\n}\n\ninterface AuthorizationCode {\n code: string;\n state: string;\n}\n\nasync function waitForAuthorizationCode(\n port: number,\n expectedState: string,\n authUrl: string,\n): Promise<AuthorizationCode> {\n return new Promise<AuthorizationCode>((resolve, reject) => {\n let settled = false;\n const finish = (fn: () => void) => {\n if (settled) return;\n settled = true;\n fn();\n };\n\n const server = http.createServer((req, res) => {\n if (!req.url) {\n res.writeHead(404).end();\n return;\n }\n const parsed = new URL(req.url, `http://127.0.0.1:${port}`);\n const code = parsed.searchParams.get(\"code\");\n const state = parsed.searchParams.get(\"state\");\n const error = parsed.searchParams.get(\"error\");\n\n if (error) {\n res.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(renderPage(\"Authorization was denied\", `Google returned: ${escapeHtml(error)}. Close this tab and re-run the command.`));\n finish(() => { server.close(); reject(new GscAuthError(`OAuth denied: ${error}`)); });\n return;\n }\n\n if (!code) {\n res.writeHead(204).end();\n return;\n }\n\n if (state !== expectedState) {\n res.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(renderPage(\"Security check failed\", \"The state parameter did not match. Please re-run the command.\"));\n finish(() => { server.close(); reject(new GscAuthError(\"OAuth state mismatch\")); });\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(renderPage(\"Signed in successfully\", \"You can close this tab and return to the terminal.\"));\n finish(() => {\n setTimeout(() => server.close(), 200);\n resolve({ code, state });\n });\n });\n\n server.on(\"error\", (err) => {\n finish(() => reject(new Error(`Loopback server failed: ${err.message}`)));\n });\n\n server.listen(port, \"127.0.0.1\", () => {\n process.stderr.write(`\\nOpening your browser to sign in with Google...\\n`);\n process.stderr.write(`If it doesn't open automatically, visit:\\n ${authUrl}\\n\\n`);\n openBrowser(authUrl).catch((err) => {\n logger.warn({ err: err.message }, \"openBrowser failed\");\n });\n });\n\n setTimeout(() => {\n finish(() => { server.close(); reject(new Error(\"Timed out waiting for OAuth callback (5 minutes).\")); });\n }, 5 * 60 * 1000);\n });\n}\n\nfunction renderPage(title: string, body: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\"><title>${escapeHtml(title)}</title>\n <style>body{font:15px -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif;max-width:480px;margin:80px auto;padding:0 24px;color:#222}h1{font-size:22px;margin-bottom:12px}p{line-height:1.5}</style>\n</head>\n<body><h1>${escapeHtml(title)}</h1><p>${escapeHtml(body)}</p></body>\n</html>`;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" })[c]!);\n}\n\n// ============================================\n// TOKEN EXCHANGE\n// ============================================\n\ninterface TokenResponse {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n scope: string;\n token_type: string;\n}\n\nasync function exchangeCodeForTokens(\n code: string,\n clientId: string,\n clientSecret: string,\n redirectUri: string,\n): Promise<TokenResponse> {\n return withResilience(async () => {\n const body = new URLSearchParams({\n code,\n client_id: clientId,\n client_secret: clientSecret,\n redirect_uri: redirectUri,\n grant_type: \"authorization_code\",\n });\n const res = await fetch(OAUTH_TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n const json = (await res.json()) as Record<string, unknown>;\n if (!res.ok || json.error) {\n const err = new Error(\n `Token exchange failed: ${json.error_description || json.error || res.statusText}`,\n );\n (err as any).status = res.status;\n (err as any).code = res.status;\n throw err;\n }\n return json as unknown as TokenResponse;\n }, \"oauth.exchangeCode\");\n}\n\n// ============================================\n// SITE ENUMERATION\n// ============================================\n\ninterface GscSite {\n siteUrl: string;\n permissionLevel: string;\n}\n\nasync function enumerateSites(accessToken: string): Promise<GscSite[]> {\n const oauth2Client = new google.auth.OAuth2();\n oauth2Client.setCredentials({ access_token: accessToken });\n\n const svc = google.searchconsole({ version: \"v1\", auth: oauth2Client });\n const resp = await withResilience(\n () => svc.sites.list(),\n \"auth.listSites\",\n );\n\n const sites = (resp.data.siteEntry || []).map((entry) => ({\n siteUrl: entry.siteUrl || \"\",\n permissionLevel: entry.permissionLevel || \"\",\n }));\n\n if (sites.length === 0) {\n throw new GscAuthError(\n \"No Search Console properties found for this Google account. \" +\n \"Make sure you signed in with an account that has access to at least one property.\",\n );\n }\n\n return sites;\n}\n\n// ============================================\n// PICKER\n// ============================================\n\nasync function pickSite(sites: GscSite[], presetSiteUrl?: string): Promise<GscSite> {\n if (presetSiteUrl) {\n const match = sites.find((s) => s.siteUrl === presetSiteUrl);\n if (!match) {\n throw new Error(\n `--site-url \"${presetSiteUrl}\" was not found among ${sites.length} accessible properties. ` +\n `Remove the flag to pick interactively.`,\n );\n }\n return match;\n }\n\n if (sites.length === 1) {\n process.stderr.write(`\\nOnly one property accessible: ${sites[0].siteUrl}. Auto-selecting.\\n`);\n return sites[0];\n }\n\n const choices = sites.map((site) => ({\n title: `${site.siteUrl} (${site.permissionLevel})`,\n value: site,\n }));\n\n const response = await prompts(\n {\n type: \"select\",\n name: \"site\",\n message: \"Which Search Console property should Claude use by default?\",\n choices,\n initial: 0,\n },\n {\n onCancel: () => { throw new Error(\"Cancelled by user\"); },\n },\n );\n\n if (!response.site) throw new Error(\"No site selected\");\n return response.site as GscSite;\n}\n\n// ============================================\n// MAIN\n// ============================================\n\nexport async function run(argv: string[] = process.argv.slice(2)): Promise<void> {\n const args = parseArgs(argv);\n if (args.help) {\n printHelp();\n return;\n }\n\n const clientId = process.env.GOOGLE_GSC_CLIENT_ID?.trim() || EMBEDDED_CLIENT_ID;\n const clientSecret = process.env.GOOGLE_GSC_CLIENT_SECRET?.trim() || EMBEDDED_CLIENT_SECRET;\n\n if (!clientId || !clientSecret) {\n process.stderr.write(\n \"This build of mcp-gsc was published without embedded OAuth credentials.\\n\" +\n \"Set GOOGLE_GSC_CLIENT_ID and GOOGLE_GSC_CLIENT_SECRET in your environment.\\n\",\n );\n process.exit(2);\n }\n\n const port = await findFreeLoopbackPort();\n const redirectUri = `http://127.0.0.1:${port}`;\n const state = randomState();\n const authUrl = buildAuthUrl(clientId, redirectUri, state);\n\n process.stderr.write(\"\\n=== mcp-gsc authentication ===\\n\");\n\n const { code } = await waitForAuthorizationCode(port, state, authUrl);\n process.stderr.write(\"Authorization code received. Exchanging for tokens...\\n\");\n\n const tokens = await exchangeCodeForTokens(code, clientId, clientSecret, redirectUri);\n if (!tokens.refresh_token) {\n throw new GscAuthError(\n \"Google did not return a refresh token. This can happen if you previously granted consent \" +\n \"to this app. Revoke access at https://myaccount.google.com/permissions and try again.\",\n );\n }\n process.stderr.write(\"Tokens received. Fetching accessible Search Console properties...\\n\");\n\n const sites = await enumerateSites(tokens.access_token);\n const chosen = await pickSite(sites, args.siteUrl);\n\n const stored: StoredCredentials = {\n version: CREDENTIALS_FILE_VERSION,\n refresh_token: tokens.refresh_token,\n site_urls: sites.map((s) => s.siteUrl),\n primary_site_url: chosen.siteUrl,\n obtained_at: new Date().toISOString(),\n scopes: [OAUTH_SCOPE],\n };\n writeStoredCredentials(stored);\n\n process.stderr.write(\n [\n \"\",\n \"Done.\",\n \"\",\n ` Property: ${chosen.siteUrl}`,\n ` Permission: ${chosen.permissionLevel}`,\n ` Saved to: ${credentialsFilePath}`,\n \"\",\n \"Next step: fully quit Claude Desktop (Cmd+Q / File > Exit) and reopen it.\",\n 'Then try: \"List my Search Console properties\"',\n \"\",\n ].join(\"\\n\"),\n );\n}\n\nfunction randomState(): string {\n const bytes = new Uint8Array(16);\n (globalThis.crypto as Crypto).getRandomValues(bytes);\n return Array.from(bytes).map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n// ============================================\n// ENTRY\n// ============================================\n\nconst isMain =\n import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1]?.endsWith(\"/auth-cli.js\") ||\n process.argv[1]?.endsWith(\"\\\\auth-cli.js\");\n\nif (isMain) {\n run().catch((err) => {\n const classified = classifyError(err);\n process.stderr.write(`\\n${classified.message}\\n`);\n process.exit(1);\n });\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n// ============================================\n// mcp-gsc-auth -- one-time OAuth + site selection\n// ============================================\n// Flow:\n// 1. Loopback HTTP listener on a free port\n// 2. Open browser to Google OAuth consent screen (webmasters.readonly scope)\n// 3. Exchange code for tokens\n// 4. Enumerate accessible GSC sites\n// 5. User picks which site to use as default\n// 6. Write credentials to ~/.config/mcp-gsc-nodejs/credentials.json\n\nimport { google } from \"googleapis\";\nimport http from \"http\";\nimport promptsImport from \"prompts\";\nimport { URL } from \"url\";\nimport { writeStoredCredentials, credentialsFilePath, CREDENTIALS_FILE_VERSION, type StoredCredentials } from \"./credentials.js\";\nimport { EMBEDDED_CLIENT_ID, EMBEDDED_CLIENT_SECRET } from \"./embedded-secrets.js\";\nimport { classifyError, GscAuthError } from \"./errors.js\";\nimport { findFreeLoopbackPort, openBrowser } from \"./platform.js\";\nimport { logger, withResilience } from \"./resilience.js\";\n\nconst prompts = (promptsImport as unknown as { default?: typeof promptsImport }).default ?? promptsImport;\n\nconst OAUTH_SCOPE = \"https://www.googleapis.com/auth/webmasters.readonly\";\nconst OAUTH_AUTH_URL = \"https://accounts.google.com/o/oauth2/v2/auth\";\nconst OAUTH_TOKEN_URL = \"https://oauth2.googleapis.com/token\";\n\ninterface CliArgs {\n siteUrl?: string;\n help: boolean;\n}\n\nfunction parseArgs(argv: string[]): CliArgs {\n const args: CliArgs = { help: false };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === \"--help\" || a === \"-h\") args.help = true;\n else if (a === \"--site-url\" && argv[i + 1]) {\n args.siteUrl = argv[++i];\n }\n }\n return args;\n}\n\nfunction printHelp(): void {\n process.stdout.write(\n [\n \"mcp-gsc-auth -- authorize Claude to access your Google Search Console data\",\n \"\",\n \"Usage:\",\n \" npx mcp-gsc-auth\",\n \" npx mcp-gsc-auth --site-url https://example.com/\",\n \"\",\n \"Options:\",\n \" --site-url <url> Skip the site picker and use this property directly\",\n \" -h, --help Show this help\",\n \"\",\n `Credentials are written to: ${credentialsFilePath}`,\n \"\",\n ].join(\"\\n\"),\n );\n}\n\n// ============================================\n// OAUTH: LOOPBACK REDIRECT FLOW\n// ============================================\n\nfunction buildAuthUrl(clientId: string, redirectUri: string, state: string): string {\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: redirectUri,\n response_type: \"code\",\n scope: OAUTH_SCOPE,\n access_type: \"offline\",\n prompt: \"consent\",\n state,\n });\n return `${OAUTH_AUTH_URL}?${params.toString()}`;\n}\n\ninterface AuthorizationCode {\n code: string;\n state: string;\n}\n\nasync function waitForAuthorizationCode(\n port: number,\n expectedState: string,\n authUrl: string,\n): Promise<AuthorizationCode> {\n return new Promise<AuthorizationCode>((resolve, reject) => {\n let settled = false;\n const finish = (fn: () => void) => {\n if (settled) return;\n settled = true;\n fn();\n };\n\n const server = http.createServer((req, res) => {\n if (!req.url) {\n res.writeHead(404).end();\n return;\n }\n const parsed = new URL(req.url, `http://127.0.0.1:${port}`);\n const code = parsed.searchParams.get(\"code\");\n const state = parsed.searchParams.get(\"state\");\n const error = parsed.searchParams.get(\"error\");\n\n if (error) {\n res.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(renderPage(\"Authorization was denied\", `Google returned: ${escapeHtml(error)}. Close this tab and re-run the command.`));\n finish(() => { server.close(); reject(new GscAuthError(`OAuth denied: ${error}`)); });\n return;\n }\n\n if (!code) {\n res.writeHead(204).end();\n return;\n }\n\n if (state !== expectedState) {\n res.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(renderPage(\"Security check failed\", \"The state parameter did not match. Please re-run the command.\"));\n finish(() => { server.close(); reject(new GscAuthError(\"OAuth state mismatch\")); });\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(renderPage(\"Signed in successfully\", \"You can close this tab and return to the terminal.\"));\n finish(() => {\n setTimeout(() => server.close(), 200);\n resolve({ code, state });\n });\n });\n\n server.on(\"error\", (err) => {\n finish(() => reject(new Error(`Loopback server failed: ${err.message}`)));\n });\n\n server.listen(port, \"127.0.0.1\", () => {\n process.stderr.write(`\\nOpening your browser to sign in with Google...\\n`);\n process.stderr.write(`If it doesn't open automatically, visit:\\n ${authUrl}\\n\\n`);\n openBrowser(authUrl).catch((err) => {\n logger.warn({ err: err.message }, \"openBrowser failed\");\n });\n });\n\n setTimeout(() => {\n finish(() => { server.close(); reject(new Error(\"Timed out waiting for OAuth callback (5 minutes).\")); });\n }, 5 * 60 * 1000);\n });\n}\n\nfunction renderPage(title: string, body: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\"><title>${escapeHtml(title)}</title>\n <style>body{font:15px -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif;max-width:480px;margin:80px auto;padding:0 24px;color:#222}h1{font-size:22px;margin-bottom:12px}p{line-height:1.5}</style>\n</head>\n<body><h1>${escapeHtml(title)}</h1><p>${escapeHtml(body)}</p></body>\n</html>`;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" })[c]!);\n}\n\n// ============================================\n// TOKEN EXCHANGE\n// ============================================\n\ninterface TokenResponse {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n scope: string;\n token_type: string;\n}\n\nasync function exchangeCodeForTokens(\n code: string,\n clientId: string,\n clientSecret: string,\n redirectUri: string,\n): Promise<TokenResponse> {\n return withResilience(async () => {\n const body = new URLSearchParams({\n code,\n client_id: clientId,\n client_secret: clientSecret,\n redirect_uri: redirectUri,\n grant_type: \"authorization_code\",\n });\n const res = await fetch(OAUTH_TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n const json = (await res.json()) as Record<string, unknown>;\n if (!res.ok || json.error) {\n const err = new Error(\n `Token exchange failed: ${json.error_description || json.error || res.statusText}`,\n );\n (err as any).status = res.status;\n (err as any).code = res.status;\n throw err;\n }\n return json as unknown as TokenResponse;\n }, \"oauth.exchangeCode\");\n}\n\n// ============================================\n// SITE ENUMERATION\n// ============================================\n\ninterface GscSite {\n siteUrl: string;\n permissionLevel: string;\n}\n\nasync function enumerateSites(accessToken: string): Promise<GscSite[]> {\n const oauth2Client = new google.auth.OAuth2();\n oauth2Client.setCredentials({ access_token: accessToken });\n\n const svc = google.searchconsole({ version: \"v1\", auth: oauth2Client });\n const resp = await withResilience(\n () => svc.sites.list(),\n \"auth.listSites\",\n );\n\n const sites = (resp.data.siteEntry || []).map((entry) => ({\n siteUrl: entry.siteUrl || \"\",\n permissionLevel: entry.permissionLevel || \"\",\n }));\n\n if (sites.length === 0) {\n throw new GscAuthError(\n \"No Search Console properties found for this Google account. \" +\n \"Make sure you signed in with an account that has access to at least one property.\",\n );\n }\n\n return sites;\n}\n\n// ============================================\n// PICKER\n// ============================================\n\nasync function pickSite(sites: GscSite[], presetSiteUrl?: string): Promise<GscSite> {\n if (presetSiteUrl) {\n const match = sites.find((s) => s.siteUrl === presetSiteUrl);\n if (!match) {\n throw new Error(\n `--site-url \"${presetSiteUrl}\" was not found among ${sites.length} accessible properties. ` +\n `Remove the flag to pick interactively.`,\n );\n }\n return match;\n }\n\n if (sites.length === 1) {\n process.stderr.write(`\\nOnly one property accessible: ${sites[0].siteUrl}. Auto-selecting.\\n`);\n return sites[0];\n }\n\n const choices = sites.map((site) => ({\n title: `${site.siteUrl} (${site.permissionLevel})`,\n value: site,\n }));\n\n const response = await prompts(\n {\n type: \"select\",\n name: \"site\",\n message: \"Which Search Console property should Claude use by default?\",\n choices,\n initial: 0,\n },\n {\n onCancel: () => { throw new Error(\"Cancelled by user\"); },\n },\n );\n\n if (!response.site) throw new Error(\"No site selected\");\n return response.site as GscSite;\n}\n\n// ============================================\n// MAIN\n// ============================================\n\nexport async function run(argv: string[] = process.argv.slice(2)): Promise<void> {\n const args = parseArgs(argv);\n if (args.help) {\n printHelp();\n return;\n }\n\n const clientId = process.env.GOOGLE_GSC_CLIENT_ID?.trim() || EMBEDDED_CLIENT_ID;\n const clientSecret = process.env.GOOGLE_GSC_CLIENT_SECRET?.trim() || EMBEDDED_CLIENT_SECRET;\n\n if (!clientId || !clientSecret) {\n process.stderr.write(\n \"This build of mcp-gsc was published without embedded OAuth credentials.\\n\" +\n \"Set GOOGLE_GSC_CLIENT_ID and GOOGLE_GSC_CLIENT_SECRET in your environment.\\n\",\n );\n process.exit(2);\n }\n\n const port = await findFreeLoopbackPort();\n const redirectUri = `http://127.0.0.1:${port}`;\n const state = randomState();\n const authUrl = buildAuthUrl(clientId, redirectUri, state);\n\n process.stderr.write(\"\\n=== mcp-gsc authentication ===\\n\");\n\n const { code } = await waitForAuthorizationCode(port, state, authUrl);\n process.stderr.write(\"Authorization code received. Exchanging for tokens...\\n\");\n\n const tokens = await exchangeCodeForTokens(code, clientId, clientSecret, redirectUri);\n if (!tokens.refresh_token) {\n throw new GscAuthError(\n \"Google did not return a refresh token. This can happen if you previously granted consent \" +\n \"to this app. Revoke access at https://myaccount.google.com/permissions and try again.\",\n );\n }\n process.stderr.write(\"Tokens received. Fetching accessible Search Console properties...\\n\");\n\n const sites = await enumerateSites(tokens.access_token);\n const chosen = await pickSite(sites, args.siteUrl);\n\n const stored: StoredCredentials = {\n version: CREDENTIALS_FILE_VERSION,\n refresh_token: tokens.refresh_token,\n site_urls: sites.map((s) => s.siteUrl),\n primary_site_url: chosen.siteUrl,\n obtained_at: new Date().toISOString(),\n scopes: [OAUTH_SCOPE],\n };\n writeStoredCredentials(stored);\n\n process.stderr.write(\n [\n \"\",\n \"Done.\",\n \"\",\n ` Property: ${chosen.siteUrl}`,\n ` Permission: ${chosen.permissionLevel}`,\n ` Saved to: ${credentialsFilePath}`,\n \"\",\n \"Next step: fully quit Claude Desktop (Cmd+Q / File > Exit) and reopen it.\",\n 'Then try: \"List my Search Console properties\"',\n \"\",\n ].join(\"\\n\"),\n );\n}\n\nfunction randomState(): string {\n const bytes = new Uint8Array(16);\n (globalThis.crypto as Crypto).getRandomValues(bytes);\n return Array.from(bytes).map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n// ============================================\n// ENTRY\n// ============================================\n\n// Always run when loaded as an entry point. The bin symlink name (mcp-gsc-auth)\n// differs from the file name (auth-cli.js), so import.meta.url checks don't\n// work reliably under npx. Since this module has no side effects when imported\n// as a library (run() must be called explicitly), unconditional execution is safe.\nrun().catch((err) => {\n const classified = classifyError(err);\n process.stderr.write(`\\n${classified.message}\\n`);\n process.exit(1);\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/build-info.json
CHANGED
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.1",
|
|
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": {
|