@disruptorganic/mcp-google-search-console 1.0.5 → 2.0.0

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 (68) hide show
  1. package/.env.example +70 -112
  2. package/README.md +0 -0
  3. package/dist/auth/account-lock.d.ts +26 -0
  4. package/dist/auth/account-lock.d.ts.map +1 -0
  5. package/dist/auth/account-lock.js +72 -0
  6. package/dist/auth/account-lock.js.map +1 -0
  7. package/dist/auth/oauth2.d.ts.map +1 -1
  8. package/dist/auth/oauth2.js +17 -33
  9. package/dist/auth/oauth2.js.map +1 -1
  10. package/dist/auth/token-validator.d.ts +18 -0
  11. package/dist/auth/token-validator.d.ts.map +1 -0
  12. package/dist/auth/token-validator.js +175 -0
  13. package/dist/auth/token-validator.js.map +1 -0
  14. package/dist/config/index.d.ts +15 -22
  15. package/dist/config/index.d.ts.map +1 -1
  16. package/dist/config/index.js +89 -79
  17. package/dist/config/index.js.map +1 -1
  18. package/dist/index.js +118 -70
  19. package/dist/index.js.map +1 -1
  20. package/dist/server/http.d.ts +36 -0
  21. package/dist/server/http.d.ts.map +1 -0
  22. package/dist/server/http.js +394 -0
  23. package/dist/server/http.js.map +1 -0
  24. package/dist/tools/compare-date-ranges.d.ts +1 -1
  25. package/dist/tools/compare-date-ranges.d.ts.map +1 -1
  26. package/dist/tools/compare-date-ranges.js +13 -12
  27. package/dist/tools/compare-date-ranges.js.map +1 -1
  28. package/dist/tools/get-property-info.d.ts +1 -1
  29. package/dist/tools/get-property-info.d.ts.map +1 -1
  30. package/dist/tools/get-property-info.js +13 -12
  31. package/dist/tools/get-property-info.js.map +1 -1
  32. package/dist/tools/get-top-pages.d.ts +1 -1
  33. package/dist/tools/get-top-pages.d.ts.map +1 -1
  34. package/dist/tools/get-top-pages.js +13 -12
  35. package/dist/tools/get-top-pages.js.map +1 -1
  36. package/dist/tools/get-top-queries.d.ts +1 -1
  37. package/dist/tools/get-top-queries.d.ts.map +1 -1
  38. package/dist/tools/get-top-queries.js +13 -12
  39. package/dist/tools/get-top-queries.js.map +1 -1
  40. package/dist/tools/health-check.d.ts +1 -1
  41. package/dist/tools/health-check.d.ts.map +1 -1
  42. package/dist/tools/health-check.js +24 -32
  43. package/dist/tools/health-check.js.map +1 -1
  44. package/dist/tools/index.d.ts +3 -19
  45. package/dist/tools/index.d.ts.map +1 -1
  46. package/dist/tools/index.js +0 -3
  47. package/dist/tools/index.js.map +1 -1
  48. package/dist/tools/list-properties.d.ts +1 -1
  49. package/dist/tools/list-properties.d.ts.map +1 -1
  50. package/dist/tools/list-properties.js +13 -12
  51. package/dist/tools/list-properties.js.map +1 -1
  52. package/dist/tools/query-advanced.d.ts +1 -1
  53. package/dist/tools/query-advanced.d.ts.map +1 -1
  54. package/dist/tools/query-advanced.js +13 -12
  55. package/dist/tools/query-advanced.js.map +1 -1
  56. package/dist/tools/query-by-keyword.d.ts +1 -1
  57. package/dist/tools/query-by-keyword.d.ts.map +1 -1
  58. package/dist/tools/query-by-keyword.js +13 -12
  59. package/dist/tools/query-by-keyword.js.map +1 -1
  60. package/dist/tools/query-by-url.d.ts +1 -1
  61. package/dist/tools/query-by-url.d.ts.map +1 -1
  62. package/dist/tools/query-by-url.js +13 -12
  63. package/dist/tools/query-by-url.js.map +1 -1
  64. package/package.json +20 -9
  65. package/dist/tools/auth.d.ts +0 -51
  66. package/dist/tools/auth.d.ts.map +0 -1
  67. package/dist/tools/auth.js +0 -83
  68. package/dist/tools/auth.js.map +0 -1
