@digestseo/mcp-gsc 0.4.10 → 0.4.11
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 +6 -0
- package/README.md +4 -4
- package/package.json +1 -1
- package/src/google.ts +3 -2
- package/src/index.ts +50 -28
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.4.11] - 2026-09-22
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Sitemap read tools now explain Google's `lastSubmitted` and `lastDownloaded` timestamp semantics so agents do not mistake Search Console submission/download times for sitemap-file modification, page-crawl, or indexing timestamps.
|
|
14
|
+
- Google News Search Analytics now rejects unsupported query grouping/filtering, marks average position unavailable, and removes Google News from query-centric and average-position comparison helpers while preserving supported page/country/date/device/appearance and News Showcase reporting.
|
|
15
|
+
|
|
10
16
|
## [0.4.10] - 2026-09-21
|
|
11
17
|
|
|
12
18
|
### Fixed
|
package/README.md
CHANGED
|
@@ -75,13 +75,13 @@ By default (`GSC_ACCESS_MODE=readwrite`), this server exposes 21 tools. Read-onl
|
|
|
75
75
|
| **`server.capabilities`** | Read | List every tool this server exposes and report whether your Google connection is currently authenticated (`connected` / `not_connected`). Takes no arguments — a good first call for discovery. |
|
|
76
76
|
| **`sites.list`** | Read | List the Search Console properties the connected Google account can access (`siteUrl`, `permissionLevel`). |
|
|
77
77
|
| **`sites.get`** | Read | Retrieve one exact Search Console property and the connected account's permission level for it. |
|
|
78
|
-
| **`analytics.query`** | Read | Impressions, clicks, CTR, and average position over a date range, with dimensions, filters, safe pagination, and selectable search type. Pass `dimensions: []` for true site totals; Google's aggregate row may omit `keys`. Search Analytics does not guarantee every data row and can return only top rows, so exhausting local pagination is not proof that the provider dataset is exhaustive. For `search_type: "discover"`, `position_supported` is `false
|
|
79
|
-
| **`insights.page_queries`** / **`insights.query_pages`** | Read | Drill from one exact page to its Search Console queries, or from one exact query to the pages Google surfaced for it, with `row_limit` / `start_row` pagination. |
|
|
78
|
+
| **`analytics.query`** | Read | Impressions, clicks, CTR, and average position over a date range, with dimensions, filters, safe pagination, and selectable search type. Pass `dimensions: []` for true site totals; Google's aggregate row may omit `keys`. Search Analytics does not guarantee every data row and can return only top rows, so exhausting local pagination is not proof that the provider dataset is exhaustive. For `search_type: "discover"` or `"googleNews"`, `position_supported` is `false`; those reports expose clicks, impressions, and CTR but not average position, and query grouping/filtering is unavailable. |
|
|
79
|
+
| **`insights.page_queries`** / **`insights.query_pages`** | Read | Drill from one exact page to its Search Console queries, or from one exact query to the pages Google surfaced for it, with `row_limit` / `start_row` pagination. These query-centric helpers support web, image, video, and the Search results News tab; Discover and the Google News report are excluded because they do not expose query data. |
|
|
80
80
|
| **`urls.inspect`** | Read | Google's URL Inspection report for the version of one page currently known in Google's index. It is not a live URL test; mobile-usability output is deprecated. |
|
|
81
81
|
| **`urls.inspect_many`** | Read | Inspect Google's indexed versions of up to 10 URLs sequentially in one call. Each URL still consumes one Google URL Inspection request and one unit of the server's shared inspection safety budget; this does not run live URL tests. |
|
|
82
|
-
| **`sitemaps.list`** / **`sitemaps.get`** | Read | List submitted sitemaps or retrieve one sitemap's details. |
|
|
82
|
+
| **`sitemaps.list`** / **`sitemaps.get`** | Read | List submitted sitemaps or retrieve one sitemap's details. `lastSubmitted` is when the sitemap was submitted to Search Console; `lastDownloaded` is when Google last downloaded the sitemap. Neither value is the sitemap file's modification/deploy time or a page crawl/indexing timestamp. |
|
|
83
83
|
| **`insights.quick_wins`** / **`insights.cannibalization`** / **`insights.content_decay`** | Read | Surface average-position opportunity rows, query/page overlap, and evidence-ranked click declines. Quick-win candidates are observed query/page rows selected by aggregate Search Console average position, not proof of a stable current rank, and CTR is context rather than an eligibility filter. Cannibalization candidate totals/shares are scoped to observed query/page rows rather than true query-level property totals; content-decay results compare only pages returned in both periods and do not turn one-sided row absence into zero traffic. |
|
|
84
|
-
| **`indexing.list_pages`** / **`analytics.compare`** | Read | Analyze pages receiving Search Console impressions and compare two periods, optionally using the same search type and query/page/country/device/search-appearance filters for both periods. `analytics.compare` compares only dimension keys returned in both period responses; a key absent from one non-exhaustive Search Analytics response is not assumed to have zero metrics. `indexing.list_pages` is performance data, not index coverage: a missing URL may still be indexed; use `urls.inspect` / `urls.inspect_many` for URL-level index status. |
|
|
84
|
+
| **`indexing.list_pages`** / **`analytics.compare`** | Read | Analyze pages receiving Search Console impressions and compare two periods, optionally using the same search type and query/page/country/device/search-appearance filters for both periods. `analytics.compare` compares only dimension keys returned in both period responses; a key absent from one non-exhaustive Search Analytics response is not assumed to have zero metrics. Because its comparison contract includes average position, it excludes Discover and Google News. `indexing.list_pages` is performance data, not index coverage: a missing URL may still be indexed; use `urls.inspect` / `urls.inspect_many` for URL-level index status. |
|
|
85
85
|
| **`reports.weekly_digest`** | Read | Generate a plain-language seven-day performance report with movers, top pages, and one recommended action. Query movers compare only rows returned in both weekly Search Analytics result sets; a query missing from one bounded response is not treated as zero because Google does not guarantee every data row. |
|
|
86
86
|
| **`sites.add`** / **`sites.delete`** | Write | Add or remove a Search Console property. |
|
|
87
87
|
| **`sitemaps.submit`** / **`sitemaps.delete`** | Write | Submit or remove a sitemap. |
|
package/package.json
CHANGED
package/src/google.ts
CHANGED
|
@@ -343,9 +343,10 @@ export function assertSearchAnalyticsQueryCompatible(body: SearchAnalyticsQuery)
|
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
if (body.type === 'discover' && hasQueryGroupingOrFilter) {
|
|
346
|
+
if ((body.type === 'discover' || body.type === 'googleNews') && hasQueryGroupingOrFilter) {
|
|
347
|
+
const surfaceName = body.type === 'discover' ? 'Google Discover' : 'Google News';
|
|
347
348
|
throw new Error(
|
|
348
|
-
|
|
349
|
+
`${surfaceName} does not support the query dimension or query filters in Search Analytics.`,
|
|
349
350
|
);
|
|
350
351
|
}
|
|
351
352
|
|
package/src/index.ts
CHANGED
|
@@ -143,21 +143,38 @@ const LISTED_SITE_OUTPUT_SCHEMA = {
|
|
|
143
143
|
const PLATFORM_PROPERTY_API_NOTE =
|
|
144
144
|
"Google Search Console now has platform properties for social/video accounts in its UI, but the current Search Console API documentation still defines siteUrl using URL-prefix and sc-domain website-property forms. mcp-gsc preserves any other identifier returned by sites.list but will not pass an undocumented property identifier to API tools until Google publishes that contract.";
|
|
145
145
|
|
|
146
|
+
const SITEMAP_PROVIDER_NOTE =
|
|
147
|
+
"Google's lastSubmitted is the time the sitemap was submitted to Search Console; it is not the sitemap file's generation, deployment, or last-modified time. lastDownloaded is the time Google last downloaded the sitemap; it is not a page crawl or indexing timestamp.";
|
|
148
|
+
|
|
146
149
|
const SITEMAP_OUTPUT_SCHEMA = z
|
|
147
150
|
.object({
|
|
148
151
|
path: z.string(),
|
|
149
|
-
lastSubmitted: z
|
|
152
|
+
lastSubmitted: z
|
|
153
|
+
.string()
|
|
154
|
+
.nullable()
|
|
155
|
+
.optional()
|
|
156
|
+
.describe(
|
|
157
|
+
'Provider-reported time the sitemap was submitted to Search Console; not the sitemap file generation, deployment, or modification time.',
|
|
158
|
+
),
|
|
150
159
|
isPending: z.boolean().nullable().optional(),
|
|
151
160
|
isSitemapsIndex: z.boolean().nullable().optional(),
|
|
152
161
|
type: z.string().nullable().optional(),
|
|
153
|
-
lastDownloaded: z
|
|
162
|
+
lastDownloaded: z
|
|
163
|
+
.string()
|
|
164
|
+
.nullable()
|
|
165
|
+
.optional()
|
|
166
|
+
.describe(
|
|
167
|
+
'Provider-reported time Google last downloaded the sitemap; not a page crawl or page indexing timestamp.',
|
|
168
|
+
),
|
|
154
169
|
warnings: z.string().nullable().optional(),
|
|
155
170
|
errors: z.string().nullable().optional(),
|
|
156
171
|
contents: z
|
|
157
172
|
.array(
|
|
158
173
|
z.object({
|
|
159
174
|
type: z.string(),
|
|
160
|
-
submitted: z
|
|
175
|
+
submitted: z
|
|
176
|
+
.string()
|
|
177
|
+
.describe('Provider-reported submitted URL count for this sitemap content type.'),
|
|
161
178
|
}),
|
|
162
179
|
)
|
|
163
180
|
.nullable()
|
|
@@ -210,6 +227,7 @@ const INSPECTION_BATCH_OUTPUT_SCHEMA = {
|
|
|
210
227
|
|
|
211
228
|
const SITEMAPS_OUTPUT_SCHEMA = {
|
|
212
229
|
sitemaps: z.array(SITEMAP_OUTPUT_SCHEMA),
|
|
230
|
+
provider_note: z.string(),
|
|
213
231
|
};
|
|
214
232
|
|
|
215
233
|
const SEARCH_ANALYTICS_OUTPUT_SCHEMA = {
|
|
@@ -217,7 +235,7 @@ const SEARCH_ANALYTICS_OUTPUT_SCHEMA = {
|
|
|
217
235
|
start_row: z.number().int().nonnegative(),
|
|
218
236
|
rows: z.array(z.object(SEARCH_ROW_OUTPUT_SCHEMA)),
|
|
219
237
|
position_supported: z.boolean().describe(
|
|
220
|
-
'Whether average position is supported for the selected Search Analytics search type. False for Google Discover.',
|
|
238
|
+
'Whether average position is supported for the selected Search Analytics search type. False for Google Discover and Google News.',
|
|
221
239
|
),
|
|
222
240
|
position_note: z.string().optional(),
|
|
223
241
|
provider_exhaustiveness_guaranteed: z.literal(false).describe(
|
|
@@ -888,7 +906,7 @@ class GscMcpRuntime {
|
|
|
888
906
|
{
|
|
889
907
|
title: 'List submitted sitemaps',
|
|
890
908
|
description:
|
|
891
|
-
'List sitemaps submitted for a Search Console property. Optionally filter to entries included by one sitemap index. Returns sitemap URLs,
|
|
909
|
+
'List sitemaps submitted for a Search Console property. Optionally filter to entries included by one sitemap index. Returns sitemap URLs, provider-reported submission/download timestamps, submitted URL counts, warning and error counts, and sitemap status. lastSubmitted is when the sitemap was submitted to Search Console; lastDownloaded is when Google last downloaded the sitemap. Neither timestamp is a sitemap-file modification time or a page crawl/indexing time. Google\'s deprecated sitemap indexed count is intentionally omitted. Use this when the user asks about sitemap health, submission status, wants to audit which sitemaps are working, or needs the child sitemaps belonging to a specific sitemap index.',
|
|
892
910
|
inputSchema: {
|
|
893
911
|
site_url: SEARCH_CONSOLE_PROPERTY_SCHEMA,
|
|
894
912
|
sitemap_index: SITEMAP_URL_SCHEMA
|
|
@@ -904,7 +922,8 @@ class GscMcpRuntime {
|
|
|
904
922
|
const googleId = this.requireGoogleId();
|
|
905
923
|
const accessToken = await this.getAccessToken(googleId);
|
|
906
924
|
const sitemaps = await listSitemaps(accessToken, site_url, sitemap_index);
|
|
907
|
-
|
|
925
|
+
const payload = { sitemaps, provider_note: SITEMAP_PROVIDER_NOTE };
|
|
926
|
+
return toolResponse(JSON.stringify(payload, null, 2), payload);
|
|
908
927
|
},
|
|
909
928
|
);
|
|
910
929
|
|
|
@@ -952,10 +971,11 @@ class GscMcpRuntime {
|
|
|
952
971
|
'- CTR in the response is a 0–1 fraction. Multiply by 100 for percent.',
|
|
953
972
|
'- Use search_type to query image/video/news/discover indexes',
|
|
954
973
|
' separately from web.',
|
|
955
|
-
'- Google Discover
|
|
956
|
-
' average position. For
|
|
957
|
-
' searchAppearance dimensions and interpret
|
|
958
|
-
' and CTR; query dimensions/filters are
|
|
974
|
+
'- Google Discover and Google News do not support query grouping/',
|
|
975
|
+
' filtering or average position. For those surfaces, use page/',
|
|
976
|
+
' country/device/date/searchAppearance dimensions and interpret',
|
|
977
|
+
' clicks, impressions, and CTR; query dimensions/filters are',
|
|
978
|
+
' rejected before the API call.',
|
|
959
979
|
'- News Showcase panel reporting: set aggregation_type to',
|
|
960
980
|
' "byNewsShowcasePanel", use search_type "discover" or',
|
|
961
981
|
' "googleNews", and include a searchAppearance equals',
|
|
@@ -993,7 +1013,7 @@ class GscMcpRuntime {
|
|
|
993
1013
|
)
|
|
994
1014
|
.default(['query'])
|
|
995
1015
|
.describe(
|
|
996
|
-
"Dimensions to group rows by. Pass [] (empty array) to get a single row of true site-level totals. The 'hour' dimension requires data_state 'hourly_all' and an inclusive date range of at most 10 days. Google Discover
|
|
1016
|
+
"Dimensions to group rows by. Pass [] (empty array) to get a single row of true site-level totals. 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.",
|
|
997
1017
|
),
|
|
998
1018
|
row_limit: z
|
|
999
1019
|
.number()
|
|
@@ -1021,7 +1041,7 @@ class GscMcpRuntime {
|
|
|
1021
1041
|
search_type: z
|
|
1022
1042
|
.enum(['web', 'image', 'video', 'news', 'discover', 'googleNews'])
|
|
1023
1043
|
.default('web')
|
|
1024
|
-
.describe('Which search index to query. Defaults to web. Google Discover
|
|
1044
|
+
.describe('Which search index to query. Defaults to web. Google Discover and Google News do not support query grouping/filtering or average position.'),
|
|
1025
1045
|
aggregation_type: z
|
|
1026
1046
|
.enum(['auto', 'byNewsShowcasePanel', 'byPage', 'byProperty'])
|
|
1027
1047
|
.default('auto')
|
|
@@ -1056,7 +1076,7 @@ class GscMcpRuntime {
|
|
|
1056
1076
|
)
|
|
1057
1077
|
.optional()
|
|
1058
1078
|
.describe(
|
|
1059
|
-
"Optional filters ANDed together, e.g. [{ groupType: 'and', filters: [{ dimension: 'country', operator: 'equals', expression: 'usa' }] }]. Countries use ISO 3166-1 alpha-3 codes. Query filters are not supported when search_type is discover.",
|
|
1079
|
+
"Optional filters ANDed together, e.g. [{ groupType: 'and', filters: [{ dimension: 'country', operator: 'equals', expression: 'usa' }] }]. Countries use ISO 3166-1 alpha-3 codes. Query filters are not supported when search_type is discover or googleNews.",
|
|
1060
1080
|
),
|
|
1061
1081
|
},
|
|
1062
1082
|
outputSchema: SEARCH_ANALYTICS_OUTPUT_SCHEMA,
|
|
@@ -1105,11 +1125,12 @@ class GscMcpRuntime {
|
|
|
1105
1125
|
row_count: bounded.items.length,
|
|
1106
1126
|
start_row,
|
|
1107
1127
|
rows: bounded.items,
|
|
1108
|
-
position_supported:
|
|
1109
|
-
|
|
1128
|
+
position_supported:
|
|
1129
|
+
search_type !== 'discover' && search_type !== 'googleNews',
|
|
1130
|
+
...(search_type === 'discover' || search_type === 'googleNews'
|
|
1110
1131
|
? {
|
|
1111
1132
|
position_note:
|
|
1112
|
-
|
|
1133
|
+
`${search_type === 'discover' ? 'Google Discover' : 'Google News'} does not support average position. Do not interpret rows[].position for search_type='${search_type}'.`,
|
|
1113
1134
|
}
|
|
1114
1135
|
: {}),
|
|
1115
1136
|
provider_exhaustiveness_guaranteed: false,
|
|
@@ -1137,16 +1158,16 @@ class GscMcpRuntime {
|
|
|
1137
1158
|
'insights.page_queries',
|
|
1138
1159
|
{
|
|
1139
1160
|
title: 'Find queries for a page',
|
|
1140
|
-
description: 'For one exact page URL, return the Search Console queries that produced impressions for it over a date range. This wraps an exact page dimension filter so agents do not need to construct analytics.query filter groups manually. Exact page matching is case-sensitive in Search Console. Use row_limit and start_row to page through bounded results; Search Console can still omit anonymized queries. Google Discover
|
|
1161
|
+
description: 'For one exact page URL, return the Search Console queries that produced impressions for it over a date range. This wraps an exact page dimension filter so agents do not need to construct analytics.query filter groups manually. Exact page matching is case-sensitive in Search Console. Use row_limit and start_row to page through bounded results; Search Console can still omit anonymized queries. Google Discover and Google News are intentionally unavailable because those reports do not expose query data.',
|
|
1141
1162
|
inputSchema: {
|
|
1142
1163
|
site_url: SEARCH_CONSOLE_PROPERTY_SCHEMA,
|
|
1143
1164
|
page_url: z.string().url().describe('Exact fully-qualified page URL to filter on, e.g. https://example.com/guides/seo/. Search Console exact page filters are case-sensitive.'),
|
|
1144
1165
|
start_date: SEARCH_CONSOLE_DATE_SCHEMA.describe('Start date (inclusive) in YYYY-MM-DD format.'),
|
|
1145
1166
|
end_date: SEARCH_CONSOLE_DATE_SCHEMA.describe('End date (inclusive) in YYYY-MM-DD format. Note the 2-3 day GSC data lag.'),
|
|
1146
1167
|
search_type: z
|
|
1147
|
-
.enum(['web', 'image', 'video', 'news'
|
|
1168
|
+
.enum(['web', 'image', 'video', 'news'])
|
|
1148
1169
|
.default('web')
|
|
1149
|
-
.describe('Which search index to query. Defaults to web. Discover
|
|
1170
|
+
.describe('Which search index to query. Defaults to web. Discover and Google News are not supported because this tool groups by query.'),
|
|
1150
1171
|
row_limit: z
|
|
1151
1172
|
.number()
|
|
1152
1173
|
.int()
|
|
@@ -1215,16 +1236,16 @@ class GscMcpRuntime {
|
|
|
1215
1236
|
'insights.query_pages',
|
|
1216
1237
|
{
|
|
1217
1238
|
title: 'Find pages for a query',
|
|
1218
|
-
description: 'For one exact search query, return the site pages that received impressions for it over a date range. This wraps an exact query dimension filter so agents do not need to construct analytics.query filter groups manually. Exact query matching is case-sensitive in Search Console. Use row_limit and start_row to page through bounded results and verify which URL Google is surfacing before diagnosing cannibalization or content targeting. Google Discover
|
|
1239
|
+
description: 'For one exact search query, return the site pages that received impressions for it over a date range. This wraps an exact query dimension filter so agents do not need to construct analytics.query filter groups manually. Exact query matching is case-sensitive in Search Console. Use row_limit and start_row to page through bounded results and verify which URL Google is surfacing before diagnosing cannibalization or content targeting. Google Discover and Google News are intentionally unavailable because those reports do not expose query data.',
|
|
1219
1240
|
inputSchema: {
|
|
1220
1241
|
site_url: SEARCH_CONSOLE_PROPERTY_SCHEMA,
|
|
1221
1242
|
query: z.string().min(1).describe('Exact Search Console query text to filter on. Exact query filters are case-sensitive.'),
|
|
1222
1243
|
start_date: SEARCH_CONSOLE_DATE_SCHEMA.describe('Start date (inclusive) in YYYY-MM-DD format.'),
|
|
1223
1244
|
end_date: SEARCH_CONSOLE_DATE_SCHEMA.describe('End date (inclusive) in YYYY-MM-DD format. Note the 2-3 day GSC data lag.'),
|
|
1224
1245
|
search_type: z
|
|
1225
|
-
.enum(['web', 'image', 'video', 'news'
|
|
1246
|
+
.enum(['web', 'image', 'video', 'news'])
|
|
1226
1247
|
.default('web')
|
|
1227
|
-
.describe('Which search index to query. Defaults to web. Discover
|
|
1248
|
+
.describe('Which search index to query. Defaults to web. Discover and Google News are not supported because this tool filters by query.'),
|
|
1228
1249
|
row_limit: z
|
|
1229
1250
|
.number()
|
|
1230
1251
|
.int()
|
|
@@ -1385,19 +1406,20 @@ class GscMcpRuntime {
|
|
|
1385
1406
|
'sitemaps.get',
|
|
1386
1407
|
{
|
|
1387
1408
|
title: 'Get sitemap details',
|
|
1388
|
-
description: 'Get status and details of a single sitemap submitted to Google Search Console.',
|
|
1409
|
+
description: 'Get status and details of a single sitemap submitted to Google Search Console. lastSubmitted is when the sitemap was submitted to Search Console; lastDownloaded is when Google last downloaded the sitemap. Neither timestamp is a sitemap-file modification time or a page crawl/indexing time.',
|
|
1389
1410
|
inputSchema: {
|
|
1390
1411
|
site_url: SEARCH_CONSOLE_PROPERTY_SCHEMA,
|
|
1391
1412
|
feedpath: SITEMAP_URL_SCHEMA.describe('The full HTTP/HTTPS URL of the sitemap file, e.g. https://example.com/sitemap.xml'),
|
|
1392
1413
|
},
|
|
1393
|
-
outputSchema: { sitemap: SITEMAP_OUTPUT_SCHEMA },
|
|
1414
|
+
outputSchema: { sitemap: SITEMAP_OUTPUT_SCHEMA, provider_note: z.string() },
|
|
1394
1415
|
annotations: READ_ONLY_ANNOTATIONS,
|
|
1395
1416
|
},
|
|
1396
1417
|
async ({ site_url, feedpath }) => {
|
|
1397
1418
|
const googleId = this.requireGoogleId();
|
|
1398
1419
|
const accessToken = await this.getAccessToken(googleId);
|
|
1399
1420
|
const details = await getSitemap(accessToken, site_url, feedpath);
|
|
1400
|
-
|
|
1421
|
+
const payload = { sitemap: details, provider_note: SITEMAP_PROVIDER_NOTE };
|
|
1422
|
+
return toolResponse(JSON.stringify(payload, null, 2), payload);
|
|
1401
1423
|
},
|
|
1402
1424
|
);
|
|
1403
1425
|
|
|
@@ -1670,7 +1692,7 @@ class GscMcpRuntime {
|
|
|
1670
1692
|
'analytics.compare',
|
|
1671
1693
|
{
|
|
1672
1694
|
title: 'Compare Performance Between Periods',
|
|
1673
|
-
description: 'Compare Search Console performance metrics (clicks, impressions, CTR, average position) between two distinct date ranges (Period A vs Period B) for a selected dimension (query, page, country, device). Only dimension keys returned in both Search Analytics period responses are compared; a key missing from one response is not treated as zero because Google does not guarantee every data row. Apply the same search type and optional dimension filters to both periods. Results are ranked by largest absolute click change, then impression change, and safely paged with limit/start_row. Percentage change is null when an explicitly returned baseline row has zero and the comparison value differs. Discover
|
|
1695
|
+
description: 'Compare Search Console performance metrics (clicks, impressions, CTR, average position) between two distinct date ranges (Period A vs Period B) for a selected dimension (query, page, country, device). Only dimension keys returned in both Search Analytics period responses are compared; a key missing from one response is not treated as zero because Google does not guarantee every data row. Apply the same search type and optional dimension filters to both periods. Results are ranked by largest absolute click change, then impression change, and safely paged with limit/start_row. Percentage change is null when an explicitly returned baseline row has zero and the comparison value differs. Discover and Google News are intentionally unavailable because this comparison contract includes average position, which those reports do not support.',
|
|
1674
1696
|
inputSchema: {
|
|
1675
1697
|
site_url: SEARCH_CONSOLE_PROPERTY_SCHEMA,
|
|
1676
1698
|
start_date_a: SEARCH_CONSOLE_DATE_SCHEMA.describe('Start date of Period A (recent, YYYY-MM-DD)'),
|
|
@@ -1679,9 +1701,9 @@ class GscMcpRuntime {
|
|
|
1679
1701
|
end_date_b: SEARCH_CONSOLE_DATE_SCHEMA.describe('End date of Period B (previous, YYYY-MM-DD)'),
|
|
1680
1702
|
dimension: z.enum(['query', 'page', 'country', 'device']).default('query').describe('The dimension to compare performance for. Defaults to query.'),
|
|
1681
1703
|
search_type: z
|
|
1682
|
-
.enum(['web', 'image', 'video', 'news'
|
|
1704
|
+
.enum(['web', 'image', 'video', 'news'])
|
|
1683
1705
|
.default('web')
|
|
1684
|
-
.describe('Which Search Console search index to compare. The same search type is used for both periods. Discover
|
|
1706
|
+
.describe('Which Search Console search index to compare. The same search type is used for both periods. Discover and Google News are excluded because this tool returns average-position comparisons.'),
|
|
1685
1707
|
dimension_filter_groups: z
|
|
1686
1708
|
.array(
|
|
1687
1709
|
z.object({
|