@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 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` because Google Discover does not support average position. |
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digestseo/mcp-gsc",
3
- "version": "0.4.10",
3
+ "version": "0.4.11",
4
4
  "private": false,
5
5
  "main": "scripts/glama-start.mjs",
6
6
  "bin": {
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
- 'Google Discover does not support the query dimension or query filters in Search Analytics.',
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.string().nullable().optional(),
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.string().nullable().optional(),
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.string(),
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, last submitted/downloaded dates, submitted URL counts, warning and error counts, and sitemap status. 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.',
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
- return toolResponse(JSON.stringify(sitemaps, null, 2), { sitemaps });
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 does not support query grouping/filtering or',
956
- ' average position. For Discover, use page/country/device/date/',
957
- ' searchAppearance dimensions and interpret clicks, impressions,',
958
- ' and CTR; query dimensions/filters are rejected before the API call.',
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 does not support the query dimension.",
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 does not support query grouping/filtering or average position.'),
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: search_type !== 'discover',
1109
- ...(search_type === 'discover'
1128
+ position_supported:
1129
+ search_type !== 'discover' && search_type !== 'googleNews',
1130
+ ...(search_type === 'discover' || search_type === 'googleNews'
1110
1131
  ? {
1111
1132
  position_note:
1112
- "Google Discover does not support average position. Do not interpret rows[].position for search_type='discover'.",
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 is intentionally unavailable because Discover does not expose query data.',
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', 'googleNews'])
1168
+ .enum(['web', 'image', 'video', 'news'])
1148
1169
  .default('web')
1149
- .describe('Which search index to query. Defaults to web. Discover is not supported because this tool groups by query.'),
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 is intentionally unavailable because Discover does not expose query data.',
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', 'googleNews'])
1246
+ .enum(['web', 'image', 'video', 'news'])
1226
1247
  .default('web')
1227
- .describe('Which search index to query. Defaults to web. Discover is not supported because this tool filters by query.'),
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
- return toolResponse(JSON.stringify(details, null, 2), { sitemap: details });
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 is intentionally unavailable because this comparison contract includes average position, which the Discover report does not support.',
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', 'googleNews'])
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 is excluded because this tool returns average-position comparisons.'),
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({