@cyanheads/eurostat-mcp-server 0.10.0 → 0.10.1
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 +3 -2
- package/CLAUDE.md +3 -2
- package/Dockerfile +5 -5
- package/README.md +34 -37
- package/changelog/0.10.x/0.10.1.md +27 -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 +9 -4
- package/dist/config/server-config.js.map +1 -1
- package/dist/index.js +25 -7
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/clamp-read-limit.d.ts +11 -0
- package/dist/mcp-server/tools/clamp-read-limit.d.ts.map +1 -0
- package/dist/mcp-server/tools/clamp-read-limit.js +14 -0
- package/dist/mcp-server/tools/clamp-read-limit.js.map +1 -0
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.d.ts +3 -1
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.js +96 -33
- 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 +100 -0
- 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 +22 -11
- package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts +101 -0
- 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 +13 -9
- 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 +45 -0
- 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 +12 -9
- package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.js.map +1 -1
- package/dist/services/eurostat-bulk/eurostat-bulk-service.d.ts.map +1 -1
- package/dist/services/eurostat-bulk/eurostat-bulk-service.js +72 -24
- package/dist/services/eurostat-bulk/eurostat-bulk-service.js.map +1 -1
- package/dist/services/eurostat-bulk/types.d.ts +1 -1
- package/dist/services/eurostat-bulk/types.d.ts.map +1 -1
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts.map +1 -1
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js +15 -6
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js.map +1 -1
- package/dist/services/eurostat-data/eurostat-data-service.d.ts.map +1 -1
- package/dist/services/eurostat-data/eurostat-data-service.js +12 -5
- package/dist/services/eurostat-data/eurostat-data-service.js.map +1 -1
- package/package.json +6 -6
- package/server.json +31 -17
package/AGENTS.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/eurostat-mcp-server
|
|
4
|
-
**Version:** 0.10.
|
|
4
|
+
**Version:** 0.10.1
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.15`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/server` `^2.3.1`
|
|
8
|
-
**Zod:** `^4.6.
|
|
8
|
+
**Zod:** `^4.6.7`
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
11
11
|
|
|
@@ -374,6 +374,7 @@ Run the `release-and-publish` skill after git wrapup — it runs the verificatio
|
|
|
374
374
|
bun publish --access public
|
|
375
375
|
|
|
376
376
|
docker buildx build --platform linux/amd64,linux/arm64 \
|
|
377
|
+
--build-arg APP_VERSION=<version> \
|
|
377
378
|
-t ghcr.io/cyanheads/eurostat-mcp-server:<version> \
|
|
378
379
|
-t ghcr.io/cyanheads/eurostat-mcp-server:latest \
|
|
379
380
|
--push .
|
package/CLAUDE.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/eurostat-mcp-server
|
|
4
|
-
**Version:** 0.10.
|
|
4
|
+
**Version:** 0.10.1
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.15`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/server` `^2.3.1`
|
|
8
|
-
**Zod:** `^4.6.
|
|
8
|
+
**Zod:** `^4.6.7`
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
11
11
|
|
|
@@ -374,6 +374,7 @@ Run the `release-and-publish` skill after git wrapup — it runs the verificatio
|
|
|
374
374
|
bun publish --access public
|
|
375
375
|
|
|
376
376
|
docker buildx build --platform linux/amd64,linux/arm64 \
|
|
377
|
+
--build-arg APP_VERSION=<version> \
|
|
377
378
|
-t ghcr.io/cyanheads/eurostat-mcp-server:<version> \
|
|
378
379
|
-t ghcr.io/cyanheads/eurostat-mcp-server:latest \
|
|
379
380
|
--push .
|
package/Dockerfile
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# output. A stage that compiles a native addon needs the target-arch toolchain
|
|
15
15
|
# and cannot cross-compile this way — drop the flag there.
|
|
16
16
|
# ==============================================================================
|
|
17
|
-
FROM --platform=$BUILDPLATFORM oven/bun:1.4.
|
|
17
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.4 AS build
|
|
18
18
|
|
|
19
19
|
WORKDIR /usr/src/app
|
|
20
20
|
|
|
@@ -46,7 +46,7 @@ RUN bun run build
|
|
|
46
46
|
# A clean image rather than `FROM build`: the build stage's node_modules holds
|
|
47
47
|
# devDependencies.
|
|
48
48
|
# ==============================================================================
|
|
49
|
-
FROM --platform=$BUILDPLATFORM oven/bun:1.4.
|
|
49
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.4 AS deps
|
|
50
50
|
|
|
51
51
|
WORKDIR /usr/src/app
|
|
52
52
|
|
|
@@ -80,8 +80,8 @@ RUN case "$TARGETARCH" in \
|
|
|
80
80
|
# The @duckdb/node-api binding that backs DataCanvas is one of this server's own
|
|
81
81
|
# dependencies, so it survives the flag, and `--cpu` picks the target's binding:
|
|
82
82
|
# the canvas is gated at runtime by CANVAS_PROVIDER_TYPE, not at build time, so
|
|
83
|
-
# the image always carries the binding
|
|
84
|
-
#
|
|
83
|
+
# the image always carries the binding. The canvas is on by default; a deployment
|
|
84
|
+
# turns it off with CANVAS_PROVIDER_TYPE=none.
|
|
85
85
|
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
86
86
|
bun install --production --omit=peer --frozen-lockfile --ignore-scripts \
|
|
87
87
|
--os="$TARGETOS" --cpu="$(cat .bun-cpu)"
|
|
@@ -118,7 +118,7 @@ RUN rm -rf node_modules/@socketsecurity/bun-security-scanner
|
|
|
118
118
|
# dependencies and build artifacts. Its only Bun invocations are HEALTHCHECK
|
|
119
119
|
# and CMD, which run on the real target at container start.
|
|
120
120
|
# ==============================================================================
|
|
121
|
-
FROM oven/bun:1.4.
|
|
121
|
+
FROM oven/bun:1.4.4-slim AS production
|
|
122
122
|
|
|
123
123
|
WORKDIR /usr/src/app
|
|
124
124
|
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
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
|
|
|
@@ -29,13 +29,11 @@
|
|
|
29
29
|
|
|
30
30
|
## Overview
|
|
31
31
|
|
|
32
|
-
EU statistics from
|
|
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.
|
|
32
|
+
EU statistics from Eurostat: economy, demography, trade, health, and NUTS regional data, including detailed Comext trade and PRODCOM industrial production. Search or browse the catalogue, inspect a dataset's dimensions, then query a slice or bulk-download the whole thing.
|
|
35
33
|
|
|
36
34
|
### Tools
|
|
37
35
|
|
|
38
|
-
|
|
36
|
+
The three `eurostat_dataframe_*` tools need the dataframe canvas, which is on by default and off with `CANVAS_PROVIDER_TYPE=none`; `eurostat_dataframe_drop` also needs `EUROSTAT_DATAFRAME_DROP_ENABLED=true`.
|
|
39
37
|
|
|
40
38
|
| Tool | Description |
|
|
41
39
|
|:---|:---|
|
|
@@ -61,64 +59,63 @@ The same metadata is available through `eurostat_get_dataset_info` for tool-only
|
|
|
61
59
|
|
|
62
60
|
### `eurostat_search_datasets` <sub>tool</sub>
|
|
63
61
|
|
|
64
|
-
- `query`
|
|
65
|
-
- Results carry `code`, `label`, `type` (`dataset` / `table`), period coverage, `obsCount`, `lastUpdated`, and `themePath`, with `totalMatches` across every page; fails as `no_match` (naming
|
|
66
|
-
-
|
|
62
|
+
- `query` words are ANDed case-insensitively across each dataset's label, theme breadcrumb, and code, ignoring spacing beside punctuation (`Rev.2` finds `Rev. 2`); `limit` is a positive integer (default 20), clamped to 100 with a notice. Page by passing `nextCursor` back as `cursor`; cursor calls ignore `limit`
|
|
63
|
+
- Results carry `code`, `label`, `type` (`dataset` / `table`), period coverage, `obsCount`, `lastUpdated`, and `themePath`, with `totalMatches` across every page; fails as `no_match` (naming the words whose removal finds matches), `invalid_cursor`, or a retryable `upstream_fault` when no catalogue is loaded and Eurostat's table of contents is unreachable
|
|
64
|
+
- If the Comext dataflow list cannot be loaded, results carry `comextListMissing` and a `notice`; a catalogue that could not be refreshed carries `catalogueLoadedAt`
|
|
67
65
|
|
|
68
66
|
---
|
|
69
67
|
|
|
70
68
|
### `eurostat_browse_themes` <sub>tool</sub>
|
|
71
69
|
|
|
72
70
|
- Omit `theme_code` for the top-level theme folders; pass a folder code for its immediate children. The Comext collections sit under `ext_go_detail` (detailed trade, in `ext_go`) and `prom` (PRODCOM, in `icts`)
|
|
73
|
-
- Items carry `code`, `label`, `type` (`folder` / `dataset` / `table`), and `hasChildren`, with a `parentPath` breadcrumb and `otherPlacements` for a folder
|
|
74
|
-
-
|
|
71
|
+
- Items carry `code`, `label`, `type` (`folder` / `dataset` / `table`), and `hasChildren`, with a `parentPath` breadcrumb and `otherPlacements` for a folder filed in several branches; fails as `not_found` for an unknown code, `not_a_folder` for a dataset or table code, or a retryable `upstream_fault` when no catalogue is loaded and Eurostat's table of contents is unreachable
|
|
72
|
+
- If the Comext dataflow list cannot be loaded, `ext_go` and `icts` carry `comextListMissing` and a `notice`; a catalogue that could not be refreshed carries `catalogueLoadedAt`
|
|
75
73
|
|
|
76
74
|
---
|
|
77
75
|
|
|
78
76
|
### `eurostat_get_dataset_info` <sub>tool</sub>
|
|
79
77
|
|
|
80
78
|
- One `dataset_code`; returns every dimension with `valuesCount` and up to 10 `sampleValues`, plus `timeRange`, `obsCount`, `lastUpdated`, and the ESMS `metadataUrl`
|
|
81
|
-
- Fails as `not_found` for an unknown dataset, or `upstream_fault` when Eurostat returns a structure
|
|
79
|
+
- Fails as `not_found` for an unknown dataset, or `upstream_fault` when Eurostat returns a structure the server cannot read (retryable when the endpoint is down)
|
|
82
80
|
|
|
83
81
|
---
|
|
84
82
|
|
|
85
83
|
### `eurostat_get_dimension_values` <sub>tool</sub>
|
|
86
84
|
|
|
87
|
-
- `dataset_code` plus `dimension`; for `geo`, `geo_level` picks a NUTS level (`aggregate`, `country` by default, `nuts1`, `nuts2`, `nuts3`).
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
- Fails as `not_found`, `no_results`, `conflicting_params`, `invalid_cursor`, `upstream_fault` (a structure or content constraint the server cannot read, or, marked retryable, a structure endpoint that answers HTTP 5xx or cannot be reached on every retry), or `canvas_not_found`
|
|
91
|
-
- `canvas_id` stages every value, whatever `filter` and `limit` are, on that canvas as a `code` / `label` table (`canvasId` / `tableName` / `stagedRowCount`) that labels a download's code columns through a join; this tool never starts a canvas of its own
|
|
85
|
+
- `dataset_code` plus `dimension`; for `geo`, `geo_level` picks a NUTS level (`aggregate`, `country` by default, `nuts1`, `nuts2`, `nuts3`). `filter` keeps values whose code and label contain every word given, ignoring case and accents (`palma frankfurt` finds `DE_EDDF_ES_LEPA`), counted in `matchCount`
|
|
86
|
+
- Long lists come back in pages of up to 64,000 bytes (or an optional `limit`), with `totalCount` for every value; a page with more after it carries `truncated`, `nextCursor` (pass back as `cursor`), and a `notice`. Fails as `not_found`, `no_results`, `conflicting_params`, `invalid_cursor`, `upstream_fault` (retryable when the endpoint is down), or `canvas_not_found`
|
|
87
|
+
- `canvas_id` stages every value on that canvas as a `code` / `label` table (`canvasId` / `tableName` / `stagedRowCount`) that labels a download's code columns through a join; it never starts a canvas of its own
|
|
92
88
|
|
|
93
89
|
---
|
|
94
90
|
|
|
95
91
|
### `eurostat_query_dataset` <sub>tool</sub>
|
|
96
92
|
|
|
97
|
-
- `dataset_code` plus `filters` (`{dimension_code: [values]}`), `geo_level`, and either `since_period` / `until_period` (`2020`, `2020-Q1`, `2020-01`, down to `YYYY-Wnn` and `YYYY-Dnnn`) or `last_n_periods`; `preview_limit`
|
|
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` is a positive integer (default 50), clamped to 500 with a notice; `lang` is `EN`, `FR`, or `DE`
|
|
98
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
|
|
99
|
-
- Fails as `not_found`, `no_results` (naming the unmatched values and the periods
|
|
95
|
+
- Fails as `not_found`, `no_results` (naming the unmatched values and the periods with no value), `invalid_dimension`, `invalid_period`, `conflicting_params`, a non-retryable `async_response` for a query too large to serve, `canvas_not_found`, or a retryable `upstream_fault` when the Statistics API is down
|
|
100
96
|
|
|
101
97
|
---
|
|
102
98
|
|
|
103
99
|
### `eurostat_download_dataset` <sub>tool</sub>
|
|
104
100
|
|
|
105
|
-
- `dataset_code` plus the same `filters` map and `since_period` / `until_period` (no `last_n_periods`: the TSV keeps a column per period unless a range drops it); `preview_limit`
|
|
106
|
-
- Returns `rowCount` (echoed as `totalCount`), `missingCount`, `periodRange`, and `bytesRead` for the whole download; fails as `not_found`, `invalid_dimension`, `invalid_period`, `filter_arity`, a non-retryable `async_queued` or `extraction_too_big`, `no_results`, `upstream_fault` (
|
|
107
|
-
- The `EUROSTAT_BULK_MAX_BYTES` budget (default 50 MiB)
|
|
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` is a positive integer (default 50), clamped to 500 with a notice
|
|
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` (retryable when the SDMX endpoint is down), or `canvas_not_found`
|
|
103
|
+
- The `EUROSTAT_BULK_MAX_BYTES` budget (default 50 MiB decoded) retains complete observations within the permitted prefix and returns `budgetExceeded: true`. A budget too small for a complete header and usable observation fails as `byte_budget_exceeded`, with the configured limit and narrowing guidance. `bytesRead` counts accepted decoded bytes, never more than the budget; incomplete trailing rows are discarded.
|
|
108
104
|
|
|
109
105
|
---
|
|
110
106
|
|
|
111
107
|
### `eurostat_dataframe_describe` <sub>tool</sub>
|
|
112
108
|
|
|
113
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`
|
|
114
|
-
- Columns
|
|
110
|
+
- Columns depend on the staging tool: `eurostat_query_dataset` writes a code and a `_label` column per dimension, `eurostat_download_dataset` codes only plus `time` (both share the `obs_*` and `conf_status*` measures), and `eurostat_get_dimension_values` writes `code` and `label`
|
|
115
111
|
|
|
116
112
|
---
|
|
117
113
|
|
|
118
114
|
### `eurostat_dataframe_query` <sub>tool</sub>
|
|
119
115
|
|
|
120
116
|
- One read-only `SELECT` per call; chained statements, other verbs, and functions that read files or external data are rejected
|
|
121
|
-
- Returns `columns`, `rows`, `rowCount`, and `truncated
|
|
117
|
+
- Returns `columns`, `rows`, `rowCount`, and required boolean `truncated`. Whole rows fit within `CANVAS_DEFAULT_ROW_LIMIT` (default 10,000) and 64,000 bytes independently for JSON-serialized `structuredContent` and `content[]`, including enrichment. At least one complete row is retained even if oversized. Cells render as lossless JSON, including nesting and quoted strings; 64-bit integers arrive as strings. Fails as `missing_table`, `canvas_not_found`, or `canvas_disabled`
|
|
118
|
+
- A cut sets `truncated: true` and adds a notice. Page an unchanged deterministic SELECT with a total `ORDER BY` (tie-breakers required), `LIMIT` and `OFFSET`; advance by actual `rowCount`. Restart an initially unordered result sorted at offset zero. Volatile SQL and changing or expired tables cannot provide stable paging
|
|
122
119
|
|
|
123
120
|
---
|
|
124
121
|
|
|
@@ -141,18 +138,17 @@ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): s
|
|
|
141
138
|
Eurostat-specific:
|
|
142
139
|
|
|
143
140
|
- 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
|
|
144
|
-
- The Comext host's `DS-*` collections
|
|
145
|
-
- NUTS geo-level filtering (`aggregate` / `country` / `nuts1` / `nuts2` / `nuts3`)
|
|
146
|
-
-
|
|
147
|
-
- A
|
|
148
|
-
- Inline rows are capped by `preview_limit` (at most 500). With `CANVAS_PROVIDER_TYPE=duckdb`, a query match above 5,000 observations, or any bulk download, is staged whole as a SQL table (`canvasId` / `tableName` / `stagedRowCount`) for the dataframe tools, and `canvas_id` stages the next result beside earlier ones for joins — including a dimension's code/label list from `eurostat_get_dimension_values`, which labels a bulk table's codes. An empty download fails as `no_results` without creating or touching a canvas. The `.mcpb` bundle strips the native DuckDB binding, so SQL analytics need the npm, Docker, or from-source install
|
|
141
|
+
- The Comext host's `DS-*` collections (detailed trade by CN8, HS, SITC, BEC and CPA, and PRODCOM) through the same tools. Filter every request, `freq` included, since trade flows mix annual and monthly series; aggregates such as `TOTAL`, `EU27_2020`, and `EXT_EU27_2020` double-count when summed with their members. PRODCOM text values arrive in `valueText` / `obs_value_text`
|
|
142
|
+
- NUTS geo-level filtering (`aggregate` / `country` / `nuts1` / `nuts2` / `nuts3`), and OBS_FLAG and CONF_STATUS decoded into separate fields
|
|
143
|
+
- Too-large-to-serve responses come back as non-retryable `async_response`, `extraction_too_big`, or `async_queued` errors that name the dimensions left to filter
|
|
144
|
+
- A query match above 5,000 observations, or any bulk download, is staged whole as a SQL table (`canvasId` / `tableName` / `stagedRowCount`) on the DuckDB dataframe canvas, which is on by default. The `.mcpb` bundle strips the native DuckDB binding and runs with `CANVAS_PROVIDER_TYPE=none`, so SQL analytics need the npm, Docker, or from-source install
|
|
149
145
|
|
|
150
146
|
Agent-friendly output:
|
|
151
147
|
|
|
152
148
|
- Typed error contracts: every declared failure carries a `reason` and a `recovery.hint` naming the next tool to call
|
|
153
149
|
- Next-step hints: `eurostat_search_datasets` and `eurostat_browse_themes` return a `nextStep` pointing at the follow-up call
|
|
154
150
|
- Unknown stays unknown: counts and period bounds Eurostat doesn't report (`obsCount`, `timeRange.start` / `end`, `lastUpdated`) are omitted rather than zeroed
|
|
155
|
-
- Effective-query echo: `appliedFilters` on `eurostat_query_dataset` and `appliedQuery` (with the SDMX `url`) on `eurostat_download_dataset`, plus a `notice` when the
|
|
151
|
+
- Effective-query echo: `appliedFilters` on `eurostat_query_dataset` and `appliedQuery` (with the SDMX `url`) on `eurostat_download_dataset`, plus a `notice` when the preview omits rows
|
|
156
152
|
|
|
157
153
|
## Getting started
|
|
158
154
|
|
|
@@ -267,15 +263,16 @@ cp .env.example .env
|
|
|
267
263
|
|:---|:---|:---|
|
|
268
264
|
| `EUROSTAT_BASE_URL` | Eurostat API base URL. | `https://ec.europa.eu/eurostat/api/dissemination` |
|
|
269
265
|
| `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` |
|
|
270
|
-
| `EUROSTAT_REQUEST_TIMEOUT_MS` |
|
|
271
|
-
| `EUROSTAT_METADATA_TIMEOUT_MS` |
|
|
272
|
-
| `EUROSTAT_TOC_CACHE_TTL_MS` | Catalogue TOC cache lifetime, in ms
|
|
273
|
-
| `EUROSTAT_BULK_TIMEOUT_MS` |
|
|
274
|
-
| `EUROSTAT_BULK_MAX_BYTES` | Byte budget for one bulk download
|
|
275
|
-
| `CANVAS_PROVIDER_TYPE` | `
|
|
266
|
+
| `EUROSTAT_REQUEST_TIMEOUT_MS` | Total allowance for one request, including retries, backoff and body reads, in ms. | `30000` |
|
|
267
|
+
| `EUROSTAT_METADATA_TIMEOUT_MS` | Total allowance for one dataset's SDMX dataflow structure, including retries, backoff and body reads, in ms. | `120000` (2 min) |
|
|
268
|
+
| `EUROSTAT_TOC_CACHE_TTL_MS` | Catalogue TOC cache lifetime, in ms. | `43200000` (12 h) |
|
|
269
|
+
| `EUROSTAT_BULK_TIMEOUT_MS` | Total allowance for one bulk transfer, including request retries, backoff and streaming, in ms. | `120000` (2 min) |
|
|
270
|
+
| `EUROSTAT_BULK_MAX_BYTES` | Byte budget for one bulk download. | `52428800` (50 MiB) |
|
|
271
|
+
| `CANVAS_PROVIDER_TYPE` | Dataframe canvas backend; `none` disables the canvas and its tools. The `.mcpb` bundle sets `none`. | `duckdb` |
|
|
276
272
|
| `CANVAS_TTL_MS` | Sliding lifetime of a staged canvas, in ms. | `86400000` (24 h) |
|
|
277
|
-
| `CANVAS_DEFAULT_ROW_LIMIT` | Max rows one `eurostat_dataframe_query` returns before reporting `truncated
|
|
278
|
-
| `
|
|
273
|
+
| `CANVAS_DEFAULT_ROW_LIMIT` | Max rows one `eurostat_dataframe_query` returns before reporting `truncated`; a separate 64,000-byte budget applies to each serialized response surface, retaining at least one complete row. | `10000` |
|
|
274
|
+
| `EUROSTAT_CLAMP_LIMITS` | Clamp positive integer preview/search limits to 500/100 with a notice. `false` restores schemas rejecting over-cap inputs; zero, negatives, fractions and nonnumeric inputs are always rejected. Each clamp logs once and increments `eurostat.limit_clamps`, labelled by tool. | `true` |
|
|
275
|
+
| `EUROSTAT_DATAFRAME_DROP_ENABLED` | `true` lists `eurostat_dataframe_drop`; no effect with `CANVAS_PROVIDER_TYPE=none`. | `false` |
|
|
279
276
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
280
277
|
| `MCP_HTTP_PORT` | HTTP server port. | `3010` |
|
|
281
278
|
| `MCP_SESSION_MODE` | HTTP session mode: `stateless`, `stateful`, or `auto`. The server declares `stateless`; a set value overrides it. | `stateless` |
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Bounded Eurostat reads and lossless SQL results."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.10.1 — 2026-10-22
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **Read limits** clamp positive integer previews to 500 and first-page searches to 100 with a notice, log and counter; `EUROSTAT_CLAMP_LIMITS=false` restores rejecting maximum schemas. ([#77](https://github.com/cyanheads/eurostat-mcp-server/issues/77))
|
|
12
|
+
- **Dataframe canvas** defaults to `duckdb`; set `CANVAS_PROVIDER_TYPE=none` for inline-only reads. The portable `.mcpb` bundle sets `none` because it excludes native bindings.
|
|
13
|
+
|
|
14
|
+
## Fixed
|
|
15
|
+
|
|
16
|
+
- **Request deadlines** bound retries, backoff and body consumption by each operation's configured allowance, preserving caller cancellation and separate metadata/bulk budgets. ([#72](https://github.com/cyanheads/eurostat-mcp-server/issues/72))
|
|
17
|
+
- **SQL cells** render as lossless JSON on the text surface, preserving nested values and distinguishing strings from nulls. ([#74](https://github.com/cyanheads/eurostat-mcp-server/issues/74))
|
|
18
|
+
- **SQL response size** applies 64,000 bytes per serialized surface, including enrichment, between complete rows; at least one row survives even if oversized. Cuts disclose `truncated` and deterministic SQL paging that advances by actual `rowCount`. ([#75](https://github.com/cyanheads/eurostat-mcp-server/issues/75))
|
|
19
|
+
- **Bulk byte budget** retains complete observations within the allowed decoded prefix; an unusable prefix fails as `byte_budget_exceeded` with narrowing guidance. `bytesRead` never exceeds the configured budget. ([#76](https://github.com/cyanheads/eurostat-mcp-server/issues/76))
|
|
20
|
+
|
|
21
|
+
## Dependencies
|
|
22
|
+
|
|
23
|
+
- **`zod`** ^4.6.6 → ^4.6.7.
|
|
24
|
+
- **`ignore`** ^7.0.12 → ^7.0.13.
|
|
25
|
+
- **`tsc-alias`** ^1.9.7 → ^1.9.8.
|
|
26
|
+
- **`vitest`** ^5.0.3 → ^5.0.5.
|
|
27
|
+
- **Bun** 1.4.3 → 1.4.4 (`packageManager` and Docker images).
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
declare const ServerConfigSchema: z.ZodObject<{
|
|
7
|
+
clampLimits: z.ZodDefault<z.ZodCodec<z.ZodString, z.ZodBoolean>>;
|
|
7
8
|
baseUrl: z.ZodDefault<z.ZodString>;
|
|
8
9
|
comextBaseUrl: z.ZodDefault<z.ZodString>;
|
|
9
10
|
requestTimeoutMs: 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;;;;;;;;;;iBAiEtB,CAAC;AAIH,wBAAgB,eAAe,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAapE"}
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
|
|
7
7
|
const ServerConfigSchema = z.object({
|
|
8
|
+
clampLimits: z
|
|
9
|
+
.stringbool()
|
|
10
|
+
.default(true)
|
|
11
|
+
.describe('Clamp positive read limits to preview 500 and search 100 with a notice. False restores rejecting maximum schemas.'),
|
|
8
12
|
baseUrl: z
|
|
9
13
|
.string()
|
|
10
14
|
.url()
|
|
@@ -20,13 +24,13 @@ const ServerConfigSchema = z.object({
|
|
|
20
24
|
.int()
|
|
21
25
|
.positive()
|
|
22
26
|
.default(30_000)
|
|
23
|
-
.describe('
|
|
27
|
+
.describe('Total allowance for one Eurostat request, including retries, backoff and body consumption, in milliseconds'),
|
|
24
28
|
metadataTimeoutMs: z.coerce
|
|
25
29
|
.number()
|
|
26
30
|
.int()
|
|
27
31
|
.positive()
|
|
28
32
|
.default(120_000)
|
|
29
|
-
.describe("
|
|
33
|
+
.describe("Total allowance for one dataset's SDMX dataflow structure, including retries, backoff and body consumption, 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."),
|
|
30
34
|
tocCacheTtlMs: z.coerce
|
|
31
35
|
.number()
|
|
32
36
|
.int()
|
|
@@ -38,7 +42,7 @@ const ServerConfigSchema = z.object({
|
|
|
38
42
|
.int()
|
|
39
43
|
.positive()
|
|
40
44
|
.default(120_000)
|
|
41
|
-
.describe('
|
|
45
|
+
.describe('Total allowance for one SDMX bulk download, including request retries, backoff and streaming body consumption, in milliseconds. Held separate from EUROSTAT_REQUEST_TIMEOUT_MS because a bulk body can take longer than a metadata call. Defaults to 2 minutes.'),
|
|
42
46
|
bulkMaxBytes: z.coerce
|
|
43
47
|
.number()
|
|
44
48
|
.int()
|
|
@@ -48,11 +52,12 @@ const ServerConfigSchema = z.object({
|
|
|
48
52
|
dataframeDropEnabled: z
|
|
49
53
|
.stringbool()
|
|
50
54
|
.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.
|
|
55
|
+
.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. Has no effect with CANVAS_PROVIDER_TYPE=none.'),
|
|
52
56
|
});
|
|
53
57
|
let _config;
|
|
54
58
|
export function getServerConfig() {
|
|
55
59
|
_config ??= parseEnvConfig(ServerConfigSchema, {
|
|
60
|
+
clampLimits: 'EUROSTAT_CLAMP_LIMITS',
|
|
56
61
|
baseUrl: 'EUROSTAT_BASE_URL',
|
|
57
62
|
comextBaseUrl: 'EUROSTAT_COMEXT_BASE_URL',
|
|
58
63
|
requestTimeoutMs: 'EUROSTAT_REQUEST_TIMEOUT_MS',
|
|
@@ -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,
|
|
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,WAAW,EAAE,CAAC;SACX,UAAU,EAAE;SACZ,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CACP,mHAAmH,CACpH;IACH,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,CACP,4GAA4G,CAC7G;IACH,iBAAiB,EAAE,CAAC,CAAC,MAAM;SACxB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,OAAO,CAAC,OAAO,CAAC;SAChB,QAAQ,CACP,wUAAwU,CACzU;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,iQAAiQ,CAClQ;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,sOAAsO,CACvO;CACJ,CAAC,CAAC;AAEH,IAAI,OAAuD,CAAC;AAE5D,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,cAAc,CAAC,kBAAkB,EAAE;QAC7C,WAAW,EAAE,uBAAuB;QACpC,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
|
@@ -4,22 +4,26 @@
|
|
|
4
4
|
* @module index
|
|
5
5
|
*/
|
|
6
6
|
import { createApp, disabledTool } from '@cyanheads/mcp-ts-core';
|
|
7
|
-
import { config } from '@cyanheads/mcp-ts-core/config';
|
|
7
|
+
import { config, parseConfig, resetConfig } from '@cyanheads/mcp-ts-core/config';
|
|
8
8
|
import { getServerConfig } from './config/server-config.js';
|
|
9
9
|
import { eurostatDatasetResource } from './mcp-server/resources/definitions/eurostat-dataset.resource.js';
|
|
10
10
|
import { eurostatBrowseThemes } from './mcp-server/tools/definitions/eurostat-browse-themes.tool.js';
|
|
11
11
|
import { eurostatDataframeDescribe } from './mcp-server/tools/definitions/eurostat-dataframe-describe.tool.js';
|
|
12
12
|
import { eurostatDataframeDrop } from './mcp-server/tools/definitions/eurostat-dataframe-drop.tool.js';
|
|
13
13
|
import { eurostatDataframeQuery } from './mcp-server/tools/definitions/eurostat-dataframe-query.tool.js';
|
|
14
|
-
import {
|
|
14
|
+
import { createEurostatDownloadDataset } from './mcp-server/tools/definitions/eurostat-download-dataset.tool.js';
|
|
15
15
|
import { eurostatGetDatasetInfo } from './mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js';
|
|
16
16
|
import { eurostatGetDimensionValues } from './mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { createEurostatQueryDataset } from './mcp-server/tools/definitions/eurostat-query-dataset.tool.js';
|
|
18
|
+
import { createEurostatSearchDatasets } from './mcp-server/tools/definitions/eurostat-search-datasets.tool.js';
|
|
19
19
|
import { setCanvas } from './services/canvas-accessor.js';
|
|
20
20
|
import { initEurostatBulkService } from './services/eurostat-bulk/eurostat-bulk-service.js';
|
|
21
21
|
import { initEurostatCatalogueService } from './services/eurostat-catalogue/eurostat-catalogue-service.js';
|
|
22
22
|
import { initEurostatDataService } from './services/eurostat-data/eurostat-data-service.js';
|
|
23
|
+
parseConfig();
|
|
24
|
+
// DataCanvas defaults on; set CANVAS_PROVIDER_TYPE=none to disable it.
|
|
25
|
+
process.env.CANVAS_PROVIDER_TYPE ||= 'duckdb';
|
|
26
|
+
resetConfig();
|
|
23
27
|
/**
|
|
24
28
|
* The dataframe tools address tables on a canvas, so without one they have
|
|
25
29
|
* nothing to talk to. `disabledTool` keeps a gated tool off `tools/list` —
|
|
@@ -67,6 +71,20 @@ function dataframeDropTool() {
|
|
|
67
71
|
hint: DROP_OFF_HINT,
|
|
68
72
|
});
|
|
69
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Registration is provisional until setup validates this same memoized config.
|
|
76
|
+
* Invalid parses are never cached: setup repeats the failure inside createApp's
|
|
77
|
+
* configuration boundary, prints its banner and exits before serving a call.
|
|
78
|
+
*/
|
|
79
|
+
function readClampLimits() {
|
|
80
|
+
try {
|
|
81
|
+
return getServerConfig().clampLimits;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const clampLimits = readClampLimits();
|
|
70
88
|
await createApp({
|
|
71
89
|
name: 'eurostat-mcp-server',
|
|
72
90
|
title: 'eurostat-mcp-server',
|
|
@@ -77,12 +95,12 @@ await createApp({
|
|
|
77
95
|
*/
|
|
78
96
|
sessionMode: 'stateless',
|
|
79
97
|
tools: [
|
|
80
|
-
|
|
98
|
+
createEurostatSearchDatasets(clampLimits),
|
|
81
99
|
eurostatBrowseThemes,
|
|
82
100
|
eurostatGetDatasetInfo,
|
|
83
101
|
eurostatGetDimensionValues,
|
|
84
|
-
|
|
85
|
-
|
|
102
|
+
createEurostatQueryDataset(clampLimits),
|
|
103
|
+
createEurostatDownloadDataset(clampLimits),
|
|
86
104
|
canvasEnabled ? eurostatDataframeDescribe : disabledTool(eurostatDataframeDescribe, CANVAS_OFF),
|
|
87
105
|
canvasEnabled ? eurostatDataframeQuery : disabledTool(eurostatDataframeQuery, CANVAS_OFF),
|
|
88
106
|
dataframeDropTool(),
|
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;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Bound read previews and search pages, disclosing each applied clamp.
|
|
3
|
+
* @module mcp-server/tools/clamp-read-limit
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
/** Returns the effective limit and records one clamp, labelled only by tool. */
|
|
7
|
+
export declare function clampReadLimit(requested: number, maximum: number, field: 'preview_limit' | 'limit', toolName: 'eurostat_query_dataset' | 'eurostat_download_dataset' | 'eurostat_search_datasets', ctx: Pick<Context, 'log'>): {
|
|
8
|
+
value: number;
|
|
9
|
+
notice?: string;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=clamp-read-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clamp-read-limit.d.ts","sourceRoot":"","sources":["../../../src/mcp-server/tools/clamp-read-limit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAStD,gFAAgF;AAChF,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,eAAe,GAAG,OAAO,EAChC,QAAQ,EAAE,wBAAwB,GAAG,2BAA2B,GAAG,0BAA0B,EAC7F,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,GACxB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAQpC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createCounter } from '@cyanheads/mcp-ts-core/utils';
|
|
2
|
+
const clamps = createCounter('eurostat.limit_clamps', 'Read limits clamped to their supported maximum', '{clamps}');
|
|
3
|
+
/** Returns the effective limit and records one clamp, labelled only by tool. */
|
|
4
|
+
export function clampReadLimit(requested, maximum, field, toolName, ctx) {
|
|
5
|
+
if (requested <= maximum)
|
|
6
|
+
return { value: requested };
|
|
7
|
+
ctx.log.info('Read limit clamped', { tool: toolName, field, requested, applied: maximum });
|
|
8
|
+
clamps.add(1, { tool: toolName });
|
|
9
|
+
return {
|
|
10
|
+
value: maximum,
|
|
11
|
+
notice: `${field} requested ${requested}; applied ${maximum}, the supported maximum.`,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=clamp-read-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clamp-read-limit.js","sourceRoot":"","sources":["../../../src/mcp-server/tools/clamp-read-limit.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,MAAM,MAAM,GAAG,aAAa,CAC1B,uBAAuB,EACvB,gDAAgD,EAChD,UAAU,CACX,CAAC;AAEF,gFAAgF;AAChF,MAAM,UAAU,cAAc,CAC5B,SAAiB,EACjB,OAAe,EACf,KAAgC,EAChC,QAA6F,EAC7F,GAAyB;IAEzB,IAAI,SAAS,IAAI,OAAO;QAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IACtD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3F,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClC,OAAO;QACL,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,GAAG,KAAK,cAAc,SAAS,aAAa,OAAO,0BAA0B;KACtF,CAAC;AACJ,CAAC"}
|
|
@@ -30,5 +30,7 @@ export declare const eurostatDataframeQuery: import("@cyanheads/mcp-ts-core").To
|
|
|
30
30
|
readonly code: JsonRpcErrorCode.NotFound;
|
|
31
31
|
readonly when: "The SQL names a table that is not staged on this canvas, or that has expired.";
|
|
32
32
|
readonly recovery: "Call eurostat_dataframe_describe for the staged table names, or re-run the tool that staged them (eurostat_query_dataset, eurostat_download_dataset, or eurostat_get_dimension_values with canvas_id).";
|
|
33
|
-
}],
|
|
33
|
+
}], {
|
|
34
|
+
readonly notice: z.ZodOptional<z.ZodString>;
|
|
35
|
+
}>;
|
|
34
36
|
//# sourceMappingURL=eurostat-dataframe-query.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurostat-dataframe-query.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-dataframe-query.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"eurostat-dataframe-query.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-dataframe-query.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAkDjE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4JjC,CAAC"}
|