@@ -0,0 +1,175 @@
1
+ import { OAuth2Client } from 'google-auth-library';
2
+ import NodeCache from 'node-cache';
3
+ import { logger } from '../utils/logger.js';
4
+ const CACHE_TTL_SECONDS = 5 * 60;
5
+ const CACHE_CHECK_PERIOD = 60;
6
+ const MAX_RETRIES = 3;
7
+ const BASE_DELAY_MS = 1000;
8
+ const validationCache = new NodeCache({
9
+ stdTTL: CACHE_TTL_SECONDS,
10
+ checkperiod: CACHE_CHECK_PERIOD,
11
+ useClones: false,
12
+ });
13
+ const oauth2Client = new OAuth2Client();
14
+ function redactToken(token) {
15
+ if (!token || token.length <= 8) {
16
+ return '***';
17
+ }
18
+ return `${token.substring(0, 8)}...`;
19
+ }
20
+ function getCacheKey(accessToken) {
21
+ let hash = 0;
22
+ for (let i = 0; i < accessToken.length; i++) {
23
+ const char = accessToken.charCodeAt(i);
24
+ hash = ((hash << 5) - hash) + char;
25
+ hash = hash & hash;
26
+ }
27
+ return `token_${Math.abs(hash)}`;
28
+ }
29
+ function sleep(ms) {
30
+ return new Promise(resolve => setTimeout(resolve, ms));
31
+ }
32
+ async function validateWithGoogle(accessToken) {
33
+ let lastError;
34
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
35
+ try {
36
+ logger.debug('Validating token with Google API', {
37
+ attempt: attempt + 1,
38
+ maxAttempts: MAX_RETRIES + 1,
39
+ token: redactToken(accessToken),
40
+ });
41
+ const tokenInfo = await oauth2Client.getTokenInfo(accessToken);
42
+ logger.debug('Token validation successful', {
43
+ email: tokenInfo.email,
44
+ userId: tokenInfo.sub,
45
+ hasScope: !!tokenInfo.scope,
46
+ expiresIn: tokenInfo.expires_in,
47
+ });
48
+ if (tokenInfo.expires_in !== undefined && tokenInfo.expires_in <= 0) {
49
+ logger.warn('Token is expired', {
50
+ expiresIn: tokenInfo.expires_in,
51
+ });
52
+ return {
53
+ valid: false,
54
+ error: 'Token expired',
55
+ };
56
+ }
57
+ return {
58
+ valid: true,
59
+ email: tokenInfo.email,
60
+ userId: tokenInfo.sub,
61
+ scope: tokenInfo.scope,
62
+ accessToken,
63
+ };
64
+ }
65
+ catch (error) {
66
+ lastError = error;
67
+ const errorMessage = error.message || String(error);
68
+ const statusCode = error.response?.status || error.code;
69
+ logger.debug('Token validation error', {
70
+ attempt: attempt + 1,
71
+ error: errorMessage,
72
+ statusCode,
73
+ });
74
+ if (errorMessage.includes('invalid_token') ||
75
+ errorMessage.includes('Invalid Value') ||
76
+ statusCode === 400) {
77
+ logger.warn('Invalid token', {
78
+ error: errorMessage,
79
+ token: redactToken(accessToken),
80
+ });
81
+ return {
82
+ valid: false,
83
+ error: 'Invalid token',
84
+ };
85
+ }
86
+ if (statusCode === 429) {
87
+ const retryAfter = error.response?.headers?.['retry-after'];
88
+ logger.warn('Rate limited by Google API', {
89
+ retryAfter,
90
+ attempt: attempt + 1,
91
+ });
92
+ return {
93
+ valid: false,
94
+ error: retryAfter
95
+ ? `Rate limited. Retry after ${retryAfter} seconds.`
96
+ : 'Rate limited by Google API. Please try again later.',
97
+ };
98
+ }
99
+ if (attempt < MAX_RETRIES) {
100
+ const delay = BASE_DELAY_MS * Math.pow(2, attempt);
101
+ logger.debug('Retrying token validation', {
102
+ attempt: attempt + 1,
103
+ delayMs: delay,
104
+ error: errorMessage,
105
+ });
106
+ await sleep(delay);
107
+ continue;
108
+ }
109
+ logger.error('Token validation failed after retries', {
110
+ attempts: MAX_RETRIES + 1,
111
+ error: errorMessage,
112
+ });
113
+ return {
114
+ valid: false,
115
+ error: `Token validation failed: ${errorMessage}`,
116
+ };
117
+ }
118
+ }
119
+ return {
120
+ valid: false,
121
+ error: `Token validation failed: ${lastError?.message || 'Unknown error'}`,
122
+ };
123
+ }
124
+ export async function validateToken(accessToken) {
125
+ if (!accessToken || typeof accessToken !== 'string' || !accessToken.trim()) {
126
+ logger.debug('Empty or invalid token provided');
127
+ return {
128
+ valid: false,
129
+ error: 'Missing or invalid token',
130
+ };
131
+ }
132
+ const token = accessToken.trim();
133
+ const cacheKey = getCacheKey(token);
134
+ const cached = validationCache.get(cacheKey);
135
+ if (cached) {
136
+ logger.debug('Token validation cache hit', {
137
+ valid: cached.valid,
138
+ email: cached.email,
139
+ userId: cached.userId,
140
+ token: redactToken(token),
141
+ });
142
+ return {
143
+ ...cached,
144
+ accessToken: token,
145
+ };
146
+ }
147
+ logger.debug('Token validation cache miss', {
148
+ token: redactToken(token),
149
+ });
150
+ const result = await validateWithGoogle(token);
151
+ validationCache.set(cacheKey, result);
152
+ logger.info('Token validated and cached', {
153
+ valid: result.valid,
154
+ email: result.email,
155
+ userId: result.userId,
156
+ error: result.error,
157
+ token: redactToken(token),
158
+ });
159
+ return result;
160
+ }
161
+ export function clearValidationCache() {
162
+ validationCache.flushAll();
163
+ logger.info('Token validation cache cleared');
164
+ }
165
+ export function getCacheStats() {
166
+ const stats = validationCache.getStats();
167
+ return {
168
+ keys: validationCache.keys().length,
169
+ hits: stats.hits,
170
+ misses: stats.misses,
171
+ hitRate: stats.hits / (stats.hits + stats.misses) || 0,
172
+ ttl: CACHE_TTL_SECONDS,
173
+ };
174
+ }
175
+ //# sourceMappingURL=token-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-validator.js","sourceRoot":"","sources":["../../src/auth/token-validator.ts"],"names":[],"mappings":"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"}
@@ -1,30 +1,23 @@
1
- import { z } from 'zod';
2
- declare const configSchema: z.ZodObject<{
3
- clientId: z.ZodString;
4
- clientSecret: z.ZodString;
5
- tokenPath: z.ZodDefault<z.ZodString>;
6
- redirectUri: z.ZodDefault<z.ZodString>;
7
- logLevel: z.ZodDefault<z.ZodEnum<["error", "warn", "info", "debug"]>>;
8
- }, "strip", z.ZodTypeAny, {
1
+ export interface AppConfig {
9
2
  clientId: string;
10
3
  clientSecret: string;
11
- tokenPath: string;
12
4
  redirectUri: string;
13
- logLevel: "info" | "error" | "warn" | "debug";
14
- }, {
15
- clientId: string;
16
- clientSecret: string;
17
- tokenPath?: string | undefined;
18
- redirectUri?: string | undefined;
19
- logLevel?: "info" | "error" | "warn" | "debug" | undefined;
20
- }>;
21
- export type Config = z.infer<typeof configSchema>;
22
- export declare function getConfig(): Config;
5
+ port: number;
6
+ host: string;
7
+ logLevel: string;
8
+ tokenPath: string;
9
+ rateLimitQPM: number;
10
+ tokenValidationCacheTTL: number;
11
+ propertyCacheTTL: number;
12
+ nodeEnv: string;
13
+ isDevelopment: boolean;
14
+ isProduction: boolean;
15
+ }
16
+ export declare const config: AppConfig;
17
+ export declare function getEnvironment(): string;
23
18
  export declare function getTokenDirectory(): string;
