@disruptorganic/mcp-google-search-console 1.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 (108) hide show
  1. package/.env.example +141 -0
  2. package/LICENSE +21 -0
  3. package/README.md +0 -0
  4. package/dist/auth/index.d.ts +3 -0
  5. package/dist/auth/index.d.ts.map +1 -0
  6. package/dist/auth/index.js +2 -0
  7. package/dist/auth/index.js.map +1 -0
  8. package/dist/auth/oauth2.d.ts +31 -0
  9. package/dist/auth/oauth2.d.ts.map +1 -0
  10. package/dist/auth/oauth2.js +380 -0
  11. package/dist/auth/oauth2.js.map +1 -0
  12. package/dist/config/index.d.ts +36 -0
  13. package/dist/config/index.d.ts.map +1 -0
  14. package/dist/config/index.js +87 -0
  15. package/dist/config/index.js.map +1 -0
  16. package/dist/gsc/client.d.ts +72 -0
  17. package/dist/gsc/client.d.ts.map +1 -0
  18. package/dist/gsc/client.js +243 -0
  19. package/dist/gsc/client.js.map +1 -0
  20. package/dist/gsc/index.d.ts +3 -0
  21. package/dist/gsc/index.d.ts.map +1 -0
  22. package/dist/gsc/index.js +3 -0
  23. package/dist/gsc/index.js.map +1 -0
  24. package/dist/gsc/properties.d.ts +42 -0
  25. package/dist/gsc/properties.d.ts.map +1 -0
  26. package/dist/gsc/properties.js +393 -0
  27. package/dist/gsc/properties.js.map +1 -0
  28. package/dist/gsc/queries.d.ts +73 -0
  29. package/dist/gsc/queries.d.ts.map +1 -0
  30. package/dist/gsc/queries.js +390 -0
  31. package/dist/gsc/queries.js.map +1 -0
  32. package/dist/index.d.ts +3 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +186 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/tools/compare-date-ranges.d.ts +83 -0
  37. package/dist/tools/compare-date-ranges.d.ts.map +1 -0
  38. package/dist/tools/compare-date-ranges.js +462 -0
  39. package/dist/tools/compare-date-ranges.js.map +1 -0
  40. package/dist/tools/get-property-info.d.ts +30 -0
  41. package/dist/tools/get-property-info.d.ts.map +1 -0
  42. package/dist/tools/get-property-info.js +174 -0
  43. package/dist/tools/get-property-info.js.map +1 -0
  44. package/dist/tools/get-top-pages.d.ts +103 -0
  45. package/dist/tools/get-top-pages.d.ts.map +1 -0
  46. package/dist/tools/get-top-pages.js +254 -0
  47. package/dist/tools/get-top-pages.js.map +1 -0
  48. package/dist/tools/get-top-queries.d.ts +103 -0
  49. package/dist/tools/get-top-queries.d.ts.map +1 -0
  50. package/dist/tools/get-top-queries.js +254 -0
  51. package/dist/tools/get-top-queries.js.map +1 -0
  52. package/dist/tools/health-check.d.ts +12 -0
  53. package/dist/tools/health-check.d.ts.map +1 -0
  54. package/dist/tools/health-check.js +107 -0
  55. package/dist/tools/health-check.js.map +1 -0
  56. package/dist/tools/index.d.ts +1124 -0
  57. package/dist/tools/index.d.ts.map +1 -0
  58. package/dist/tools/index.js +70 -0
  59. package/dist/tools/index.js.map +1 -0
  60. package/dist/tools/list-properties.d.ts +50 -0
  61. package/dist/tools/list-properties.d.ts.map +1 -0
  62. package/dist/tools/list-properties.js +234 -0
  63. package/dist/tools/list-properties.js.map +1 -0
  64. package/dist/tools/query-advanced.d.ts +109 -0
  65. package/dist/tools/query-advanced.d.ts.map +1 -0
  66. package/dist/tools/query-advanced.js +378 -0
  67. package/dist/tools/query-advanced.js.map +1 -0
  68. package/dist/tools/query-by-keyword.d.ts +115 -0
  69. package/dist/tools/query-by-keyword.d.ts.map +1 -0
  70. package/dist/tools/query-by-keyword.js +339 -0
  71. package/dist/tools/query-by-keyword.js.map +1 -0
  72. package/dist/tools/query-by-url.d.ts +116 -0
  73. package/dist/tools/query-by-url.d.ts.map +1 -0
  74. package/dist/tools/query-by-url.js +366 -0
  75. package/dist/tools/query-by-url.js.map +1 -0
  76. package/dist/utils/cache.d.ts +22 -0
  77. package/dist/utils/cache.d.ts.map +1 -0
  78. package/dist/utils/cache.js +75 -0
  79. package/dist/utils/cache.js.map +1 -0
  80. package/dist/utils/index.d.ts +8 -0
  81. package/dist/utils/index.d.ts.map +1 -0
  82. package/dist/utils/index.js +8 -0
  83. package/dist/utils/index.js.map +1 -0
  84. package/dist/utils/logger.d.ts +4 -0
  85. package/dist/utils/logger.d.ts.map +1 -0
  86. package/dist/utils/logger.js +15 -0
  87. package/dist/utils/logger.js.map +1 -0
  88. package/dist/utils/metrics.d.ts +9 -0
  89. package/dist/utils/metrics.d.ts.map +1 -0
  90. package/dist/utils/metrics.js +54 -0
  91. package/dist/utils/metrics.js.map +1 -0
  92. package/dist/utils/rate-limiter.d.ts +24 -0
  93. package/dist/utils/rate-limiter.d.ts.map +1 -0
  94. package/dist/utils/rate-limiter.js +175 -0
  95. package/dist/utils/rate-limiter.js.map +1 -0
  96. package/dist/utils/token-estimator.d.ts +33 -0
  97. package/dist/utils/token-estimator.d.ts.map +1 -0
  98. package/dist/utils/token-estimator.js +226 -0
  99. package/dist/utils/token-estimator.js.map +1 -0
  100. package/dist/utils/types.d.ts +68 -0
  101. package/dist/utils/types.d.ts.map +1 -0
  102. package/dist/utils/types.js +13 -0
  103. package/dist/utils/types.js.map +1 -0
  104. package/dist/utils/validators.d.ts +579 -0
  105. package/dist/utils/validators.d.ts.map +1 -0
  106. package/dist/utils/validators.js +358 -0
  107. package/dist/utils/validators.js.map +1 -0
  108. package/package.json +73 -0
