@cyanheads/eurostat-mcp-server 0.8.1 → 0.10.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 (82) hide show
  1. package/AGENTS.md +27 -21
  2. package/CLAUDE.md +27 -21
  3. package/Dockerfile +94 -46
  4. package/README.md +42 -38
  5. package/changelog/0.10.x/0.10.0.md +40 -0
  6. package/changelog/0.9.x/0.9.0.md +43 -0
  7. package/dist/config/server-config.d.ts +1 -0
  8. package/dist/config/server-config.d.ts.map +1 -1
  9. package/dist/config/server-config.js +5 -0
  10. package/dist/config/server-config.js.map +1 -1
  11. package/dist/index.js +45 -5
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.d.ts +10 -2
  14. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.d.ts.map +1 -1
  15. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.js +63 -10
  16. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.js.map +1 -1
  17. package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.d.ts +0 -1
  18. package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.d.ts.map +1 -1
  19. package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.js +15 -5
  20. package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.js.map +1 -1
  21. package/dist/mcp-server/tools/definitions/eurostat-dataframe-drop.tool.d.ts +34 -0
  22. package/dist/mcp-server/tools/definitions/eurostat-dataframe-drop.tool.d.ts.map +1 -0
  23. package/dist/mcp-server/tools/definitions/eurostat-dataframe-drop.tool.js +112 -0
  24. package/dist/mcp-server/tools/definitions/eurostat-dataframe-drop.tool.js.map +1 -0
  25. package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.d.ts +0 -2
  26. package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.d.ts.map +1 -1
  27. package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.js +18 -6
  28. package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.js.map +1 -1
  29. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.d.ts +1 -2
  30. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.d.ts.map +1 -1
  31. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js +39 -14
  32. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js.map +1 -1
  33. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.d.ts +1 -1
  34. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.d.ts.map +1 -1
  35. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js +10 -1
  36. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js.map +1 -1
  37. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.d.ts +13 -6
  38. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.d.ts.map +1 -1
  39. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js +235 -53
  40. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js.map +1 -1
  41. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts +9 -5
  42. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts.map +1 -1
  43. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js +45 -19
  44. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js.map +1 -1
  45. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.d.ts +10 -2
  46. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.d.ts.map +1 -1
  47. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.js +79 -14
  48. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.js.map +1 -1
  49. package/dist/mcp-server/tools/narrowing-advice.d.ts +2 -1
  50. package/dist/mcp-server/tools/narrowing-advice.d.ts.map +1 -1
  51. package/dist/mcp-server/tools/narrowing-advice.js +4 -1
  52. package/dist/mcp-server/tools/narrowing-advice.js.map +1 -1
  53. package/dist/mcp-server/tools/value-list-paging.d.ts +49 -0
  54. package/dist/mcp-server/tools/value-list-paging.d.ts.map +1 -0
  55. package/dist/mcp-server/tools/value-list-paging.js +73 -0
  56. package/dist/mcp-server/tools/value-list-paging.js.map +1 -0
  57. package/dist/services/canvas-accessor.d.ts +21 -7
  58. package/dist/services/canvas-accessor.d.ts.map +1 -1
  59. package/dist/services/canvas-accessor.js +26 -11
  60. package/dist/services/canvas-accessor.js.map +1 -1
  61. package/dist/services/eurostat-bulk/eurostat-bulk-service.d.ts +8 -4
  62. package/dist/services/eurostat-bulk/eurostat-bulk-service.d.ts.map +1 -1
  63. package/dist/services/eurostat-bulk/eurostat-bulk-service.js +62 -25
  64. package/dist/services/eurostat-bulk/eurostat-bulk-service.js.map +1 -1
  65. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts +46 -4
  66. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts.map +1 -1
  67. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js +134 -33
  68. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js.map +1 -1
  69. package/dist/services/eurostat-data/eurostat-data-service.d.ts +5 -0
  70. package/dist/services/eurostat-data/eurostat-data-service.d.ts.map +1 -1
  71. package/dist/services/eurostat-data/eurostat-data-service.js +133 -24
  72. package/dist/services/eurostat-data/eurostat-data-service.js.map +1 -1
  73. package/dist/services/eurostat-filters.d.ts +13 -0
  74. package/dist/services/eurostat-filters.d.ts.map +1 -0
  75. package/dist/services/eurostat-filters.js +21 -0
  76. package/dist/services/eurostat-filters.js.map +1 -0
  77. package/dist/services/eurostat-outage.d.ts +27 -0
  78. package/dist/services/eurostat-outage.d.ts.map +1 -0
  79. package/dist/services/eurostat-outage.js +44 -0
  80. package/dist/services/eurostat-outage.js.map +1 -0
  81. package/package.json +12 -11
  82. package/server.json +26 -26
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  <div align="center">
2
2
  <h1>@cyanheads/eurostat-mcp-server</h1>
3
3
  <p><b>Search and query the Eurostat catalogue — EU economy, demography, trade, health, and NUTS regional data via MCP. STDIO or Streamable HTTP.</b>
4
- <div>6 Tools (8 with the dataframe canvas) • 1 Resource</div>
4
+ <div>6 Tools (up to 9 with the dataframe canvas) • 1 Resource</div>
5
5
  </p>
6
6
  </div>
7
7
 
8
8
  <div align="center">
9
9
 