24
19
  export declare function isDevelopment(): boolean;
25
20
  export declare function isProduction(): boolean;
26
- export declare function getEnvironment(): string;
21
+ export declare function logConfiguration(): void;
27
22
  export declare function getConfigSummary(): Record<string, string>;
28
- export declare function logConfigSummary(): void;
29
- export {};
30
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA+BxB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;EAiDhB,CAAC;AASH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAyFlD,wBAAgB,SAAS,IAAI,MAAM,CAKlC;AAoCD,wBAAgB,iBAAiB,IAAI,MAAM,CAG1C;AAKD,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAKD,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAKD,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAUD,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUzD;AAKD,wBAAgB,gBAAgB,IAAI,IAAI,CAMvC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,SAAS;IAExB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IAGpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IAGb,QAAQ,EAAE,MAAM,CAAC;IAGjB,SAAS,EAAE,MAAM,CAAC;IAGlB,YAAY,EAAE,MAAM,CAAC;IAGrB,uBAAuB,EAAE,MAAM,CAAC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IAGzB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;CACvB;AA8GD,eAAO,MAAM,MAAM,EAAE,SAAwB,CAAC;AAS9C,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAKD,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAKD,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAKD,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AASD,wBAAgB,gBAAgB,IAAI,IAAI,CAsBvC;AAMD,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAczD"}
@@ -1,101 +1,111 @@
1
- import { z } from 'zod';
2
1
  import * as path from 'path';
