@cyanheads/eurostat-mcp-server 0.6.5 → 0.8.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.
- package/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/README.md +85 -85
- package/changelog/0.7.x/0.7.0.md +33 -0
- package/changelog/0.8.x/0.8.0.md +30 -0
- package/dist/config/server-config.d.ts +2 -0
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +13 -0
- package/dist/config/server-config.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.js +4 -2
- package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.d.ts +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.js +4 -4
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.d.ts +2 -2
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.js +4 -4
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.d.ts +16 -23
- package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js +156 -65
- package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.d.ts +3 -4
- package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js +8 -9
- package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.d.ts +21 -7
- package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js +115 -19
- package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts +10 -3
- package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js +156 -24
- package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.d.ts +2 -2
- package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.js +19 -6
- package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.js.map +1 -1
- package/dist/mcp-server/tools/narrowing-advice.d.ts +22 -0
- package/dist/mcp-server/tools/narrowing-advice.d.ts.map +1 -0
- package/dist/mcp-server/tools/narrowing-advice.js +44 -0
- package/dist/mcp-server/tools/narrowing-advice.js.map +1 -0
- package/dist/services/eurostat-bulk/eurostat-bulk-service.d.ts +12 -1
- package/dist/services/eurostat-bulk/eurostat-bulk-service.d.ts.map +1 -1
- package/dist/services/eurostat-bulk/eurostat-bulk-service.js +66 -12
- package/dist/services/eurostat-bulk/eurostat-bulk-service.js.map +1 -1
- package/dist/services/eurostat-bulk/types.d.ts +5 -0
- package/dist/services/eurostat-bulk/types.d.ts.map +1 -1
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts +47 -1
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts.map +1 -1
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js +188 -13
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js.map +1 -1
- package/dist/services/eurostat-codelists.d.ts +20 -0
- package/dist/services/eurostat-codelists.d.ts.map +1 -1
- package/dist/services/eurostat-codelists.js +25 -0
- package/dist/services/eurostat-codelists.js.map +1 -1
- package/dist/services/eurostat-data/eurostat-data-service.d.ts +78 -9
- package/dist/services/eurostat-data/eurostat-data-service.d.ts.map +1 -1
- package/dist/services/eurostat-data/eurostat-data-service.js +306 -51
- package/dist/services/eurostat-data/eurostat-data-service.js.map +1 -1
- package/dist/services/eurostat-data/sdmx-metadata.d.ts +26 -0
- package/dist/services/eurostat-data/sdmx-metadata.d.ts.map +1 -1
- package/dist/services/eurostat-data/sdmx-metadata.js +38 -1
- package/dist/services/eurostat-data/sdmx-metadata.js.map +1 -1
- package/dist/services/eurostat-data/types.d.ts +38 -2
- package/dist/services/eurostat-data/types.d.ts.map +1 -1
- package/dist/services/eurostat-data/types.js.map +1 -1
- package/dist/services/eurostat-hosts.d.ts +17 -0
- package/dist/services/eurostat-hosts.d.ts.map +1 -0
- package/dist/services/eurostat-hosts.js +23 -0
- package/dist/services/eurostat-hosts.js.map +1 -0
- package/dist/services/eurostat-periods.d.ts +68 -0
- package/dist/services/eurostat-periods.d.ts.map +1 -0
- package/dist/services/eurostat-periods.js +204 -0
- package/dist/services/eurostat-periods.js.map +1 -0
- package/dist/services/shared-load.d.ts +16 -0
- package/dist/services/shared-load.d.ts.map +1 -0
- package/dist/services/shared-load.js +27 -0
- package/dist/services/shared-load.js.map +1 -0
- package/package.json +2 -2
- package/server.json +31 -3
package/AGENTS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/eurostat-mcp-server
|
|
4
|
-
**Version:** 0.
|
|
4
|
+
**Version:** 0.8.0
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.6`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/server` `^2.0.0`
|
package/CLAUDE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/eurostat-mcp-server
|
|
4
|
-
**Version:** 0.
|
|
4
|
+
**Version:** 0.8.0
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.6`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/server` `^2.0.0`
|
package/README.md
CHANGED
|
@@ -7,9 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/eurostat-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/eurostat-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
10
|
+
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/eurostat-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/eurostat-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
13
11
|
|
|
14
12
|
</div>
|
|
15
13
|
|
|
@@ -31,7 +29,9 @@
|
|
|
31
29
|
|
|
32
30
|
## Overview
|
|
33
31
|
|
|
34
|
-
EU statistics from the Eurostat catalogue
|
|
32
|
+
EU statistics from the Eurostat catalogue: economy, demography, trade, health, and NUTS regional data. Search and browse the catalogue by keyword or theme, inspect dataset dimensions, then query a slice or bulk-download a whole dataset. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
|
|
33
|
+
|
|
34
|
+
The catalogue spans two Eurostat hosts. Most datasets come from the dissemination API; the `DS-*` collections — detailed trade by CN8, HS, SITC, BEC and CPA (Comext), and PRODCOM industrial production — come from the Comext dissemination host. Every tool routes a `DS-*` code there by its prefix, in any case, so the same calls work on both.
|
|
35
35
|
|
|
36
36
|
### Tools
|
|
37
37
|
|
|
@@ -45,99 +45,91 @@ Two of the eight are listed only when the dataframe canvas is enabled (`CANVAS_P
|
|
|
45
45
|
| `eurostat_get_dimension_values` | List all valid codes for one dataset dimension, with 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
|
-
| `eurostat_dataframe_describe` | List the tables staged on a dataframe canvas, with row counts and column types
|
|
49
|
-
| `eurostat_dataframe_query` | Run a read-only SQL SELECT across staged tables
|
|
48
|
+
| `eurostat_dataframe_describe` | List the tables staged on a dataframe canvas, with row counts and column types |
|
|
49
|
+
| `eurostat_dataframe_query` | Run a read-only SQL SELECT across staged tables |
|
|
50
50
|
|
|
51
51
|
### Resources
|
|
52
52
|
|
|
53
53
|
| Resource | Description |
|
|
54
54
|
|:---|:---|
|
|
55
|
-
| `eurostat://dataset/{dataset_code}` | Dataset metadata (dimensions, time range, observation count, last-updated) by URI
|
|
55
|
+
| `eurostat://dataset/{dataset_code}` | Dataset metadata (dimensions, time range, observation count, last-updated) by URI |
|
|
56
|
+
|
|
57
|
+
The same metadata is available through `eurostat_get_dataset_info` for tool-only clients.
|
|
56
58
|
|
|
57
59
|
## Capability reference
|
|
58
60
|
|
|
59
61
|
### `eurostat_search_datasets` <sub>tool</sub>
|
|
60
62
|
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
- `nextStep` on each result names the next tool to call
|
|
66
|
-
- Catalogue TOC is cached in memory for 12 hours (`EUROSTAT_TOC_CACHE_TTL_MS`), refreshed on the next call past that age
|
|
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
|
|
67
67
|
|
|
68
68
|
---
|
|
69
69
|
|
|
70
70
|
### `eurostat_browse_themes` <sub>tool</sub>
|
|
71
71
|
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
- One branch per folder code — Eurostat files a few folder codes under several branches; a code resolves to the branch listed first in the catalogue (never fewer children than the ones it shadows), and `otherPlacements` names those so the ambiguity is visible
|
|
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
|
|
77
76
|
|
|
78
77
|
---
|
|
79
78
|
|
|
80
79
|
### `eurostat_get_dataset_info` <sub>tool</sub>
|
|
81
80
|
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
- For a dimension with more than 10 values, call `eurostat_get_dimension_values` for the full list
|
|
86
|
-
- `metadataUrl` links to the ESMS metadata page when Eurostat provides one
|
|
81
|
+
- 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
|
|
87
84
|
|
|
88
85
|
---
|
|
89
86
|
|
|
90
87
|
### `eurostat_get_dimension_values` <sub>tool</sub>
|
|
91
88
|
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
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`
|
|
95
94
|
|
|
96
95
|
---
|
|
97
96
|
|
|
98
97
|
### `eurostat_query_dataset` <sub>tool</sub>
|
|
99
98
|
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
- `canvas_id` reuses an existing canvas so a result can be joined against earlier ones; an oversized unfiltered query is caught by async-response detection and returned as an actionable, non-retryable error instead of timing out
|
|
105
|
-
- Fetches a slice — for a whole dataset, `eurostat_download_dataset` reads the SDMX bulk endpoint instead, at roughly half the bytes
|
|
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`
|
|
106
103
|
|
|
107
104
|
---
|
|
108
105
|
|
|
109
106
|
### `eurostat_download_dataset` <sub>tool</sub>
|
|
110
107
|
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
115
|
-
- Failure modes are typed: an async queue ticket (Eurostat's too-costly-to-serve-inline response) is a non-retryable error; XML SOAP faults map to `not_found` (100), `filter_arity` (140), and `invalid_dimension` (150 — also covers an out-of-coverage period range), each with a recovery hint naming the next tool
|
|
116
|
-
- With the dataframe canvas enabled, every observation is staged as a SQL table (`canvasId` / `tableName` / `stagedRowCount`), streamed row by row — call `eurostat_dataframe_describe` before `eurostat_dataframe_query`. Without a canvas, only `preview_limit` rows (default 50, max 500) survive the call; `rowCount` / `missingCount` / `periodRange` still describe the whole download
|
|
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`
|
|
117
112
|
|
|
118
113
|
---
|
|
119
114
|
|
|
120
115
|
### `eurostat_dataframe_describe` <sub>tool</sub>
|
|
121
116
|
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
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
|
|
125
120
|
|
|
126
121
|
---
|
|
127
122
|
|
|
128
123
|
### `eurostat_dataframe_query` <sub>tool</sub>
|
|
129
124
|
|
|
130
|
-
-
|
|
131
|
-
- `
|
|
132
|
-
- A confidential cell reads `obs_flag = NULL` with `conf_status = 'C'` on either table — JSON-stat folds the two into one string (`|C`) that `eurostat_query_dataset` splits before staging
|
|
133
|
-
- Results are bounded by `CANVAS_DEFAULT_ROW_LIMIT` (default 10,000); `truncated: true` means add a `LIMIT`, an aggregate, or a narrower `WHERE`. 64-bit integer results — `COUNT(*)` included — arrive as strings so values outside the JSON number range survive intact
|
|
134
|
-
- The DuckDB binding ships with the server — `CANVAS_PROVIDER_TYPE=duckdb` is the only switch — except the one-click `.mcpb` bundle, which strips native bindings to stay portable; use the npm, Docker, or from-source install for SQL analytics
|
|
125
|
+
- 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`
|
|
135
127
|
|
|
136
128
|
---
|
|
137
129
|
|
|
138
130
|
### `eurostat://dataset/{dataset_code}` <sub>resource</sub>
|
|
139
131
|
|
|
140
|
-
- Same payload as `eurostat_get_dataset_info`,
|
|
132
|
+
- Same payload as `eurostat_get_dataset_info`, returned as `application/json`
|
|
141
133
|
- `dataset_code` comes from `eurostat_search_datasets` or `eurostat_browse_themes`
|
|
142
134
|
|
|
143
135
|
## Features
|
|
@@ -146,18 +138,19 @@ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): s
|
|
|
146
138
|
|
|
147
139
|
Eurostat-specific:
|
|
148
140
|
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
-
|
|
152
|
-
-
|
|
153
|
-
-
|
|
141
|
+
- 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
|
|
145
|
+
- 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
|
|
146
|
+
- 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
|
|
154
147
|
|
|
155
148
|
Agent-friendly output:
|
|
156
149
|
|
|
157
|
-
-
|
|
158
|
-
- Next-step hints
|
|
159
|
-
-
|
|
160
|
-
-
|
|
150
|
+
- Typed error contracts: every declared failure carries a `reason` and a `recovery.hint` naming the next tool to call
|
|
151
|
+
- Next-step hints: `eurostat_search_datasets` and `eurostat_browse_themes` return a `nextStep` pointing at the follow-up call
|
|
152
|
+
- Unknown stays unknown: counts and period bounds Eurostat doesn't report (`obsCount`, `timeRange.start` / `end`, `lastUpdated`) are omitted rather than zeroed
|
|
153
|
+
- Effective-query echo: `appliedFilters` on `eurostat_query_dataset` and `appliedQuery` (with the SDMX `url`) on `eurostat_download_dataset`, plus a `notice` when the inline preview omits rows, naming the staged table when there is one; `eurostat_query_dataset`'s `notice` also names any filter value that matched nothing
|
|
161
154
|
|
|
162
155
|
## Getting started
|
|
163
156
|
|
|
@@ -237,7 +230,8 @@ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
|
|
|
237
230
|
|
|
238
231
|
### Prerequisites
|
|
239
232
|
|
|
240
|
-
- [Bun v1.4.0](https://bun.sh/) or higher
|
|
233
|
+
- [Bun v1.4.0](https://bun.sh/) or higher (or Node.js v24+).
|
|
234
|
+
- No API key: Eurostat's dissemination API and its Comext host are public.
|
|
241
235
|
|
|
242
236
|
### Installation
|
|
243
237
|
|
|
@@ -259,32 +253,34 @@ cd eurostat-mcp-server
|
|
|
259
253
|
bun install
|
|
260
254
|
```
|
|
261
255
|
|
|
262
|
-
|
|
256
|
+
4. **Configure environment (optional, every setting has a default):**
|
|
263
257
|
|
|
264
|
-
|
|
258
|
+
```sh
|
|
259
|
+
cp .env.example .env
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Configuration
|
|
265
263
|
|
|
266
264
|
| Variable | Description | Default |
|
|
267
265
|
|:---|:---|:---|
|
|
268
|
-
| `
|
|
269
|
-
| `
|
|
270
|
-
| `
|
|
271
|
-
| `
|
|
272
|
-
| `
|
|
273
|
-
| `
|
|
274
|
-
| `
|
|
275
|
-
| `
|
|
276
|
-
| `
|
|
277
|
-
| `
|
|
278
|
-
| `
|
|
279
|
-
| `
|
|
280
|
-
| `
|
|
281
|
-
| `
|
|
282
|
-
| `
|
|
283
|
-
| `
|
|
284
|
-
| `
|
|
285
|
-
| `
|
|
286
|
-
| `CANVAS_DEFAULT_ROW_LIMIT` | Max rows one `eurostat_dataframe_query` returns before reporting `truncated` | `10000` |
|
|
287
|
-
| `OTEL_ENABLED` | Enable OpenTelemetry | `false` |
|
|
266
|
+
| `EUROSTAT_BASE_URL` | Eurostat API base URL. | `https://ec.europa.eu/eurostat/api/dissemination` |
|
|
267
|
+
| `EUROSTAT_COMEXT_BASE_URL` | Comext dissemination host, which serves every `DS-*` dataset code (detailed trade and PRODCOM). | `https://ec.europa.eu/eurostat/api/comext/dissemination` |
|
|
268
|
+
| `EUROSTAT_REQUEST_TIMEOUT_MS` | HTTP request timeout, in ms. | `30000` |
|
|
269
|
+
| `EUROSTAT_METADATA_TIMEOUT_MS` | Timeout for one dataset's SDMX dataflow structure, in ms — 23 MB, uncompressed, for `DS-045409`. | `120000` (2 min) |
|
|
270
|
+
| `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
|
+
| `EUROSTAT_BULK_TIMEOUT_MS` | Timeout for one `eurostat_download_dataset` transfer, in ms. | `120000` (2 min) |
|
|
272
|
+
| `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` |
|
|
274
|
+
| `CANVAS_TTL_MS` | Sliding lifetime of a staged canvas, in ms. | `86400000` (24 h) |
|
|
275
|
+
| `CANVAS_DEFAULT_ROW_LIMIT` | Max rows one `eurostat_dataframe_query` returns before reporting `truncated`. | `10000` |
|
|
276
|
+
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
277
|
+
| `MCP_HTTP_PORT` | HTTP server port. | `3010` |
|
|
278
|
+
| `MCP_SESSION_MODE` | HTTP session mode: `stateless`, `stateful`, or `auto`. The server declares `stateless`; a set value overrides it. | `stateless` |
|
|
279
|
+
| `MCP_AUTH_MODE` | Authentication: `none`, `jwt`, or `oauth`. | `none` |
|
|
280
|
+
| `MCP_LOG_LEVEL` | Log level (`debug`, `info`, `warning`, `error`, etc.). The Docker image sets `info`. | `debug` |
|
|
281
|
+
| `LOGS_DIR` | Directory for log files (Node.js only). | `<project-root>/logs` |
|
|
282
|
+
| `STORAGE_PROVIDER_TYPE` | Storage backend: `in-memory`, `filesystem`, `supabase`, `cloudflare-kv/r2/d1`. | `in-memory` |
|
|
283
|
+
| `OTEL_ENABLED` | Enable [OpenTelemetry](https://github.com/cyanheads/mcp-ts-core/tree/main/docs/telemetry). | `false` |
|
|
288
284
|
|
|
289
285
|
See [`.env.example`](./.env.example) for the full list of optional overrides.
|
|
290
286
|
|
|
@@ -324,12 +320,16 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
|
|
|
324
320
|
|
|
325
321
|
| Directory | Purpose |
|
|
326
322
|
|:---|:---|
|
|
327
|
-
| `src/index.ts` | `createApp()` entry point — registers tools and
|
|
328
|
-
| `src/mcp-server/tools` | Tool definitions (`*.tool.ts`). Six
|
|
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. |
|
|
329
325
|
| `src/mcp-server/resources` | Resource definitions. Dataset metadata resource. |
|
|
330
|
-
| `src/services/eurostat-catalogue` | Catalogue service — fetches and parses the Eurostat TOC
|
|
331
|
-
| `src/services/eurostat-data` |
|
|
332
|
-
| `src/services/
|
|
326
|
+
| `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
|
+
| `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. |
|
|
328
|
+
| `src/services/eurostat-bulk` | SDMX 2.1 TSV bulk service — streaming download, byte budget, SOAP fault mapping, canvas row source. |
|
|
329
|
+
| `src/services/eurostat-codelists.ts` | OBS_FLAG and CONF_STATUS codelists, the measure column names both stagers write, and the text-value decoder. |
|
|
330
|
+
| `src/services/eurostat-hosts.ts` | Which host serves a dataset code: `DS-*` to the Comext host, everything else to the main one. |
|
|
331
|
+
| `src/services/canvas-accessor.ts` | Accessor for the optional DataCanvas and the acquire helper canvas-touching tools share. |
|
|
332
|
+
| `src/services/shared-load.ts` | Lets concurrent callers await one shared download, so one caller's cancellation releases only that caller. |
|
|
333
333
|
| `src/config` | Server-specific environment variable parsing and validation with Zod. |
|
|
334
334
|
| `tests/` | Unit and integration tests, mirroring the `src/` structure. |
|
|
335
335
|
|
|
@@ -339,7 +339,7 @@ See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rule
|
|
|
339
339
|
|
|
340
340
|
- Handlers throw, framework catches — no `try/catch` in tool logic
|
|
341
341
|
- Use `ctx.log` for logging, `ctx.state` for storage
|
|
342
|
-
- Register new tools and resources in the `createApp()` arrays
|
|
342
|
+
- Register new tools and resources in the `createApp()` arrays in `src/index.ts`
|
|
343
343
|
- Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
|
|
344
344
|
|
|
345
345
|
## Contributing
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Both data tools now reject malformed, non-existent, and inverted period ranges as invalid_period before any request; eurostat_query_dataset explains an empty match and names filter values that matched nothing; eurostat_download_dataset reports totalCount instead of truncated."
|
|
3
|
+
breaking: true
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.7.0 — 2026-09-25
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`invalid_period` on `eurostat_query_dataset` and `eurostat_download_dataset`** ([#47](https://github.com/cyanheads/eurostat-mcp-server/issues/47), [#53](https://github.com/cyanheads/eurostat-mcp-server/issues/53)). `since_period`/`until_period` are checked in the handler before any request: the literal must be an accepted form, every month, quarter, semester, trimester, week, and day it names must exist, and `since_period` must not start after `until_period` ends. Cross-frequency pairs such as `2020-06` to `2020` stay valid.
|
|
12
|
+
- **`unmatchedValues` on `eurostat_query_dataset`** ([#52](https://github.com/cyanheads/eurostat-mcp-server/issues/52)) — filter values that matched nothing, keyed by dimension and spelled as sent. `notice` and the text output name them too; omitted when every value matched.
|
|
13
|
+
- **`no_results` diagnosis on `eurostat_query_dataset`** ([#48](https://github.com/cyanheads/eurostat-mcp-server/issues/48)) — read from the empty reply with no extra request: `data.unmatchedValues`, and `data.matchedPeriods` (the newest 24 selected periods, none carrying a value) with `data.matchedPeriodCount`. The message and hint name the cause: an unmatched value, a range outside the dataset's coverage (with its oldest and latest period), `last_n_periods` counting back past the slice's latest period, or a combination that carries no data.
|
|
14
|
+
|
|
15
|
+
## Changed
|
|
16
|
+
|
|
17
|
+
- **Breaking: `eurostat_download_dataset` enrichment drops `truncated`, `shown`, and `cap`, and adds `totalCount`** ([#49](https://github.com/cyanheads/eurostat-mcp-server/issues/49)), equal to `rowCount`. A preview shorter than the download is disclosed as a `notice` sentence; `budgetExceeded` remains the only signal that the download is incomplete.
|
|
18
|
+
- **Breaking: period literals that name a component that does not exist fail as `invalid_period`** ([#47](https://github.com/cyanheads/eurostat-mcp-server/issues/47), [#53](https://github.com/cyanheads/eurostat-mcp-server/issues/53)) instead of reaching Eurostat, which rolled some into a neighbouring period (`2020-13`, `2020-Q5`, `2021-W53`, `2021-02-29`). An inverted range (`since_period` `2024-01` with `until_period` `2020-01`), which Eurostat answered with data outside it, fails the same way.
|
|
19
|
+
- **Breaking: period faults move to `invalid_period`** ([#47](https://github.com/cyanheads/eurostat-mcp-server/issues/47)) from `conflicting_params` on `eurostat_query_dataset` and from `filter_arity` on `eurostat_download_dataset`. Bulk fault 140 is split on its fault string: `TIME_PERIOD_FILTER_SPEC_INVALID` maps to `invalid_period`, `INVALID_QUERY_NB_FILTERS` stays `filter_arity`.
|
|
20
|
+
- **Breaking: an upper-case filter key with `geo_level` fails as `conflicting_params`** ([#54](https://github.com/cyanheads/eurostat-mcp-server/issues/54)); `GEO` previously bypassed the check.
|
|
21
|
+
- **Filter keys match dimension codes in any case** on both data tools ([#54](https://github.com/cyanheads/eurostat-mcp-server/issues/54)). `eurostat_download_dataset` places `GEO` at `geo` instead of rejecting it, and keys that differ only in case pool their values.
|
|
22
|
+
- **Period literals are sent in canonical form** and echoed that way in `appliedFilters`/`appliedQuery`: extra leading zeros after the letter are dropped (`2020-Q01` → `2020-Q1`), a day of the year is sent as three digits (`2026-D1` → `2026-D001`), and `YYYY-A1` is sent as `YYYY`.
|
|
23
|
+
- **`eurostat_dataframe_describe` and `eurostat_dataframe_query` recovery hints** name both staging tools for an unknown or expired canvas or table.
|
|
24
|
+
- **Tool descriptions and docs**: `last_n_periods` states it counts back from the dataset's latest period, not the slice's; `eurostat_get_dimension_values` states how each data tool reports an invalid code — named in `unmatchedValues` or the `no_results` error by `eurostat_query_dataset`, a fault on `eurostat_download_dataset`; the README capability reference, Features list, and configuration table are rewritten to match current behavior.
|
|
25
|
+
|
|
26
|
+
## Fixed
|
|
27
|
+
|
|
28
|
+
- **`eurostat_download_dataset`'s no-canvas notice** ([#49](https://github.com/cyanheads/eurostat-mcp-server/issues/49)) no longer recommends a narrower query when every row came back inline, and names the `preview_limit` that returns them all when the download holds 500 rows or fewer.
|
|
29
|
+
- **`eurostat_download_dataset`'s `no_results` hint** ([#47](https://github.com/cyanheads/eurostat-mcp-server/issues/47)) also names a `since_period`/`until_period` range that misses the filtered series — one inside the dataset's coverage, which downloads as an empty table (a range wholly outside it fails as `invalid_dimension`).
|
|
30
|
+
|
|
31
|
+
## Dependencies
|
|
32
|
+
|
|
33
|
+
- `@socketsecurity/bun-security-scanner` (dev) `^1.1.2` → `^1.1.3`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Every tool now reaches Eurostat's Comext host for the DS-* detailed-trade and PRODCOM collections, and eurostat_get_dimension_values caps inline values at 2,000 while staging the full list as a code/label table on a caller's canvas."
|
|
3
|
+
breaking: true
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.8.0 — 2026-09-25
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **Comext `DS-*` collections on every tool** ([#46](https://github.com/cyanheads/eurostat-mcp-server/issues/46)). A dataset code starting `DS-`, in any case, is routed to the Comext dissemination host: detailed trade by CN8, HS, SITC, BEC and CPA, and PRODCOM. Comext entries report `lastUpdated` but no period coverage or observation count.
|
|
12
|
+
- **Comext dataflows in the catalogue** ([#46](https://github.com/cyanheads/eurostat-mcp-server/issues/46)). `eurostat_search_datasets` and `eurostat_browse_themes` merge the Comext dataflow list into the table of contents, under `ext_go_detail` (in `ext_go`) and `prom` (in `icts`); a failed Comext fetch leaves the catalogue answering from the table of contents alone.
|
|
13
|
+
- **`canvas_id` on `eurostat_get_dimension_values`** ([#50](https://github.com/cyanheads/eurostat-mcp-server/issues/50)) stages the dimension's whole value list as a `code` / `label` table on that canvas, returned as `canvasId` / `tableName` / `stagedRowCount`, to label a download's code columns through a join. The tool never starts a canvas; an unknown or expired `canvas_id` fails as `canvas_not_found`.
|
|
14
|
+
- **`valueText` on `eurostat_query_dataset` observations, and `obs_value_text` on `DS-*` staged tables** from either data tool, holding a value Eurostat published as text (PRODCOM's unit `KG`) beside a null `value` / `obs_value`. PRODCOM's `:C` decodes to `confStatus` / `conf_status` `C`.
|
|
15
|
+
- **`EUROSTAT_COMEXT_BASE_URL`** (default `https://ec.europa.eu/eurostat/api/comext/dissemination`) and **`EUROSTAT_METADATA_TIMEOUT_MS`** (default `120000`), the timeout for one dataset's SDMX dataflow structure: 23 MB for `DS-045409`.
|
|
16
|
+
|
|
17
|
+
## Changed
|
|
18
|
+
|
|
19
|
+
- **Breaking: `eurostat_get_dimension_values` returns at most 2,000 values inline** ([#50](https://github.com/cyanheads/eurostat-mcp-server/issues/50)), with `truncated`, `shown`, `cap`, and a `notice` saying where the rest are; `totalCount` still counts every value. Seven main-host lists are cut: `time` on `ert_bil_eur_d`, `ert_h_eur_d` and `irt_euryld_d`, and `airp_pr` on `avia_par_uk`, `avia_par_de`, `avia_par_it` and `avia_par_es`. Pass `canvas_id` to stage the full list.
|
|
20
|
+
- **Breaking: `eurostat_download_dataset` maps SDMX fault 413 to non-retryable `extraction_too_big`**, not `upstream_fault`, on either host. The hint names the dataset's dimensions the request left unfiltered.
|
|
21
|
+
- **Breaking: `eurostat_get_dataset_info` and `eurostat_get_dimension_values` no longer declare `async_response`; both declare `upstream_fault`** ([#58](https://github.com/cyanheads/eurostat-mcp-server/issues/58)) for a structure or content constraint the server cannot read.
|
|
22
|
+
- **`eurostat_query_dataset`'s `async_response` hint names the dataset's own unfiltered dimensions**, and the message carries Eurostat's `EXTRACTION_TOO_BIG` label for an HTTP-413 refusal.
|
|
23
|
+
- **Dataset metadata is cached per dataset for an hour**, within a 64 MiB budget, so repeat `eurostat_get_dataset_info` and `eurostat_get_dimension_values` calls skip the structure download; a failed read is not cached.
|
|
24
|
+
- **Tool descriptions and server instructions** state where the Comext and main-host catalogues end ([#45](https://github.com/cyanheads/eurostat-mcp-server/issues/45)). A query naming a `DS-*` code on neither list, such as the legacy `DS-056120`, fails `no_match` saying the collection is not disseminated.
|
|
25
|
+
|
|
26
|
+
## Fixed
|
|
27
|
+
|
|
28
|
+
- **A filtered `eurostat_download_dataset` no longer fails on datasets whose latest period exceeds Eurostat's 5,000,000-row extraction limit** ([#57](https://github.com/cyanheads/eurostat-mcp-server/issues/57)) (`earn_ses_annual`). Key order is read from the dataset's structure definition instead of a one-period observation request.
|
|
29
|
+
- **An empty `eurostat_download_dataset` fails `no_results` without creating or touching a canvas** ([#56](https://github.com/cyanheads/eurostat-mcp-server/issues/56)); it previously staged a 0-row table on a fresh or caller-supplied canvas.
|
|
30
|
+
- **Cancelling one catalogue or metadata call no longer aborts the shared load** other concurrent callers are waiting on.
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
declare const ServerConfigSchema: z.ZodObject<{
|
|
7
7
|
baseUrl: z.ZodDefault<z.ZodString>;
|
|
8
|
+
comextBaseUrl: z.ZodDefault<z.ZodString>;
|
|
8
9
|
requestTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
10
|
+
metadataTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
9
11
|
tocCacheTtlMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
10
12
|
bulkTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
11
13
|
bulkMaxBytes: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -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
|
|
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"}
|
|
@@ -10,12 +10,23 @@ const ServerConfigSchema = z.object({
|
|
|
10
10
|
.url()
|
|
11
11
|
.default('https://ec.europa.eu/eurostat/api/dissemination')
|
|
12
12
|
.describe('Eurostat API base URL'),
|
|
13
|
+
comextBaseUrl: z
|
|
14
|
+
.string()
|
|
15
|
+
.url()
|
|
16
|
+
.default('https://ec.europa.eu/eurostat/api/comext/dissemination')
|
|
17
|
+
.describe('Base URL of the Comext dissemination host, which serves the DS-* collections (detailed trade and PRODCOM) the main host does not. Every dataset code starting "DS-", in any case, is routed here.'),
|
|
13
18
|
requestTimeoutMs: z.coerce
|
|
14
19
|
.number()
|
|
15
20
|
.int()
|
|
16
21
|
.positive()
|
|
17
22
|
.default(30_000)
|
|
18
23
|
.describe('HTTP request timeout in milliseconds'),
|
|
24
|
+
metadataTimeoutMs: z.coerce
|
|
25
|
+
.number()
|
|
26
|
+
.int()
|
|
27
|
+
.positive()
|
|
28
|
+
.default(120_000)
|
|
29
|
+
.describe("HTTP timeout for one dataset's SDMX dataflow structure, in milliseconds. Held separate from EUROSTAT_REQUEST_TIMEOUT_MS because the structure carries a label for every code the dataset uses: 23 MB, uncompressed, for the CN8 trade collection DS-045409. Defaults to 2 minutes."),
|
|
19
30
|
tocCacheTtlMs: z.coerce
|
|
20
31
|
.number()
|
|
21
32
|
.int()
|
|
@@ -39,7 +50,9 @@ let _config;
|
|
|
39
50
|
export function getServerConfig() {
|
|
40
51
|
_config ??= parseEnvConfig(ServerConfigSchema, {
|
|
41
52
|
baseUrl: 'EUROSTAT_BASE_URL',
|
|
53
|
+
comextBaseUrl: 'EUROSTAT_COMEXT_BASE_URL',
|
|
42
54
|
requestTimeoutMs: 'EUROSTAT_REQUEST_TIMEOUT_MS',
|
|
55
|
+
metadataTimeoutMs: 'EUROSTAT_METADATA_TIMEOUT_MS',
|
|
43
56
|
tocCacheTtlMs: 'EUROSTAT_TOC_CACHE_TTL_MS',
|
|
44
57
|
bulkTimeoutMs: 'EUROSTAT_BULK_TIMEOUT_MS',
|
|
45
58
|
bulkMaxBytes: 'EUROSTAT_BULK_MAX_BYTES',
|
|
@@ -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,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,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,gBAAgB,EAAE,6BAA6B;QAC/C,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;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"}
|
package/dist/index.js
CHANGED
|
@@ -55,7 +55,8 @@ await createApp({
|
|
|
55
55
|
instructions: `Eurostat MCP server — EU statistical data across the Eurostat catalogue.
|
|
56
56
|
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
57
|
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
|
-
|
|
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.
|
|
59
|
+
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.
|
|
59
60
|
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.`,
|
|
60
61
|
landing: { requireAuth: false },
|
|
61
62
|
setup(core) {
|
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
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurostat-dataset.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/eurostat-dataset.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGrD,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"eurostat-dataset.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/eurostat-dataset.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGrD,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;6BA2ElC,CAAC"}
|
|
@@ -6,10 +6,12 @@ import { resource, z } from '@cyanheads/mcp-ts-core';
|
|
|
6
6
|
import { getEurostatDataService } from '../../../services/eurostat-data/eurostat-data-service.js';
|
|
7
7
|
export const eurostatDatasetResource = resource('eurostat://dataset/{dataset_code}', {
|
|
8
8
|
name: 'eurostat-dataset-info',
|
|
9
|
-
description: 'Dataset metadata for a Eurostat dataset — dimensions, time range, observation count, and last-updated date. Equivalent to eurostat_get_dataset_info but accessible as a resource URI for cache-injectable context.',
|
|
9
|
+
description: 'Dataset metadata for a Eurostat dataset — dimensions, time range, observation count, and last-updated date. Equivalent to eurostat_get_dataset_info but accessible as a resource URI for cache-injectable context. A DS-* code (detailed trade and PRODCOM) is read from the Comext dissemination host, which reports no time range or observation count.',
|
|
10
10
|
mimeType: 'application/json',
|
|
11
11
|
params: z.object({
|
|
12
|
-
dataset_code: z
|
|
12
|
+
dataset_code: z
|
|
13
|
+
.string()
|
|
14
|
+
.describe('Dataset code (e.g., "nama_10_gdp", or "DS-045409" for a Comext collection).'),
|
|
13
15
|
}),
|
|
14
16
|
output: z.object({
|
|
15
17
|
code: z.string().describe('Dataset code.'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurostat-dataset.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/eurostat-dataset.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mDAAmD,CAAC;AAE3F,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC,mCAAmC,EAAE;IACnF,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"eurostat-dataset.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/eurostat-dataset.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mDAAmD,CAAC;AAE3F,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC,mCAAmC,EAAE;IACnF,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,2VAA2V;IAC7V,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,CAAC,6EAA6E,CAAC;KAC3F,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;QAC1C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QAC3D,UAAU,EAAE,CAAC;aACV,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAC5C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAC7C,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,gLAAgL,CACjL;YACH,YAAY,EAAE,CAAC;iBACZ,KAAK,CACJ,CAAC;iBACE,MAAM,CAAC;gBACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;gBACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;aAC3C,CAAC;iBACD,QAAQ,CAAC,wCAAwC,CAAC,CACtD;iBACA,QAAQ,EAAE;iBACV,QAAQ,CACP,wIAAwI,CACzI;SACJ,CAAC;aACD,QAAQ,CAAC,4CAA4C,CAAC,CAC1D;aACA,QAAQ,CAAC,qBAAqB,CAAC;QAClC,SAAS,EAAE,CAAC;aACT,MAAM,CAAC;YACN,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,sEAAsE,CAAC;YACnF,GAAG,EAAE,CAAC;iBACH,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,yEAAyE,CAAC;SACvF,CAAC;aACD,QAAQ,CACP,gIAAgI,CACjI;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,iHAAiH,CAClH;QACH,WAAW,EAAE,CAAC;aACX,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,mFAAmF,CACpF;QACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;KAC3F,CAAC;IAEF,OAAO,CAAC,MAAM,EAAE,GAAG;QACjB,MAAM,GAAG,GAAG,sBAAsB,EAAE,CAAC;QACrC,OAAO,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -7,7 +7,7 @@ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
|
7
7
|
import { getEurostatCatalogueService } from '../../../services/eurostat-catalogue/eurostat-catalogue-service.js';
|
|
8
8
|
export const eurostatBrowseThemes = tool('eurostat_browse_themes', {
|
|
9
9
|
title: 'Browse Eurostat Theme Hierarchy',
|
|
10
|
-
description: 'Navigate the Eurostat theme tree. Without theme_code returns the top-level theme folders (Economy, Population, Transport, etc.) — the practical starting points. With a theme_code returns its immediate children: subtheme folders and datasets in that branch. Use this for structured discovery when you know the domain but not the dataset code, or to drill down from a broad topic to a specific dataset. Pair with eurostat_search_datasets for keyword-based discovery.',
|
|
10
|
+
description: 'Navigate the Eurostat theme tree. Without theme_code returns the top-level theme folders (Economy, Population, Transport, etc.) — the practical starting points. With a theme_code returns its immediate children: subtheme folders and datasets in that branch. Use this for structured discovery when you know the domain but not the dataset code, or to drill down from a broad topic to a specific dataset. Pair with eurostat_search_datasets for keyword-based discovery. The tree is the dissemination table of contents plus the Comext host\'s DS-* collections: detailed trade under ext_go_detail (inside ext_go, "International trade in goods") and PRODCOM under prom (inside icts, "Industry, trade and services"). A collection on neither, such as the legacy PRODCOM DS-056120, is not disseminated and appears nowhere in the tree.',
|
|
11
11
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
12
12
|
input: z.object({
|
|
13
13
|
theme_code: z
|