10
- [![Version](https://img.shields.io/badge/Version-0.8.1-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/eurostat-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/eurostat-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/eurostat-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.4.2-blueviolet.svg?style=flat-square)](https://bun.sh/)
10
+ [![Version](https://img.shields.io/badge/Version-0.10.0-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/eurostat-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.3.1-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/eurostat-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/eurostat-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.4.3-blueviolet.svg?style=flat-square)](https://bun.sh/)
11
11
 
12
12
  </div>
13
13
 
@@ -35,18 +35,19 @@ The catalogue spans two Eurostat hosts. Most datasets come from the disseminatio
35
35
 
36
36
  ### Tools
37
37
 
38
- Two of the eight are listed only when the dataframe canvas is enabled (`CANVAS_PROVIDER_TYPE=duckdb`).
38
+ Three of the nine are listed only when the dataframe canvas is enabled (`CANVAS_PROVIDER_TYPE=duckdb`), and `eurostat_dataframe_drop` also needs `EUROSTAT_DATAFRAME_DROP_ENABLED=true`.
39
39
 
40
40
  | Tool | Description |
41
41
  |:---|:---|
42
42
  | `eurostat_search_datasets` | Search the Eurostat catalogue by keyword — returns codes, descriptions, period coverage, and theme breadcrumbs |
43
43
  | `eurostat_browse_themes` | Navigate the Eurostat theme hierarchy — list root themes or drill into subthemes and datasets |
44
44
  | `eurostat_get_dataset_info` | Fetch dataset metadata: dimensions with sample values, time range, observation count, and last-update date |
45
- | `eurostat_get_dimension_values` | List all valid codes for one dataset dimension, with NUTS hierarchy filtering for `geo` |
45
+ | `eurostat_get_dimension_values` | List all valid codes for one dataset dimension, paged, with a code/label word filter and NUTS hierarchy filtering for `geo` |
46
46
  | `eurostat_query_dataset` | Fetch a bounded preview of decoded observations with dimension filters, NUTS geo-level, and time-range controls |
47
47
  | `eurostat_download_dataset` | Download a whole dataset via the SDMX bulk endpoint and stage every observation on the dataframe canvas |
48
48
  | `eurostat_dataframe_describe` | List the tables staged on a dataframe canvas, with row counts and column types |
49
49
  | `eurostat_dataframe_query` | Run a read-only SQL SELECT across staged tables |
50
+ | `eurostat_dataframe_drop` | Remove one staged table from a dataframe canvas, leaving its other tables in place (opt-in) |
50
51
 
51
52
  ### Resources
52
53
 
@@ -60,76 +61,77 @@ The same metadata is available through `eurostat_get_dataset_info` for tool-only
60
61
 
61
62
  ### `eurostat_search_datasets` <sub>tool</sub>
62
63
 
63
- - `query` tokens are ANDed case-insensitively across each dataset's label, theme breadcrumb, and code; `limit` 1–100 (default 20), paged by passing `nextCursor` back as `cursor`
64
- - Results carry `code`, `label`, `type` (`dataset` / `table`), period coverage, `obsCount`, `lastUpdated`, and `themePath`; `totalMatches` counts every match
65
- - Searches the dissemination table of contents plus the Comext host's dataflow list, whose `DS-*` entries carry `lastUpdated` but no period coverage or `obsCount`. A collection on neither, such as the legacy PRODCOM `DS-056120`, is not disseminated and cannot be reached
66
- - Fails as `no_match` — for a query naming such a `DS-*` code, saying the collection is not disseminated rather than suggesting a broader search — or `invalid_cursor` when a cursor is reused with a different query or after the catalogue refreshes
64
+ - `query` tokens are ANDed case-insensitively across each dataset's label, theme breadcrumb, and code, ignoring spacing beside punctuation in the catalogue (`Rev.2` finds `Rev. 2`); `limit` 1–100 (default 20), paged by passing `nextCursor` back as `cursor`
65
+ - Results carry `code`, `label`, `type` (`dataset` / `table`), period coverage, `obsCount`, `lastUpdated`, and `themePath`, with `totalMatches` across every page; fails as `no_match` (naming each word whose removal alone finds matches, with the count), `invalid_cursor`, or a retryable `upstream_fault` when the server has no catalogue loaded yet and Eurostat's table of contents answers HTTP 5xx or cannot be reached on every retry
66
+ - While the Comext dataflow list cannot be loaded, results come from the dissemination catalogue alone and carry `comextListMissing` and a `notice`; a catalogue a failed refresh could not replace carries `catalogueLoadedAt`, and a `no_match` hint names both
67
67
 
68
68
  ---
69
69
 
70
70
  ### `eurostat_browse_themes` <sub>tool</sub>
71
71
 
72
- - Omit `theme_code` for the top-level theme folders; pass a folder code for its immediate children
73
- - The Comext collections sit in two folders the table of contents lacks: `ext_go_detail` (detailed trade) under `ext_go`, and `prom` (PRODCOM) under `icts`
74
- - Items carry `code`, `label`, `type` (`folder` / `dataset` / `table`), and `hasChildren`, with a `parentPath` breadcrumb; `otherPlacements` names other branches that file the same folder code
75
- - Fails as `not_found` for an unknown code, `not_a_folder` for a dataset or table code
72
+ - Omit `theme_code` for the top-level theme folders; pass a folder code for its immediate children. The Comext collections sit under `ext_go_detail` (detailed trade, in `ext_go`) and `prom` (PRODCOM, in `icts`)
73
+ - Items carry `code`, `label`, `type` (`folder` / `dataset` / `table`), and `hasChildren`, with a `parentPath` breadcrumb and `otherPlacements` for a folder code filed in several branches; fails as `not_found` for an unknown code, `not_a_folder` for a dataset or table code, or a retryable `upstream_fault` when the server has no catalogue loaded yet and Eurostat's table of contents answers HTTP 5xx or cannot be reached on every retry
74
+ - While the Comext dataflow list cannot be loaded, `ext_go` and `icts` carry `comextListMissing` and a `notice`, and `not_found` on a Comext folder or `DS-*` code says the list could not be loaded; a catalogue a failed refresh could not replace carries `catalogueLoadedAt`, and a `not_found` hint gives its load time
76
75
 
77
76
  ---
78
77
 
79
78
  ### `eurostat_get_dataset_info` <sub>tool</sub>
80
79
 
81
80
  - One `dataset_code`; returns every dimension with `valuesCount` and up to 10 `sampleValues`, plus `timeRange`, `obsCount`, `lastUpdated`, and the ESMS `metadataUrl`
82
- - The Comext host reports no `timeRange` or `obsCount` for a `DS-*` collection, so both read as unreported. Its structure carries a label for every code, 23 MB for `DS-045409`: parsed metadata is cached per dataset for an hour, within a 64 MiB memory budget, so only the first call pays for it
83
- - Fails as `not_found` for an unknown dataset, or `upstream_fault` when Eurostat returns a structure or content constraint the server cannot read; a failed read is not cached, so a later call downloads it afresh
81
+ - Fails as `not_found` for an unknown dataset, or `upstream_fault` when Eurostat returns a structure or content constraint the server cannot read, or when the structure endpoint answers HTTP 5xx or cannot be reached on every retry (marked retryable)
84
82
 
85
83
  ---
86
84
 
87
85
  ### `eurostat_get_dimension_values` <sub>tool</sub>
88
86
 
89
- - `dataset_code` plus `dimension`; returns the dataset-available code/label pairs in `values`, with `totalCount`
90
- - At most 2,000 values come back inline, in Eurostat's order. A longer list — the 37,069 CN8 codes of `DS-045409`, a daily `time` dimension, the largest airport-pair lists — is cut there, with `truncated`, `shown`, `cap`, and a `notice` saying where the rest is
91
- - For `geo`, `geo_level` picks a NUTS level (`aggregate`, `country` by default, `nuts1`, `nuts2`, `nuts3`)
92
- - `canvas_id` also stages every value, past the inline cap too, on that canvas as a `code` / `label` table (`canvasId` / `tableName` / `stagedRowCount`), to search with SQL or to label a download's code-only columns through a join; this tool never starts a canvas of its own, and ignores `canvas_id` on a deployment without one
93
- - Fails as `not_found` for an unknown dataset or dimension, `no_results` for a NUTS level with no values, `conflicting_params` for `geo_level` on any other dimension, `upstream_fault` for a structure or content constraint the server cannot read, or `canvas_not_found` for an unknown or expired `canvas_id`
87
+ - `dataset_code` plus `dimension`; for `geo`, `geo_level` picks a NUTS level (`aggregate`, `country` by default, `nuts1`, `nuts2`, `nuts3`). Values come back in Eurostat's order
88
+ - `filter` keeps the values whose code and label contain every word given, ignoring case and accents (`palma frankfurt` finds `DE_EDDF_ES_LEPA`), with `matchCount` counting the matches
89
+ - A long list comes back a page at a time: each response holds whole values within 64,000 bytes, up to an optional `limit`, and a page with more after it carries `truncated`, `nextCursor` (pass it back as `cursor`), and a `notice`. `totalCount` counts every value
90
+ - Fails as `not_found`, `no_results`, `conflicting_params`, `invalid_cursor`, `upstream_fault` (a structure or content constraint the server cannot read, or, marked retryable, a structure endpoint that answers HTTP 5xx or cannot be reached on every retry), or `canvas_not_found`
91
+ - `canvas_id` stages every value, whatever `filter` and `limit` are, on that canvas as a `code` / `label` table (`canvasId` / `tableName` / `stagedRowCount`) that labels a download's code columns through a join; this tool never starts a canvas of its own
94
92
 
95
93
  ---
96
94
 
97
95
  ### `eurostat_query_dataset` <sub>tool</sub>
98
96
 
99
- - `dataset_code` plus `filters` (`{dimension_code: [values]}`, codes in any case), `geo_level`, and either `since_period` / `until_period` (`YYYY`, `YYYY-MM`, `YYYY-MM-DD`, `YYYY-Qn`, `YYYY-Sn`, `YYYY-Tn`, `YYYY-Mnn`, `YYYY-Wnn`, `YYYY-Dnnn`; extra leading zeros after the letter are dropped, so `2020-Q01` is sent as `2020-Q1`, and `YYYY-A1` is sent as `YYYY`) or `last_n_periods`, which counts back from the dataset's latest period rather than the slice's; `preview_limit` 1–500 (default 50) sets the inline row count; `lang` is `EN`, `FR`, or `DE`
100
- - Each observation carries code/label pairs per dimension, a nullable `value`, an OBS_FLAG `status`, and a CONF_STATUS `confStatus`; `obsCount`, `missingObsCount`, and `timeRange` cover the whole match, `truncated` is true above 5,000 observations, and `unmatchedValues` names filter values that matched nothing
101
- - PRODCOM publishes its flag and unit indicators as text in the value itself: `:C` comes back as a null `value` with `confStatus` `C`, and anything else, such as the unit `KG`, verbatim in `valueText` with a null `value`
102
- - Fails as `not_found`, `no_results` (naming the filter values that matched nothing and, up to the newest 24 with a full count, the selected periods that carry no value), `invalid_dimension`, `invalid_period` (a malformed or non-existent period, or a `since_period` that starts after `until_period` ends, rejected before any request), `conflicting_params` (`geo` filter with `geo_level`, or a period range with `last_n_periods`), a non-retryable `async_response` for a query too large to serve inline, or `canvas_not_found` for an unknown or expired `canvas_id`
97
+ - `dataset_code` plus `filters` (`{dimension_code: [values]}`), `geo_level`, and either `since_period` / `until_period` (`2020`, `2020-Q1`, `2020-01`, down to `YYYY-Wnn` and `YYYY-Dnnn`) or `last_n_periods`; `preview_limit` 1–500 (default 50) sets the inline rows; `lang` is `EN`, `FR`, or `DE`
98
+ - Each observation carries code/label pairs per dimension, a nullable `value`, `status` (OBS_FLAG), and `confStatus` (CONF_STATUS); `obsCount`, `missingObsCount`, and `timeRange` cover the whole match, `truncated` is true above 5,000 observations, and `unmatchedValues` names filter values that matched nothing
99
+ - Fails as `not_found`, `no_results` (naming the unmatched values and the periods that carry no value), `invalid_dimension`, `invalid_period`, `conflicting_params`, a non-retryable `async_response` for a query too large to serve inline, `canvas_not_found`, or a retryable `upstream_fault` when the Statistics API answers HTTP 5xx or cannot be reached on every retry
103
100
 
104
101
  ---
105
102
 
106
103
  ### `eurostat_download_dataset` <sub>tool</sub>
107
104
 
108
- - `dataset_code` plus the same `filters` map and `since_period` / `until_period` in the same period forms (no `last_n_periods`: the TSV keeps a column per period unless a range drops it); `preview_limit` 1–500 (default 50)
109
- - Returns `rowCount` (echoed as `totalCount`), `missingCount`, `periodRange`, and `bytesRead` for the whole download; the `EUROSTAT_BULK_MAX_BYTES` budget (default 50 MiB) stops a transfer mid-stream and returns what arrived with `budgetExceeded: true`
110
- - On a `DS-*` table, `obs_value_text` holds a value published as text (PRODCOM's `KG`), and a PRODCOM `:C` lands in `conf_status`
111
- - Fails as `not_found`, `invalid_dimension` (including a range wholly outside the dataset's coverage), `invalid_period` (a malformed or non-existent period, or a `since_period` that starts after `until_period` ends, rejected before any request), `filter_arity`, a non-retryable `async_queued` when Eurostat queues the extraction, a non-retryable `extraction_too_big` when Eurostat refuses it as too large (past its 5,000,000-row limit, or an unfiltered download of a large Comext collection) with the dimensions left to filter, `no_results` (including a range inside the dataset's coverage that misses the filtered series), `upstream_fault`, or `canvas_not_found` for an unknown or expired `canvas_id`
105
+ - `dataset_code` plus the same `filters` map and `since_period` / `until_period` (no `last_n_periods`: the TSV keeps a column per period unless a range drops it); `preview_limit` 1–500 (default 50)
106
+ - Returns `rowCount` (echoed as `totalCount`), `missingCount`, `periodRange`, and `bytesRead` for the whole download; fails as `not_found`, `invalid_dimension`, `invalid_period`, `filter_arity`, a non-retryable `async_queued` or `extraction_too_big`, `no_results`, `upstream_fault` (an unmodelled fault or a body that is not a TSV table, or, marked retryable, an SDMX endpoint that answers HTTP 5xx or cannot be reached on every retry), or `canvas_not_found`
107
+ - The `EUROSTAT_BULK_MAX_BYTES` budget (default 50 MiB) stops a transfer mid-stream and returns what arrived with `budgetExceeded: true`
112
108
 
113
109
  ---
114
110
 
115
111
  ### `eurostat_dataframe_describe` <sub>tool</sub>
116
112
 
117
- - `canvas_id` from a staging response; lists each table's `name`, `rowCount`, and typed columns, plus canvas and table `expiresAt` (sliding `CANVAS_TTL_MS`, default 24h); fails as `canvas_not_found` for an unknown or expired ID, or `canvas_disabled` on a deployment without a canvas
118
- - `eurostat_query_dataset` tables carry a code and a `_label` column per dimension; `eurostat_download_dataset` tables carry codes only, plus `time`. Both share `obs_value`, `obs_flag`, `obs_flag_label`, `conf_status`, and `conf_status_label`, so they join on dimension codes and `time`; a `DS-*` table from either adds `obs_value_text`
119
- - `eurostat_get_dimension_values` tables carry `code` and `label`: join one to a download on its dimension column (`d.geo = g.code`) to label it
113
+ - `canvas_id` from a staging response; lists each table's `name`, `rowCount`, typed columns, and `expiresAt` (sliding `CANVAS_TTL_MS`, default 24h); fails as `canvas_not_found` or `canvas_disabled`
114
+ - Columns differ by the tool that staged them: `eurostat_query_dataset` writes a code and a `_label` column per dimension, `eurostat_download_dataset` codes only plus `time` — both with the same `obs_*` and `conf_status*` measures, so they join on dimension codes and `time` — and `eurostat_get_dimension_values` writes `code` and `label`
120
115
 
121
116
  ---
122
117
 
123
118
  ### `eurostat_dataframe_query` <sub>tool</sub>
124
119
 
125
120
  - One read-only `SELECT` per call; chained statements, other verbs, and functions that read files or external data are rejected
126
- - Returns `columns`, `rows`, `rowCount`, and `truncated`, which is true past `CANVAS_DEFAULT_ROW_LIMIT` (default 10,000) rows; 64-bit integers, `COUNT(*)` included, arrive as strings. Fails as `missing_table`, `canvas_not_found`, or `canvas_disabled`
121
+ - Returns `columns`, `rows`, `rowCount`, and `truncated`, true past `CANVAS_DEFAULT_ROW_LIMIT` (default 10,000) rows; 64-bit integers arrive as strings. Fails as `missing_table`, `canvas_not_found`, or `canvas_disabled`
122
+
123
+ ---
124
+
125
+ ### `eurostat_dataframe_drop` <sub>tool</sub>
126
+
127
+ - `canvas_id` plus `table_name`, exactly as `eurostat_dataframe_describe` lists it; removes that one table and leaves the canvas and its other tables in place. Listed only when `EUROSTAT_DATAFRAME_DROP_ENABLED=true` is set beside the canvas
128
+ - Returns `canvasId`, `tableName`, `dropped`, and `expiresAt`; `dropped` is `false`, with a `notice`, when nothing by that name was staged, so repeating a drop is safe. Fails as `canvas_not_found`, `identifier_reserved`, or `canvas_disabled`
127
129
 
128
130
  ---
129
131
 
130
132
  ### `eurostat://dataset/{dataset_code}` <sub>resource</sub>
131
133
 
132
- - Same payload as `eurostat_get_dataset_info`, returned as `application/json`
134
+ - Same payload as `eurostat_get_dataset_info`, returned as `application/json`; a failed read carries the same `reason`, and `retryable` on an outage
133
135
  - `dataset_code` comes from `eurostat_search_datasets` or `eurostat_browse_themes`
134
136
 
135
137
  ## Features
@@ -139,10 +141,10 @@ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): s
139
141
  Eurostat-specific:
140
142
 
141
143
  - The Statistics API (JSON-stat 2.0) for slices, the SDMX 2.1 TSV bulk endpoint for whole datasets at roughly half the bytes, and the catalogue TOC cached in memory for 12 hours
142
- - The Comext host's `DS-*` collections through the same tools: detailed trade by CN8, HS, SITC, BEC and CPA, and PRODCOM. The trade flows mix annual and monthly series in one dataset, so filter `freq`; `product`, `reporter` and `partner` carry aggregates (`TOTAL`, `EU27_2020`, `EXT_EU27_2020`) that double-count when summed with their members. The Comext host serves no large collection unfiltered
143
- - NUTS geo-level filtering (`aggregate` / `country` / `nuts1` / `nuts2` / `nuts3`) on `eurostat_query_dataset` and `eurostat_get_dimension_values`
144
- - OBS_FLAG (provisional, estimated, and so on) and CONF_STATUS (confidentiality) decoded into separate fields, with the same codes from JSON-stat and the bulk TSV
144
+ - The Comext host's `DS-*` collections through the same tools: detailed trade by CN8, HS, SITC, BEC and CPA, and PRODCOM. They report no period coverage or `obsCount`, and the trade flows mix annual and monthly series in one dataset, so filter `freq`; `product`, `reporter` and `partner` carry aggregates (`TOTAL`, `EU27_2020`, `EXT_EU27_2020`) that double-count when summed with their members. The Comext host serves no large collection unfiltered. PRODCOM values published as text arrive in `valueText` / `obs_value_text` (the unit `KG`), and its `:C` as confidentiality status `C`. A collection on neither host, such as the legacy `DS-056120`, is not disseminated
145
+ - NUTS geo-level filtering (`aggregate` / `country` / `nuts1` / `nuts2` / `nuts3`) on `eurostat_query_dataset` and `eurostat_get_dimension_values`, and OBS_FLAG (provisional, estimated, and so on) and CONF_STATUS (confidentiality) decoded into separate fields, with the same codes from JSON-stat and the bulk TSV
145
146
  - Eurostat's too-large-to-serve responses (HTTP-200 async warnings, HTTP 413, SOAP fault 413, SOAP queue tickets) come back as non-retryable `async_response`, `extraction_too_big`, or `async_queued` errors that name the dataset's own dimensions left to filter, not timeouts
147
+ - A Eurostat outage — HTTP 5xx or an unreachable host on all four attempts, about seven seconds of backoff in all — comes back as `upstream_fault` marked `retryable`, with a hint naming the endpoint and saying to retry in a few minutes. HTTP 501 fails on its first attempt, marked not retryable
146
148
  - Inline rows are capped by `preview_limit` (at most 500). With `CANVAS_PROVIDER_TYPE=duckdb`, a query match above 5,000 observations, or any bulk download, is staged whole as a SQL table (`canvasId` / `tableName` / `stagedRowCount`) for the dataframe tools, and `canvas_id` stages the next result beside earlier ones for joins — including a dimension's code/label list from `eurostat_get_dimension_values`, which labels a bulk table's codes. An empty download fails as `no_results` without creating or touching a canvas. The `.mcpb` bundle strips the native DuckDB binding, so SQL analytics need the npm, Docker, or from-source install
147
149
 
148
150
  Agent-friendly output:
@@ -270,15 +272,17 @@ cp .env.example .env
270
272
  | `EUROSTAT_TOC_CACHE_TTL_MS` | Catalogue TOC cache lifetime, in ms; the first search or browse call past it refreshes the TOC. | `43200000` (12 h) |
271
273
  | `EUROSTAT_BULK_TIMEOUT_MS` | Timeout for one `eurostat_download_dataset` transfer, in ms. | `120000` (2 min) |
272
274
  | `EUROSTAT_BULK_MAX_BYTES` | Byte budget for one bulk download, counted on the decoded TSV and enforced while streaming. | `52428800` (50 MiB) |
273
- | `CANVAS_PROVIDER_TYPE` | `duckdb` enables the dataframe canvas: lists the two dataframe tools and turns on staging. | `none` |
275
+ | `CANVAS_PROVIDER_TYPE` | `duckdb` enables the dataframe canvas: lists `eurostat_dataframe_describe` and `eurostat_dataframe_query` and turns on staging. | `none` |
274
276
  | `CANVAS_TTL_MS` | Sliding lifetime of a staged canvas, in ms. | `86400000` (24 h) |
275
277
  | `CANVAS_DEFAULT_ROW_LIMIT` | Max rows one `eurostat_dataframe_query` returns before reporting `truncated`. | `10000` |
278
+ | `EUROSTAT_DATAFRAME_DROP_ENABLED` | `true` lists `eurostat_dataframe_drop`, which removes one staged table; needs `CANVAS_PROVIDER_TYPE=duckdb`. Off by default because a drop cannot be undone. | `false` |
276
279
  | `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
277
280
  | `MCP_HTTP_PORT` | HTTP server port. | `3010` |
278
281
  | `MCP_SESSION_MODE` | HTTP session mode: `stateless`, `stateful`, or `auto`. The server declares `stateless`; a set value overrides it. | `stateless` |
279
282
  | `MCP_AUTH_MODE` | Authentication: `none`, `jwt`, or `oauth`. | `none` |
280
283
  | `MCP_LOG_LEVEL` | Log level (`debug`, `info`, `warning`, `error`, etc.). The Docker image sets `info`. | `debug` |
281
284
  | `LOGS_DIR` | Directory for log files (Node.js only). | `<project-root>/logs` |
285
+ | `LOG_TOOL_FAILURE_PAYLOADS` | Log each failed tool call's arguments and result, redacted by key name and capped at `LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES` (default `16384`). A secret inside a free-form value is not redacted. | `false` |
282
286
  | `STORAGE_PROVIDER_TYPE` | Storage backend: `in-memory`, `filesystem`, `supabase`, `cloudflare-kv/r2/d1`. | `in-memory` |
283
287
  | `OTEL_ENABLED` | Enable [OpenTelemetry](https://github.com/cyanheads/mcp-ts-core/tree/main/docs/telemetry). | `false` |
284
288
 
@@ -320,8 +324,8 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
320
324
 
321
325
  | Directory | Purpose |
322
326
  |:---|:---|
323
- | `src/index.ts` | `createApp()` entry point — registers tools and the resource, inits services, gates the dataframe tools on the canvas. |
324
- | `src/mcp-server/tools` | Tool definitions (`*.tool.ts`). Six discovery and data tools, plus two canvas-gated dataframe tools. |
327
+ | `src/index.ts` | `createApp()` entry point — registers tools and the resource, inits services, gates the dataframe tools on the canvas and the drop tool on its own flag. |
328
+ | `src/mcp-server/tools` | Tool definitions (`*.tool.ts`). Six discovery and data tools, plus three canvas-gated dataframe tools, one of them opt-in. |
325
329
  | `src/mcp-server/resources` | Resource definitions. Dataset metadata resource. |
326
330
  | `src/services/eurostat-catalogue` | Catalogue service — fetches and parses the Eurostat TOC, merges the Comext dataflow list into it, with a TTL-bounded in-memory cache. |
327
331
  | `src/services/eurostat-data` | Statistics API service — SDMX metadata parsing with a per-dataset cache, JSON-stat 2.0 decoding, async-response detection, canvas row source. |
@@ -0,0 +1,40 @@
1
+ ---
2
+ summary: "Pages long dimension-value lists with filter and cursor, rejects filter keys named like API controls, reports upstream outages and partial or stale catalogues, fixes blank filters, time-selection conflicts and canvas recoveries, matches search terms across spacing beside punctuation, and adopts mcp-ts-core 0.13.15."
3
+ breaking: true
4
+ security: false
5
+ ---
6
+
7
+ # 0.10.0 — 2026-10-14
8
+
9
+ ## Added
10
+
11
+ - **`eurostat_get_dimension_values` takes `filter`, `limit`, and `cursor`** ([#64](https://github.com/cyanheads/eurostat-mcp-server/issues/64)) — `filter` keeps values whose code and label contain every word given (case- and accent-blind, any order), with `matchCount` counting the matches; a page with more after it carries `truncated`, `nextCursor`, and a `notice`. A cursor bound to another `dataset_code`, `dimension`, `geo_level`, or `filter`, or resuming after a code no longer listed, fails as `invalid_cursor`; every binding but `geo_level` is checked before the dimension's structure is fetched. On a deployment with a dataframe canvas, `canvas_id` beside `cursor` fails as `conflicting_params`; without one, `canvas_id` is ignored and the page is served. A filter that matches nothing on a call that staged the list names the staged table.
12
+ - **Partial and stale catalogues are disclosed** ([#63](https://github.com/cyanheads/eurostat-mcp-server/issues/63)) — while the Comext dataflow list is unmerged, `eurostat_search_datasets` and `eurostat_browse_themes` (on `ext_go` and `icts`) carry `comextListMissing` and a `notice`, `no_match` hints name it, and `not_found` on a Comext folder or `DS-*` code says the list could not be loaded. A catalogue a failed TOC refresh could not replace carries `catalogueLoadedAt`, and a search `no_match` or browse `not_found` answered from it names that load time in its hint.
13
+ - **`eurostat_search_datasets` `no_match` names the blocking word** ([#69](https://github.com/cyanheads/eurostat-mcp-server/issues/69)) — for two or more distinct words, each word whose removal alone yields matches is listed with its count (`Without "rates": 7 matches.`), counted in one pass over the catalogue.
14
+ - **Upstream outages fail as retryable `upstream_fault`** ([#71](https://github.com/cyanheads/eurostat-mcp-server/issues/71)) — an HTTP 5xx or an unreachable host that outlasts the retries, on every tool that calls Eurostat, with an outage hint (HTTP 501 is not retryable); the `eurostat://dataset/{dataset_code}` resource fails with the same retryable `upstream_fault`, without a hint. `eurostat_download_dataset`, filtered or not, now retries its SDMX data request on an outage instead of failing on the first attempt, and `eurostat_search_datasets` and `eurostat_browse_themes` fail the same way when no catalogue has loaded yet.
15
+
16
+ ## Changed
17
+
18
+ - **Breaking: `eurostat_query_dataset` rejects filter keys named like Eurostat API controls** (`lang`, `format`, `geoLevel`, `sinceTimePeriod`, `untilTimePeriod`, `lastTimePeriod`, any case) as `invalid_dimension` ([#62](https://github.com/cyanheads/eurostat-mcp-server/issues/62)). Some such calls used to return data; set the `lang`, `geo_level`, `since_period`, `until_period`, or `last_n_periods` input instead.
19
+ - **Breaking: `eurostat_get_dimension_values` no longer returns `shown` and `cap`** ([#64](https://github.com/cyanheads/eurostat-mcp-server/issues/64)). Long lists are paged within a 64,000-byte budget per response surface with `nextCursor`, instead of being cut at 2,000 values.
20
+ - **`eurostat_search_datasets` matches across spacing beside punctuation** ([#69](https://github.com/cyanheads/eurostat-mcp-server/issues/69)) — `Rev.2` finds `Rev. 2`, and `R&D`, `non-EU`, and `DS-045409` keep their punctuation. Search text is built once per catalogue snapshot.
21
+ - **Eurostat error labels in messages end in one period**, and server log lines no longer carry request URLs; fetches are labelled by endpoint.
22
+ - **`instructions`, tool descriptions, `README.md`, and `docs/design.md`** describe paging, outage and partial-catalogue behavior, and the new rejections.
23
+ - **`CLAUDE.md`/`AGENTS.md`** follow the 0.13.15 template, and the framework anti-pattern checks in `scripts/check-framework-antipatterns.ts` use POSIX character classes.
24
+ - **Framework** — `cyanheads/mcp-ts-core` ^0.13.11 → ^0.13.15: log records carry no request URLs, and `eurostat_dataframe_query` runs on a DuckDB canvas with external access off, with an SQL gate that refuses more functions and file references. Framework skills are synced to 0.13.15.
25
+
26
+ ## Fixed
27
+
28
+ - **A blank or whitespace-only filter element is unset** ([#61](https://github.com/cyanheads/eurostat-mcp-server/issues/61)) — `[""]` accepts every value and `["", "DE"]` is `["DE"]` on `eurostat_query_dataset` and `eurostat_download_dataset`, in the request, the `geo`/`geo_level` check, `appliedFilters`/`appliedQuery`, and the too-large hint. A blank used to be sent upstream and echoed as applied.
29
+ - **A time filter beside a period input fails as `conflicting_params`** ([#70](https://github.com/cyanheads/eurostat-mcp-server/issues/70)) — `filters.time` or `filters.time_period` (any case) with `since_period`, `until_period`, or `last_n_periods` is refused before any request, and Eurostat's own "cannot be set at the same time" refusal is no longer reported as `invalid_period`.
30
+ - **Declared `canvas_not_found` and `missing_table` recoveries reach callers** ([#68](https://github.com/cyanheads/eurostat-mcp-server/issues/68)) on `eurostat_query_dataset`, `eurostat_download_dataset`, `eurostat_get_dimension_values`, `eurostat_dataframe_describe`, and `eurostat_dataframe_query`, in place of the canvas service's generic hints.
31
+ - **The canvas-off over-cap notice and truncation banner of `eurostat_query_dataset` name only filters and a period range** ([#65](https://github.com/cyanheads/eurostat-mcp-server/issues/65)); they used to route to `eurostat_download_dataset`, which keeps only its preview without a canvas.
32
+
33
+ ## Dependencies
34
+
35
+ - `@cyanheads/mcp-ts-core` ^0.13.11 → ^0.13.15
36
+ - `pino-pretty` ^13.1.3 → ^13.2.0
37
+ - `zod` ^4.6.5 → ^4.6.6
38
+ - Dev: `@types/node` 26.6.3 → 26.6.5
39
+ - Dev: `ignore` ^7.0.11 → ^7.0.12
40
+ - Bun 1.4.2 → 1.4.3 (`packageManager`, Dockerfile)
@@ -0,0 +1,43 @@
1
+ ---
2
+ summary: "Opt-in eurostat_dataframe_drop removes one staged table from a canvas, the server moves to mcp-ts-core 0.13.11, and an unwritable CANVAS_TEMP_PATH now fails as a configuration error naming its errno."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.9.0 — 2026-10-03
8
+
9
+ ## Added
10
+
11
+ - **`eurostat_dataframe_drop`** removes one table from a dataframe canvas, leaving the canvas and its other tables in place, and returns `canvasId`, `tableName`, `dropped`, and `expiresAt`. `dropped: false`, with a `notice`, means nothing by that name was staged, so repeating a drop is safe.
12
+ - **`EUROSTAT_DATAFRAME_DROP_ENABLED`** (default `false`) gates it, since a drop cannot be undone: the tool is listed only with this set to `true` beside `CANVAS_PROVIDER_TYPE=duckdb`, and is otherwise registered disabled, shown on the landing page with the setting or settings that turn it on. A boot test pins that a `.env` file in the working directory sets the gate as the environment does.
13
+ - **The drop tool's errors carry its own recovery** ([#66](https://github.com/cyanheads/eurostat-mcp-server/issues/66)) — `canvas_not_found` and `identifier_reserved` reach the caller with the tool's declared recovery instead of the canvas service's hints, which are worded for staging (stage the data again, choose another table name), and `identifier_reserved` with the tool's own message.
14
+
15
+ ## Changed
16
+
17
+ - **The server config is parsed in `setup()`**, so a bad `EUROSTAT_*` value fails startup with the framework's configuration banner naming the variable. The first tool call used to parse it, so the server reported ready and then failed every call.
18
+ - **Dockerfile installs in a `deps` stage** on `$BUILDPLATFORM`, cross-installing for the target with `--os`/`--cpu` through `bunfig.toml`'s release-age gate and scanner; `scripts/install-otel.ts` installs the OTel peers and `scripts/prune-musl-packages.ts` drops musl-only packages. `MCP_FORCE_CONSOLE_LOGGING`, which nothing read, is gone.
19
+ - **`server.json` npm entries launch the bin via `npx`** without the `run start:*` arguments, and the `streamable-http` entry fixes `MCP_TRANSPORT_TYPE` to `http`; the bin ignored those arguments, so the HTTP entry started on stdio.
20
+ - **Tool handlers no longer forward `ctx.recoveryFor`**, which the framework now fills (0.13.10); the recovery hints on the wire are unchanged.
21
+ - **Repo and packaging config** — `.gitignore` and `.dockerignore` cover every `.env*` file (the three templates stay tracked) and `.dockerignore` adds the MCP registry token files, CodeQL runs one job per language under `/language:<language>`, `.mcpbignore` excludes `docs/idea.md` and `logs/`, and `package.json` `files` excludes `dist/*.mcpb`.
22
+ - **Docs** — the README documents the drop tool and condenses the per-tool reference, `.env.example` documents `EUROSTAT_DATAFRAME_DROP_ENABLED`, `LOG_TOOL_FAILURE_PAYLOADS`, and the per-signal OTLP endpoints, `CANVAS_TEMP_PATH` is described as a parent directory throughout, and `CLAUDE.md`/`AGENTS.md` follow the 0.13.11 template.
23
+ - **Framework skills and scripts resynced** from mcp-ts-core 0.13.11, adding `scripts/install-otel.ts` and `scripts/prune-musl-packages.ts` and removing the one-shot `scripts/split-changelog.ts`; `lint:packaging` gains the `.mcpb` exclusion, manifest version, Dockerfile build platform, and npm launch shape checks.
24
+ - **mcp-ts-core 0.13.7** — server stack traces (`originalStack`, `causeChain`) no longer reach clients through error `data`. With `OTEL_ENABLED=true`, `OTEL_EXPORTER_OTLP_ENDPOINT` alone exports traces and metrics to `<base>/v1/traces` and `<base>/v1/metrics`, and with no endpoint set nothing is exported (it used to send to `localhost:4318`).
25
+ - **mcp-ts-core 0.13.8** — request context (tenant, operation, `extra` fields) no longer reaches client error `data`, and a tool result that breaks its own output schema fails as `-32603` (was `-32007`). Opt-in OTLP log export (`OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`) and failed-call payload logging (`LOG_TOOL_FAILURE_PAYLOADS`, `LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES`).
26
+ - **mcp-ts-core 0.13.9** — a JSON-stringified object sent for an object field, or an integer sent for a string field, is repaired before validation, and argument rejections name alias rewrites and dropped keys. Canvas scratch files live in a private directory inside `CANVAS_TEMP_PATH`. MCP SDK 2.1.0 refuses a JSON-RPC batch over 100 messages, and stdin EOF on stdio aborts in-flight requests.
27
+ - **mcp-ts-core 0.13.10** — a declared `recovery` hint reaches the wire on any typed error that carries none of its own, service throws included. Error results carry `data.requestId`, and their `content[]` closes with `request <id>`. `invalid_arguments` refusals log at `notice`. The multi-arch Docker build installs dependencies on the build platform, so Bun no longer runs under QEMU.
28
+ - **mcp-ts-core 0.13.11** — `ctx.log` messages mirrored to the client honor `MCP_LOG_LEVEL` and mask sensitive fields, the log level filter compares RFC 5424 severity, and resource-read logs cap the URI at 1,024 characters. The Docker image drops musl-only bindings, `lint:packaging` enforces the `server.json` npm launch shape above, and `@modelcontextprotocol/server` moves to 2.2.0.
29
+
30
+ ## Fixed
31
+
32
+ - **An unwritable `CANVAS_TEMP_PATH` fails as `-32008` `ConfigurationError`** (was `-32000` `ServiceUnavailable`), naming its errno in the message and in `data.errno` beside `data.reason: "canvas_unavailable"`. Since mcp-ts-core 0.13.9 the provider fails with that code itself; the server keeps it and adds the errno and the `CANVAS_PROVIDER_TYPE=none` way out, which the framework's message omits.
33
+ - **A cancelled `eurostat_query_dataset` or `eurostat_download_dataset` call stays a cancellation** when it reaches the too-large refusal's dimension lookup, which rethrows the abort instead of swallowing it into a generic narrowing hint.
34
+
35
+ ## Dependencies
36
+
37
+ - `@cyanheads/mcp-ts-core` ^0.13.6 → ^0.13.11 (`@modelcontextprotocol/server` 2.0.0 → 2.2.0 transitively).
38
+ - `@duckdb/node-api` ^1.5.5-r.5 → ^1.5.6-r.1.
39
+ - Dev: `@biomejs/biome` 2.5.14 → 2.5.15.
40
+ - Dev: `@types/node` 26.6.2 → 26.6.3.
41
+ - Dev: `ignore` ^7.0.9 → ^7.0.11.
42
+ - Dev: `tsc-alias` ^1.9.5 → ^1.9.7.
43
+ - Dev: `vitest` ^5.0.1 → ^5.0.3.
@@ -11,6 +11,7 @@ declare const ServerConfigSchema: z.ZodObject<{
11
11
  tocCacheTtlMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
12
12
  bulkTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
13
13
  bulkMaxBytes: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
14
+ dataframeDropEnabled: z.ZodDefault<z.ZodCodec<z.ZodString, z.ZodBoolean>>;
14
15
  }, z.core.$strip>;
15
16
  export declare function getServerConfig(): z.infer<typeof ServerConfigSchema>;
16
17
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C,QAAA,MAAM,kBAAkB;;;;;;;;iBAmDtB,CAAC;AAIH,wBAAgB,eAAe,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAWpE"}
1
+ {"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C,QAAA,MAAM,kBAAkB;;;;;;;;;iBAyDtB,CAAC;AAIH,wBAAgB,eAAe,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAYpE"}
@@ -45,6 +45,10 @@ const ServerConfigSchema = z.object({
45
45
  .positive()
46
46
  .default(52_428_800)
47
47
  .describe('Byte budget for one SDMX bulk download, measured on the decoded TSV rather than on the wire. Eurostat sends the body chunked with no Content-Length, so the budget is enforced while streaming and the transfer is aborted the moment it is reached. Defaults to 50 MiB.'),
48
+ dataframeDropEnabled: z
49
+ .stringbool()
50
+ .default(false)
51
+ .describe('Register eurostat_dataframe_drop, which removes one staged table from a dataframe canvas. Off by default: a drop cannot be undone, and staged tables already expire with their canvas. Takes effect only with CANVAS_PROVIDER_TYPE=duckdb.'),
48
52
  });
49
53
  let _config;
50
54
  export function getServerConfig() {
@@ -56,6 +60,7 @@ export function getServerConfig() {
56
60
  tocCacheTtlMs: 'EUROSTAT_TOC_CACHE_TTL_MS',
57
61
  bulkTimeoutMs: 'EUROSTAT_BULK_TIMEOUT_MS',
58
62
  bulkMaxBytes: 'EUROSTAT_BULK_MAX_BYTES',
63
+ dataframeDropEnabled: 'EUROSTAT_DATAFRAME_DROP_ENABLED',
59
64
  });
60
65
  return _config;
61
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,GAAG,EAAE;SACL,OAAO,CAAC,iDAAiD,CAAC;SAC1D,QAAQ,CAAC,uBAAuB,CAAC;IACpC,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,GAAG,EAAE;SACL,OAAO,CAAC,wDAAwD,CAAC;SACjE,QAAQ,CACP,mMAAmM,CACpM;IACH,gBAAgB,EAAE,CAAC,CAAC,MAAM;SACvB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,MAAM,CAAC;SACf,QAAQ,CAAC,sCAAsC,CAAC;IACnD,iBAAiB,EAAE,CAAC,CAAC,MAAM;SACxB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,OAAO,CAAC;SAChB,QAAQ,CACP,oRAAoR,CACrR;IACH,aAAa,EAAE,CAAC,CAAC,MAAM;SACpB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,UAAU,CAAC;SACnB,QAAQ,CACP,qLAAqL,CACtL;IACH,aAAa,EAAE,CAAC,CAAC,MAAM;SACpB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,OAAO,CAAC;SAChB,QAAQ,CACP,mNAAmN,CACpN;IACH,YAAY,EAAE,CAAC,CAAC,MAAM;SACnB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,UAAU,CAAC;SACnB,QAAQ,CACP,0QAA0Q,CAC3Q;CACJ,CAAC,CAAC;AAEH,IAAI,OAAuD,CAAC;AAE5D,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,cAAc,CAAC,kBAAkB,EAAE;QAC7C,OAAO,EAAE,mBAAmB;QAC5B,aAAa,EAAE,0BAA0B;QACzC,gBAAgB,EAAE,6BAA6B;QAC/C,iBAAiB,EAAE,8BAA8B;QACjD,aAAa,EAAE,2BAA2B;QAC1C,aAAa,EAAE,0BAA0B;QACzC,YAAY,EAAE,yBAAyB;KACxC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,GAAG,EAAE;SACL,OAAO,CAAC,iDAAiD,CAAC;SAC1D,QAAQ,CAAC,uBAAuB,CAAC;IACpC,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,GAAG,EAAE;SACL,OAAO,CAAC,wDAAwD,CAAC;SACjE,QAAQ,CACP,mMAAmM,CACpM;IACH,gBAAgB,EAAE,CAAC,CAAC,MAAM;SACvB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,MAAM,CAAC;SACf,QAAQ,CAAC,sCAAsC,CAAC;IACnD,iBAAiB,EAAE,CAAC,CAAC,MAAM;SACxB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,OAAO,CAAC;SAChB,QAAQ,CACP,oRAAoR,CACrR;IACH,aAAa,EAAE,CAAC,CAAC,MAAM;SACpB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,UAAU,CAAC;SACnB,QAAQ,CACP,qLAAqL,CACtL;IACH,aAAa,EAAE,CAAC,CAAC,MAAM;SACpB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,OAAO,CAAC;SAChB,QAAQ,CACP,mNAAmN,CACpN;IACH,YAAY,EAAE,CAAC,CAAC,MAAM;SACnB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,UAAU,CAAC;SACnB,QAAQ,CACP,0QAA0Q,CAC3Q;IACH,oBAAoB,EAAE,CAAC;SACpB,UAAU,EAAE;SACZ,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CACP,4OAA4O,CAC7O;CACJ,CAAC,CAAC;AAEH,IAAI,OAAuD,CAAC;AAE5D,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,cAAc,CAAC,kBAAkB,EAAE;QAC7C,OAAO,EAAE,mBAAmB;QAC5B,aAAa,EAAE,0BAA0B;QACzC,gBAAgB,EAAE,6BAA6B;QAC/C,iBAAiB,EAAE,8BAA8B;QACjD,aAAa,EAAE,2BAA2B;QAC1C,aAAa,EAAE,0BAA0B;QACzC,YAAY,EAAE,yBAAyB;QACvC,oBAAoB,EAAE,iCAAiC;KACxD,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/dist/index.js CHANGED
@@ -5,9 +5,11 @@
5
5
  */
6
6
  import { createApp, disabledTool } from '@cyanheads/mcp-ts-core';
7
7
  import { config } from '@cyanheads/mcp-ts-core/config';
8
+ import { getServerConfig } from './config/server-config.js';
8
9
  import { eurostatDatasetResource } from './mcp-server/resources/definitions/eurostat-dataset.resource.js';
9
10
  import { eurostatBrowseThemes } from './mcp-server/tools/definitions/eurostat-browse-themes.tool.js';
10
11
  import { eurostatDataframeDescribe } from './mcp-server/tools/definitions/eurostat-dataframe-describe.tool.js';
12
+ import { eurostatDataframeDrop } from './mcp-server/tools/definitions/eurostat-dataframe-drop.tool.js';
11
13
  import { eurostatDataframeQuery } from './mcp-server/tools/definitions/eurostat-dataframe-query.tool.js';
12
14
  import { eurostatDownloadDataset } from './mcp-server/tools/definitions/eurostat-download-dataset.tool.js';
13
15
  import { eurostatGetDatasetInfo } from './mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js';
@@ -20,17 +22,51 @@ import { initEurostatCatalogueService } from './services/eurostat-catalogue/euro
20
22
  import { initEurostatDataService } from './services/eurostat-data/eurostat-data-service.js';
21
23
  /**
22
24
  * The dataframe tools address tables on a canvas, so without one they have
23
- * nothing to talk to. `disabledTool` keeps them off `tools/list` — clients
24
- * cannot call them — while leaving them visible on the landing page and the
25
- * server card with the variable that turns them on, so an operator can see the
25
+ * nothing to talk to. `disabledTool` keeps a gated tool off `tools/list` —
26
+ * clients cannot call it — while the landing page still renders it with the
27
+ * reason it is off and the setting that turns it on, so an operator can see the
26
28
  * capability exists rather than wondering why the README documents a tool the
27
- * server does not advertise.
29
+ * server does not advertise. The drop tool carries a second gate: a drop cannot
30
+ * be undone, so it stays off until EUROSTAT_DATAFRAME_DROP_ENABLED opts in, and
31
+ * its hint names every setting still missing.
28
32
  */
29
33
  const canvasEnabled = config.canvas.providerType !== 'none';
30
34
  const CANVAS_OFF = {
31
35
  reason: 'This deployment runs without a dataframe canvas, so there are no tables to address.',
32
36
  hint: 'CANVAS_PROVIDER_TYPE=duckdb',
33
37
  };
38
+ const DROP_OFF_HINT = 'EUROSTAT_DATAFRAME_DROP_ENABLED=true';
39
+ /**
40
+ * Read before `createApp()` because the drop tool's registration depends on it.
41
+ * A value that fails to parse is not reported here: `setup()` reads the server
42
+ * config again inside `createApp()`, which prints the configuration banner and
43
+ * exits 1 — thrown at this point, the same error would escape as an uncaught
44
+ * stack trace.
45
+ */
46
+ function dataframeDropEnabled() {
47
+ try {
48
+ return getServerConfig().dataframeDropEnabled;
49
+ }
50
+ catch {
51
+ return false;
52
+ }
53
+ }
54
+ /** The drop tool, or its disabled card naming every setting it still needs. */
55
+ function dataframeDropTool() {
56
+ const dropEnabled = dataframeDropEnabled();
57
+ if (!canvasEnabled) {
58
+ return disabledTool(eurostatDataframeDrop, {
59
+ reason: CANVAS_OFF.reason,
60
+ hint: dropEnabled ? CANVAS_OFF.hint : `${CANVAS_OFF.hint}\n${DROP_OFF_HINT}`,
61
+ });
62
+ }
63
+ return dropEnabled
64
+ ? eurostatDataframeDrop
65
+ : disabledTool(eurostatDataframeDrop, {
66
+ reason: 'Table cleanup is disabled in this deployment, so a staged table leaves only when its canvas expires.',
67
+ hint: DROP_OFF_HINT,
68
+ });
69
+ }
34
70
  await createApp({
35
71
  name: 'eurostat-mcp-server',
36
72
  title: 'eurostat-mcp-server',
@@ -49,17 +85,21 @@ await createApp({
49
85
  eurostatDownloadDataset,
50
86
  canvasEnabled ? eurostatDataframeDescribe : disabledTool(eurostatDataframeDescribe, CANVAS_OFF),
51
87
  canvasEnabled ? eurostatDataframeQuery : disabledTool(eurostatDataframeQuery, CANVAS_OFF),
88
+ dataframeDropTool(),
52
89
  ],
53
90
  resources: [eurostatDatasetResource],
54
91
  prompts: [],
55
92
  instructions: `Eurostat MCP server — EU statistical data across the Eurostat catalogue.
56
93
  Workflow: eurostat_search_datasets or eurostat_browse_themes to find a dataset code → eurostat_get_dataset_info to see dimensions → eurostat_get_dimension_values to list valid filter values → eurostat_query_dataset to fetch observations.
57
94
  Apply dimension filters to keep queries small: an unfiltered query on a large dataset is slow and can return an async response error instead of data.
58
- The catalogue covers two hosts. Most datasets come from the Eurostat dissemination table of contents; the DS-* codes — detailed trade by CN8, HS, SITC, BEC and CPA, and PRODCOM — come from the Comext host, and every tool routes a DS-* code there by its prefix. Comext collections are large: filter every request (freq included, since the trade flows mix annual and monthly series), and expect eurostat_get_dimension_values to return only the first 2,000 values of a long list inline. A collection on neither host, such as the legacy DS-056120, is not disseminated.
95
+ The catalogue covers two hosts. Most datasets come from the Eurostat dissemination table of contents; the DS-* codes — detailed trade by CN8, HS, SITC, BEC and CPA, and PRODCOM — come from the Comext host, and every tool routes a DS-* code there by its prefix. Comext collections are large: filter every request (freq included, since the trade flows mix annual and monthly series), and expect eurostat_get_dimension_values to page a long list such as the 37,069 CN8 product codes — pass filter with words of the code or label to find one value, or follow nextCursor. A collection on neither host, such as the legacy DS-056120, is not disseminated.
59
96
  Two paths past eurostat_query_dataset's 5,000-observation inline cap. For a slice of a dataset, keep using eurostat_query_dataset: when the match is larger than the cap and this deployment runs a dataframe canvas, the whole match is also staged as a SQL table named in the response. For a whole dataset, use eurostat_download_dataset, which reads the SDMX bulk endpoint instead — about half the bytes — and stages every observation the same way, bounded by a byte budget it reports back. Read either staged table with eurostat_dataframe_query (eurostat_dataframe_describe lists the table and column names); the two stage different column sets, since the bulk endpoint carries dimension codes with no labels. To label a download's codes, pass its canvasId to eurostat_get_dimension_values as canvas_id: the dimension's values are staged beside it as a code/label table to join on.
97
+ Staged tables expire with their canvas. eurostat_dataframe_drop removes one sooner, leaving the canvas and its other tables in place; it is opt-in, listed only where the deployment also sets EUROSTAT_DATAFRAME_DROP_ENABLED=true.
60
98
  The dataframe tools are not listed when the canvas is off. There, narrowing the filters is what brings a capped match into reach, and eurostat_download_dataset retains only its inline preview.`,
61
99
  landing: { requireAuth: false },
62
100
  setup(core) {
101
+ // Parsed here so a bad value fails startup with the configuration banner, not every call.
102
+ getServerConfig();
63
103
  initEurostatCatalogueService(core.config, core.storage);
64
104
  initEurostatDataService(core.config, core.storage);
65
105
  initEurostatBulkService(core.config, core.storage);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,EAAE,oBAAoB,EAAE,MAAM,+DAA+D,CAAC;AACrG,OAAO,EAAE,yBAAyB,EAAE,MAAM,oEAAoE,CAAC;AAC/G,OAAO,EAAE,sBAAsB,EAAE,MAAM,iEAAiE,CAAC;AACzG,OAAO,EAAE,uBAAuB,EAAE,MAAM,kEAAkE,CAAC;AAC3G,OAAO,EAAE,sBAAsB,EAAE,MAAM,kEAAkE,CAAC;AAC1G,OAAO,EAAE,0BAA0B,EAAE,MAAM,sEAAsE,CAAC;AAClH,OAAO,EAAE,oBAAoB,EAAE,MAAM,+DAA+D,CAAC;AACrG,OAAO,EAAE,sBAAsB,EAAE,MAAM,iEAAiE,CAAC;AACzG,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC5F,OAAO,EAAE,4BAA4B,EAAE,MAAM,6DAA6D,CAAC;AAC3G,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAE5F;;;;;;;GAOG;AACH,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,KAAK,MAAM,CAAC;AAC5D,MAAM,UAAU,GAAG;IACjB,MAAM,EAAE,qFAAqF;IAC7F,IAAI,EAAE,6BAA6B;CAC3B,CAAC;AAEX,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,qBAAqB;IAC3B,KAAK,EAAE,qBAAqB;IAC5B;;;;OAIG;IACH,WAAW,EAAE,WAAW;IACxB,KAAK,EAAE;QACL,sBAAsB;QACtB,oBAAoB;QACpB,sBAAsB;QACtB,0BAA0B;QAC1B,oBAAoB;QACpB,uBAAuB;QACvB,aAAa,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,YAAY,CAAC,yBAAyB,EAAE,UAAU,CAAC;QAC/F,aAAa,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,YAAY,CAAC,sBAAsB,EAAE,UAAU,CAAC;KAC1F;IACD,SAAS,EAAE,CAAC,uBAAuB,CAAC;IACpC,OAAO,EAAE,EAAE;IACX,YAAY,EAAE;;;;;iMAKiL;IAC/L,OAAO,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE;IAC/B,KAAK,CAAC,IAAI;QACR,4BAA4B,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACxD,uBAAuB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,uBAAuB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,EAAE,oBAAoB,EAAE,MAAM,+DAA+D,CAAC;AACrG,OAAO,EAAE,yBAAyB,EAAE,MAAM,oEAAoE,CAAC;AAC/G,OAAO,EAAE,qBAAqB,EAAE,MAAM,gEAAgE,CAAC;AACvG,OAAO,EAAE,sBAAsB,EAAE,MAAM,iEAAiE,CAAC;AACzG,OAAO,EAAE,uBAAuB,EAAE,MAAM,kEAAkE,CAAC;AAC3G,OAAO,EAAE,sBAAsB,EAAE,MAAM,kEAAkE,CAAC;AAC1G,OAAO,EAAE,0BAA0B,EAAE,MAAM,sEAAsE,CAAC;AAClH,OAAO,EAAE,oBAAoB,EAAE,MAAM,+DAA+D,CAAC;AACrG,OAAO,EAAE,sBAAsB,EAAE,MAAM,iEAAiE,CAAC;AACzG,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAC5F,OAAO,EAAE,4BAA4B,EAAE,MAAM,6DAA6D,CAAC;AAC3G,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAE5F;;;;;;;;;GASG;AACH,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,KAAK,MAAM,CAAC;AAC5D,MAAM,UAAU,GAAG;IACjB,MAAM,EAAE,qFAAqF;IAC7F,IAAI,EAAE,6BAA6B;CAC3B,CAAC;AACX,MAAM,aAAa,GAAG,sCAAsC,CAAC;AAE7D;;;;;;GAMG;AACH,SAAS,oBAAoB;IAC3B,IAAI,CAAC;QACH,OAAO,eAAe,EAAE,CAAC,oBAAoB,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,SAAS,iBAAiB;IACxB,MAAM,WAAW,GAAG,oBAAoB,EAAE,CAAC;IAC3C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,YAAY,CAAC,qBAAqB,EAAE;YACzC,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,KAAK,aAAa,EAAE;SAC7E,CAAC,CAAC;IACL,CAAC;IACD,OAAO,WAAW;QAChB,CAAC,CAAC,qBAAqB;QACvB,CAAC,CAAC,YAAY,CAAC,qBAAqB,EAAE;YAClC,MAAM,EACJ,sGAAsG;YACxG,IAAI,EAAE,aAAa;SACpB,CAAC,CAAC;AACT,CAAC;AAED,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,qBAAqB;IAC3B,KAAK,EAAE,qBAAqB;IAC5B;;;;OAIG;IACH,WAAW,EAAE,WAAW;IACxB,KAAK,EAAE;QACL,sBAAsB;QACtB,oBAAoB;QACpB,sBAAsB;QACtB,0BAA0B;QAC1B,oBAAoB;QACpB,uBAAuB;QACvB,aAAa,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,YAAY,CAAC,yBAAyB,EAAE,UAAU,CAAC;QAC/F,aAAa,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,YAAY,CAAC,sBAAsB,EAAE,UAAU,CAAC;QACzF,iBAAiB,EAAE;KACpB;IACD,SAAS,EAAE,CAAC,uBAAuB,CAAC;IACpC,OAAO,EAAE,EAAE;IACX,YAAY,EAAE;;;;;;iMAMiL;IAC/L,OAAO,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE;IAC/B,KAAK,CAAC,IAAI;QACR,0FAA0F;QAC1F,eAAe,EAAE,CAAC;QAClB,4BAA4B,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACxD,uBAAuB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,uBAAuB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;CACF,CAAC,CAAC"}
@@ -26,15 +26,23 @@ export declare const eurostatBrowseThemes: import("@cyanheads/mcp-ts-core").Tool
26
26
  }, z.core.$strip>, readonly [{
27
27
  readonly reason: "not_found";
28
28
  readonly code: JsonRpcErrorCode.NotFound;
29
- readonly when: "The provided theme_code does not exist in the TOC.";
30
- readonly recovery: "Call eurostat_browse_themes without theme_code to see valid root themes, then navigate from there.";
29
+ readonly when: "The provided theme_code does not exist in the TOC — or is a Comext folder (ext_go_detail, prom, comext) or DS-* code while the Comext dataflow list cannot be loaded.";
30
+ readonly recovery: "Call eurostat_browse_themes without theme_code to see valid root themes, then navigate from there. A Comext folder missing because its list could not be loaded returns once the merge is retried, about once a minute; eurostat_get_dataset_info reads a DS-* code directly.";
31
31
  }, {
32
32
  readonly reason: "not_a_folder";
33
33
  readonly code: JsonRpcErrorCode.ValidationError;
34
34
  readonly when: "The provided theme_code identifies a dataset or table entry instead of a folder.";
35
35
  readonly recovery: "Pass the code to eurostat_get_dataset_info to inspect it, then eurostat_query_dataset to retrieve data.";
36
+ }, {
37
+ readonly reason: "upstream_fault";
38
+ readonly code: JsonRpcErrorCode.ServiceUnavailable;
39
+ readonly when: "The server had no catalogue loaded yet, and Eurostat's table of contents answered HTTP 5xx or could not be reached on every retry, which the error marks retryable. Once a catalogue is loaded, a failed refresh serves that copy instead.";
40
+ readonly recovery: "Retry in a few minutes: the catalogue load failed on Eurostat's side and runs again on the next call.";
36
41
  }], {
37
42
  readonly itemCount: z.ZodNumber;
38
43
  readonly themeCode: z.ZodOptional<z.ZodString>;
44
+ readonly comextListMissing: z.ZodOptional<z.ZodBoolean>;
45
+ readonly catalogueLoadedAt: z.ZodOptional<z.ZodString>;
46
+ readonly notice: z.ZodOptional<z.ZodString>;
39
47
  }>;
40
48
  //# sourceMappingURL=eurostat-browse-themes.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"eurostat-browse-themes.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-browse-themes.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAiB,MAAM,+BAA+B,CAAC;AAGhF,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmK/B,CAAC"}
1
+ {"version":3,"file":"eurostat-browse-themes.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-browse-themes.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAiB,MAAM,+BAA+B,CAAC;AAIhF,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiO/B,CAAC"}