@digestseo/mcp-gsc 0.4.31 → 0.4.33
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/CHANGELOG.md +16 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/google.ts +64 -0
- package/src/index.ts +111 -19
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.4.33] - 2026-09-24
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- `analytics.query` responses now echo the ordered requested `dimensions` and `search_type`, so `rows[].keys` remain self-describing when responses are saved, forwarded, or consumed outside the original request context.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- `analytics.query` now rejects duplicate grouping dimensions and mixed `searchAppearance` grouping at MCP input validation, before local rate-limit, Google credential, or provider work.
|
|
17
|
+
|
|
18
|
+
## [0.4.32] - 2026-09-24
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- `urls.inspect` and successful `urls.inspect_many` items now include a conservative, schema-discoverable `index_status_summary` derived from Google's documented index-status verdict and key crawl/indexing fields while preserving the complete raw provider response.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- Successful `sitemaps.submit` and `sitemaps.delete` results now expose explicit Search Console effect boundaries so agents do not mistake submission for completed processing/indexing or Search Console removal for deletion of the hosted sitemap file/deindexing.
|
|
25
|
+
|
|
10
26
|
## [0.4.31] - 2026-09-24
|
|
11
27
|
|
|
12
28
|
### Added
|
package/README.md
CHANGED
|
@@ -78,7 +78,7 @@ The marketplace path makes the plugin discoverable and updateable through Copilo
|
|
|
78
78
|
**Gemini CLI**
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
gemini extensions install https://github.com/AKzar1el/mcp-gsc
|
|
81
|
+
gemini extensions install https://github.com/AKzar1el/mcp-gsc
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
The Gemini CLI extension bundles the verified local loopback MCP configuration plus the same three Agent Skills: `gsc-weekly-review`, `gsc-indexing-triage`, and `gsc-search-opportunities`. Start the npm launcher before using the extension; the extension does not start or deploy mcp-gsc for you.
|
package/package.json
CHANGED
package/src/google.ts
CHANGED
|
@@ -548,6 +548,70 @@ export async function inspectUrl(
|
|
|
548
548
|
return data.inspectionResult ?? null;
|
|
549
549
|
}
|
|
550
550
|
|
|
551
|
+
export type UrlInspectionIndexedState = 'indexed' | 'not_indexed' | 'unknown';
|
|
552
|
+
|
|
553
|
+
export interface UrlInspectionIndexStatusSummary {
|
|
554
|
+
indexed_state: UrlInspectionIndexedState;
|
|
555
|
+
verdict?: string;
|
|
556
|
+
coverage_state?: string;
|
|
557
|
+
robots_txt_state?: string;
|
|
558
|
+
indexing_state?: string;
|
|
559
|
+
last_crawl_time?: string;
|
|
560
|
+
page_fetch_state?: string;
|
|
561
|
+
google_canonical?: string;
|
|
562
|
+
user_canonical?: string;
|
|
563
|
+
crawled_as?: string;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function asUnknownRecord(value: unknown): Record<string, unknown> | undefined {
|
|
567
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
568
|
+
? (value as Record<string, unknown>)
|
|
569
|
+
: undefined;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function optionalStringField(
|
|
573
|
+
record: Record<string, unknown> | undefined,
|
|
574
|
+
key: string,
|
|
575
|
+
): string | undefined {
|
|
576
|
+
const value = record?.[key];
|
|
577
|
+
return typeof value === 'string' ? value : undefined;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
export function summarizeUrlInspectionIndexStatus(
|
|
581
|
+
inspectionResult: unknown,
|
|
582
|
+
): UrlInspectionIndexStatusSummary {
|
|
583
|
+
const result = asUnknownRecord(inspectionResult);
|
|
584
|
+
const indexStatus = asUnknownRecord(result?.indexStatusResult);
|
|
585
|
+
const verdict = optionalStringField(indexStatus, 'verdict');
|
|
586
|
+
const coverageState = optionalStringField(indexStatus, 'coverageState');
|
|
587
|
+
const robotsTxtState = optionalStringField(indexStatus, 'robotsTxtState');
|
|
588
|
+
const indexingState = optionalStringField(indexStatus, 'indexingState');
|
|
589
|
+
const lastCrawlTime = optionalStringField(indexStatus, 'lastCrawlTime');
|
|
590
|
+
const pageFetchState = optionalStringField(indexStatus, 'pageFetchState');
|
|
591
|
+
const googleCanonical = optionalStringField(indexStatus, 'googleCanonical');
|
|
592
|
+
const userCanonical = optionalStringField(indexStatus, 'userCanonical');
|
|
593
|
+
const crawledAs = optionalStringField(indexStatus, 'crawledAs');
|
|
594
|
+
const indexedState: UrlInspectionIndexedState =
|
|
595
|
+
verdict === 'PASS'
|
|
596
|
+
? 'indexed'
|
|
597
|
+
: verdict === 'FAIL' || verdict === 'NEUTRAL'
|
|
598
|
+
? 'not_indexed'
|
|
599
|
+
: 'unknown';
|
|
600
|
+
|
|
601
|
+
return {
|
|
602
|
+
indexed_state: indexedState,
|
|
603
|
+
...(verdict !== undefined ? { verdict } : {}),
|
|
604
|
+
...(coverageState !== undefined ? { coverage_state: coverageState } : {}),
|
|
605
|
+
...(robotsTxtState !== undefined ? { robots_txt_state: robotsTxtState } : {}),
|
|
606
|
+
...(indexingState !== undefined ? { indexing_state: indexingState } : {}),
|
|
607
|
+
...(lastCrawlTime !== undefined ? { last_crawl_time: lastCrawlTime } : {}),
|
|
608
|
+
...(pageFetchState !== undefined ? { page_fetch_state: pageFetchState } : {}),
|
|
609
|
+
...(googleCanonical !== undefined ? { google_canonical: googleCanonical } : {}),
|
|
610
|
+
...(userCanonical !== undefined ? { user_canonical: userCanonical } : {}),
|
|
611
|
+
...(crawledAs !== undefined ? { crawled_as: crawledAs } : {}),
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
|
|
551
615
|
export interface UrlInspectionBatchResult {
|
|
552
616
|
inspectionUrl: string;
|
|
553
617
|
inspectionResult?: unknown;
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
MCP_RECONNECT_INSTRUCTION,
|
|
14
14
|
inspectUrl,
|
|
15
15
|
inspectUrlsBoundedConcurrently,
|
|
16
|
+
summarizeUrlInspectionIndexStatus,
|
|
16
17
|
URL_INSPECTION_BATCH_CONCURRENCY,
|
|
17
18
|
listSitemaps,
|
|
18
19
|
listSites,
|
|
@@ -319,8 +320,24 @@ const INDEXING_PROVIDER_USAGE_NOTE =
|
|
|
319
320
|
const URL_INSPECTION_SCOPE_NOTE =
|
|
320
321
|
"Google's URL Inspection API reports the version currently known in Google's index; it does not run a live URL test or prove current live-page indexability. The mobileUsabilityResult field is deprecated and may be absent.";
|
|
321
322
|
|
|
323
|
+
const URL_INSPECTION_INDEX_STATUS_SUMMARY_SCHEMA = z.object({
|
|
324
|
+
indexed_state: z.enum(['indexed', 'not_indexed', 'unknown']).describe(
|
|
325
|
+
"Conservative state derived only from Google's indexStatusResult.verdict: PASS => indexed, FAIL/NEUTRAL => not_indexed, and missing/unknown/reserved verdicts => unknown.",
|
|
326
|
+
),
|
|
327
|
+
verdict: z.string().optional(),
|
|
328
|
+
coverage_state: z.string().optional(),
|
|
329
|
+
robots_txt_state: z.string().optional(),
|
|
330
|
+
indexing_state: z.string().optional(),
|
|
331
|
+
last_crawl_time: z.string().optional(),
|
|
332
|
+
page_fetch_state: z.string().optional(),
|
|
333
|
+
google_canonical: z.string().optional(),
|
|
334
|
+
user_canonical: z.string().optional(),
|
|
335
|
+
crawled_as: z.string().optional(),
|
|
336
|
+
});
|
|
337
|
+
|
|
322
338
|
const INSPECTION_OUTPUT_SCHEMA = {
|
|
323
339
|
inspection_result: z.unknown(),
|
|
340
|
+
index_status_summary: URL_INSPECTION_INDEX_STATUS_SUMMARY_SCHEMA,
|
|
324
341
|
note: z.string(),
|
|
325
342
|
};
|
|
326
343
|
|
|
@@ -333,6 +350,7 @@ const INSPECTION_BATCH_OUTPUT_SCHEMA = {
|
|
|
333
350
|
z.object({
|
|
334
351
|
inspection_url: z.string(),
|
|
335
352
|
inspection_result: z.unknown().optional(),
|
|
353
|
+
index_status_summary: URL_INSPECTION_INDEX_STATUS_SUMMARY_SCHEMA.optional(),
|
|
336
354
|
error: z.string().optional(),
|
|
337
355
|
}),
|
|
338
356
|
),
|
|
@@ -347,6 +365,24 @@ const SEARCH_ANALYTICS_OUTPUT_SCHEMA = {
|
|
|
347
365
|
row_count: z.number().int().nonnegative(),
|
|
348
366
|
start_row: z.number().int().nonnegative(),
|
|
349
367
|
rows: z.array(z.object(SEARCH_ROW_OUTPUT_SCHEMA)),
|
|
368
|
+
dimensions: z
|
|
369
|
+
.array(
|
|
370
|
+
z.enum([
|
|
371
|
+
'query',
|
|
372
|
+
'page',
|
|
373
|
+
'country',
|
|
374
|
+
'device',
|
|
375
|
+
'date',
|
|
376
|
+
'hour',
|
|
377
|
+
'searchAppearance',
|
|
378
|
+
]),
|
|
379
|
+
)
|
|
380
|
+
.describe(
|
|
381
|
+
'Ordered labels for rows[].keys. Each key position corresponds to the dimension at the same index. Empty for aggregate dimensions: [] queries.',
|
|
382
|
+
),
|
|
383
|
+
search_type: z
|
|
384
|
+
.enum(['web', 'image', 'video', 'news', 'discover', 'googleNews'])
|
|
385
|
+
.describe('The Search Analytics search type requested for this response.'),
|
|
350
386
|
data_state: z.enum(['all', 'final', 'hourly_all']).describe(
|
|
351
387
|
'The Search Analytics dataState requested from Google for this response.',
|
|
352
388
|
),
|
|
@@ -404,6 +440,22 @@ const SITE_DELETE_OUTPUT_SCHEMA = {
|
|
|
404
440
|
provider_scope_note: z.string(),
|
|
405
441
|
};
|
|
406
442
|
|
|
443
|
+
const SITEMAP_SUBMIT_OUTPUT_SCHEMA = {
|
|
444
|
+
message: z.string(),
|
|
445
|
+
submitted_to_search_console: z.literal(true),
|
|
446
|
+
sitemap_processing_completion_proven: z.literal(false),
|
|
447
|
+
page_indexing_proven: z.literal(false),
|
|
448
|
+
provider_scope_note: z.string(),
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
const SITEMAP_DELETE_OUTPUT_SCHEMA = {
|
|
452
|
+
message: z.string(),
|
|
453
|
+
removed_from_search_console: z.literal(true),
|
|
454
|
+
sitemap_file_deleted: z.literal(false),
|
|
455
|
+
page_deindexing_proven: z.literal(false),
|
|
456
|
+
provider_scope_note: z.string(),
|
|
457
|
+
};
|
|
458
|
+
|
|
407
459
|
const SEARCH_ANALYTICS_PAGINATION_OUTPUT_SCHEMA = z.object({
|
|
408
460
|
rows_fetched: z.number().int().nonnegative(),
|
|
409
461
|
pages_fetched: z.number().int().positive(),
|
|
@@ -758,12 +810,12 @@ const TOOL_CATALOG = [
|
|
|
758
810
|
{
|
|
759
811
|
name: 'urls.inspect',
|
|
760
812
|
description:
|
|
761
|
-
"Inspect Google's indexed version of a single URL: index status, last crawl, page-fetch/indexing state, canonicals, and rich-results/AMP analysis where available. This is not a live URL test; mobile usability is a deprecated response field. Use urls.inspect_many for 2-10 URLs.",
|
|
813
|
+
"Inspect Google's indexed version of a single URL: a conservative normalized index-status summary plus Google's raw index status, last crawl, page-fetch/indexing state, canonicals, and rich-results/AMP analysis where available. This is not a live URL test; mobile usability is a deprecated response field. Use urls.inspect_many for 2-10 URLs.",
|
|
762
814
|
},
|
|
763
815
|
{
|
|
764
816
|
name: 'urls.inspect_many',
|
|
765
817
|
description:
|
|
766
|
-
`Inspect Google's indexed versions of up to 10 URLs with bounded concurrency of ${URL_INSPECTION_BATCH_CONCURRENCY} in one MCP call while charging the same URL Inspection safety budget per URL. This does not run live URL tests.`,
|
|
818
|
+
`Inspect Google's indexed versions of up to 10 URLs with a conservative normalized index-status summary per successful item and bounded concurrency of ${URL_INSPECTION_BATCH_CONCURRENCY} in one MCP call while charging the same URL Inspection safety budget per URL. This does not run live URL tests.`,
|
|
767
819
|
},
|
|
768
820
|
{
|
|
769
821
|
name: 'sitemaps.list',
|
|
@@ -773,12 +825,12 @@ const TOOL_CATALOG = [
|
|
|
773
825
|
{
|
|
774
826
|
name: 'sitemaps.submit',
|
|
775
827
|
description:
|
|
776
|
-
'Submit a
|
|
828
|
+
'Submit a sitemap URL to a Search Console property. A successful API response proves the Search Console submission request succeeded; it does not prove sitemap processing completed or that any page was indexed.',
|
|
777
829
|
},
|
|
778
830
|
{
|
|
779
831
|
name: 'sitemaps.delete',
|
|
780
832
|
description:
|
|
781
|
-
'Remove
|
|
833
|
+
'Remove a submitted sitemap from a Search Console property. This removes the Search Console sitemap entry; it does not delete the remotely hosted sitemap file or prove that any page was deindexed.',
|
|
782
834
|
},
|
|
783
835
|
{
|
|
784
836
|
name: 'sitemaps.get',
|
|
@@ -1012,7 +1064,7 @@ class GscMcpRuntime {
|
|
|
1012
1064
|
'urls.inspect',
|
|
1013
1065
|
{
|
|
1014
1066
|
title: 'Inspect URL index status',
|
|
1015
|
-
description: `Inspect the version of a single URL currently known in Google's index. Returns Google's index-status analysis, last crawl, page-fetch/indexing state, canonicals, and rich-results/AMP analysis where available. This API does not test the live URL or prove current live-page indexability, and its mobile-usability result is deprecated. Use this when the user asks 'is X indexed?' or wants Google's indexed-state evidence for one page. For a bounded group of 2-10 URLs, prefer urls.inspect_many; Google still processes one URL Inspection request per URL and applies the same quota semantics.`,
|
|
1067
|
+
description: `Inspect the version of a single URL currently known in Google's index. Returns a conservative normalized index-status summary alongside Google's raw index-status analysis, last crawl, page-fetch/indexing state, canonicals, and rich-results/AMP analysis where available. This API does not test the live URL or prove current live-page indexability, and its mobile-usability result is deprecated. Use this when the user asks 'is X indexed?' or wants Google's indexed-state evidence for one page. For a bounded group of 2-10 URLs, prefer urls.inspect_many; Google still processes one URL Inspection request per URL and applies the same quota semantics.`,
|
|
1016
1068
|
inputSchema: {
|
|
1017
1069
|
site_url: SEARCH_CONSOLE_PROPERTY_SCHEMA,
|
|
1018
1070
|
inspection_url: z
|
|
@@ -1041,8 +1093,10 @@ class GscMcpRuntime {
|
|
|
1041
1093
|
inspection_url,
|
|
1042
1094
|
language_code,
|
|
1043
1095
|
);
|
|
1044
|
-
|
|
1096
|
+
const indexStatusSummary = summarizeUrlInspectionIndexStatus(result);
|
|
1097
|
+
return toolResponse(JSON.stringify({ note: URL_INSPECTION_SCOPE_NOTE, index_status_summary: indexStatusSummary, inspection_result: result }, null, 2), {
|
|
1045
1098
|
inspection_result: result,
|
|
1099
|
+
index_status_summary: indexStatusSummary,
|
|
1046
1100
|
note: URL_INSPECTION_SCOPE_NOTE,
|
|
1047
1101
|
});
|
|
1048
1102
|
},
|
|
@@ -1052,7 +1106,7 @@ class GscMcpRuntime {
|
|
|
1052
1106
|
'urls.inspect_many',
|
|
1053
1107
|
{
|
|
1054
1108
|
title: 'Inspect multiple URLs',
|
|
1055
|
-
description: `Inspect the versions of up to 10 URLs currently known in Google's index from one Search Console property. This API does not run live URL tests. Google still processes one URL Inspection request per URL, so every requested URL consumes one quota unit and one unit of this server's shared URL-inspection safety budget. Requests use bounded concurrency of ${URL_INSPECTION_BATCH_CONCURRENCY}; results preserve input order, and a Google-access revocation stops later chunks from starting. Use this for a small group of important or debugging-target URLs; do not use it to crawl an entire site.`,
|
|
1109
|
+
description: `Inspect the versions of up to 10 URLs currently known in Google's index from one Search Console property. Each successful item includes a conservative normalized index-status summary alongside Google's raw response. This API does not run live URL tests. Google still processes one URL Inspection request per URL, so every requested URL consumes one quota unit and one unit of this server's shared URL-inspection safety budget. Requests use bounded concurrency of ${URL_INSPECTION_BATCH_CONCURRENCY}; results preserve input order, and a Google-access revocation stops later chunks from starting. Use this for a small group of important or debugging-target URLs; do not use it to crawl an entire site.`,
|
|
1056
1110
|
inputSchema: {
|
|
1057
1111
|
site_url: SEARCH_CONSOLE_PROPERTY_SCHEMA,
|
|
1058
1112
|
inspection_urls: z
|
|
@@ -1096,7 +1150,12 @@ class GscMcpRuntime {
|
|
|
1096
1150
|
const results = batchResults.map((result) => ({
|
|
1097
1151
|
inspection_url: result.inspectionUrl,
|
|
1098
1152
|
...(result.inspectionResult !== undefined
|
|
1099
|
-
? {
|
|
1153
|
+
? {
|
|
1154
|
+
inspection_result: result.inspectionResult,
|
|
1155
|
+
index_status_summary: summarizeUrlInspectionIndexStatus(
|
|
1156
|
+
result.inspectionResult,
|
|
1157
|
+
),
|
|
1158
|
+
}
|
|
1100
1159
|
: {}),
|
|
1101
1160
|
...(result.error !== undefined ? { error: result.error } : {}),
|
|
1102
1161
|
}));
|
|
@@ -1147,10 +1206,13 @@ class GscMcpRuntime {
|
|
|
1147
1206
|
title: 'Query search analytics',
|
|
1148
1207
|
description: [
|
|
1149
1208
|
'Query Google Search Console search analytics data. Returns',
|
|
1150
|
-
'{ row_count, start_row, rows,
|
|
1151
|
-
' provider_note, has_more,
|
|
1209
|
+
'{ row_count, start_row, rows, dimensions, search_type,',
|
|
1210
|
+
' provider_exhaustiveness_guaranteed, provider_note, has_more,',
|
|
1211
|
+
' truncated, byte_limit_reached }',
|
|
1152
1212
|
'where dimensioned rows have keys plus clicks, impressions, ctr, and',
|
|
1153
|
-
'position.
|
|
1213
|
+
'position. The echoed dimensions array labels rows[].keys in order,',
|
|
1214
|
+
'so saved or forwarded responses remain self-describing. Aggregate',
|
|
1215
|
+
'rows from dimensions: [] may omit keys because',
|
|
1154
1216
|
'Google itself omits that field. When has_more is true, the response',
|
|
1155
1217
|
'includes next_start_row — pass it back as start_row to fetch the next',
|
|
1156
1218
|
'safe page. Large requested row_limit values are automatically split',
|
|
@@ -1251,6 +1313,20 @@ class GscMcpRuntime {
|
|
|
1251
1313
|
'searchAppearance',
|
|
1252
1314
|
]),
|
|
1253
1315
|
)
|
|
1316
|
+
.superRefine((dimensions, ctx) => {
|
|
1317
|
+
if (new Set(dimensions).size !== dimensions.length) {
|
|
1318
|
+
ctx.addIssue({
|
|
1319
|
+
code: 'custom',
|
|
1320
|
+
message: 'Search Analytics dimensions must not contain duplicates.',
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
if (dimensions.includes('searchAppearance') && dimensions.length > 1) {
|
|
1324
|
+
ctx.addIssue({
|
|
1325
|
+
code: 'custom',
|
|
1326
|
+
message: 'Search Analytics searchAppearance must be the only grouping dimension.',
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
})
|
|
1254
1330
|
.default(['query'])
|
|
1255
1331
|
.describe(
|
|
1256
1332
|
"Dimensions to group rows by. Pass [] (empty array) to get a single row of true site-level totals. searchAppearance must be the only grouping dimension; discover an appearance value with ['searchAppearance'], then filter to that value in a separate query when grouping by another dimension. The 'hour' dimension requires data_state 'hourly_all' and an inclusive date range of at most 10 days. Google Discover and Google News do not support the query dimension.",
|
|
@@ -1345,6 +1421,8 @@ class GscMcpRuntime {
|
|
|
1345
1421
|
row_count: bounded.items.length,
|
|
1346
1422
|
start_row,
|
|
1347
1423
|
rows: bounded.items,
|
|
1424
|
+
dimensions,
|
|
1425
|
+
search_type,
|
|
1348
1426
|
data_state,
|
|
1349
1427
|
preliminary_data_possible: data_state !== 'final',
|
|
1350
1428
|
position_supported:
|
|
@@ -1606,12 +1684,12 @@ class GscMcpRuntime {
|
|
|
1606
1684
|
'sitemaps.submit',
|
|
1607
1685
|
{
|
|
1608
1686
|
title: 'Submit sitemap',
|
|
1609
|
-
description: 'Submit a
|
|
1687
|
+
description: 'Submit a sitemap URL to a Search Console property. A successful API response means the Search Console submission request succeeded; it does not prove sitemap processing completed or that any page was indexed.',
|
|
1610
1688
|
inputSchema: {
|
|
1611
1689
|
site_url: SEARCH_CONSOLE_PROPERTY_SCHEMA,
|
|
1612
1690
|
feedpath: SITEMAP_URL_SCHEMA.describe('The full HTTP/HTTPS URL of the sitemap file to submit, e.g. https://example.com/sitemap.xml'),
|
|
1613
1691
|
},
|
|
1614
|
-
outputSchema:
|
|
1692
|
+
outputSchema: SITEMAP_SUBMIT_OUTPUT_SCHEMA,
|
|
1615
1693
|
annotations: WRITE_TOOL_ANNOTATIONS['sitemaps.submit'],
|
|
1616
1694
|
},
|
|
1617
1695
|
async ({ site_url, feedpath }) => {
|
|
@@ -1620,8 +1698,15 @@ class GscMcpRuntime {
|
|
|
1620
1698
|
if (rateLimitError) return rateLimitError;
|
|
1621
1699
|
const accessToken = await this.getAccessToken(googleId);
|
|
1622
1700
|
await submitSitemap(accessToken, site_url, feedpath);
|
|
1623
|
-
const message = `Successfully submitted sitemap: ${feedpath} for site: ${site_url}`;
|
|
1624
|
-
|
|
1701
|
+
const message = `Successfully submitted sitemap to Search Console: ${feedpath} for site: ${site_url}`;
|
|
1702
|
+
const payload = {
|
|
1703
|
+
message,
|
|
1704
|
+
submitted_to_search_console: true as const,
|
|
1705
|
+
sitemap_processing_completion_proven: false as const,
|
|
1706
|
+
page_indexing_proven: false as const,
|
|
1707
|
+
provider_scope_note: "Google's Sitemaps.submit method returns an empty body on success. That success confirms the Search Console submission operation, not completed sitemap processing or page indexing.",
|
|
1708
|
+
};
|
|
1709
|
+
return toolResponse(`${message}\n\n${payload.provider_scope_note}`, payload);
|
|
1625
1710
|
},
|
|
1626
1711
|
);
|
|
1627
1712
|
|
|
@@ -1629,12 +1714,12 @@ class GscMcpRuntime {
|
|
|
1629
1714
|
'sitemaps.delete',
|
|
1630
1715
|
{
|
|
1631
1716
|
title: 'Delete sitemap',
|
|
1632
|
-
description: 'Remove
|
|
1717
|
+
description: 'Remove a submitted sitemap from a Search Console property. This removes the Search Console sitemap entry; it does not delete the remotely hosted sitemap file or prove that any page was deindexed.',
|
|
1633
1718
|
inputSchema: {
|
|
1634
1719
|
site_url: SEARCH_CONSOLE_PROPERTY_SCHEMA,
|
|
1635
1720
|
feedpath: SITEMAP_URL_SCHEMA.describe('The full HTTP/HTTPS URL of the sitemap file to delete, e.g. https://example.com/sitemap.xml'),
|
|
1636
1721
|
},
|
|
1637
|
-
outputSchema:
|
|
1722
|
+
outputSchema: SITEMAP_DELETE_OUTPUT_SCHEMA,
|
|
1638
1723
|
annotations: WRITE_TOOL_ANNOTATIONS['sitemaps.delete'],
|
|
1639
1724
|
},
|
|
1640
1725
|
async ({ site_url, feedpath }) => {
|
|
@@ -1643,8 +1728,15 @@ class GscMcpRuntime {
|
|
|
1643
1728
|
if (rateLimitError) return rateLimitError;
|
|
1644
1729
|
const accessToken = await this.getAccessToken(googleId);
|
|
1645
1730
|
await deleteSitemap(accessToken, site_url, feedpath);
|
|
1646
|
-
const message = `Successfully
|
|
1647
|
-
|
|
1731
|
+
const message = `Successfully removed sitemap from Search Console: ${feedpath} for site: ${site_url}`;
|
|
1732
|
+
const payload = {
|
|
1733
|
+
message,
|
|
1734
|
+
removed_from_search_console: true as const,
|
|
1735
|
+
sitemap_file_deleted: false as const,
|
|
1736
|
+
page_deindexing_proven: false as const,
|
|
1737
|
+
provider_scope_note: "Google's Sitemaps.delete method removes the submitted sitemap from the Search Console property. It does not delete the remotely hosted sitemap file or prove that any page was deindexed.",
|
|
1738
|
+
};
|
|
1739
|
+
return toolResponse(`${message}\n\n${payload.provider_scope_note}`, payload);
|
|
1648
1740
|
},
|
|
1649
1741
|
);
|
|
1650
1742
|
}
|