@cyanheads/eurostat-mcp-server 0.8.0 → 0.9.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 +25 -19
- package/CLAUDE.md +25 -19
- package/Dockerfile +93 -46
- package/README.md +34 -35
- package/changelog/0.8.x/0.8.1.md +11 -0
- package/changelog/0.9.x/0.9.0.md +43 -0
- package/dist/config/server-config.d.ts +1 -0
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +5 -0
- package/dist/config/server-config.js.map +1 -1
- package/dist/index.js +44 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-drop.tool.d.ts +34 -0
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-drop.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-drop.tool.js +112 -0
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-drop.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js +2 -2
- package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js.map +1 -1
- package/dist/mcp-server/tools/narrowing-advice.d.ts +2 -1
- package/dist/mcp-server/tools/narrowing-advice.d.ts.map +1 -1
- package/dist/mcp-server/tools/narrowing-advice.js +4 -1
- package/dist/mcp-server/tools/narrowing-advice.js.map +1 -1
- package/dist/services/canvas-accessor.d.ts +10 -6
- package/dist/services/canvas-accessor.d.ts.map +1 -1
- package/dist/services/canvas-accessor.js +14 -10
- package/dist/services/canvas-accessor.js.map +1 -1
- package/package.json +10 -9
- 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 (
|
|
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
|
-
[](./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/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -35,7 +35,7 @@ The catalogue spans two Eurostat hosts. Most datasets come from the disseminatio
|
|
|
35
35
|
|
|
36
36
|
### Tools
|
|
37
37
|
|
|
38
|
-
|
|
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
|
|:---|:---|
|
|
@@ -47,6 +47,7 @@ Two of the eight are listed only when the dataframe canvas is enabled (`CANVAS_P
|
|
|
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
|
|
|
@@ -61,69 +62,66 @@ The same metadata is available through `eurostat_get_dataset_info` for tool-only
|
|
|
61
62
|
### `eurostat_search_datasets` <sub>tool</sub>
|
|
62
63
|
|
|
63
64
|
- `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
|
|
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
|
|
65
|
+
- Results carry `code`, `label`, `type` (`dataset` / `table`), period coverage, `obsCount`, `lastUpdated`, and `themePath`, with `totalMatches` across every page; fails as `no_match` or `invalid_cursor`
|
|
67
66
|
|
|
68
67
|
---
|
|
69
68
|
|
|
70
69
|
### `eurostat_browse_themes` <sub>tool</sub>
|
|
71
70
|
|
|
72
|
-
- Omit `theme_code` for the top-level theme folders; pass a folder code for its immediate children
|
|
73
|
-
-
|
|
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
|
|
71
|
+
- 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`)
|
|
72
|
+
- 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
|
|
76
73
|
|
|
77
74
|
---
|
|
78
75
|
|
|
79
76
|
### `eurostat_get_dataset_info` <sub>tool</sub>
|
|
80
77
|
|
|
81
78
|
- One `dataset_code`; returns every dimension with `valuesCount` and up to 10 `sampleValues`, plus `timeRange`, `obsCount`, `lastUpdated`, and the ESMS `metadataUrl`
|
|
82
|
-
-
|
|
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
|
|
79
|
+
- Fails as `not_found` for an unknown dataset, or `upstream_fault` when Eurostat returns a structure or content constraint the server cannot read
|
|
84
80
|
|
|
85
81
|
---
|
|
86
82
|
|
|
87
83
|
### `eurostat_get_dimension_values` <sub>tool</sub>
|
|
88
84
|
|
|
89
|
-
- `dataset_code` plus `dimension`;
|
|
90
|
-
-
|
|
91
|
-
-
|
|
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`
|
|
85
|
+
- `dataset_code` plus `dimension`; for `geo`, `geo_level` picks a NUTS level (`aggregate`, `country` by default, `nuts1`, `nuts2`, `nuts3`). At most 2,000 values come back inline, in Eurostat's order
|
|
86
|
+
- Returns code/label pairs in `values` with `totalCount`, and `truncated` / `shown` / `cap` past the inline cap; fails as `not_found`, `no_results`, `conflicting_params`, `upstream_fault`, or `canvas_not_found`
|
|
87
|
+
- `canvas_id` stages every value, past the inline cap too, 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
88
|
|
|
95
89
|
---
|
|
96
90
|
|
|
97
91
|
### `eurostat_query_dataset` <sub>tool</sub>
|
|
98
92
|
|
|
99
|
-
- `dataset_code` plus `filters` (`{dimension_code: [values]}
|
|
100
|
-
- Each observation carries code/label pairs per dimension, a nullable `value`,
|
|
101
|
-
-
|
|
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`
|
|
93
|
+
- `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`
|
|
94
|
+
- 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
|
|
95
|
+
- 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, or `canvas_not_found`
|
|
103
96
|
|
|
104
97
|
---
|
|
105
98
|
|
|
106
99
|
### `eurostat_download_dataset` <sub>tool</sub>
|
|
107
100
|
|
|
108
|
-
- `dataset_code` plus the same `filters` map and `since_period` / `until_period`
|
|
109
|
-
- Returns `rowCount` (echoed as `totalCount`), `missingCount`, `periodRange`, and `bytesRead` for the whole download;
|
|
110
|
-
-
|
|
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`
|
|
101
|
+
- `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)
|
|
102
|
+
- 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`, or `canvas_not_found`
|
|
103
|
+
- The `EUROSTAT_BULK_MAX_BYTES` budget (default 50 MiB) stops a transfer mid-stream and returns what arrived with `budgetExceeded: true`
|
|
112
104
|
|
|
113
105
|
---
|
|
114
106
|
|
|
115
107
|
### `eurostat_dataframe_describe` <sub>tool</sub>
|
|
116
108
|
|
|
117
|
-
- `canvas_id` from a staging response; lists each table's `name`, `rowCount`,
|
|
118
|
-
- `eurostat_query_dataset`
|
|
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
|
|
109
|
+
- `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`
|
|
110
|
+
- 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
111
|
|
|
121
112
|
---
|
|
122
113
|
|
|
123
114
|
### `eurostat_dataframe_query` <sub>tool</sub>
|
|
124
115
|
|
|
125
116
|
- 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`,
|
|
117
|
+
- 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`
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### `eurostat_dataframe_drop` <sub>tool</sub>
|
|
122
|
+
|
|
123
|
+
- `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
|
|
124
|
+
- 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
125
|
|
|
128
126
|
---
|
|
129
127
|
|
|
@@ -139,9 +137,8 @@ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): s
|
|
|
139
137
|
Eurostat-specific:
|
|
140
138
|
|
|
141
139
|
- 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.
|
|
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
|
|
140
|
+
- 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
|
|
141
|
+
- 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
142
|
- 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
143
|
- 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
144
|
|
|
@@ -270,15 +267,17 @@ cp .env.example .env
|
|
|
270
267
|
| `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
268
|
| `EUROSTAT_BULK_TIMEOUT_MS` | Timeout for one `eurostat_download_dataset` transfer, in ms. | `120000` (2 min) |
|
|
272
269
|
| `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
|
|
270
|
+
| `CANVAS_PROVIDER_TYPE` | `duckdb` enables the dataframe canvas: lists `eurostat_dataframe_describe` and `eurostat_dataframe_query` and turns on staging. | `none` |
|
|
274
271
|
| `CANVAS_TTL_MS` | Sliding lifetime of a staged canvas, in ms. | `86400000` (24 h) |
|
|
275
272
|
| `CANVAS_DEFAULT_ROW_LIMIT` | Max rows one `eurostat_dataframe_query` returns before reporting `truncated`. | `10000` |
|
|
273
|
+
| `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
274
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
277
275
|
| `MCP_HTTP_PORT` | HTTP server port. | `3010` |
|
|
278
276
|
| `MCP_SESSION_MODE` | HTTP session mode: `stateless`, `stateful`, or `auto`. The server declares `stateless`; a set value overrides it. | `stateless` |
|
|
279
277
|
| `MCP_AUTH_MODE` | Authentication: `none`, `jwt`, or `oauth`. | `none` |
|
|
280
278
|
| `MCP_LOG_LEVEL` | Log level (`debug`, `info`, `warning`, `error`, etc.). The Docker image sets `info`. | `debug` |
|
|
281
279
|
| `LOGS_DIR` | Directory for log files (Node.js only). | `<project-root>/logs` |
|
|
280
|
+
| `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
281
|
| `STORAGE_PROVIDER_TYPE` | Storage backend: `in-memory`, `filesystem`, `supabase`, `cloudflare-kv/r2/d1`. | `in-memory` |
|
|
283
282
|
| `OTEL_ENABLED` | Enable [OpenTelemetry](https://github.com/cyanheads/mcp-ts-core/tree/main/docs/telemetry). | `false` |
|
|
284
283
|
|
|
@@ -320,8 +319,8 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
|
|
|
320
319
|
|
|
321
320
|
| Directory | Purpose |
|
|
322
321
|
|:---|:---|
|
|
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
|
|
322
|
+
| `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. |
|
|
323
|
+
| `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
324
|
| `src/mcp-server/resources` | Resource definitions. Dataset metadata resource. |
|
|
326
325
|
| `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
326
|
| `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,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "The Docker images and packageManager pin move to Bun 1.4.2."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.8.1 — 2026-09-25
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **Bun runtime pinned to 1.4.2**: the Docker build and production stages use `oven/bun:1.4.2` and `oven/bun:1.4.2-slim`, and `packageManager` is `bun@1.4.2` (the `engines.bun` floor stays `>=1.4.0`).
|
|
@@ -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
|
|
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;
|
|
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
|
|
24
|
-
* cannot call
|
|
25
|
-
*
|
|
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,6 +85,7 @@ 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: [],
|
|
@@ -57,9 +94,12 @@ Workflow: eurostat_search_datasets or eurostat_browse_themes to find a dataset c
|
|
|
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
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 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
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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -68,7 +68,7 @@ export const eurostatDataframeDescribe = tool('eurostat_dataframe_describe', {
|
|
|
68
68
|
async handler(input, ctx) {
|
|
69
69
|
const canvas = getCanvas();
|
|
70
70
|
if (!canvas) {
|
|
71
|
-
throw ctx.fail('canvas_disabled'
|
|
71
|
+
throw ctx.fail('canvas_disabled');
|
|
72
72
|
}
|
|
73
73
|
const instance = await acquireCanvas(canvas, input.canvas_id, ctx);
|
|
74
74
|
const tables = await instance.describe();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurostat-dataframe-describe.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAEzE,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAAC,6BAA6B,EAAE;IAC3E,KAAK,EAAE,8BAA8B;IACrC,WAAW,EACT,g0CAAg0C;IACl0C,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;IAC/E,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,SAAS,EAAE,cAAc,CAAC,QAAQ,CAChC,oLAAoL,CACrL;KACF,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;QAC7E,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,QAAQ,CACP,mFAAmF,CACpF;QACH,MAAM,EAAE,CAAC;aACN,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;YAC5D,IAAI,EAAE,CAAC;iBACJ,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;iBACvB,QAAQ,CAAC,8CAA8C,CAAC;YAC3D,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;YACtD,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,uHAAuH,CACxH;YACH,OAAO,EAAE,CAAC;iBACP,KAAK,CACJ,CAAC;iBACE,MAAM,CAAC;gBACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;gBACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;gBACxE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;aAClE,CAAC;iBACD,QAAQ,CAAC,0BAA0B,CAAC,CACxC;iBACA,QAAQ,CAAC,+BAA+B,CAAC;SAC7C,CAAC;aACD,QAAQ,CAAC,yCAAyC,CAAC,CACvD;aACA,QAAQ,CACP,+GAA+G,CAChH;KACJ,CAAC;IACF,UAAU,EAAE;QACV,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,+EAA+E,CAAC;KAC7F;IAED,MAAM,EAAE;QACN;YACE,MAAM,EAAE,iBAAiB;YACzB,IAAI,EAAE,gBAAgB,CAAC,kBAAkB;YACzC,IAAI,EAAE,mFAAmF;YACzF,SAAS,EAAE,KAAK;YAChB,QAAQ,EACN,uGAAuG;SAC1G;QACD;YACE,MAAM,EAAE,kBAAkB;YAC1B,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,uDAAuD;YAC7D,QAAQ,EACN,2LAA2L;YAC7L,QAAQ,EAAE,SAAS;SACpB;KACF;IAED,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,CAAC,IAAI,CAAC,iBAAiB,
|
|
1
|
+
{"version":3,"file":"eurostat-dataframe-describe.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool for removing one staged table from a Eurostat DataCanvas.
|
|
3
|
+
* @module mcp-server/tools/definitions/eurostat-dataframe-drop.tool
|
|
4
|
+
*/
|
|
5
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
+
export declare const eurostatDataframeDrop: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
|
+
canvas_id: z.ZodString;
|
|
9
|
+
table_name: z.ZodString;
|
|
10
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
11
|
+
canvasId: z.ZodString;
|
|
12
|
+
tableName: z.ZodString;
|
|
13
|
+
dropped: z.ZodBoolean;
|
|
14
|
+
expiresAt: z.ZodString;
|
|
15
|
+
}, z.core.$strip>, readonly [{
|
|
16
|
+
readonly reason: "canvas_disabled";
|
|
17
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
18
|
+
readonly when: "This deployment runs without a dataframe canvas, so there are no staged tables to drop.";
|
|
19
|
+
readonly retryable: false;
|
|
20
|
+
readonly recovery: "Nothing is staged without a dataframe canvas, so there is nothing to drop; eurostat_query_dataset answers inline with narrower dimension filters.";
|
|
21
|
+
}, {
|
|
22
|
+
readonly reason: "canvas_not_found";
|
|
23
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
24
|
+
readonly when: "The canvas_id is unknown or its lifetime has elapsed.";
|
|
25
|
+
readonly recovery: "An expired canvas has already released every table it held, so nothing is left to drop; otherwise copy the canvasId exactly as eurostat_query_dataset, eurostat_download_dataset, or eurostat_get_dimension_values returned it.";
|
|
26
|
+
}, {
|
|
27
|
+
readonly reason: "identifier_reserved";
|
|
28
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
29
|
+
readonly when: "The table_name is a bare SQL keyword (e.g. \"select\"), which no staged table can carry.";
|
|
30
|
+
readonly recovery: "Call eurostat_dataframe_describe and copy a table name exactly as it is listed.";
|
|
31
|
+
}], {
|
|
32
|
+
readonly notice: z.ZodOptional<z.ZodString>;
|
|
33
|
+
}>;
|
|
34
|
+
//# sourceMappingURL=eurostat-dataframe-drop.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eurostat-dataframe-drop.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-dataframe-drop.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAY,MAAM,+BAA+B,CAAC;AAG3E,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;EAsIhC,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool for removing one staged table from a Eurostat DataCanvas.
|
|
3
|
+
* @module mcp-server/tools/definitions/eurostat-dataframe-drop.tool
|
|
4
|
+
*/
|
|
5
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { CANVAS_IDENTIFIER_REGEX, CanvasIdSchema } from '@cyanheads/mcp-ts-core/canvas';
|
|
7
|
+
import { JsonRpcErrorCode, McpError } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
import { acquireCanvas, getCanvas } from '../../../services/canvas-accessor.js';
|
|
9
|
+
export const eurostatDataframeDrop = tool('eurostat_dataframe_drop', {
|
|
10
|
+
title: 'Drop Eurostat Dataframe',
|
|
11
|
+
description: 'Remove one table from a Eurostat dataframe canvas, leaving the canvas and every other table on it in place — to free the memory a large eurostat_download_dataset table holds once its analysis is done, or to discard an intermediate result. Pass the table name exactly as eurostat_dataframe_describe lists it, case included. A drop cannot be undone: re-run the tool that staged the table to stage it again. A name with nothing staged under it — never staged, already dropped, or expired — returns dropped: false rather than an error, so repeating a drop is safe.',
|
|
12
|
+
annotations: {
|
|
13
|
+
readOnlyHint: false,
|
|
14
|
+
destructiveHint: true,
|
|
15
|
+
idempotentHint: true,
|
|
16
|
+
openWorldHint: false,
|
|
17
|
+
},
|
|
18
|
+
input: z.object({
|
|
19
|
+
canvas_id: CanvasIdSchema.describe('Canvas identifier returned as canvasId by eurostat_query_dataset, eurostat_download_dataset, or eurostat_get_dimension_values. Identifies the workspace holding the table to drop.'),
|
|
20
|
+
table_name: z
|
|
21
|
+
.string()
|
|
22
|
+
.regex(CANVAS_IDENTIFIER_REGEX, 'Expected a table name exactly as eurostat_dataframe_describe lists it: letters, digits, and underscores, starting with a letter or underscore, at most 63 characters.')
|
|
23
|
+
.describe('Name of the table to drop, exactly as eurostat_dataframe_describe lists it, case included (e.g. "df_a1b2c3d4"): letters, digits, and underscores.'),
|
|
24
|
+
}),
|
|
25
|
+
output: z.object({
|
|
26
|
+
canvasId: z.string().describe('Canvas identifier the drop ran against.'),
|
|
27
|
+
tableName: z.string().describe('Table name the drop was asked to remove, as sent.'),
|
|
28
|
+
dropped: z
|
|
29
|
+
.boolean()
|
|
30
|
+
.describe('True when a table by that name was staged and is now removed. False when nothing by that name was staged at call time — never staged, already dropped, or expired — so the canvas is unchanged.'),
|
|
31
|
+
expiresAt: z
|
|
32
|
+
.string()
|
|
33
|
+
.describe('ISO 8601 timestamp when the canvas expires. The drop slid it forward; the canvas and its other tables remain.'),
|
|
34
|
+
}),
|
|
35
|
+
enrichment: {
|
|
36
|
+
notice: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('Guidance when nothing by that name was staged, so nothing was dropped. Omitted when a table was dropped.'),
|
|
40
|
+
},
|
|
41
|
+
errors: [
|
|
42
|
+
{
|
|
43
|
+
reason: 'canvas_disabled',
|
|
44
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
45
|
+
when: 'This deployment runs without a dataframe canvas, so there are no staged tables to drop.',
|
|
46
|
+
retryable: false,
|
|
47
|
+
recovery: 'Nothing is staged without a dataframe canvas, so there is nothing to drop; eurostat_query_dataset answers inline with narrower dimension filters.',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
reason: 'canvas_not_found',
|
|
51
|
+
code: JsonRpcErrorCode.NotFound,
|
|
52
|
+
when: 'The canvas_id is unknown or its lifetime has elapsed.',
|
|
53
|
+
recovery: 'An expired canvas has already released every table it held, so nothing is left to drop; otherwise copy the canvasId exactly as eurostat_query_dataset, eurostat_download_dataset, or eurostat_get_dimension_values returned it.',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
reason: 'identifier_reserved',
|
|
57
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
58
|
+
when: 'The table_name is a bare SQL keyword (e.g. "select"), which no staged table can carry.',
|
|
59
|
+
recovery: 'Call eurostat_dataframe_describe and copy a table name exactly as it is listed.',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
async handler(input, ctx) {
|
|
63
|
+
const canvas = getCanvas();
|
|
64
|
+
if (!canvas) {
|
|
65
|
+
throw ctx.fail('canvas_disabled');
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The canvas words both rejections for staging — re-run the tool that
|
|
69
|
+
* staged the data, choose another table name — which for a drop restores
|
|
70
|
+
* what was meant to go. Re-thrown through `ctx.fail`, they carry this tool's
|
|
71
|
+
* declared recovery instead.
|
|
72
|
+
*/
|
|
73
|
+
const asDropFailure = (err) => {
|
|
74
|
+
if (err instanceof McpError && err.data?.reason === 'canvas_not_found') {
|
|
75
|
+
throw ctx.fail('canvas_not_found', err.message, { canvasId: input.canvas_id });
|
|
76
|
+
}
|
|
77
|
+
if (err instanceof McpError && err.data?.reason === 'identifier_reserved') {
|
|
78
|
+
throw ctx.fail('identifier_reserved', `"${input.table_name}" is a reserved SQL keyword, so no staged table carries that name.`, { tableName: input.table_name });
|
|
79
|
+
}
|
|
80
|
+
throw err;
|
|
81
|
+
};
|
|
82
|
+
const instance = await acquireCanvas(canvas, input.canvas_id, ctx).catch(asDropFailure);
|
|
83
|
+
const dropped = await instance.drop(input.table_name).catch(asDropFailure);
|
|
84
|
+
ctx.log.info('Canvas table drop', {
|
|
85
|
+
canvasId: instance.canvasId,
|
|
86
|
+
tableName: input.table_name,
|
|
87
|
+
dropped,
|
|
88
|
+
});
|
|
89
|
+
if (!dropped) {
|
|
90
|
+
ctx.enrich.notice(`Canvas ${instance.canvasId} holds no table named "${input.table_name}", so nothing was dropped. Names match exactly, case included — eurostat_dataframe_describe lists what is staged.`);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
canvasId: instance.canvasId,
|
|
94
|
+
tableName: input.table_name,
|
|
95
|
+
dropped,
|
|
96
|
+
expiresAt: instance.expiresAt,
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
format: (result) => [
|
|
100
|
+
{
|
|
101
|
+
type: 'text',
|
|
102
|
+
text: [
|
|
103
|
+
`# Drop \`${result.tableName}\` (canvas \`${result.canvasId}\`)`,
|
|
104
|
+
`**Dropped:** ${result.dropped} — ${result.dropped
|
|
105
|
+
? 'removed; the canvas and its other tables are unchanged'
|
|
106
|
+
: 'nothing by that name was staged'}`,
|
|
107
|
+
`**Canvas expires:** ${result.expiresAt}`,
|
|
108
|
+
].join('\n'),
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=eurostat-dataframe-drop.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eurostat-dataframe-drop.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-dataframe-drop.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -57,7 +57,7 @@ export const eurostatDataframeQuery = tool('eurostat_dataframe_query', {
|
|
|
57
57
|
async handler(input, ctx) {
|
|
58
58
|
const canvas = getCanvas();
|
|
59
59
|
if (!canvas) {
|
|
60
|
-
throw ctx.fail('canvas_disabled'
|
|
60
|
+
throw ctx.fail('canvas_disabled');
|
|
61
61
|
}
|
|
62
62
|
const instance = await acquireCanvas(canvas, input.canvas_id, ctx);
|
|
63
63
|
/**
|