@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.
Files changed (56) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/README.md +8 -7
  4. package/changelog/0.11.x/0.11.2.md +27 -0
  5. package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.d.ts +14 -1
  6. package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.d.ts.map +1 -1
  7. package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.js +17 -0
  8. package/dist/mcp-server/resources/definitions/eurostat-dataset.resource.js.map +1 -1
  9. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.d.ts +1 -1
  10. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.js +1 -1
  11. package/dist/mcp-server/tools/definitions/eurostat-browse-themes.tool.js.map +1 -1
  12. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.d.ts +8 -6
  13. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.d.ts.map +1 -1
  14. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js +66 -30
  15. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js.map +1 -1
  16. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.d.ts +1 -1
  17. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.d.ts.map +1 -1
  18. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js +10 -1
  19. package/dist/mcp-server/tools/definitions/eurostat-get-dataset-info.tool.js.map +1 -1
  20. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.d.ts +2 -2
  21. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.d.ts.map +1 -1
  22. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js +10 -1
  23. package/dist/mcp-server/tools/definitions/eurostat-get-dimension-values.tool.js.map +1 -1
  24. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts +2 -0
  25. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts.map +1 -1
  26. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js +11 -4
  27. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js.map +1 -1
  28. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.d.ts +4 -4
  29. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.d.ts.map +1 -1
  30. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.js +18 -6
  31. package/dist/mcp-server/tools/definitions/eurostat-search-datasets.tool.js.map +1 -1
  32. package/dist/services/eurostat-bulk/eurostat-bulk-service.d.ts +5 -4
  33. package/dist/services/eurostat-bulk/eurostat-bulk-service.d.ts.map +1 -1
  34. package/dist/services/eurostat-bulk/eurostat-bulk-service.js +66 -14
  35. package/dist/services/eurostat-bulk/eurostat-bulk-service.js.map +1 -1
  36. package/dist/services/eurostat-bulk/types.d.ts +21 -4
  37. package/dist/services/eurostat-bulk/types.d.ts.map +1 -1
  38. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts +14 -8
  39. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts.map +1 -1
  40. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js +34 -17
  41. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js.map +1 -1
  42. package/dist/services/eurostat-codelists.d.ts +2 -1
  43. package/dist/services/eurostat-codelists.d.ts.map +1 -1
  44. package/dist/services/eurostat-codelists.js +2 -1
  45. package/dist/services/eurostat-codelists.js.map +1 -1
  46. package/dist/services/eurostat-data/eurostat-data-service.d.ts +7 -0
  47. package/dist/services/eurostat-data/eurostat-data-service.d.ts.map +1 -1
  48. package/dist/services/eurostat-data/eurostat-data-service.js +84 -10
  49. package/dist/services/eurostat-data/eurostat-data-service.js.map +1 -1
  50. package/dist/services/eurostat-data/types.d.ts +17 -3
  51. package/dist/services/eurostat-data/types.d.ts.map +1 -1
  52. package/dist/services/eurostat-data/types.js.map +1 -1
  53. package/package.json +4 -4
  54. package/server.json +3 -3
  55. package/skills/eurostat-guide/SKILL.md +2 -1
  56. 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.1
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.1
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
- [![Version](https://img.shields.io/badge/Version-0.11.1-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/eurostat-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.4.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/eurostat-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/eurostat-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.4.4-blueviolet.svg?style=flat-square)](https://bun.sh/)
10
+ [![Version](https://img.shields.io/badge/Version-0.11.2-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/eurostat-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.4.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/eurostat-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/eurostat-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.4.4-blueviolet.svg?style=flat-square)](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 observation on the dataframe canvas |
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
- - 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`
112
- - 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.
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`, and `retryable` on an outage
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>, undefined>;
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;AAGrD,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;6BA2ElC,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;IAEF,OAAO,CAAC,MAAM,EAAE,GAAG;QACjB,MAAM,GAAG,GAAG,sBAAsB,EAAE,CAAC;QACrC,OAAO,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;CACF,CAAC,CAAC"}
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 observation could be read.";
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 carried no populated observation cells. Nothing is staged, and no canvas is created or touched.";
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; or the data endpoint — or, for a filtered download, the structure endpoint — answered HTTP 5xx or could not be reached on every retry, which the error marks retryable.";
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 observation could be read.";
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 carried no populated observation cells. Nothing is staged, and no canvas is created or touched.";
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; or the data endpoint — or, for a filtered download, the structure endpoint — answered HTTP 5xx or could not be reached on every retry, which the error marks retryable.";
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsgB9D,CAAC;AAEL,sFAAsF;AACtF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAsC,CAAC"}
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 every observation 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 observation. 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 observations within the allowed prefix are retained with budgetExceeded set; a budget too small for a usable observation 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.',
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 observations 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 carries no observations fails as no_results and leaves the canvas untouched.'),
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('Observations expanded from the download — one per populated cell, counting those Eurostat reports as unavailable.'),
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('Downloaded observations carrying no numeric value (obs_value is null).'),
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 nothing was downloaded.'),
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 nothing was downloaded.'),
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 rows actually downloaded. Narrower than the dataset when budgetExceeded is true or a period range was applied.'),
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 observation as a flat 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.'))
104
- .describe('The first preview_limit observations of the download, in the order Eurostat streamed them. A prefix of the staged table, not a sample.'),
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 observation. 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.'),
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('Observations the download produced — equal to rowCount. The inline observations array holds only the first preview_limit of them; budgetExceeded, not this count, says whether the download is the whole dataset.'),
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 observation could be read.',
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 carried no populated observation cells. Nothing is staged, and no canvas is created or touched.',
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; or the data endpoint — or, for a filtered download, the structure endpoint — answered HTTP 5xx or could not be reached on every retry, which the error marks retryable.',
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}" carried no observations.`, {
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
- // The header is the only frequency signal: it shows a frequency only when a period
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()} observations 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.`);
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 observations inline; it does not reduce the download.`);
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 observations are returned inline.`
392
- : `This deployment runs without a dataframe canvas, so nothing was staged: only the ${preview.length.toLocaleString()} observations returned inline are retained, and the other ${discarded.toLocaleString()} were counted and discarded. ${stats.rowCount <= PREVIEW_MAX
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 observations 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.`);
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 UNREPORTED = 'not reported by Eurostat';
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
- `**Observations:** ${result.rowCount} (${result.missingCount} missing) | **Period:** ${period}`,
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, which an outage hint names.
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,