@cyanheads/eurostat-mcp-server 0.11.1 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/README.md +8 -7
- package/changelog/0.11.x/0.11.2.md +27 -0
- package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.d.ts +14 -1
- package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.js +17 -0
- package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.d.ts +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.d.ts +8 -6
- 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 +66 -30
- package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.d.ts +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js +10 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.d.ts +2 -2
- package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js +10 -1
- package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts +2 -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 +11 -4
- 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 +4 -4
- 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 +18 -6
- package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.js.map +1 -1
- package/dist/services/eurostat-bulk/eurostat-bulk-service.d.ts +5 -4
- package/dist/services/eurostat-bulk/eurostat-bulk-service.d.ts.map +1 -1
- package/dist/services/eurostat-bulk/eurostat-bulk-service.js +66 -14
- package/dist/services/eurostat-bulk/eurostat-bulk-service.js.map +1 -1
- package/dist/services/eurostat-bulk/types.d.ts +21 -4
- package/dist/services/eurostat-bulk/types.d.ts.map +1 -1
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts +14 -8
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts.map +1 -1
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js +34 -17
- package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js.map +1 -1
- package/dist/services/eurostat-codelists.d.ts +2 -1
- package/dist/services/eurostat-codelists.d.ts.map +1 -1
- package/dist/services/eurostat-codelists.js +2 -1
- package/dist/services/eurostat-codelists.js.map +1 -1
- package/dist/services/eurostat-data/eurostat-data-service.d.ts +7 -0
- package/dist/services/eurostat-data/eurostat-data-service.d.ts.map +1 -1
- package/dist/services/eurostat-data/eurostat-data-service.js +84 -10
- package/dist/services/eurostat-data/eurostat-data-service.js.map +1 -1
- package/dist/services/eurostat-data/types.d.ts +17 -3
- package/dist/services/eurostat-data/types.d.ts.map +1 -1
- package/dist/services/eurostat-data/types.js.map +1 -1
- package/package.json +4 -4
- package/server.json +3 -3
- package/skills/eurostat-guide/SKILL.md +2 -1
- package/skills/eurostat-guide/references/sql-analysis.md +18 -2
package/AGENTS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/eurostat-mcp-server
|
|
4
|
-
**Version:** 0.11.
|
|
4
|
+
**Version:** 0.11.2
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.18`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/server` `^2.4.0`
|
package/CLAUDE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/eurostat-mcp-server
|
|
4
|
-
**Version:** 0.11.
|
|
4
|
+
**Version:** 0.11.2
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.18`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/server` `^2.4.0`
|
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
|
|
|
@@ -42,7 +42,7 @@ The three `eurostat_dataframe_*` tools need the dataframe canvas, which is on by
|
|
|
42
42
|
| `eurostat_get_dataset_info` | Fetch dataset metadata: dimensions with sample values, time range, observation count, and last-update date |
|
|
43
43
|
| `eurostat_get_dimension_values` | List all valid codes for one dataset dimension, paged, with a code/label word filter and NUTS hierarchy filtering for `geo` |
|
|
44
44
|
| `eurostat_query_dataset` | Fetch a bounded preview of decoded observations with dimension filters, NUTS geo-level, and time-range controls |
|
|
45
|
-
| `eurostat_download_dataset` | Download a whole dataset via the SDMX bulk endpoint and stage every
|
|
45
|
+
| `eurostat_download_dataset` | Download a whole dataset via the SDMX bulk endpoint and stage every row on the dataframe canvas |
|
|
46
46
|
| `eurostat_dataframe_describe` | List the tables staged on a dataframe canvas, with row counts and column types |
|
|
47
47
|
| `eurostat_dataframe_query` | Run a read-only SQL SELECT across staged tables |
|
|
48
48
|
| `eurostat_dataframe_drop` | Remove one staged table from a dataframe canvas, leaving its other tables in place (opt-in) |
|
|
@@ -65,7 +65,7 @@ The same metadata is available through `eurostat_get_dataset_info` for tool-only
|
|
|
65
65
|
### `eurostat_search_datasets` <sub>tool</sub>
|
|
66
66
|
|
|
67
67
|
- `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`
|
|
68
|
-
- 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
|
|
68
|
+
- 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 or, when none does, the words that match no dataset), `invalid_cursor`, or a retryable `upstream_fault` when no catalogue is loaded and Eurostat's table of contents is unreachable
|
|
69
69
|
- If the Comext dataflow list cannot be loaded, results carry `comextListMissing` and a `notice`; a catalogue that could not be refreshed carries `catalogueLoadedAt`
|
|
70
70
|
|
|
71
71
|
---
|
|
@@ -99,7 +99,7 @@ The same metadata is available through `eurostat_get_dataset_info` for tool-only
|
|
|
99
99
|
- `stage: true` stages the whole match on an available canvas, regardless of size; reuse `canvas_id` or omit it to create one. Without it, automatic staging starts above 5,000 observations. `truncated` still describes that threshold; `tableName` identifies a staged result. Canvas-disabled deployments disclose an explicit staging request as unavailable
|
|
100
100
|
- `last_n_periods` counts dataset time positions, which can include periods with no populated cells. A notice names gaps across the full match (up to the newest 24, with an omitted count); increase N or replace it with `until_period` to reach earlier observations
|
|
101
101
|
- Eurostat keeps only periods wholly inside `since_period`–`until_period`, per frequency. A notice names a period a bound falls inside and the bound that includes it. A one-day range goes out as `time=<date>`, because Eurostat ignores one-day bounds
|
|
102
|
-
- 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
|
|
102
|
+
- Each observation carries code/label pairs per dimension, a nullable `value`, `status` (OBS_FLAG), and `confStatus` (CONF_STATUS); `obsCount`, `missingObsCount`, `absentCellCount` (periods a matched series lacks, which are not observations and are never staged), and `timeRange` cover the whole match, `truncated` is true above 5,000 observations, and `unmatchedValues` names filter values that matched nothing
|
|
103
103
|
- Fails as `not_found`, `no_results` (naming the unmatched values, the periods with no value, why a range selected no period, or `geo_level` as the likely cause when Eurostat's reply says nothing more), `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
|
|
104
104
|
|
|
105
105
|
---
|
|
@@ -108,8 +108,9 @@ The same metadata is available through `eurostat_get_dataset_info` for tool-only
|
|
|
108
108
|
|
|
109
109
|
- `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 25), clamped to 500 with a notice
|
|
110
110
|
- The wholly-inside rule and its notice apply here too. A one-day range requests that day and the next, and the later day's column is dropped before anything is counted or staged
|
|
111
|
-
-
|
|
112
|
-
-
|
|
111
|
+
- Stages one row per non-blank TSV cell. A row with null `obs_value` and no flag, status or text (an unflagged `:`) is not an observation: it is a period the series lacks, or a period of a frequency the series has no observation of (the padding of a mixed-frequency slice)
|
|
112
|
+
- Returns `rowCount` (echoed as `totalCount`), `missingCount`, `absentCellCount` (the unflagged rows at periods of a frequency the series carries), `periodRange` (bounded by rows carrying a value, flag, status, or text), 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`
|
|
113
|
+
- The `EUROSTAT_BULK_MAX_BYTES` budget (default 50 MiB decoded) retains complete rows within the permitted prefix and returns `budgetExceeded: true`. A budget too small for a complete header and usable row 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.
|
|
113
114
|
|
|
114
115
|
---
|
|
115
116
|
|
|
@@ -137,7 +138,7 @@ The same metadata is available through `eurostat_get_dataset_info` for tool-only
|
|
|
137
138
|
|
|
138
139
|
### `eurostat://dataset/{dataset_code}` <sub>resource</sub>
|
|
139
140
|
|
|
140
|
-
- Same payload as `eurostat_get_dataset_info`, returned as `application/json`; a failed read carries the same `reason
|
|
141
|
+
- Same payload as `eurostat_get_dataset_info`, returned as `application/json`; a failed read carries the same `reason` and a recovery hint, and `retryable` on an outage
|
|
141
142
|
- `dataset_code` comes from `eurostat_search_datasets` or `eurostat_browse_themes`
|
|
142
143
|
|
|
143
144
|
## Features
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "eurostat_query_dataset and eurostat_download_dataset report absentCellCount, the periods a series lacks; the dataset resource's errors carry recovery hints; a search no_match names the query words that match no catalogue entry; the download's periodRange spans observations only; an HTTP 501 gets its own hint."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.11.2 — 2026-11-02
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`absentCellCount`** on `eurostat_query_dataset` and `eurostat_download_dataset`: the periods a matched series lacks, counted only at frequencies that series carries (an annual series beside a monthly one lacks no months). The query stages no row for them and, when the count is above zero, adds a notice naming it and how many series it falls in; the download keeps them as rows with null `obs_value` and describes them as non-observations ([#90](https://github.com/cyanheads/eurostat-mcp-server/issues/90)).
|
|
12
|
+
- **`eurostat_search_datasets`** `no_match` names the query words that match no dataset label, theme breadcrumb, or code when no single word's removal finds matches. It names none while the Comext dataflow list is missing ([#92](https://github.com/cyanheads/eurostat-mcp-server/issues/92)).
|
|
13
|
+
|
|
14
|
+
## Changed
|
|
15
|
+
|
|
16
|
+
- **`eurostat_download_dataset`** descriptions, notices, error messages and `content[]` call downloaded items rows rather than observations, and say what an unflagged `:` row is: a period its series lacks or, in a mixed-frequency slice, a period of a frequency the series does not carry; `rowCount`, `missingCount` and `totalCount` keep their values ([#90](https://github.com/cyanheads/eurostat-mcp-server/issues/90)). A download whose rows are all unflagged `:` cells, which already succeeded, now carries a notice and a `content[]` period line saying no row carries an observation ([#93](https://github.com/cyanheads/eurostat-mcp-server/issues/93)).
|
|
17
|
+
- **`skills/eurostat-guide`** 1.1 → 1.1.1: the coverage gate and the SQL missingness query separate absent periods from observations ([#90](https://github.com/cyanheads/eurostat-mcp-server/issues/90)).
|
|
18
|
+
|
|
19
|
+
## Fixed
|
|
20
|
+
|
|
21
|
+
- **`eurostat://dataset/{dataset_code}`** declares the `not_found` and `upstream_fault` contract entries of `eurostat_get_dataset_info`, so a read failing with either reason carries `data.recovery.hint` ([#91](https://github.com/cyanheads/eurostat-mcp-server/issues/91)).
|
|
22
|
+
- **`eurostat_download_dataset` `periodRange`** is bounded by rows carrying a value, flag, status or text; unflagged `:` rows no longer set a bound, and with no such row both bounds are omitted ([#93](https://github.com/cyanheads/eurostat-mcp-server/issues/93)).
|
|
23
|
+
- **HTTP 501** from the SDMX structure or data endpoint gets a hint naming the status and `eurostat_query_dataset` as the fallback, in `eurostat_get_dataset_info`, `eurostat_get_dimension_values` and `eurostat_download_dataset`; it no longer reads as an unreadable structure or TSV body. A filtered download whose structure read returns a definition it cannot build a filter key from gets a hint saying so, where it said the endpoint returned no TSV table. The `upstream_fault` `when` of those tools, `eurostat_search_datasets` and `eurostat_browse_themes` covers the non-retried 501 ([#94](https://github.com/cyanheads/eurostat-mcp-server/issues/94)).
|
|
24
|
+
|
|
25
|
+
## Dependencies
|
|
26
|
+
|
|
27
|
+
- `@biomejs/biome` 2.6.3 → 2.6.4, `@types/node` 26.6.5 → 26.6.6, `tsc-alias` ^1.9.9 → ^1.9.10 (dev).
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @module mcp-server/resources/definitions/eurostat-dataset.resource
|
|
4
4
|
*/
|
|
5
5
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
6
7
|
export declare const eurostatDatasetResource: import("@cyanheads/mcp-ts-core").ResourceDefinition<z.ZodObject<{
|
|
7
8
|
dataset_code: z.ZodString;
|
|
8
9
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -24,5 +25,17 @@ export declare const eurostatDatasetResource: import("@cyanheads/mcp-ts-core").R
|
|
|
24
25
|
obsCount: z.ZodOptional<z.ZodNumber>;
|
|
25
26
|
lastUpdated: z.ZodOptional<z.ZodString>;
|
|
26
27
|
metadataUrl: z.ZodOptional<z.ZodString>;
|
|
27
|
-
}, z.core.$strip>,
|
|
28
|
+
}, z.core.$strip>, readonly [{
|
|
29
|
+
readonly reason: "not_found";
|
|
30
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
31
|
+
readonly when: "The dataset code does not exist or is not available for dissemination.";
|
|
32
|
+
readonly recovery: "Use eurostat_search_datasets or eurostat_browse_themes to find a valid dataset code.";
|
|
33
|
+
readonly thrownBy: "service";
|
|
34
|
+
}, {
|
|
35
|
+
readonly reason: "upstream_fault";
|
|
36
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
37
|
+
readonly when: "Eurostat returned a dataset structure or content constraint this server cannot read — malformed, truncated, not XML, or missing the requested dataset's dataflow; the structure endpoint answered HTTP 501, which is not retried; or it answered another HTTP 5xx or could not be reached on every retry, which the error marks retryable.";
|
|
38
|
+
readonly recovery: "Retry in a few minutes, since a failed structure read is not cached. If it fails the same way, eurostat_query_dataset reads the observations, with dimension codes and labels, from a separate endpoint.";
|
|
39
|
+
readonly thrownBy: "service";
|
|
40
|
+
}]>;
|
|
28
41
|
//# sourceMappingURL=eurostat-dataset.resource.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurostat-dataset.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/eurostat-dataset.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"eurostat-dataset.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/eurostat-dataset.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6FlC,CAAC"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @module mcp-server/resources/definitions/eurostat-dataset.resource
|
|
4
4
|
*/
|
|
5
5
|
import { resource, z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
6
7
|
import { getEurostatDataService } from '../../../services/eurostat-data/eurostat-data-service.js';
|
|
7
8
|
export const eurostatDatasetResource = resource('eurostat://dataset/{dataset_code}', {
|
|
8
9
|
name: 'eurostat-dataset-info',
|
|
@@ -59,6 +60,22 @@ export const eurostatDatasetResource = resource('eurostat://dataset/{dataset_cod
|
|
|
59
60
|
.describe('ISO 8601 timestamp of last data update. Omitted when Eurostat does not report it.'),
|
|
60
61
|
metadataUrl: z.string().optional().describe('Link to ESMS metadata page, when available.'),
|
|
61
62
|
}),
|
|
63
|
+
errors: [
|
|
64
|
+
{
|
|
65
|
+
reason: 'not_found',
|
|
66
|
+
code: JsonRpcErrorCode.NotFound,
|
|
67
|
+
when: 'The dataset code does not exist or is not available for dissemination.',
|
|
68
|
+
recovery: 'Use eurostat_search_datasets or eurostat_browse_themes to find a valid dataset code.',
|
|
69
|
+
thrownBy: 'service',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
reason: 'upstream_fault',
|
|
73
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
74
|
+
when: "Eurostat returned a dataset structure or content constraint this server cannot read — malformed, truncated, not XML, or missing the requested dataset's dataflow; the structure endpoint answered HTTP 501, which is not retried; or it answered another HTTP 5xx or could not be reached on every retry, which the error marks retryable.",
|
|
75
|
+
recovery: 'Retry in a few minutes, since a failed structure read is not cached. If it fails the same way, eurostat_query_dataset reads the observations, with dimension codes and labels, from a separate endpoint.',
|
|
76
|
+
thrownBy: 'service',
|
|
77
|
+
},
|
|
78
|
+
],
|
|
62
79
|
handler(params, ctx) {
|
|
63
80
|
const svc = getEurostatDataService();
|
|
64
81
|
return svc.getDatasetInfo(params.dataset_code, ctx);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurostat-dataset.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/eurostat-dataset.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mDAAmD,CAAC;AAE3F,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC,mCAAmC,EAAE;IACnF,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,2VAA2V;IAC7V,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,CAAC,6EAA6E,CAAC;KAC3F,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;QAC1C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QAC3D,UAAU,EAAE,CAAC;aACV,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAC5C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAC7C,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,gLAAgL,CACjL;YACH,YAAY,EAAE,CAAC;iBACZ,KAAK,CACJ,CAAC;iBACE,MAAM,CAAC;gBACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;gBACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;aAC3C,CAAC;iBACD,QAAQ,CAAC,wCAAwC,CAAC,CACtD;iBACA,QAAQ,EAAE;iBACV,QAAQ,CACP,wIAAwI,CACzI;SACJ,CAAC;aACD,QAAQ,CAAC,4CAA4C,CAAC,CAC1D;aACA,QAAQ,CAAC,qBAAqB,CAAC;QAClC,SAAS,EAAE,CAAC;aACT,MAAM,CAAC;YACN,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,sEAAsE,CAAC;YACnF,GAAG,EAAE,CAAC;iBACH,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,yEAAyE,CAAC;SACvF,CAAC;aACD,QAAQ,CACP,gIAAgI,CACjI;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,iHAAiH,CAClH;QACH,WAAW,EAAE,CAAC;aACX,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,mFAAmF,CACpF;QACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;KAC3F,CAAC;
|
|
1
|
+
{"version":3,"file":"eurostat-dataset.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/eurostat-dataset.resource.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,7 +36,7 @@ export declare const eurostatBrowseThemes: import("@cyanheads/mcp-ts-core").Tool
|
|
|
36
36
|
}, {
|
|
37
37
|
readonly reason: "upstream_fault";
|
|
38
38
|
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
39
|
-
readonly when: "The server had no catalogue loaded yet, and Eurostat's table of contents answered HTTP 5xx or could not be reached on every retry, which the error marks retryable. Once a catalogue is loaded, a failed refresh serves that copy instead.";
|
|
39
|
+
readonly when: "The server had no catalogue loaded yet, and Eurostat's table of contents answered HTTP 501, which is not retried; or it answered another HTTP 5xx or could not be reached on every retry, which the error marks retryable. Once a catalogue is loaded, a failed refresh serves that copy instead.";
|
|
40
40
|
readonly recovery: "Retry in a few minutes: the catalogue load failed on Eurostat's side and runs again on the next call.";
|
|
41
41
|
}], {
|
|
42
42
|
readonly itemCount: z.ZodNumber;
|
|
@@ -91,7 +91,7 @@ export const eurostatBrowseThemes = tool('eurostat_browse_themes', {
|
|
|
91
91
|
{
|
|
92
92
|
reason: 'upstream_fault',
|
|
93
93
|
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
94
|
-
when: "The server had no catalogue loaded yet, and Eurostat's table of contents answered HTTP 5xx or could not be reached on every retry, which the error marks retryable. Once a catalogue is loaded, a failed refresh serves that copy instead.",
|
|
94
|
+
when: "The server had no catalogue loaded yet, and Eurostat's table of contents answered HTTP 501, which is not retried; or it answered another HTTP 5xx or could not be reached on every retry, which the error marks retryable. Once a catalogue is loaded, a failed refresh serves that copy instead.",
|
|
95
95
|
recovery: "Retry in a few minutes: the catalogue load failed on Eurostat's side and runs again on the next call.",
|
|
96
96
|
},
|
|
97
97
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurostat-browse-themes.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-browse-themes.tool.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"eurostat-browse-themes.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-browse-themes.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,6 +18,7 @@ export declare const createEurostatDownloadDataset: (clampLimits: boolean) => im
|
|
|
18
18
|
dimensionsUsed: z.ZodArray<z.ZodString>;
|
|
19
19
|
rowCount: z.ZodNumber;
|
|
20
20
|
missingCount: z.ZodNumber;
|
|
21
|
+
absentCellCount: z.ZodNumber;
|
|
21
22
|
periodRange: z.ZodObject<{
|
|
22
23
|
start: z.ZodOptional<z.ZodString>;
|
|
23
24
|
end: z.ZodOptional<z.ZodString>;
|
|
@@ -32,7 +33,7 @@ export declare const createEurostatDownloadDataset: (clampLimits: boolean) => im
|
|
|
32
33
|
}, z.core.$strip>, readonly [{
|
|
33
34
|
readonly reason: "byte_budget_exceeded";
|
|
34
35
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
35
|
-
readonly when: "The decoded TSV byte budget was exhausted before a complete header and usable
|
|
36
|
+
readonly when: "The decoded TSV byte budget was exhausted before a complete header and usable row could be read.";
|
|
36
37
|
readonly recovery: "Add dimension filters or narrow since_period/until_period to reduce the transfer, or raise EUROSTAT_BULK_MAX_BYTES.";
|
|
37
38
|
readonly thrownBy: "service";
|
|
38
39
|
}, {
|
|
@@ -68,7 +69,7 @@ export declare const createEurostatDownloadDataset: (clampLimits: boolean) => im
|
|
|
68
69
|
}, {
|
|
69
70
|
readonly reason: "no_results";
|
|
70
71
|
readonly code: JsonRpcErrorCode.NotFound;
|
|
71
|
-
readonly when: "The download completed but
|
|
72
|
+
readonly when: "The download completed but yielded no row: a header-only table, or a one-day reply whose only cells fall on the next day. Nothing is staged, and no canvas is created or touched. A table whose only rows are unflagged \":\" cells succeeds with those rows, with periodRange omitted.";
|
|
72
73
|
readonly recovery: "Verify the filter values with eurostat_get_dimension_values and keep since_period/until_period inside the series' coverage, holding a whole period — a combination that exists in no cell and a range that misses the series both download as an empty table.";
|
|
73
74
|
}, {
|
|
74
75
|
readonly reason: "extraction_too_big";
|
|
@@ -80,7 +81,7 @@ export declare const createEurostatDownloadDataset: (clampLimits: boolean) => im
|
|
|
80
81
|
}, {
|
|
81
82
|
readonly reason: "upstream_fault";
|
|
82
83
|
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
83
|
-
readonly when: "The SDMX data endpoint returned a fault this server does not model, or a body that is not a TSV table;
|
|
84
|
+
readonly when: "The SDMX data endpoint returned a fault this server does not model, or a body that is not a TSV table; for a filtered download, the structure endpoint returned a structure this server cannot build a filter key from; the data endpoint — or, for a filtered download, the structure endpoint — answered HTTP 501, which is not retried; or it answered another HTTP 5xx or could not be reached on every retry, which the error marks retryable.";
|
|
84
85
|
readonly recovery: "Retry in a few minutes, or narrow the request with dimension filters.";
|
|
85
86
|
readonly thrownBy: "service";
|
|
86
87
|
}, {
|
|
@@ -111,6 +112,7 @@ export declare const eurostatDownloadDataset: import("@cyanheads/mcp-ts-core").T
|
|
|
111
112
|
dimensionsUsed: z.ZodArray<z.ZodString>;
|
|
112
113
|
rowCount: z.ZodNumber;
|
|
113
114
|
missingCount: z.ZodNumber;
|
|
115
|
+
absentCellCount: z.ZodNumber;
|
|
114
116
|
periodRange: z.ZodObject<{
|
|
115
117
|
start: z.ZodOptional<z.ZodString>;
|
|
116
118
|
end: z.ZodOptional<z.ZodString>;
|
|
@@ -125,7 +127,7 @@ export declare const eurostatDownloadDataset: import("@cyanheads/mcp-ts-core").T
|
|
|
125
127
|
}, z.core.$strip>, readonly [{
|
|
126
128
|
readonly reason: "byte_budget_exceeded";
|
|
127
129
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
128
|
-
readonly when: "The decoded TSV byte budget was exhausted before a complete header and usable
|
|
130
|
+
readonly when: "The decoded TSV byte budget was exhausted before a complete header and usable row could be read.";
|
|
129
131
|
readonly recovery: "Add dimension filters or narrow since_period/until_period to reduce the transfer, or raise EUROSTAT_BULK_MAX_BYTES.";
|
|
130
132
|
readonly thrownBy: "service";
|
|
131
133
|
}, {
|
|
@@ -161,7 +163,7 @@ export declare const eurostatDownloadDataset: import("@cyanheads/mcp-ts-core").T
|
|
|
161
163
|
}, {
|
|
162
164
|
readonly reason: "no_results";
|
|
163
165
|
readonly code: JsonRpcErrorCode.NotFound;
|
|
164
|
-
readonly when: "The download completed but
|
|
166
|
+
readonly when: "The download completed but yielded no row: a header-only table, or a one-day reply whose only cells fall on the next day. Nothing is staged, and no canvas is created or touched. A table whose only rows are unflagged \":\" cells succeeds with those rows, with periodRange omitted.";
|
|
165
167
|
readonly recovery: "Verify the filter values with eurostat_get_dimension_values and keep since_period/until_period inside the series' coverage, holding a whole period — a combination that exists in no cell and a range that misses the series both download as an empty table.";
|
|
166
168
|
}, {
|
|
167
169
|
readonly reason: "extraction_too_big";
|
|
@@ -173,7 +175,7 @@ export declare const eurostatDownloadDataset: import("@cyanheads/mcp-ts-core").T
|
|
|
173
175
|
}, {
|
|
174
176
|
readonly reason: "upstream_fault";
|
|
175
177
|
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
176
|
-
readonly when: "The SDMX data endpoint returned a fault this server does not model, or a body that is not a TSV table;
|
|
178
|
+
readonly when: "The SDMX data endpoint returned a fault this server does not model, or a body that is not a TSV table; for a filtered download, the structure endpoint returned a structure this server cannot build a filter key from; the data endpoint — or, for a filtered download, the structure endpoint — answered HTTP 501, which is not retried; or it answered another HTTP 5xx or could not be reached on every retry, which the error marks retryable.";
|
|
177
179
|
readonly recovery: "Retry in a few minutes, or narrow the request with dimension filters.";
|
|
178
180
|
readonly thrownBy: "service";
|
|
179
181
|
}, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurostat-download-dataset.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-download-dataset.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAiB,MAAM,+BAA+B,CAAC;AAoDhF,+DAA+D;AAC/D,eAAO,MAAM,6BAA6B,gBAAiB,OAAO
|
|
1
|
+
{"version":3,"file":"eurostat-download-dataset.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurostat-download-dataset.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAiB,MAAM,+BAA+B,CAAC;AAoDhF,+DAA+D;AAC/D,eAAO,MAAM,6BAA6B,gBAAiB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8hB9D,CAAC;AAEL,sFAAsF;AACtF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAsC,CAAC"}
|
|
@@ -39,7 +39,7 @@ async function* prepend(first, rest) {
|
|
|
39
39
|
/** Selects the advertised limit policy before registration. */
|
|
40
40
|
export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_download_dataset', {
|
|
41
41
|
title: 'Download Eurostat Dataset',
|
|
42
|
-
description: 'Download a Eurostat dataset in bulk through the SDMX 2.1 TSV endpoint and stage
|
|
42
|
+
description: 'Download a Eurostat dataset in bulk through the SDMX 2.1 TSV endpoint and stage it as a SQL table on the dataframe canvas — the route to a whole dataset, where eurostat_query_dataset is the route to a slice of one. The TSV wire format is roughly half the bytes of the JSON-stat body eurostat_query_dataset reads, so it reaches datasets that would otherwise time out, and it is expanded here into one row per non-blank TSV cell, including the unflagged ":" cells that mark a period a series lacks or a period of a frequency it has no observation of. Filters take the same dimension-code map eurostat_query_dataset uses and are applied server-side by Eurostat; call eurostat_get_dataset_info first for the dimension codes and eurostat_get_dimension_values for their values. Narrow with since_period/until_period rather than asking for the most recent N periods — the TSV layout keeps a column for every period whichever is requested, so a period range is what actually shrinks the response. Transfers are bounded by a decoded-byte budget enforced while streaming: complete rows within the allowed prefix are retained with budgetExceeded set; a budget too small for a usable row fails as byte_budget_exceeded with narrowing guidance. Only preview_limit rows come back inline. When a table is staged, call eurostat_dataframe_describe first to confirm its columns, then eurostat_dataframe_query; without a canvas, rows past the preview are not retained.',
|
|
43
43
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
44
44
|
input: z.object({
|
|
45
45
|
dataset_code: z
|
|
@@ -62,8 +62,8 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
62
62
|
? z.number().multipleOf(1).min(1)
|
|
63
63
|
: z.number().int().min(1).max(PREVIEW_MAX))
|
|
64
64
|
.default(25)
|
|
65
|
-
.describe(`How many
|
|
66
|
-
canvas_id: CanvasIdSchema.optional().describe('Reuse an existing dataframe canvas so this download lands beside earlier results and can be joined against them. Pass the canvasId a previous eurostat_download_dataset or eurostat_query_dataset response returned; omit to start a fresh canvas. Ignored on deployments without a dataframe canvas. A download that
|
|
65
|
+
.describe(`How many rows to echo inline, from the start of the download. Default 25; ${clampLimits ? 'positive integers above 500 are clamped to 500 with a notice' : 'maximum 500; larger values are rejected'}. The full download is on the canvas table when one was staged; this is orientation, not the result set.`),
|
|
66
|
+
canvas_id: CanvasIdSchema.optional().describe('Reuse an existing dataframe canvas so this download lands beside earlier results and can be joined against them. Pass the canvasId a previous eurostat_download_dataset or eurostat_query_dataset response returned; omit to start a fresh canvas. Ignored on deployments without a dataframe canvas. A download that yields no row (a header-only table) fails as no_results and leaves the canvas untouched.'),
|
|
67
67
|
}),
|
|
68
68
|
output: z.object({
|
|
69
69
|
datasetCode: z.string().describe('Dataset code as provided.'),
|
|
@@ -72,22 +72,25 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
72
72
|
.describe('Dimension codes carried by the downloaded rows, in the order Eurostat keys them (e.g., ["freq", "unit", "na_item", "geo"]). Read from the TSV header, so it reflects the response rather than metadata. The period lives in the separate "time" column.'),
|
|
73
73
|
rowCount: z
|
|
74
74
|
.number()
|
|
75
|
-
.describe('
|
|
75
|
+
.describe('Rows expanded from the download, one per non-blank cell. A row carrying a value, a flag, a status or a text value is an observation, a flagged ":" (a value Eurostat reports as unavailable) included. A row holding an unflagged ":" — obs_value null with no flag, status or text — is not: it is a period its series lacks (counted in absentCellCount when the series has an observation of that frequency) or a period of a frequency its series has no observation of.'),
|
|
76
76
|
missingCount: z
|
|
77
77
|
.number()
|
|
78
|
-
.describe('
|
|
78
|
+
.describe('Rows carrying no numeric value (obs_value is null): observations published without a number — a flagged ":" or a text value — and every unflagged ":" row, a period its series lacks or a period of a frequency its series has no observation of.'),
|
|
79
|
+
absentCellCount: z
|
|
80
|
+
.number()
|
|
81
|
+
.describe('Unflagged ":" rows — obs_value null with no flag, status or text — at a period of a frequency the same series carries in another downloaded row: periods that series lacks, where Eurostat publishes no observation. Unflagged rows at the periods of a frequency the series has no observation of (the padding of a mixed-frequency slice, or a series that is ":" throughout) are left out, and a flagged ":" or a text value is an observation, never counted. Part of rowCount and missingCount, and counted over the rows downloaded, so a budget-cut download counts its prefix.'),
|
|
79
82
|
periodRange: z
|
|
80
83
|
.object({
|
|
81
84
|
start: z
|
|
82
85
|
.string()
|
|
83
86
|
.optional()
|
|
84
|
-
.describe('Earliest period carrying an observation. Omitted when
|
|
87
|
+
.describe('Earliest period of a row carrying an observation — a value, a flag, a status or a text value; an unflagged ":" row sets no bound. Omitted, with the other bound, when no row carries an observation.'),
|
|
85
88
|
end: z
|
|
86
89
|
.string()
|
|
87
90
|
.optional()
|
|
88
|
-
.describe('Latest period carrying an observation. Omitted when
|
|
91
|
+
.describe('Latest period of a row carrying an observation, read the same way as start. Omitted, with the other bound, when no row carries an observation.'),
|
|
89
92
|
})
|
|
90
|
-
.describe('Period coverage of the
|
|
93
|
+
.describe('Period coverage of the observations actually downloaded. Narrower than the dataset when budgetExceeded is true or a period range was applied.'),
|
|
91
94
|
bytesRead: z
|
|
92
95
|
.number()
|
|
93
96
|
.describe('Decoded TSV bytes accepted for parsing, after decompression when applicable; never more than EUROSTAT_BULK_MAX_BYTES, including an incomplete trailing line that is discarded.'),
|
|
@@ -100,8 +103,8 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
100
103
|
observations: z
|
|
101
104
|
.array(z
|
|
102
105
|
.record(z.string(), z.union([z.string(), z.number(), z.null()]))
|
|
103
|
-
.describe('One
|
|
104
|
-
.describe('The first preview_limit
|
|
106
|
+
.describe('One downloaded row: one column per dimension holding its code, "time" for the period, then obs_value, obs_flag, obs_flag_label, conf_status, conf_status_label. A label column is null when Eurostat publishes no label for that code. Rows of a DS-* dataset also carry obs_value_text after obs_value: a value Eurostat published as text, such as a PRODCOM quantity unit ("KG"), kept verbatim with obs_value null; a PRODCOM ":C" arrives as conf_status "C" instead.'))
|
|
107
|
+
.describe('The first preview_limit rows of the download, in the order Eurostat streamed them. A prefix of the staged table, not a sample.'),
|
|
105
108
|
canvasId: z
|
|
106
109
|
.string()
|
|
107
110
|
.optional()
|
|
@@ -109,7 +112,7 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
109
112
|
tableName: z
|
|
110
113
|
.string()
|
|
111
114
|
.optional()
|
|
112
|
-
.describe('Canvas table holding every downloaded
|
|
115
|
+
.describe('Canvas table holding every downloaded row. Call eurostat_dataframe_describe with canvasId first to confirm the table and columns, then eurostat_dataframe_query. Omitted when this deployment runs without a dataframe canvas, in which case only the inline preview survives the call.'),
|
|
113
116
|
stagedRowCount: z
|
|
114
117
|
.number()
|
|
115
118
|
.optional()
|
|
@@ -118,7 +121,7 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
118
121
|
enrichment: {
|
|
119
122
|
totalCount: z
|
|
120
123
|
.number()
|
|
121
|
-
.describe('
|
|
124
|
+
.describe('Rows the download produced — equal to rowCount, unflagged ":" rows included: a period their series lacks (absentCellCount) or a period of a frequency their series has no observation of. The inline observations array holds only the first preview_limit of them; budgetExceeded, not this count, says whether the download is the whole dataset.'),
|
|
122
125
|
appliedQuery: z
|
|
123
126
|
.object({
|
|
124
127
|
filters: z
|
|
@@ -134,7 +137,7 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
134
137
|
notice: z
|
|
135
138
|
.string()
|
|
136
139
|
.optional()
|
|
137
|
-
.describe('Guidance on every download: the staged table with the required eurostat_dataframe_describe then eurostat_dataframe_query sequence (or, without a canvas, what was returned inline and what was discarded), preceded by a period a bound falls inside when the TSV header shows that frequency, by byte-budget disclosure when the budget stopped the transfer, and by the inline-preview length when preview_limit returns fewer rows than were downloaded.'),
|
|
140
|
+
.describe('Guidance on every download: the staged table with the required eurostat_dataframe_describe then eurostat_dataframe_query sequence (or, without a canvas, what was returned inline and what was discarded), preceded by a period a bound falls inside when the TSV header shows that frequency, by byte-budget disclosure when the budget stopped the transfer, by what the unflagged ":" rows are when a series lacks periods or the slice mixes frequencies, and by the inline-preview length when preview_limit returns fewer rows than were downloaded.'),
|
|
138
141
|
},
|
|
139
142
|
enrichmentTrailer: {
|
|
140
143
|
appliedQuery: {
|
|
@@ -156,7 +159,7 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
156
159
|
{
|
|
157
160
|
reason: 'byte_budget_exceeded',
|
|
158
161
|
code: JsonRpcErrorCode.ValidationError,
|
|
159
|
-
when: 'The decoded TSV byte budget was exhausted before a complete header and usable
|
|
162
|
+
when: 'The decoded TSV byte budget was exhausted before a complete header and usable row could be read.',
|
|
160
163
|
recovery: 'Add dimension filters or narrow since_period/until_period to reduce the transfer, or raise EUROSTAT_BULK_MAX_BYTES.',
|
|
161
164
|
thrownBy: 'service',
|
|
162
165
|
},
|
|
@@ -198,7 +201,7 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
198
201
|
{
|
|
199
202
|
reason: 'no_results',
|
|
200
203
|
code: JsonRpcErrorCode.NotFound,
|
|
201
|
-
when: 'The download completed but
|
|
204
|
+
when: 'The download completed but yielded no row: a header-only table, or a one-day reply whose only cells fall on the next day. Nothing is staged, and no canvas is created or touched. A table whose only rows are unflagged ":" cells succeeds with those rows, with periodRange omitted.',
|
|
202
205
|
recovery: "Verify the filter values with eurostat_get_dimension_values and keep since_period/until_period inside the series' coverage, holding a whole period — a combination that exists in no cell and a range that misses the series both download as an empty table.",
|
|
203
206
|
},
|
|
204
207
|
{
|
|
@@ -212,7 +215,7 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
212
215
|
{
|
|
213
216
|
reason: 'upstream_fault',
|
|
214
217
|
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
215
|
-
when: 'The SDMX data endpoint returned a fault this server does not model, or a body that is not a TSV table;
|
|
218
|
+
when: 'The SDMX data endpoint returned a fault this server does not model, or a body that is not a TSV table; for a filtered download, the structure endpoint returned a structure this server cannot build a filter key from; the data endpoint — or, for a filtered download, the structure endpoint — answered HTTP 501, which is not retried; or it answered another HTTP 5xx or could not be reached on every retry, which the error marks retryable.',
|
|
216
219
|
recovery: 'Retry in a few minutes, or narrow the request with dimension filters.',
|
|
217
220
|
thrownBy: 'service',
|
|
218
221
|
},
|
|
@@ -296,7 +299,7 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
296
299
|
...(sinceP ? [`since_period "${sinceP}"`] : []),
|
|
297
300
|
...(untilP ? [`until_period "${untilP}"`] : []),
|
|
298
301
|
].join(' and ');
|
|
299
|
-
throw ctx.fail('no_results', `The download of "${input.dataset_code}"
|
|
302
|
+
throw ctx.fail('no_results', `The download of "${input.dataset_code}" yielded no row.`, {
|
|
300
303
|
recovery: {
|
|
301
304
|
hint: `Eurostat returned a table with no populated cells for "${input.dataset_code}". Verify the filter values with eurostat_get_dimension_values — a combination present in no cell downloads as an empty body.${range
|
|
302
305
|
? ` Also check that ${range} overlaps the series and holds a whole period of it: Eurostat keeps only periods wholly inside the range, so a range outside the series' own coverage or inside one period downloads as an empty table too.`
|
|
@@ -367,18 +370,32 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
367
370
|
*/
|
|
368
371
|
ctx.enrich.total(stats.rowCount);
|
|
369
372
|
const notices = previewLimit.notice ? [previewLimit.notice] : [];
|
|
373
|
+
// The header is the only frequency signal: it shows a frequency only when a period
|
|
374
|
+
// of it is in range, so one it hides gets no notice. No coverage reaches the TSV.
|
|
375
|
+
const frequencies = frequenciesOf(download.header.periods);
|
|
370
376
|
if (sinceP || untilP) {
|
|
371
|
-
|
|
372
|
-
// of it is in range, so one it hides gets no notice. No coverage reaches the TSV.
|
|
373
|
-
const cuts = periodCuts({ since_period: sinceP, until_period: untilP }, frequenciesOf(download.header.periods));
|
|
377
|
+
const cuts = periodCuts({ since_period: sinceP, until_period: untilP }, frequencies);
|
|
374
378
|
if (cuts.length > 0)
|
|
375
379
|
notices.push(cutNotice(cuts, written));
|
|
376
380
|
}
|
|
377
381
|
if (stats.budgetExceeded) {
|
|
378
|
-
notices.push(`The byte budget stopped this transfer after ${stats.bytesRead.toLocaleString()} bytes, so these ${stats.rowCount.toLocaleString()}
|
|
382
|
+
notices.push(`The byte budget stopped this transfer after ${stats.bytesRead.toLocaleString()} bytes, so these ${stats.rowCount.toLocaleString()} rows are the start of "${input.dataset_code}" and not all of it. Add dimension filters or a since_period/until_period range to fit the dataset inside the budget, or raise EUROSTAT_BULK_MAX_BYTES.`);
|
|
383
|
+
}
|
|
384
|
+
if (stats.absentCellCount > 0) {
|
|
385
|
+
notices.push(`${stats.absentCellCount.toLocaleString()} of the ${stats.rowCount.toLocaleString()} downloaded rows (absentCellCount) ${stats.absentCellCount === 1
|
|
386
|
+
? 'is a period its series lacks, not an observation: an unflagged ":" cell'
|
|
387
|
+
: 'are periods their series lacks, not observations: unflagged ":" cells'}, obs_value null with no flag, status or text.`);
|
|
388
|
+
}
|
|
389
|
+
if (stats.periodsSeen.length === 0) {
|
|
390
|
+
notices.push(`No downloaded row carries an observation: ${stats.rowCount === 1
|
|
391
|
+
? 'the row is an unflagged ":" cell'
|
|
392
|
+
: `all ${stats.rowCount.toLocaleString()} rows are unflagged ":" cells`} (obs_value null with no flag, status or text), so periodRange has no bound.`);
|
|
393
|
+
}
|
|
394
|
+
if (frequencies.size > 1) {
|
|
395
|
+
notices.push('Frequencies are mixed in this slice, and the TSV gives every series a column for each period of each frequency, so a series also holds unflagged ":" rows (obs_value null with no flag, status or text) at the periods of a frequency it does not carry: they are not observations, and absentCellCount leaves them out.');
|
|
379
396
|
}
|
|
380
397
|
if (stats.rowCount > preview.length) {
|
|
381
|
-
notices.push(`preview_limit=${input.preview_limit.toLocaleString()} returns the first ${preview.length.toLocaleString()} of ${stats.rowCount.toLocaleString()} downloaded
|
|
398
|
+
notices.push(`preview_limit=${input.preview_limit.toLocaleString()} returns the first ${preview.length.toLocaleString()} of ${stats.rowCount.toLocaleString()} downloaded rows inline; it does not reduce the download.`);
|
|
382
399
|
}
|
|
383
400
|
if (!staged) {
|
|
384
401
|
/**
|
|
@@ -388,13 +405,13 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
388
405
|
*/
|
|
389
406
|
const discarded = stats.rowCount - preview.length;
|
|
390
407
|
notices.push(discarded === 0
|
|
391
|
-
? `This deployment runs without a dataframe canvas, so nothing was staged; all ${stats.rowCount.toLocaleString()} downloaded
|
|
392
|
-
: `This deployment runs without a dataframe canvas, so nothing was staged: only the ${preview.length.toLocaleString()}
|
|
408
|
+
? `This deployment runs without a dataframe canvas, so nothing was staged; all ${stats.rowCount.toLocaleString()} downloaded rows are returned inline.`
|
|
409
|
+
: `This deployment runs without a dataframe canvas, so nothing was staged: only the ${preview.length.toLocaleString()} rows returned inline are retained, and the other ${discarded.toLocaleString()} were counted and discarded. ${stats.rowCount <= PREVIEW_MAX
|
|
393
410
|
? `Raise preview_limit to ${stats.rowCount.toLocaleString()} to return every one inline, or set CANVAS_PROVIDER_TYPE=duckdb to keep the download.`
|
|
394
411
|
: 'Set CANVAS_PROVIDER_TYPE=duckdb to keep the download, or use eurostat_query_dataset with dimension filters to fetch a slice small enough to return whole.'}`);
|
|
395
412
|
}
|
|
396
413
|
else {
|
|
397
|
-
notices.push(`All ${staged.stagedRowCount.toLocaleString()} downloaded
|
|
414
|
+
notices.push(`All ${staged.stagedRowCount.toLocaleString()} downloaded rows are staged as table "${staged.tableName}" on canvas "${staged.canvasId}". Call eurostat_dataframe_describe with that canvas_id first to confirm the table and columns, then call eurostat_dataframe_query.`);
|
|
398
415
|
}
|
|
399
416
|
ctx.enrich.notice(notices.join(' '));
|
|
400
417
|
return {
|
|
@@ -402,6 +419,7 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
402
419
|
dimensionsUsed: download.header.dimensions,
|
|
403
420
|
rowCount: stats.rowCount,
|
|
404
421
|
missingCount: stats.missingCount,
|
|
422
|
+
absentCellCount: stats.absentCellCount,
|
|
405
423
|
periodRange: {
|
|
406
424
|
...(firstPeriod && { start: firstPeriod }),
|
|
407
425
|
...(lastPeriod && { end: lastPeriod }),
|
|
@@ -415,18 +433,17 @@ export const createEurostatDownloadDataset = (clampLimits) => tool('eurostat_dow
|
|
|
415
433
|
},
|
|
416
434
|
format: (result) => {
|
|
417
435
|
const { start, end } = result.periodRange;
|
|
418
|
-
const
|
|
419
|
-
const period = start || end ? `${start ?? UNREPORTED} – ${end ?? UNREPORTED}` : UNREPORTED;
|
|
436
|
+
const period = start && end ? `${start} – ${end}` : 'none — no row carries an observation';
|
|
420
437
|
const lines = [
|
|
421
438
|
`# Bulk download \`${result.datasetCode}\``,
|
|
422
|
-
`**
|
|
439
|
+
`**Rows:** ${result.rowCount} (${result.missingCount} missing) | **Absent cells:** ${result.absentCellCount} | **Period:** ${period}`,
|
|
423
440
|
`**Dimensions:** ${result.dimensionsUsed.join(', ')}`,
|
|
424
441
|
`**Transfer:** ${result.bytesRead} bytes decoded | **Compressed:** ${result.compressed} | **Budget exceeded:** ${result.budgetExceeded}${result.budgetExceeded ? ' — these rows are the start of the dataset, not all of it' : ''}`,
|
|
425
442
|
];
|
|
426
443
|
lines.push(result.tableName
|
|
427
444
|
? `**Staged:** table \`${result.tableName}\` on canvas \`${result.canvasId}\` (stagedRowCount ${result.stagedRowCount}) — inspect it with eurostat_dataframe_describe first, then query it with eurostat_dataframe_query`
|
|
428
445
|
: '**Staged:** nothing — this deployment runs without a dataframe canvas, so only the rows below are retained');
|
|
429
|
-
lines.push('', `## First ${result.observations.length} observations`);
|
|
446
|
+
lines.push('', `## First ${result.observations.length} rows (\`observations\`)`);
|
|
430
447
|
// dimensionsUsed leaves out the period column, which hoists like any other dimension.
|
|
431
448
|
// The value and flag columns are not candidates, so they stay on every row.
|
|
432
449
|
const { header, hoisted } = hoistDimensions(result.observations, [...result.dimensionsUsed, TIME_COLUMN], (row, col) => (row[col] == null ? undefined : `${col}=${row[col]}`));
|
|
@@ -455,7 +472,8 @@ export const eurostatDownloadDataset = createEurostatDownloadDataset(true);
|
|
|
455
472
|
* `request.dimensions` is the dataset's dimension list, when known, and
|
|
456
473
|
* `request.filtered` the dimensions the request already filtered — together they let
|
|
457
474
|
* a too-large refusal name the dimensions still open to filter. `request.endpoint` is
|
|
458
|
-
* the endpoint the failed read went to
|
|
475
|
+
* the endpoint the failed read went to: each `upstream_fault` hint names it, and on the
|
|
476
|
+
* structure read a fault with no HTTP status is a structure the order cannot be read from.
|
|
459
477
|
*/
|
|
460
478
|
function mapBulkFailure(err, datasetCode, request) {
|
|
461
479
|
const data = err.data;
|
|
@@ -514,6 +532,24 @@ function mapBulkFailure(err, datasetCode, request) {
|
|
|
514
532
|
: `Eurostat's SDMX data endpoint ${answer} for "${datasetCode}" on every attempt — an upstream outage, not a fault in the request. Retry in a few minutes.`,
|
|
515
533
|
};
|
|
516
534
|
}
|
|
535
|
+
// An HTTP status the fetch layer does not retry (a 501): an answer, not a body to read.
|
|
536
|
+
if (typeof data?.status === 'number') {
|
|
537
|
+
return {
|
|
538
|
+
reason,
|
|
539
|
+
message,
|
|
540
|
+
hint: request.endpoint === 'structure'
|
|
541
|
+
? `Eurostat's SDMX structure endpoint answered HTTP ${data.status} for "${datasetCode}", a status this server does not retry on its own, so the dimension order a filtered download needs could not be read. Retry in a few minutes. If it fails the same way, eurostat_query_dataset takes the same filters through the Statistics API, which does not depend on this structure, and a download without filters skips the read.`
|
|
542
|
+
: `Eurostat's SDMX data endpoint answered HTTP ${data.status} for "${datasetCode}", a status this server does not retry on its own. Retry in a few minutes. If it fails the same way, eurostat_query_dataset reads the observations through the Statistics API, a separate endpoint, for a slice small enough to return.`,
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
// The structure read answered, but with no dimension order to key a filter on.
|
|
546
|
+
if (request.endpoint === 'structure') {
|
|
547
|
+
return {
|
|
548
|
+
reason,
|
|
549
|
+
message,
|
|
550
|
+
hint: `Eurostat returned a structure definition for "${datasetCode}" that this server cannot build a positional filter key from, so the filtered download was not sent. Retry in a few minutes. If it fails the same way, eurostat_query_dataset takes the same filters through the Statistics API, which does not depend on this structure, and a download without filters skips the read.`,
|
|
551
|
+
};
|
|
552
|
+
}
|
|
517
553
|
return {
|
|
518
554
|
reason,
|
|
519
555
|
message,
|