3
2
  import * as os from 'os';
4
- const EMBEDDED_CLIENT_ID = '34697290414-f3416jghvqmstm167lklfo1lbddnlsf4.apps.googleusercontent.com';
5
- const EMBEDDED_CLIENT_SECRET = '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';
6
- const configSchema = z.object({
7
- clientId: z.string().min(1, 'Client ID is required'),
8
- clientSecret: z.string().min(1, 'Client Secret is required'),
9
- tokenPath: z.string().default(path.join(os.homedir(), '.mcp-gsc', 'tokens.json')),
10
- redirectUri: z.string().default('urn:ietf:wg:oauth:2.0:oob'),
11
- logLevel: z.enum(['error', 'warn', 'info', 'debug']).default('info'),
12
- });
13
- function loadConfig() {
14
- const rawConfig = {
15
- clientId: EMBEDDED_CLIENT_ID,
16
- clientSecret: EMBEDDED_CLIENT_SECRET,
17
- tokenPath: process.env.GSC_TOKEN_PATH,
18
- redirectUri: process.env.GSC_REDIRECT_URI,
19
- logLevel: process.env.LOG_LEVEL,
20
- };
21
- try {
22
- return configSchema.parse(rawConfig);
3
+ import { logger } from '../utils/logger.js';
4
+ function validateRequiredEnvVars() {
5
+ const required = ['GOOGLE_CLIENT_ID', 'GOOGLE_CLIENT_SECRET'];
6
+ const missing = [];
7
+ for (const varName of required) {
8
+ if (!process.env[varName]) {
9
+ missing.push(varName);
10
+ }
23
11
  }
24
- catch (error) {
25
- if (error instanceof z.ZodError) {
26
- const missingFields = error.issues
27
- .map(issue => {
28
- const field = issue.path.join('.');
29
- return ` - ${field}: ${issue.message}`;
30
- })
31
- .join('\n');
32
- const errorMessage = `
33
- Configuration Error: Invalid configuration
12
+ if (missing.length > 0) {
13
+ const errorMessage = `
14
+ ╔════════════════════════════════════════════════════════════════╗
15
+ ║ CONFIGURATION ERROR: Missing Required Environment Variables ║
16
+ ╚════════════════════════════════════════════════════════════════╝
34
17
 
35
- ${missingFields}
18
+ The following required environment variables are not set:
19
+ ${missing.map(v => ` - ${v}`).join('\n')}
36
20
 
37
- OAuth2 credentials are pre-configured and embedded in this package.
38
- No setup required for authentication credentials.
21
+ To fix this:
39
22
 
40
- Optional environment variables (with defaults):
41
- - GSC_TOKEN_PATH: Token storage path (default: ~/.mcp-gsc/tokens.json)
42
- - GSC_REDIRECT_URI: OAuth redirect URI (default: urn:ietf:wg:oauth:2.0:oob)
43
- - LOG_LEVEL: Logging level (default: info, options: error, warn, info, debug)
23
+ 1. Create a .env file in the project root
24
+ 2. Copy .env.example to .env: cp .env.example .env
25
+ 3. Add your Google OAuth credentials:
26
+ - Get them from: https://console.cloud.google.com
27
+ - See docs/GOOGLE_OAUTH_SETUP.md for instructions
44
28
 
45
- See documentation for configuration details.
46
- `.trim();
47
- throw new Error(errorMessage);
48
- }
49
- throw error;
29
+ Example .env file:
30
+ GOOGLE_CLIENT_ID=123456789-abc...apps.googleusercontent.com
31
+ GOOGLE_CLIENT_SECRET=GOCSPX-abc...xyz
32
+
33
+ Then restart the server.
34
+ `.trim();
35
+ logger.error(errorMessage);
36
+ throw new Error('Missing required environment variables');
50
37
  }
51
38
  }
52
- let cachedConfig = null;
53
- export function getConfig() {
54
- if (!cachedConfig) {
55
- cachedConfig = loadConfig();
56
- }
57
- return cachedConfig;
39
+ function loadConfig() {
40
+ validateRequiredEnvVars();
41
+ const nodeEnv = process.env.NODE_ENV || 'production';
42
+ return {
43
+ clientId: process.env.GOOGLE_CLIENT_ID,
44
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
45
+ redirectUri: process.env.GOOGLE_REDIRECT_URI ||
46
+ 'http://localhost:3456/oauth/callback',
47
+ port: parseInt(process.env.MCP_PORT || '3456', 10),
48
+ host: process.env.MCP_HOST || 'localhost',
49
+ logLevel: process.env.LOG_LEVEL || 'info',
50
+ tokenPath: process.env.GSC_TOKEN_PATH ||
51
+ path.join(os.homedir(), '.config/gsc-mcp/tokens.json'),
52
+ rateLimitQPM: parseInt(process.env.GSC_RATE_LIMIT_QPM || '1200', 10),
53
+ tokenValidationCacheTTL: parseInt(process.env.TOKEN_VALIDATION_CACHE_TTL || '300', 10),
54
+ propertyCacheTTL: parseInt(process.env.PROPERTY_CACHE_TTL || '86400', 10),
55
+ nodeEnv,
56
+ isDevelopment: nodeEnv === 'development',
57
+ isProduction: nodeEnv === 'production',
58
+ };
59
+ }
60
+ export const config = loadConfig();
61
+ export function getEnvironment() {
62
+ return config.nodeEnv;
58
63
  }
59
- let _deprecatedConfig = null;
60
- Object.defineProperty(exports, 'config', {
61
- get() {
62
- if (!_deprecatedConfig) {
63
- _deprecatedConfig = getConfig();
64
- }
65
- return _deprecatedConfig;
66
- },
67
- enumerable: true,
68
- configurable: false,
69
- });
70
64
  export function getTokenDirectory() {
71
- const cfg = getConfig();
72
- return path.dirname(cfg.tokenPath);
65
+ return path.dirname(config.tokenPath);
73
66
  }
74
67
  export function isDevelopment() {
75
- return process.env.NODE_ENV === 'development';
68
+ return config.isDevelopment;
76
69
  }
77
70
  export function isProduction() {
78
- return process.env.NODE_ENV === 'production';
71
+ return config.isProduction;
79
72
  }
80
- export function getEnvironment() {
81
- return process.env.NODE_ENV || 'development';
73
+ export function logConfiguration() {
74
+ logger.info('Configuration loaded', {
75
+ server: {
76
+ port: config.port,
77
+ host: config.host,
78
+ nodeEnv: config.nodeEnv,
79
+ },
80
+ oauth: {
81
+ clientId: config.clientId.substring(0, 20) + '...',
82
+ redirectUri: config.redirectUri,
83
+ },
84
+ caching: {
85
+ tokenValidationCacheTTL: config.tokenValidationCacheTTL,
86
+ propertyCacheTTL: config.propertyCacheTTL,
87
+ },
88
+ rateLimiting: {
89
+ qpm: config.rateLimitQPM,
90
+ },
91
+ logging: {
92
+ level: config.logLevel,
93
+ },
94
+ });
82
95
  }
83
96
  export function getConfigSummary() {
84
- const cfg = getConfig();
85
97
  return {
86
- clientId: cfg.clientId.substring(0, 8) + '...',
87
- clientSecret: '***',
88
- tokenPath: cfg.tokenPath,
89
- redirectUri: cfg.redirectUri,
90
- logLevel: cfg.logLevel,
91
- environment: getEnvironment(),
98
+ clientId: config.clientId.substring(0, 20) + '...',
99
+ clientSecret: '***REDACTED***',
100
+ redirectUri: config.redirectUri,
101
+ tokenPath: config.tokenPath,
102
+ port: config.port.toString(),
103
+ host: config.host,
104
+ logLevel: config.logLevel,
105
+ environment: config.nodeEnv,
106
+ rateLimitQPM: config.rateLimitQPM.toString(),
107
+ tokenValidationCacheTTL: config.tokenValidationCacheTTL.toString(),
108
+ propertyCacheTTL: config.propertyCacheTTL.toString(),
92
109
  };
93
110
  }
94
- export function logConfigSummary() {
95
- console.log('Configuration loaded successfully:');
96
- const summary = getConfigSummary();
97
- Object.entries(summary).forEach(([key, value]) => {
98
- console.log(` ${key}: ${value}`);
99
- });
100
- }
101
111
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}