@@ -0,0 +1,366 @@
1
+ import { z } from 'zod';
2
+ import { listProperties, matchProperty, generatePropertyMatchError } from '../gsc/properties.js';
3
+ import { executeParallelQueries, aggregateResults } from '../gsc/queries.js';
4
+ import { chunkResults } from '../utils/token-estimator.js';
5
+ import { validateDateRangeStrict, validateDimensions } from '../utils/validators.js';
6
+ import { logger } from '../utils/logger.js';
7
+ export const QueryByUrlSchema = z.object({
8
+ property: z.string()
9
+ .min(1, 'Property identifier is required')
10
+ .describe('Property identifier from list_properties (e.g., "sc-domain:example.com")'),
11
+ urls: z.array(z.string().url('Must be a valid URL').refine(url => url.startsWith('http://') || url.startsWith('https://'), 'URL must start with http:// or https://'))
12
+ .min(1, 'At least one URL is required')
13
+ .max(50, 'Maximum 50 URLs allowed per request')
14
+ .describe('Array of page URLs to query (1-50 URLs)'),
15
+ startDate: z.string()
16
+ .regex(/^\d{4}-\d{2}-\d{2}$/, 'Start date must be in ISO 8601 format (YYYY-MM-DD)')
17
+ .describe('Start date in ISO 8601 format (YYYY-MM-DD)'),
18
+ endDate: z.string()
19
+ .regex(/^\d{4}-\d{2}-\d{2}$/, 'End date must be in ISO 8601 format (YYYY-MM-DD)')
20
+ .describe('End date in ISO 8601 format (YYYY-MM-DD)'),
21
+ searchType: z.enum(['web', 'image', 'video', 'news', 'discover', 'googleNews'])
22
+ .optional()
23
+ .default('web')
24
+ .describe('Search type filter (default: web)'),
25
+ dimensions: z.array(z.enum(['query', 'device', 'country', 'searchAppearance', 'date']))
26
+ .optional()
27
+ .describe('Additional dimensions beyond page (max 2 additional for total of 3)'),
28
+ deviceType: z.enum(['desktop', 'mobile', 'tablet'])
29
+ .optional()
30
+ .describe('Filter by device type'),
31
+ country: z.string()
32
+ .length(3, 'Country code must be 3 letters')
33
+ .regex(/^[a-z]{3}$/, 'Country code must be 3 lowercase letters (ISO 3166-1 alpha-3)')
34
+ .optional()
35
+ .describe('Filter by country code (e.g., "usa", "gbr")'),
36
+ offset: z.number()
37
+ .int('Offset must be an integer')
38
+ .min(0, 'Offset must be non-negative')
39
+ .optional()
40
+ .default(0)
41
+ .describe('Pagination offset for chunked responses (default: 0)'),
42
+ limit: z.number()
43
+ .int('Limit must be an integer')
44
+ .min(1, 'Limit must be at least 1')
45
+ .max(25000, 'Limit cannot exceed 25,000 (GSC API limit)')
46
+ .optional()
47
+ .describe('Max rows per chunk (auto-calculated if not provided)'),
48
+ });
49
+ export const queryByUrlTool = {
50
+ name: 'query_by_url',
51
+ description: 'Retrieves search performance data for specific URLs/pages from Google Search Console. Shows which keywords drive traffic to each URL with clicks, impressions, CTR, and position. Supports filtering by date range, search type (web/image/video/news), device, and country. Automatically chunks large results under 20k tokens with pagination. IMPORTANT: Use list_properties first to get the correct property identifier.',
52
+ inputSchema: {
53
+ type: 'object',
54
+ properties: {
55
+ property: {
56
+ type: 'string',
57
+ description: 'Property identifier from list_properties (e.g., "sc-domain:example.com")',
58
+ },
59
+ urls: {
60
+ type: 'array',
61
+ items: { type: 'string', format: 'uri' },
62
+ description: 'Array of page URLs to query (1-50 URLs)',
63
+ minItems: 1,
64
+ maxItems: 50,
65
+ },
66
+ startDate: {
67
+ type: 'string',
68
+ description: 'Start date in ISO 8601 format (YYYY-MM-DD)',
69
+ pattern: '^\\d{4}-\\d{2}-\\d{2}$',
70
+ },
71
+ endDate: {
72
+ type: 'string',
73
+ description: 'End date in ISO 8601 format (YYYY-MM-DD)',
74
+ pattern: '^\\d{4}-\\d{2}-\\d{2}$',
75
+ },
76
+ searchType: {
77
+ type: 'string',
78
+ enum: ['web', 'image', 'video', 'news', 'discover', 'googleNews'],
79
+ description: 'Search type filter (default: web)',
80
+ default: 'web',
81
+ },
82
+ dimensions: {
83
+ type: 'array',
84
+ items: {
85
+ type: 'string',
86
+ enum: ['query', 'device', 'country', 'searchAppearance', 'date'],
87
+ },
88
+ description: 'Additional dimensions beyond page (max 2 additional for total of 3)',
89
+ },
90
+ deviceType: {
91
+ type: 'string',
92
+ enum: ['desktop', 'mobile', 'tablet'],
93
+ description: 'Filter by device type',
94
+ },
95
+ country: {
96
+ type: 'string',
97
+ description: 'Filter by country code (e.g., "usa", "gbr")',
98
+ pattern: '^[a-z]{3}$',
99
+ },
100
+ offset: {
101
+ type: 'number',
102
+ description: 'Pagination offset for chunked responses (default: 0)',
103
+ default: 0,
104
+ minimum: 0,
105
+ },
106
+ limit: {
107
+ type: 'number',
108
+ description: 'Max rows per chunk (auto-calculated if not provided)',
109
+ minimum: 1,
110
+ maximum: 25000,
111
+ },
112
+ },
113
+ required: ['property', 'urls', 'startDate', 'endDate'],
114
+ },
115
+ };
116
+ function formatResultRow(keys, dimensions, clicks, impressions, ctr, position) {
117
+ const row = {};
118
+ dimensions.forEach((dim, index) => {
119
+ row[dim] = keys[index] || '';
120
+ });
121
+ row.clicks = clicks;
122
+ row.impressions = impressions;
123
+ row.ctr = parseFloat((ctr * 100).toFixed(2));
124
+ row.position = parseFloat(position.toFixed(1));
125
+ return row;
126
+ }
127
+ function createPageFilter(url) {
128
+ return {
129
+ dimension: 'page',
130
+ operator: 'equals',
131
+ expression: url,
132
+ };
133
+ }
134
+ export async function handleQueryByUrl(params, client) {
135
+ try {
136
+ logger.info('Handling query_by_url request', {
137
+ propertyInput: params.property,
138
+ urlCount: params.urls?.length,
139
+ dateRange: params.startDate && params.endDate ? `${params.startDate} to ${params.endDate}` : 'not provided',
140
+ });
141
+ const validationResult = QueryByUrlSchema.safeParse(params);
142
+ if (!validationResult.success) {
143
+ const errorMessages = validationResult.error.issues.map(issue => {
144
+ const path = issue.path.length > 0 ? `${issue.path.join('.')}: ` : '';
145
+ return `${path}${issue.message}`;
146
+ }).join('; ');
147
+ logger.error('Input validation failed', {
148
+ errors: errorMessages,
149
+ params,
150
+ });
151
+ return {
152
+ content: [{
153
+ type: 'text',
154
+ text: JSON.stringify({
155
+ error: 'Input validation failed',
156
+ details: errorMessages,
157
+ }, null, 2),
158
+ }],
159
+ isError: true,
160
+ };
161
+ }
162
+ const validated = validationResult.data;
163
+ try {
164
+ validateDateRangeStrict(validated.startDate, validated.endDate);
165
+ }
166
+ catch (error) {
167
+ const errorMessage = error instanceof Error ? error.message : String(error);
168
+ logger.error('Date range validation failed', {
169
+ startDate: validated.startDate,
170
+ endDate: validated.endDate,
171
+ error: errorMessage,
172
+ });
173
+ return {
174
+ content: [{
175
+ type: 'text',
176
+ text: JSON.stringify({
177
+ error: 'Invalid date range',
178
+ details: errorMessage,
179
+ }, null, 2),
180
+ }],
181
+ isError: true,
182
+ };
183
+ }
184
+ const allDimensions = ['page', ...(validated.dimensions || [])];
185
+ try {
186
+ validateDimensions(allDimensions, 3);
187
+ }
188
+ catch (error) {
189
+ const errorMessage = error instanceof Error ? error.message : String(error);
190
+ logger.error('Dimension validation failed', {
191
+ dimensions: allDimensions,
192
+ error: errorMessage,
193
+ });
194
+ return {
195
+ content: [{
196
+ type: 'text',
197
+ text: JSON.stringify({
198
+ error: 'Too many dimensions',
199
+ details: errorMessage,
200
+ }, null, 2),
201
+ }],
202
+ isError: true,
203
+ };
204
+ }
205
+ logger.debug('Fetching available properties');
206
+ const availableProperties = await listProperties(client);
207
+ if (availableProperties.length === 0) {
208
+ logger.warn('No properties found for this account');
209
+ return {
210
+ content: [{
211
+ type: 'text',
212
+ text: JSON.stringify({
213
+ error: 'No properties found',
214
+ details: 'No Google Search Console properties are accessible with this account. Please verify your account has access to at least one property.',
215
+ }, null, 2),
216
+ }],
217
+ isError: true,
218
+ };
219
+ }
220
+ const matchResult = matchProperty(validated.property, availableProperties);
221
+ if (!matchResult.matched) {
222
+ const errorMessage = generatePropertyMatchError(matchResult, availableProperties);
223
+ logger.error('Property matching failed', {
224
+ searchInput: validated.property,
225
+ matchType: matchResult.matchType,
226
+ alternativeCount: matchResult.alternatives?.length || 0,
227
+ });
228
+ return {
229
+ content: [{
230
+ type: 'text',
231
+ text: JSON.stringify({
232
+ error: 'Property not found or ambiguous',
233
+ details: errorMessage,
234
+ }, null, 2),
235
+ }],
236
+ isError: true,
237
+ };
238
+ }
239
+ const matchedProperty = matchResult.matched;
240
+ logger.info('Property matched successfully', {
241
+ searchInput: validated.property,
242
+ matched: matchedProperty.propertyUrl,
243
+ matchType: matchResult.matchType,
244
+ });
245
+ const baseFilters = [];
246
+ if (validated.deviceType) {
247
+ baseFilters.push({
248
+ dimension: 'device',
249
+ operator: 'equals',
250
+ expression: validated.deviceType,
251
+ });
252
+ }
253
+ if (validated.country) {
254
+ baseFilters.push({
255
+ dimension: 'country',
256
+ operator: 'equals',
257
+ expression: validated.country.toLowerCase(),
258
+ });
259
+ }
260
+ const queries = validated.urls.map(url => ({
261
+ propertyUrl: matchedProperty.propertyUrl,
262
+ startDate: validated.startDate,
263
+ endDate: validated.endDate,
264
+ dimensions: allDimensions,
265
+ filters: [
266
+ {
267
+ filters: [
268
+ createPageFilter(url),
269
+ ...baseFilters,
270
+ ],
271
+ },
272
+ ],
273
+ searchType: validated.searchType,
274
+ rowLimit: 25000,
275
+ startRow: 0,
276
+ }));
277
+ logger.info('Executing multi-URL query', {
278
+ property: matchedProperty.propertyUrl,
279
+ urlCount: validated.urls.length,
280
+ dateRange: `${validated.startDate} to ${validated.endDate}`,
281
+ dimensions: allDimensions,
282
+ searchType: validated.searchType,
283
+ });
284
+ const rateLimiter = client.getRateLimiter();
285
+ const results = await executeParallelQueries(client, queries, rateLimiter);
286
+ const aggregated = aggregateResults(results);
287
+ const errors = [];
288
+ results.forEach((result, index) => {
289
+ if (!result.rows || result.rows.length === 0) {
290
+ const url = validated.urls[index];
291
+ if (url) {
292
+ errors.push({
293
+ url,
294
+ error: 'Query returned no results or failed',
295
+ });
296
+ }
297
+ }
298
+ });
299
+ logger.info('Multi-URL query completed', {
300
+ totalRows: aggregated.totalRows,
301
+ successful: aggregated.queryCounts.successful,
302
+ failed: aggregated.queryCounts.failed,
303
+ });
304
+ const formattedResults = aggregated.rows.map(row => formatResultRow(row.keys, allDimensions, row.clicks, row.impressions, row.ctr, row.position));
305
+ const chunked = chunkResults(formattedResults, validated.offset, validated.limit);
306
+ logger.info('Results chunked', {
307
+ totalRows: formattedResults.length,
308
+ offset: validated.offset,
309
+ limit: chunked.pagination.limit,
310
+ currentChunk: chunked.pagination.current_chunk,
311
+ totalChunks: chunked.pagination.total_chunks,
312
+ hasMore: chunked.pagination.has_more,
313
+ });
314
+ const response = {
315
+ property: matchedProperty.propertyUrl,
316
+ urls: validated.urls,
317
+ dateRange: {
318
+ start: validated.startDate,
319
+ end: validated.endDate,
320
+ },
321
+ filters: {
322
+ searchType: validated.searchType,
323
+ deviceType: validated.deviceType,
324
+ country: validated.country,
325
+ },
326
+ results: chunked.results,
327
+ pagination: chunked.pagination,
328
+ metadata: {
329
+ queryCounts: aggregated.queryCounts,
330
+ errors: errors.length > 0 ? errors : undefined,
331
+ },
332
+ };
333
+ logger.info('Query by URL completed successfully', {
334
+ property: matchedProperty.propertyUrl,
335
+ urlCount: validated.urls.length,
336
+ resultsReturned: chunked.results.length,
337
+ hasMore: chunked.pagination.has_more,
338
+ });
339
+ return {
340
+ content: [{
341
+ type: 'text',
342
+ text: JSON.stringify(response, null, 2),
343
+ }],
344
+ };
345
+ }
346
+ catch (error) {
347
+ const errorMessage = error instanceof Error ? error.message : String(error);
348
+ const errorStack = error instanceof Error ? error.stack : undefined;
349
+ logger.error('Query by URL handler failed', {
350
+ error: errorMessage,
351
+ stack: errorStack,
352
+ params,
353
+ });
354
+ return {
355
+ content: [{
356
+ type: 'text',
357
+ text: JSON.stringify({
358
+ error: 'Query execution failed',
359
+ details: errorMessage,
360
+ }, null, 2),
361
+ }],
362
+ isError: true,
363
+ };
364
+ }
365
+ }
366
+ //# sourceMappingURL=query-by-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-by-url.js","sourceRoot":"","sources":["../../src/tools/query-by-url.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export declare class PropertyCache {
2
+ private cache;
3
+ private readonly defaultTtl;
4
+ constructor(ttlSeconds?: number);
5
+ get<T>(key: string): T | undefined;
6
+ set(key: string, value: unknown, ttl?: number): void;
7
+ invalidate(key?: string): void;
8
+ getStats(): {
9
+ keys: number;
10
+ hits: number;
11
+ misses: number;
12
+ hitRate: number;
13
+ };
14
+ has(key: string): boolean;
15
+ getTtl(key: string): number | undefined;
16
+ keys(): string[];
17
+ }
18
+ export declare const propertyCache: PropertyCache;
19
+ export declare const CACHE_KEYS: {
20
+ readonly PROPERTIES: "gsc:properties";
21
+ };
22
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAoCA,qBAAa,aAAa;IACxB,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAOxB,UAAU,GAAE,MAAc;IAoBtC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAmBlC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAoBpD,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAe9B,QAAQ,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAmB3E,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAUzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IASvC,IAAI,IAAI,MAAM,EAAE;CAGjB;AAQD,eAAO,MAAM,aAAa,eAA2B,CAAC;AAKtD,eAAO,MAAM,UAAU;;CAEb,CAAC"}
@@ -0,0 +1,75 @@
1
+ import NodeCache from 'node-cache';
2
+ import { logger } from './logger.js';
3
+ export class PropertyCache {
4
+ constructor(ttlSeconds = 86400) {
5
+ this.defaultTtl = ttlSeconds;
6
+ this.cache = new NodeCache({
7
+ stdTTL: ttlSeconds,
8
+ checkperiod: 600,
9
+ useClones: false,
10
+ });
11
+ logger.info('PropertyCache initialized', {
12
+ defaultTtl: ttlSeconds,
13
+ defaultTtlHours: ttlSeconds / 3600,
14
+ });
15
+ }
16
+ get(key) {
17
+ const value = this.cache.get(key);
18
+ if (value !== undefined) {
19
+ logger.debug('Cache hit', { key });
20
+ }
21
+ else {
22
+ logger.debug('Cache miss', { key });
23
+ }
24
+ return value;
25
+ }
26
+ set(key, value, ttl) {
27
+ const effectiveTtl = ttl ?? this.defaultTtl;
28
+ const success = this.cache.set(key, value, effectiveTtl);
29
+ if (success) {
30
+ logger.debug('Cache set', {
31
+ key,
32
+ ttl: effectiveTtl,
33
+ ttlHours: effectiveTtl / 3600,
34
+ });
35
+ }
36
+ else {
37
+ logger.warn('Failed to set cache value', { key });
38
+ }
39
+ }
40
+ invalidate(key) {
41
+ if (key) {
42
+ const deleted = this.cache.del(key);
43
+ logger.info('Cache key invalidated', { key, deleted: deleted > 0 });
44
+ }
45
+ else {
46
+ this.cache.flushAll();
47
+ logger.info('Cache completely invalidated');
48
+ }
49
+ }
50
+ getStats() {
51
+ const stats = this.cache.getStats();
52
+ const total = stats.hits + stats.misses;
53
+ const hitRate = total > 0 ? (stats.hits / total) * 100 : 0;
54
+ return {
55
+ keys: this.cache.keys().length,
56
+ hits: stats.hits,
57
+ misses: stats.misses,
58
+ hitRate: parseFloat(hitRate.toFixed(2)),
59
+ };
60
+ }
61
+ has(key) {
62
+ return this.cache.has(key);
63
+ }
64
+ getTtl(key) {
65
+ return this.cache.getTtl(key);
66
+ }
67
+ keys() {
68
+ return this.cache.keys();
69
+ }
70
+ }
71
+ export const propertyCache = new PropertyCache(86400);
72
+ export const CACHE_KEYS = {
73
+ PROPERTIES: 'gsc:properties',
74
+ };
75
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { logger, type LogLevel } from './logger.js';
2
+ export { propertyCache, CACHE_KEYS } from './cache.js';
3
+ export { TokenBucketRateLimiter, withExponentialBackoff, createRateLimitedFunction, type BackoffOptions } from './rate-limiter.js';
4
+ export { estimateTokens, estimateTokensForJson, calculateChunkSize, chunkResults, estimateTotalTokens, needsChunking, generatePaginationMetadata, validatePaginationParams, MAX_SAFE_TOKENS, CHARS_PER_TOKEN, type PaginationMetadata, type ChunkedResponse } from './token-estimator.js';
5
+ export { type DimensionFilter, type GSCDimension, type FilterOperator, type SortMetric, type SortOrder, type PositionRange, type TopQueryResult, type TopPageResult, type PeriodMetrics, type MetricChanges, type MetricComparison, type QueryComparison, type PageComparison, type PropertyInfo, type AdvancedQueryResult, isGSCDimension, isFilterOperator, isSortMetric, isSortOrder } from './types.js';
6
+ export { calculateAbsoluteChange, calculatePercentChange, calculatePositionChange, calculateMetricChanges, formatPercentChange, formatPositionChange, isSignificantChange } from './metrics.js';
7
+ export { comparisonSortBySchema, positionRangeSchema, topNLimitSchema, minClicksSchema, minImpressionsSchema, queryAdvancedParamsSchema, getTopQueriesParamsSchema, getTopPagesParamsSchema, compareDateRangesParamsSchema, getPropertyInfoParamsSchema, VALID_GSC_DIMENSIONS, VALID_FILTER_OPERATORS, VALID_SORT_METRICS, VALID_COMPARISON_SORT_METRICS, type ValidFilterOperator, type ValidSortMetric, type ComparisonSortMetric, type QueryAdvancedParams, type GetTopQueriesParams, type GetTopPagesParams, type CompareDateRangesParams, type GetPropertyInfoParams } from './validators.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,EACzB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,0BAA0B,EAC1B,wBAAwB,EACxB,eAAe,EACf,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,EACvB,6BAA6B,EAC7B,2BAA2B,EAC3B,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,6BAA6B,EAC7B,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC3B,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { logger } from './logger.js';
2
+ export { propertyCache, CACHE_KEYS } from './cache.js';
3
+ export { TokenBucketRateLimiter, withExponentialBackoff, createRateLimitedFunction } from './rate-limiter.js';
4
+ export { estimateTokens, estimateTokensForJson, calculateChunkSize, chunkResults, estimateTotalTokens, needsChunking, generatePaginationMetadata, validatePaginationParams, MAX_SAFE_TOKENS, CHARS_PER_TOKEN } from './token-estimator.js';
5
+ export { isGSCDimension, isFilterOperator, isSortMetric, isSortOrder } from './types.js';
6
+ export { calculateAbsoluteChange, calculatePercentChange, calculatePositionChange, calculateMetricChanges, formatPercentChange, formatPositionChange, isSignificantChange } from './metrics.js';
7
+ export { comparisonSortBySchema, positionRangeSchema, topNLimitSchema, minClicksSchema, minImpressionsSchema, queryAdvancedParamsSchema, getTopQueriesParamsSchema, getTopPagesParamsSchema, compareDateRangesParamsSchema, getPropertyInfoParamsSchema, VALID_GSC_DIMENSIONS, VALID_FILTER_OPERATORS, VALID_SORT_METRICS, VALID_COMPARISON_SORT_METRICS } from './validators.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,EAE1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,0BAA0B,EAC1B,wBAAwB,EACxB,eAAe,EACf,eAAe,EAGhB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAgBL,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,EACvB,6BAA6B,EAC7B,2BAA2B,EAC3B,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,6BAA6B,EAS9B,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import winston from 'winston';
2
+ export declare const logger: winston.Logger;
3
+ export type LogLevel = 'error' | 'warn' | 'info' | 'debug';
4
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAuBA,OAAO,OAAO,MAAM,SAAS,CAAC;AAgB9B,eAAO,MAAM,MAAM,gBAmBjB,CAAC;AASH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC"}
@@ -0,0 +1,15 @@
1
+ import winston from 'winston';
2
+ export const logger = winston.createLogger({
3
+ level: process.env.LOG_LEVEL || 'info',
4
+ format: winston.format.combine(winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json()),
5
+ defaultMeta: { service: 'mcp-gsc' },
6
+ transports: [
7
+ new winston.transports.Console({
8
+ format: winston.format.combine(winston.format.colorize(), winston.format.printf(({ timestamp, level, message, ...meta }) => {
9
+ const metaStr = Object.keys(meta).length ? JSON.stringify(meta, null, 2) : '';
10
+ return `${timestamp} [${level}]: ${message} ${metaStr}`;
11
+ })),
12
+ }),
13
+ ],
14
+ });
15
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAuBA,OAAO,OAAO,MAAM,SAAS,CAAC;AAgB9B,MAAM,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IACzC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;IACtC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAC5B,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,EAC1B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EACtC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CACtB;IACD,WAAW,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE;IACnC,UAAU,EAAE;QACV,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC;YAC7B,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,EACzB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE;gBAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9E,OAAO,GAAG,SAAS,KAAK,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;YAC1D,CAAC,CAAC,CACH;SACF,CAAC;KACH;CACF,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { MetricChanges, PeriodMetrics } from './types.js';
2
+ export declare function calculateAbsoluteChange(current: number, previous: number): number;
3
+ export declare function calculatePercentChange(current: number, previous: number): number | null;
4
+ export declare function calculatePositionChange(current: number, previous: number): number;
5
+ export declare function calculateMetricChanges(current: PeriodMetrics, previous: PeriodMetrics): MetricChanges;
6
+ export declare function formatPercentChange(percentChange: number | null, precision?: number): string;
7
+ export declare function formatPositionChange(positionChange: number, precision?: number): string;
8
+ export declare function isSignificantChange(absoluteChange: number, percentChange: number | null, absoluteThreshold?: number, percentThreshold?: number): boolean;
9
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/utils/metrics.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAuB1D,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjF;AAgCD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAavF;AA6BD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjF;AAwCD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,aAAa,GACtB,aAAa,CAaf;AAuBD,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,GAAE,MAAU,GAAG,MAAM,CAO/F;AAoBD,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,SAAS,GAAE,MAAU,GAAG,MAAM,CAW1F;AAsBD,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,iBAAiB,GAAE,MAAW,EAC9B,gBAAgB,GAAE,MAAW,GAC5B,OAAO,CAYT"}
@@ -0,0 +1,54 @@
1
+ export function calculateAbsoluteChange(current, previous) {
2
+ return current - previous;
3
+ }
4
+ export function calculatePercentChange(current, previous) {
5
+ if (previous === 0 && current === 0) {
6
+ return 0;
7
+ }
8
+ if (previous === 0) {
9
+ return null;
10
+ }
11
+ return ((current - previous) / previous) * 100;
12
+ }
13
+ export function calculatePositionChange(current, previous) {
14
+ return current - previous;
15
+ }
16
+ export function calculateMetricChanges(current, previous) {
17
+ return {
18
+ clicks: calculateAbsoluteChange(current.clicks, previous.clicks),
19
+ clicksPercent: calculatePercentChange(current.clicks, previous.clicks),
20
+ impressions: calculateAbsoluteChange(current.impressions, previous.impressions),
21
+ impressionsPercent: calculatePercentChange(current.impressions, previous.impressions),
22
+ position: calculatePositionChange(current.position, previous.position),
23
+ };
24
+ }
25
+ export function formatPercentChange(percentChange, precision = 1) {
26
+ if (percentChange === null) {
27
+ return 'N/A (from zero)';
28
+ }
29
+ const sign = percentChange > 0 ? '+' : '';
30
+ return `${sign}${percentChange.toFixed(precision)}%`;
31
+ }
32
+ export function formatPositionChange(positionChange, precision = 1) {
33
+ const sign = positionChange > 0 ? '+' : '';
34
+ const value = `${sign}${positionChange.toFixed(precision)}`;
35
+ if (positionChange < 0) {
36
+ return `${value} (improved)`;
37
+ }
38
+ else if (positionChange > 0) {
39
+ return `${value} (declined)`;
40
+ }
41
+ else {
42
+ return `${value} (no change)`;
43
+ }
44
+ }
45
+ export function isSignificantChange(absoluteChange, percentChange, absoluteThreshold = 10, percentThreshold = 10) {
46
+ if (Math.abs(absoluteChange) >= absoluteThreshold) {
47
+ return true;
48
+ }
49
+ if (percentChange !== null && Math.abs(percentChange) >= percentThreshold) {
50
+ return true;
51
+ }
52
+ return false;
53
+ }
54
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/utils/metrics.ts"],"names":[],"mappings":"AAmDA,MAAM,UAAU,uBAAuB,CAAC,OAAe,EAAE,QAAgB;IACvE,OAAO,OAAO,GAAG,QAAQ,CAAC;AAC5B,CAAC;AAgCD,MAAM,UAAU,sBAAsB,CAAC,OAAe,EAAE,QAAgB;IAEtE,IAAI,QAAQ,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,CAAC;IACX,CAAC;IAGD,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAGD,OAAO,CAAC,CAAC,OAAO,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC;AACjD,CAAC;AA6BD,MAAM,UAAU,uBAAuB,CAAC,OAAe,EAAE,QAAgB;IACvE,OAAO,OAAO,GAAG,QAAQ,CAAC;AAC5B,CAAC;AAwCD,MAAM,UAAU,sBAAsB,CACpC,OAAsB,EACtB,QAAuB;IAEvB,OAAO;QAEL,MAAM,EAAE,uBAAuB,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;QAChE,aAAa,EAAE,sBAAsB,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;QAGtE,WAAW,EAAE,uBAAuB,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC;QAC/E,kBAAkB,EAAE,sBAAsB,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC;QAGrF,QAAQ,EAAE,uBAAuB,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC;KACvE,CAAC;AACJ,CAAC;AAuBD,MAAM,UAAU,mBAAmB,CAAC,aAA4B,EAAE,YAAoB,CAAC;IACrF,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3B,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1C,OAAO,GAAG,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC;AACvD,CAAC;AAoBD,MAAM,UAAU,oBAAoB,CAAC,cAAsB,EAAE,YAAoB,CAAC;IAChF,MAAM,IAAI,GAAG,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG,GAAG,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;IAE5D,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,KAAK,aAAa,CAAC;IAC/B,CAAC;SAAM,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,GAAG,KAAK,aAAa,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,KAAK,cAAc,CAAC;IAChC,CAAC;AACH,CAAC;AAsBD,MAAM,UAAU,mBAAmB,CACjC,cAAsB,EACtB,aAA4B,EAC5B,oBAA4B,EAAE,EAC9B,mBAA2B,EAAE;IAG7B,IAAI,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,iBAAiB,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAGD,IAAI,aAAa,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,gBAAgB,EAAE,CAAC;QAC1E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}