@cyanheads/eurostat-mcp-server 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/AGENTS.md +386 -0
  2. package/CLAUDE.md +32 -9
  3. package/Dockerfile +5 -5
  4. package/README.md +6 -6
  5. package/changelog/0.1.x/0.1.0.md +20 -0
  6. package/changelog/0.1.x/0.1.1.md +21 -0
  7. package/changelog/0.1.x/0.1.10.md +24 -0
  8. package/changelog/0.1.x/0.1.11.md +15 -0
  9. package/changelog/0.1.x/0.1.12.md +28 -0
  10. package/changelog/0.1.x/0.1.13.md +20 -0
  11. package/changelog/0.1.x/0.1.14.md +38 -0
  12. package/changelog/0.1.x/0.1.15.md +13 -0
  13. package/changelog/0.1.x/0.1.16.md +36 -0
  14. package/changelog/0.1.x/0.1.2.md +17 -0
  15. package/changelog/0.1.x/0.1.3.md +12 -0
  16. package/changelog/0.1.x/0.1.4.md +17 -0
  17. package/changelog/0.1.x/0.1.5.md +11 -0
  18. package/changelog/0.1.x/0.1.6.md +14 -0
  19. package/changelog/0.1.x/0.1.7.md +16 -0
  20. package/changelog/0.1.x/0.1.8.md +19 -0
  21. package/changelog/0.1.x/0.1.9.md +20 -0
  22. package/changelog/0.2.x/0.2.0.md +29 -0
  23. package/changelog/0.3.x/0.3.0.md +17 -0
  24. package/changelog/0.4.x/0.4.0.md +24 -0
  25. package/changelog/0.5.x/0.5.0.md +20 -0
  26. package/changelog/0.6.x/0.6.0.md +20 -0
  27. package/changelog/0.6.x/0.6.1.md +30 -0
  28. package/changelog/template.md +168 -0
  29. package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.js +1 -1
  30. package/dist/mcp-server/tools/definitions/eurostat-dataframe-describe.tool.js.map +1 -1
  31. package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.js +1 -1
  32. package/dist/mcp-server/tools/definitions/eurostat-dataframe-query.tool.js.map +1 -1
  33. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.d.ts +3 -0
  34. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.d.ts.map +1 -1
  35. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js +9 -0
  36. package/dist/mcp-server/tools/definitions/eurostat-download-dataset.tool.js.map +1 -1
  37. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts +6 -2
  38. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.d.ts.map +1 -1
  39. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js +23 -11
  40. package/dist/mcp-server/tools/definitions/eurostat-query-dataset.tool.js.map +1 -1
  41. package/dist/services/eurostat-bulk/eurostat-bulk-service.d.ts.map +1 -1
  42. package/dist/services/eurostat-bulk/eurostat-bulk-service.js +3 -5
  43. package/dist/services/eurostat-bulk/eurostat-bulk-service.js.map +1 -1
  44. package/dist/services/eurostat-bulk/types.d.ts +3 -29
  45. package/dist/services/eurostat-bulk/types.d.ts.map +1 -1
  46. package/dist/services/eurostat-bulk/types.js +3 -76
  47. package/dist/services/eurostat-bulk/types.js.map +1 -1
  48. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.d.ts.map +1 -1
  49. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js +3 -6
  50. package/dist/services/eurostat-catalogue/eurostat-catalogue-service.js.map +1 -1
  51. package/dist/services/eurostat-codelists.d.ts +45 -0
  52. package/dist/services/eurostat-codelists.d.ts.map +1 -0
  53. package/dist/services/eurostat-codelists.js +92 -0
  54. package/dist/services/eurostat-codelists.js.map +1 -0
  55. package/dist/services/eurostat-data/eurostat-data-service.d.ts +36 -5
  56. package/dist/services/eurostat-data/eurostat-data-service.d.ts.map +1 -1
  57. package/dist/services/eurostat-data/eurostat-data-service.js +70 -19
  58. package/dist/services/eurostat-data/eurostat-data-service.js.map +1 -1
  59. package/dist/services/eurostat-data/types.d.ts +16 -8
  60. package/dist/services/eurostat-data/types.d.ts.map +1 -1
  61. package/dist/services/eurostat-data/types.js +0 -4
  62. package/dist/services/eurostat-data/types.js.map +1 -1
  63. package/package.json +20 -12
  64. package/server.json +3 -3
@@ -0,0 +1,21 @@
1
+ ---
2
+ summary: "First public release — 5 tools, 1 resource, full Eurostat implementation covering 8,900+ datasets and NUTS regional data"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.1 — 2026-05-23
8
+
9
+ ## Added
10
+
11
+ - **`eurostat_search_datasets`** — keyword search across 8,933 Eurostat datasets using a session-cached TOC TXT file
12
+ - **`eurostat_browse_themes`** — hierarchical navigation of the Eurostat theme tree (11 root themes)
13
+ - **`eurostat_get_dataset_info`** — dataset metadata: dimensions, valid values, time range, obs count, last-updated date
14
+ - **`eurostat_get_dimension_values`** — full value list for a specific dataset dimension; supports NUTS geo-level filtering
15
+ - **`eurostat_query_dataset`** — decoded JSON-stat 2.0 observations with dimension filters, NUTS geo-level, and time-range support
16
+ - **`eurostat://dataset/{dataset_code}`** resource — dataset metadata accessible by URI
17
+ - `EurostatCatalogueService` — fetches and parses the TOC TXT file with session-level in-memory cache
18
+ - `EurostatDataService` — Statistics API HTTP client with JSON-stat 2.0 stride decoder, async-response polling, and retry logic
19
+ - `EUROSTAT_BASE_URL` env var — override API base URL (default: `https://ec.europa.eu/eurostat/api/dissemination`)
20
+ - `EUROSTAT_REQUEST_TIMEOUT_MS` env var — HTTP request timeout in ms (default: `30000`)
21
+ - 37 tests across all tools and the dataset resource
@@ -0,0 +1,24 @@
1
+ ---
2
+ summary: "@cyanheads/mcp-ts-core ^0.9.16 → ^0.9.21 — per-request log context fix, secret-stripping in fetch errors, withRetry fail-fast; skill sync (api-mirror, orchestrations, 8 updated)"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.10 — 2026-06-02
8
+
9
+ ## Changed
10
+
11
+ - **`@cyanheads/mcp-ts-core`** `^0.9.16` → `^0.9.21` — adopts three framework fixes:
12
+ - Per-request logs and traces now carry fresh request + trace/span IDs instead of the frozen boot context (HTTP transport log context fix).
13
+ - **`fetchWithTimeout`** strips query-string secrets (e.g. `?api_key=`) from error messages and logs.
14
+ - **`withRetry`** fails fast on non-retryable errors; `ctx.fail` auto-populates the `retryable` flag.
15
+ - **Skills synced** — 8 updated (`add-tool`, `api-canvas`, `api-context`, `api-linter`, `api-utils`, `design-mcp-server`, `release-and-publish`, `add-service`); new `api-mirror` and `orchestrations` skills added.
16
+ - **`scripts/release-github.ts`** added — `bun run release:github` creates the GitHub Release from the latest annotated tag.
17
+ - **`scripts/devcheck.ts`** updated — consolidated devcheck script.
18
+ - **README client-config keys** renamed to full package name `eurostat-mcp-server` (was `eurostat`).
19
+
20
+ ## Dependencies
21
+
22
+ - `@cyanheads/mcp-ts-core` `^0.9.16` → `^0.9.21`
23
+ - `tsx` `^4.22.3` → `^4.22.4`
24
+ - `vitest` `^4.1.7` → `^4.1.8`
@@ -0,0 +1,15 @@
1
+ ---
2
+ summary: "Populate data.recovery.hint via ctx.fail in all four tool handlers — agents now get actionable next-step guidance on every declared error path"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.11 — 2026-06-04
8
+
9
+ ## Fixed
10
+
11
+ - **`eurostat_browse_themes`** — handler now catches `not_found` from the service and re-throws via `ctx.fail`, populating `data.recovery.hint` with navigation guidance back to root themes ([#10](https://github.com/cyanheads/eurostat-mcp-server/issues/10)).
12
+ - **`eurostat_get_dataset_info`** — handler catches `not_found` and `async_response` and re-throws via `ctx.fail` with contextual recovery hints (search suggestion; retry note for the unexpected async path) ([#10](https://github.com/cyanheads/eurostat-mcp-server/issues/10)).
13
+ - **`eurostat_get_dimension_values`** — handler catches `not_found` and re-throws via `ctx.fail` with a hint pointing to `eurostat_search_datasets` and `eurostat_get_dataset_info` ([#10](https://github.com/cyanheads/eurostat-mcp-server/issues/10)).
14
+ - **`eurostat_query_dataset`** — handler catches all four declared error reasons (`no_results`, `async_response`, `not_found`, `invalid_dimension`) and re-throws via `ctx.fail` with dataset-contextual recovery hints; `conflicting_params` continues to fall through ([#11](https://github.com/cyanheads/eurostat-mcp-server/issues/11)).
15
+ - **Tests** — updated and extended to assert `data.recovery.hint` is populated on every error path; added new test cases for `async_response` in `eurostat_get_dataset_info` and `invalid_dimension` in `eurostat_query_dataset`.
@@ -0,0 +1,28 @@
1
+ ---
2
+ summary: "Adopt @cyanheads/mcp-ts-core ^0.10.6: server identity name/title, Docker HEALTHCHECK + image.version label, bundle cleaner for dependency-shipped agent docs, packaging/antipattern lint additions."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.12 — 2026-06-15
8
+
9
+ ## Added
10
+
11
+ - **Server identity** — `createApp()` now sets `name` and `title` to `eurostat-mcp-server`, pinning the display identity to the unscoped repo name on every client surface ([core #213](https://github.com/cyanheads/mcp-ts-core/issues/213)).
12
+ - **`Dockerfile` `HEALTHCHECK`** — bun-native `fetch` against `/healthz` (slim image ships no curl/wget), plus `org.opencontainers.image.version` stamped from the `APP_VERSION` build arg.
13
+ - **`scripts/clean-mcpb.ts`** — post-pack step that strips dependency-shipped agent docs (`node_modules/**/skills/`, `.claude/`, `.agents/`, `SKILL.md`) from the `.mcpb` bundle; wired into the `bundle` script ([core #230](https://github.com/cyanheads/mcp-ts-core/issues/230)).
14
+
15
+ ## Changed
16
+
17
+ - **`@cyanheads/mcp-ts-core`** `^0.9.21` → `^0.10.6` — env booleans now parse via Zod `stringbool` (rejects values outside `true/false/1/0/yes/no/on/off`); DataCanvas SQL gate fails closed on non-SELECT and denies `pragma_*`/system-catalog table functions; wire-level elicitation + URL-mode elicitation; `outlineOnOverflow()` and `ctx.enrich.truncated()` utilities; `RootsRegistry` and the sampling surface removed. No server code depends on the removed surfaces.
18
+ - **`.mcpbignore`** — root dev-dir patterns anchored with `/` (`/skills/`, `/.agents/`, `/.claude/`) so they no longer also strip nested runtime paths like `node_modules/x/skills/` ([core #172](https://github.com/cyanheads/mcp-ts-core/issues/172), [#207](https://github.com/cyanheads/mcp-ts-core/issues/207)).
19
+ - **`scripts/lint-packaging.ts`** — adds bundle-content guards (unanchored-pattern and critical-runtime-path checks, post-bundle `node_modules` agent-doc scan) and an entrypoint identity check that `name`/`title` equal the unscoped package name ([core #230](https://github.com/cyanheads/mcp-ts-core/issues/230), [#231](https://github.com/cyanheads/mcp-ts-core/issues/231)).
20
+ - **`scripts/check-framework-antipatterns.ts`** — adds the `coerce-boolean-env-flag` rule flagging `z.coerce.boolean()` on env flags (use `z.stringbool()`), and skips comment-line matches.
21
+ - **Skills** — re-synced from the framework; adds the `techniques` skill (outline-on-overflow pattern catalog).
22
+
23
+ ## Dependencies
24
+
25
+ - `@biomejs/biome` `^2.4.16` → `^2.5.0`
26
+ - `@types/node` `^25.9.1` → `^25.9.3`
27
+ - `tsx` `^4.22.3` → `^4.22.4`
28
+ - `vitest` `^4.1.8` → `^4.1.9`
@@ -0,0 +1,20 @@
1
+ ---
2
+ summary: "Adopt @cyanheads/mcp-ts-core ^0.10.9: DataCanvas describe() binder-error fix, SQL-gate invalid_sql classification, ctx.content collector, two new devcheck guards (dependency specifiers, plugin-manifest correctness)."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.13 — 2026-06-20
8
+
9
+ ## Changed
10
+
11
+ - **`@cyanheads/mcp-ts-core`** `^0.10.6` → `^0.10.9` — `DuckdbProvider.describe({ tableName })` qualifies its `WHERE` filters with the table alias, fixing the DuckDB Binder Error (ambiguous `table_name`) that hit every filtered describe ([core #235](https://github.com/cyanheads/mcp-ts-core/issues/235)); the Canvas SQL gate now classifies a `SELECT`-shaped statement that parses but fails to prepare (mistyped column, unknown function) as `ValidationError` with `data.reason: 'invalid_sql'` and the DuckDB binder detail in `data.binderMessage`, instead of the misleading `non_select_statement` ([core #236](https://github.com/cyanheads/mcp-ts-core/issues/236)); adds `ctx.content` — an always-present collector for image/audio blocks that ride `content[]` only and never enter `structuredContent` ([core #239](https://github.com/cyanheads/mcp-ts-core/issues/239)); corrects `OTEL_SERVICE_NAME` seeding precedence (`createApp({ name })` seeds it only when unset) ([core #233](https://github.com/cyanheads/mcp-ts-core/issues/233)); biome `2.4.16` → `2.5.0` and fresh-scaffold devcheck guards that skip git-dependent checks cleanly when `.git` is absent ([core #243](https://github.com/cyanheads/mcp-ts-core/issues/243)).
12
+ - **`scripts/check-dependency-specifiers.ts`** — new devcheck step (`Dependency Specifiers`, `--no-dep-specifiers`) that hard-fails on floating specifiers (`latest`, `*`, pre-release dist-tags) in `package.json`'s dependency sections and `bun.lock`'s `workspaces` map; catches `bun update --latest` writing a literal `latest` dist-tag into the lock's workspace map, which would re-resolve the dep past the `package.json` range on the next install ([core #246](https://github.com/cyanheads/mcp-ts-core/issues/246)).
13
+ - **`scripts/lint-packaging.ts`** — adds plugin-marketplace manifest checks (check 10) validating `.claude-plugin/plugin.json` and `.codex-plugin/plugin.json`: non-empty descriptions, the unscoped machine name in display fields, and the full scoped name in the `npx -y` install arg (an unscoped arg for a scoped package is a guaranteed install 404) ([core #240](https://github.com/cyanheads/mcp-ts-core/issues/240)).
14
+ - **`devcheck.config.json`** — enables `packaging.pluginManifests`, running the Packaging gate against the plugin manifests now that this server ships them.
15
+ - **Skills** — re-synced from the framework; seven `metadata.version` bumps propagate body drift (`api-auth`, `api-errors`, `api-services`, `api-telemetry`, `field-test`, `report-issue-local`, `tool-defs-analysis`) ([core #238](https://github.com/cyanheads/mcp-ts-core/issues/238)).
16
+
17
+ ## Dependencies
18
+
19
+ - `@cyanheads/mcp-ts-core` `^0.10.6` → `^0.10.9`
20
+ - `@types/node` `^25.9.3` → `^26.0.0`
@@ -0,0 +1,38 @@
1
+ ---
2
+ summary: "Tokenized multi-word search, cursor pagination, and nextStep hints for the discovery tools; multi-root theme browse fix; stale catalogue counts removed; mcp-ts-core ^0.10.9 → ^0.10.14."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.14 — 2026-07-10
8
+
9
+ ## Added
10
+
11
+ - **`eurostat_search_datasets` cursor pagination** — new optional `cursor` input; `limit` is now the page size (previously a hard ceiling on total results). Enrichment adds `nextCursor` (opaque, omitted on the last page) and `truncated` (more matches remain); `totalMatches` now reports the full count across all pages. Built on the framework's `paginateArray` primitive ([#16](https://github.com/cyanheads/eurostat-mcp-server/issues/16)).
12
+ - **`nextStep` output field** on `eurostat_search_datasets` and `eurostat_browse_themes` — a suggested follow-up call (e.g. pointing at `eurostat_get_dataset_info`), rendered as a "Next step" line in `format()` text; omitted when there's no clear follow-up, such as an empty theme folder ([#13](https://github.com/cyanheads/eurostat-mcp-server/issues/13)).
13
+ - **`skills/api-linter` `definition-invalid` rule** — flags a `null`/`undefined` entry in a `tools`/`resources`/`prompts` array passed to `validateDefinitions()` instead of crashing the lint run.
14
+ - **Supply chain** — adds `.gitattributes` (LF normalization, binary-asset markers, `linguist-generated` tags for `bun.lock`/`CHANGELOG.md`/`docs/tree.md`) and `.github/SECURITY.md` (vulnerability reporting policy).
15
+ - **`bunfig.toml` install guard** — `minimumReleaseAge` blocks installing package versions published less than 3 days ago (`@cyanheads/mcp-ts-core` excluded, adopted same-day), with `@socketsecurity/bun-security-scanner` wired as the install-time package scanner; `scripts/devcheck.ts`'s outdated-dependency check now treats a guard-held row (Update equals Current, `*`-flagged) as expected rather than a failure.
16
+
17
+ ## Changed
18
+
19
+ - **Tool descriptions and docs** — dropped the hardcoded "8,933 datasets" and "11 top-level themes" figures from `eurostat_search_datasets`, `eurostat_browse_themes`, the server's `instructions` string, and `docs/design.md`; both counts drift upstream and were already stale ([#19](https://github.com/cyanheads/eurostat-mcp-server/issues/19)).
20
+ - **`@cyanheads/mcp-ts-core`** `^0.10.9` → `^0.10.14` — adopts `ctx.state.getMany(keys)`, the `ctx.elicit.url(message, url)` external-link form, explicit `ctx.enrich` helpers (`.notice()`/`.total()`/`.echo()`/`.truncated()`), and the `ctx.content` non-text block collector (`.image()`/`.audio()`).
21
+ - **Skills** — re-synced from the framework; 12 `metadata.version` bumps propagate body drift (`add-tool`, `api-canvas`, `api-linter`, `api-utils`, `api-workers`, `code-simplifier`, `design-mcp-server`, `git-wrapup`, `orchestrations`, `polish-docs-meta`, `release-and-publish`, `techniques`).
22
+ - **`Dockerfile`** — pins `oven/bun:1.3` → `1.3.14` in both stages, adds BuildKit cache mounts (`--mount=type=cache,target=/root/.bun/install/cache`) around every `bun install`, and adds `--ignore-scripts` to the build-stage install.
23
+
24
+ ## Fixed
25
+
26
+ - **`eurostat_search_datasets` multi-word queries** — the query is now tokenized on whitespace and every token must match (AND), case-insensitively, across a combined `label + themePath + code` haystack, replacing a single substring match against the label alone; queries like "business demography NUTS 3" or "regional economic accounts" now resolve ([#14](https://github.com/cyanheads/eurostat-mcp-server/issues/14)).
27
+ - **`eurostat_browse_themes` root browse** — `findRootChildren` now unions the depth-1 children of every depth-0 TOC folder root instead of only the first, so themes under a second root (e.g. `tb_eu`, `cc` under "Cross cutting topics") are reachable from a root-level browse ([#20](https://github.com/cyanheads/eurostat-mcp-server/issues/20)).
28
+
29
+ ## Dependencies
30
+
31
+ - `@cyanheads/mcp-ts-core` `^0.10.9` → `^0.10.14`
32
+ - `@biomejs/biome` `^2.5.0` → `2.5.2` (pinned exact)
33
+ - `@types/node` `^26.0.0` → `26.1.0` (pinned exact)
34
+ - `tsc-alias` `^1.8.17` → `^1.9.0`
35
+ - `tsx` `^4.22.4` → `^4.23.0`
36
+ - `vitest` `^4.1.9` → `^4.1.10`
37
+ - `@socketsecurity/bun-security-scanner` `^1.1.2` (new)
38
+ - Transitive, via the framework bump — `hono` → `4.12.28`, `js-yaml` → `3.15.0`, `vite`/`esbuild` patched; clears the prior `bun audit` advisories on all three
@@ -0,0 +1,13 @@
1
+ ---
2
+ summary: "content[]/structuredContent parity for query_dataset and browse_themes; get_dimension_values returns the full time range and defaults geo to country; invalid dimension values now surface the declared error contract."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.15 — 2026-07-10
8
+
9
+ ## Fixed
10
+
11
+ - **`eurostat_query_dataset` / `eurostat_browse_themes` content[] parity** — `query_dataset`'s `format()` rendered only the first 200 observations behind a hardcoded cap while `structuredContent` carried up to 5,000; the cap and its "N more not shown" note are removed so both channels carry identical rows. `browse_themes`'s `format()` rendered `hasChildren` only when `true`; the `false` state now renders explicitly as "(no children)" ([#15](https://github.com/cyanheads/eurostat-mcp-server/issues/15)).
12
+ - **`eurostat_get_dimension_values` full time range + geo default** — every non-geo dimension was queried with `lastTimePeriod=1`, truncating `time` to its latest period; `getDimensionValues()` now probes a single period, pins every other dimension to its first value, and leaves `time` unfiltered to enumerate the complete range in one bounded call. `geo` without `geo_level` now defaults to `geoLevel=country` per the tool's documented default. Adds a declared `async_response` error variant (non-retryable) for dimension queries too large to bound this way ([#17](https://github.com/cyanheads/eurostat-mcp-server/issues/17)).
13
+ - **`eurostat_query_dataset` invalid-dimension error classification** — an invalid filter dimension (Eurostat HTTP 400, error id 150) bypassed the declared `invalid_dimension` contract and surfaced the raw `FetchHttpError` with the wrong JSON-RPC code (`-32602` instead of `-32007`). `fetchJson()`'s catch block now re-parses the captured error body for any non-2xx response and routes it through the existing classifier, so `invalid_dimension` and `not_found` are reachable on the live HTTP path, not just the 200-wrapped async-413 warning ([#18](https://github.com/cyanheads/eurostat-mcp-server/issues/18)).
@@ -0,0 +1,36 @@
1
+ ---
2
+ summary: "Catalogue TOC now refreshes on a 12h TTL instead of the process lifetime; search results deduplicated by dataset code; search cursors bound to their query and catalogue snapshot; whitespace-only queries and openWorldHint fixed; mcp-ts-core ^0.10.14 → ^0.11.1."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.16 — 2026-08-03
8
+
9
+ ## Added
10
+
11
+ - **`EUROSTAT_TOC_CACHE_TTL_MS`** — configures how long the catalogue TOC cache stays valid before the next `eurostat_search_datasets`/`eurostat_browse_themes` call refreshes it; defaults to `43200000` (12 hours), matching Eurostat's twice-daily update cadence ([#23](https://github.com/cyanheads/eurostat-mcp-server/issues/23)).
12
+ - **`.mcpb` bundle** — the clean step now also strips platform-specific `@duckdb/node-bindings-*` native binaries, keeping the bundle portable across platforms and under the registry size cap.
13
+
14
+ ## Changed
15
+
16
+ - **`@cyanheads/mcp-ts-core`** `^0.10.14` → `^0.11.1` — adopts the `fetchWithTimeout` error-data field rename (`responseBody` → `body`) and the new `expectedStatuses` option in `eurostat-data-service.ts`.
17
+ - **Catalogue TOC caching** — the in-memory TOC cache now expires after `EUROSTAT_TOC_CACHE_TTL_MS` instead of living for the process lifetime; concurrent callers past the TTL share one in-flight refresh, and a failed refresh serves the last loaded cache and holds the next attempt off for 60 seconds ([#23](https://github.com/cyanheads/eurostat-mcp-server/issues/23)).
18
+ - **`eurostat_search_datasets` result set** — matches are deduplicated by dataset code before pagination, so a code Eurostat files under multiple TOC branches is counted and returned once, keeping its first matching placement as the canonical `themePath` ([#26](https://github.com/cyanheads/eurostat-mcp-server/issues/26)).
19
+ - **`eurostat_search_datasets` / `eurostat_browse_themes`** now advertise `annotations.openWorldHint: true`, matching their live Catalogue API dependency ([#29](https://github.com/cyanheads/eurostat-mcp-server/issues/29)).
20
+ - Skills re-synced from the framework (12 files).
21
+
22
+ ## Fixed
23
+
24
+ - **`eurostat_search_datasets` whitespace-only query** — now rejected at the input schema (a `\S` pattern on `query`); the service also treats an empty token list as zero matches rather than matching the full catalogue ([#24](https://github.com/cyanheads/eurostat-mcp-server/issues/24)).
25
+ - **`eurostat_search_datasets` cross-query cursors** — a cursor is now bound to the normalized query and the TOC snapshot that produced it. A cursor presented with a different query, a malformed cursor, or one issued against a since-refreshed catalogue is rejected as the new `invalid_cursor` contract instead of silently paging a different result set ([#28](https://github.com/cyanheads/eurostat-mcp-server/issues/28), [#23](https://github.com/cyanheads/eurostat-mcp-server/issues/23)).
26
+
27
+ ## Dependencies
28
+
29
+ - `@cyanheads/mcp-ts-core` `^0.10.14` → `^0.11.1`
30
+ - `@biomejs/biome` `2.5.2` → `2.5.6` (pinned exact)
31
+ - `@types/node` `26.1.0` → `26.1.2` (pinned exact)
32
+ - `typescript` `^6.0.3` → `^7.0.2`
33
+ - `tsc-alias` `^1.9.0` → `^1.9.1`
34
+ - `tsx` `^4.23.0` → `^4.23.1`
35
+ - `ignore` `^7.0.5` → `^7.0.6`
36
+ - Transitive, via the framework bump — `hono` → `4.12.33`, `@modelcontextprotocol/sdk` → `1.30.0`, `jose` → `6.2.6`
@@ -0,0 +1,17 @@
1
+ ---
2
+ summary: "Bug fixes: depth-encoding whitespace in browse_themes, timeRange computed from observations, not_found error contract, description cleanup"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.2 — 2026-05-24
8
+
9
+ ## Changed
10
+
11
+ - **`eurostat_search_datasets`**, **`eurostat_get_dataset_info`**, **`eurostat_get_dimension_values`** — tool descriptions trimmed; removed implementation-detail sentences that don't help callers
12
+
13
+ ## Fixed
14
+
15
+ - **`eurostat_browse_themes`** — `unquote()` now preserves leading spaces when stripping quotes, fixing the depth-encoding whitespace that encodes NUTS hierarchy indentation
16
+ - **`eurostat_get_dataset_info`**, **`eurostat_query_dataset`** — `timeRange.start/end` computed from actual time dimension codes in the response; annotation-based fallback used only when no time dimension is present
17
+ - **`eurostat_get_dataset_info`**, **`eurostat_query_dataset`** — 404 responses from the Statistics API are now caught via `McpError` and re-thrown as `notFound` with an actionable message; previously surfaced as raw `FetchHttpError`
@@ -0,0 +1,12 @@
1
+ ---
2
+ summary: "Sync tagline across README, package.json, server.json, and manifest.json"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.3 — 2026-05-23
8
+
9
+ ## Changed
10
+
11
+ - **Tagline** — canonical description synced across all surfaces: README header, `package.json`, `server.json`, and `manifest.json`. Full form: "Search and query 8,933 Eurostat datasets — EU economy, demography, trade, health, and NUTS regional data via MCP. STDIO or Streamable HTTP." Condensed form (server.json, manifest.json): "Search and query 8,933 Eurostat datasets — EU economy, demography, trade, and NUTS data."
12
+ - **`manifest.json`** — version updated from `0.1.1` to `0.1.3` (was two versions behind)
@@ -0,0 +1,17 @@
1
+ ---
2
+ summary: "Metadata alignment: Dockerfile restored to oven/bun:1.3, package.json scripts/fields, manifest.json fields, server.json env vars, CLAUDE.md + AGENTS.md, vitest.config.ts simplified"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.4 — 2026-05-23
8
+
9
+ ## Changed
10
+
11
+ - **`Dockerfile`** — build stage restored to `oven/bun:1.3` (reverts the `node:24-slim` workaround); LABEL `title` and `description` aligned to the canonical package tagline.
12
+ - **`package.json`** — scripts updated to `bun run scripts/...` form; `start:stdio` / `start:http` use `bun ./dist/index.js`; `engines.bun` bumped to `>=1.3.2`; `files[]` trimmed to exclude `changelog/` and `AGENTS.md`; stale `start` script removed.
13
+ - **`manifest.json`** — `description` aligned to full canonical tagline; `repository`, `homepage`, and `license` fields added.
14
+ - **`server.json`** — `MCP_PUBLIC_URL` env var added to the HTTP package block.
15
+ - **`CLAUDE.md` / `AGENTS.md`** — synced to current framework template (header renamed "Agent Protocol", commands table updated to `bun run`, skills table current).
16
+ - **`vitest.config.ts`** — simplified to single `include` pattern; multi-project scaffold removed.
17
+ - **`devcheck.config.json`** — `tsx` added to depcheck ignores (used as shebang in `scripts/devcheck.ts` and `scripts/lint-mcp.ts`).
@@ -0,0 +1,11 @@
1
+ ---
2
+ summary: "Added hosted server endpoint: remotes block in server.json pointing to https://eurostat.caseyjhand.com/mcp"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.5 — 2026-05-23
8
+
9
+ ## Added
10
+
11
+ - **`server.json`** — `remotes` array with the hosted Streamable HTTP endpoint (`https://eurostat.caseyjhand.com/mcp`), enabling MCP registry clients to discover the public server directly.
@@ -0,0 +1,14 @@
1
+ ---
2
+ summary: "Four field-test bug fixes: obs cap (355MB crash), conflicting param validation, notFound reason field, dataStart/dataEnd whitespace"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.6 — 2026-05-24
8
+
9
+ ## Fixed
10
+
11
+ - **`eurostat_query_dataset`** — unfiltered queries that return > 5,000 observations now cap at 5,000 rows and set `truncated: true` on the result, preventing the ~355MB crash seen with broad dataset requests ([#4](https://github.com/cyanheads/eurostat-mcp-server/issues/4)).
12
+ - **`eurostat_query_dataset`** — `since_period`/`until_period` combined with `last_n_periods` now raises a `conflicting_params` error instead of silently ignoring the date range ([#5](https://github.com/cyanheads/eurostat-mcp-server/issues/5)).
13
+ - **`eurostat_browse_themes`** — `notFound` error now includes `data.reason: "not_found"` so agents can branch on the error code ([#6](https://github.com/cyanheads/eurostat-mcp-server/issues/6)).
14
+ - **TOC parser** — `dataStart`/`dataEnd` values are trimmed before the falsy check, so entries that carry only whitespace no longer surface as `" "` in folder results ([#7](https://github.com/cyanheads/eurostat-mcp-server/issues/7)).
@@ -0,0 +1,16 @@
1
+ ---
2
+ summary: "Code simplification, error code corrections (InvalidParams → ValidationError), mcp-ts-core ^0.9.7 → ^0.9.9, skills synced"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.7 — 2026-05-24
8
+
9
+ ## Changed
10
+
11
+ - **`mcp-ts-core`** ^0.9.7 → ^0.9.9 (`@hono/node-server` ^2.0.3 → ^2.0.4; fuzz pre-parse fix; `fast-check` moved to optional peer dep; `git-wrapup` skill added; "Close the loop on issues" rule in CLAUDE.md/AGENTS.md).
12
+ - **Error codes** — 4 sites corrected from `InvalidParams` to `ValidationError`: `invalid_dimension` and `conflicting_params` (×2) error contracts in `eurostat-query-dataset.tool.ts`, and the generic HTTP 400 branch in `eurostat-data-service.ts`. Imports updated: `invalidParams` → `validationError`.
13
+ - **`indexesWhere` helper** — consolidates 3 repeated `entries.map((_, i) => i).filter(...)` patterns in `eurostat-catalogue-service.ts` into a single private method.
14
+ - **Code simplification** — `Number.isNaN` over global `isNaN` (2 sites); dot notation over bracket access (4 sites); `?.trim() || undefined` optional-chaining form for `themeCode`; removed spurious `async` on resource handler; `biome-ignore` suppression replaces stale `eslint-disable` comments; destructure-after-length-guard replaces repeated `cols[N]!` non-null assertions in TOC parser.
15
+ - **Skills** — `git-wrapup` v1.0 added; `release-and-publish` v2.5 → v2.6.
16
+ - **CLAUDE.md / AGENTS.md** — "Close the loop on issues" rule; framework version reference updated.
@@ -0,0 +1,19 @@
1
+ ---
2
+ summary: "mcp-ts-core ^0.9.9 → ^0.9.13: 413 body cap, session-init gate, quieter expected-error logs, GET /mcp keywords; skill sync, plugin metadata scaffolding"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.8 — 2026-05-28
8
+
9
+ ## Changed
10
+
11
+ - **`@cyanheads/mcp-ts-core`** `^0.9.9` → `^0.9.13` — picks up four framework releases:
12
+ - **`MCP_HTTP_MAX_BODY_BYTES`** — configurable inbound request-body cap (default 1 MiB); oversized requests rejected with HTTP 413 before parsing ([#157](https://github.com/cyanheads/mcp-ts-core/issues/157))
13
+ - **HTTP session-init gate** — stateful HTTP mode now rejects requests without `Mcp-Session-Id` with HTTP 400, preventing uninit session minting ([#154](https://github.com/cyanheads/mcp-ts-core/issues/154))
14
+ - **Expected client error log levels** — 401/403/400/404 errors use `logger.warning` instead of the full error-handler pipeline, reducing stack-trace noise in logs ([#158](https://github.com/cyanheads/mcp-ts-core/issues/158))
15
+ - **`GET /mcp` keywords** — `package.json` `keywords` now surfaced on the status JSON response ([#165](https://github.com/cyanheads/mcp-ts-core/issues/165))
16
+ - **`landing.requireAuth: false`** — explicitly opts the landing page into public inventory (keeps current behavior against the 0.9.13 `jwt`/`oauth` default-auth change; this server uses `MCP_AUTH_MODE=none` but the explicit opt-in future-proofs the config).
17
+ - **`@biomejs/biome`** `^2.4.15` → `^2.4.16`
18
+ - **Skills synced** to mcp-ts-core 0.9.13 — `api-canvas`, `api-config`, `design-mcp-server`, `git-wrapup`, `polish-docs-meta`, `release-and-publish`, `report-issue-framework`; `migrate-mcp-ts-template` removed; `code-simplifier` added.
19
+ - **Plugin metadata scaffolded** — `.claude-plugin/plugin.json` and `.codex-plugin/plugin.json` + `mcp.json` added.
@@ -0,0 +1,20 @@
1
+ ---
2
+ summary: "Enrichment adoption — search/browse/query tools surface query echoes, result totals, and empty-result guidance via typed enrichment block; mcp-ts-core ^0.9.13 → ^0.9.16"
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.1.9 — 2026-05-30
8
+
9
+ ## Added
10
+
11
+ - **`enrichment` block** on `eurostat_search_datasets`, `eurostat_browse_themes`, and `eurostat_query_dataset` — surfaces agent-facing metadata in a typed `enrichment` block reaching both `structuredContent` JSON and the `content[]` markdown trailer, so both Claude Code and Claude Desktop clients receive the same signal.
12
+ - `eurostat_search_datasets`: `query` (echoed search terms), `totalMatches` (true count before limit)
13
+ - `eurostat_browse_themes`: `itemCount` (items returned), `themeCode` (folder browsed, when set)
14
+ - `eurostat_query_dataset`: `appliedFilters` (dimension filters, geo level, time range), `notice` (truncation guidance when the 5,000-row cap is hit)
15
+
16
+ ## Changed
17
+
18
+ - **`eurostat_search_datasets` `format()`** — text header changed from `N total matches (showing N)` to `Showing N results`; the true result count now surfaces in the `enrichment` block.
19
+ - **`eurostat_search_datasets` `structuredContent`** — `totalMatches` moved from the `output` object to `enrichment`; value and presence preserved in both channels, key path changed (`result.totalMatches` → `result.enrichment.totalMatches`).
20
+ - **`@cyanheads/mcp-ts-core`** `^0.9.13` → `^0.9.16` — picks up enrichment builder, `ctx.enrich()` / `ctx.enrich.notice()`, enrichment schema support, and skill sync.
@@ -0,0 +1,29 @@
1
+ ---
2
+ summary: "Ten output fields become optional across three schemas — absent annotations are omitted, not fabricated as 0/\"\" (#30, #33); dataset_info's time valuesCount reflects real coverage (#21); its async_response is non-retryable (#31); dimension_values rejects geo_level on a non-geo dimension (#25); query_dataset normalizes empty filter arrays (#22)."
3
+ breaking: true
4
+ security: false
5
+ ---
6
+
7
+ # 0.2.0 — 2026-08-04
8
+
9
+ ## Breaking
10
+
11
+ - **Ten output fields move from required to optional, across three independently declared schemas**, because Eurostat's annotation-derived metadata is no longer fabricated as `0` / `""` when absent — it is omitted. A consumer reading any of these fields unconditionally will break:
12
+ - `eurostat_get_dataset_info` output: `timeRange.start`, `timeRange.end`, `obsCount`, `lastUpdated`.
13
+ - `eurostat://dataset/{dataset_code}` resource output: `timeRange.start`, `timeRange.end`, `obsCount`, `lastUpdated`.
14
+ - `eurostat_query_dataset` output: `timeRange.start`, `timeRange.end`.
15
+
16
+ ([#30](https://github.com/cyanheads/eurostat-mcp-server/issues/30), [#33](https://github.com/cyanheads/eurostat-mcp-server/issues/33))
17
+
18
+ ## Changed
19
+
20
+ - **`eurostat_get_dataset_info` `dimensions[].valuesCount` for `time`** now reflects the dataset's real period count instead of the single-period artifact of the `lastTimePeriod=1` metadata query. Costs one bounded extra upstream request (pinning every other dimension, unfiltered on `time`), and only when the dataset has a `time` dimension. ([#21](https://github.com/cyanheads/eurostat-mcp-server/issues/21))
21
+ - **`eurostat_get_dataset_info`'s `async_response` error is no longer `retryable`.** The tool exposes no filters to narrow, so an identical retry produces the identical oversized response. The recovery hint now points to `eurostat_search_datasets`/`eurostat_browse_themes` for catalogue-level coverage or `eurostat_get_dimension_values` for one dimension at a time. ([#31](https://github.com/cyanheads/eurostat-mcp-server/issues/31))
22
+ - **`eurostat_query_dataset` `filters` drops zero-length arrays** before building the request, the `geo`/`geo_level` conflict check, and the `appliedFilters` echoed back in both `structuredContent` and `ctx.enrich`. `{"geo": []}` now neither restricts the query nor conflicts with `geo_level`. `appliedFilters` (`Record<string, string[]>`) is added to the tool's output as the filters actually sent upstream. ([#22](https://github.com/cyanheads/eurostat-mcp-server/issues/22))
23
+
24
+ ## Fixed
25
+
26
+ - **`eurostat_get_dimension_values` rejects `geo_level` paired with any dimension other than `geo`** as a new `conflicting_params` error, instead of silently accepting and ignoring it. ([#25](https://github.com/cyanheads/eurostat-mcp-server/issues/25))
27
+ - **Absent Eurostat annotations are omitted rather than fabricated.** `eurostat_get_dataset_info` and the `eurostat://dataset/{dataset_code}` resource no longer default a missing `OBS_COUNT` to `0` or a missing period bound to `""`; `format()` renders each as "not reported by Eurostat" instead of a blank or zero value. ([#30](https://github.com/cyanheads/eurostat-mcp-server/issues/30))
28
+ - **`eurostat_query_dataset`'s `timeRange` has the same fabricated-empty-bounds defect fixed**, found during verification of this release: a period bound absent from both the returned observations and the dataset-wide annotations is now omitted rather than reported as `""`. ([#33](https://github.com/cyanheads/eurostat-mcp-server/issues/33))
29
+ - **`docs/design.md` and `README.md` corrected** — stale error-code labels (`InvalidParams` → `ValidationError`), the single-request description of `get_dataset_info`, the mutual-exclusion description for `geo`/`geo_level`, and a quoted `async_response` recovery hint that no longer exists.
@@ -0,0 +1,17 @@
1
+ ---
2
+ summary: "`get_dataset_info` output and the dataset resource narrow `dimensions[].valuesCount`/`sampleValues` to optional — a failed time-enumeration request now returns partial metadata instead of failing (#34); `query_dataset`'s row cap moves into the decoder (#27); duplicate `browse_themes` folder codes resolve to their first placement (#32)."
3
+ breaking: true
4
+ security: false
5
+ ---
6
+
7
+ # 0.3.0 — 2026-08-04
8
+
9
+ ## Breaking
10
+
11
+ - **`dimensions[].valuesCount` and `dimensions[].sampleValues` move from required to optional**, on both `eurostat_get_dataset_info`'s output and the independently declared `eurostat://dataset/{dataset_code}` resource output. They're omitted — not filled from the one-period slice — when the `time` dimension's enumeration follow-up request fails. A consumer reading either field unconditionally will break. ([#34](https://github.com/cyanheads/eurostat-mcp-server/issues/34))
12
+
13
+ ## Fixed
14
+
15
+ - **`eurostat_get_dataset_info` no longer discards metadata it already retrieved when the follow-up `time`-enumeration request fails.** It now catches that failure and returns everything the primary request produced, with `time`'s `valuesCount`/`sampleValues` omitted — the schema change above. A failure on the primary request still fails the call. This is a regression introduced in 0.2.0: readers on 0.1.x are unaffected; readers on 0.2.0 should upgrade. ([#34](https://github.com/cyanheads/eurostat-mcp-server/issues/34))
16
+ - **`eurostat_query_dataset`'s 5,000-row cap now applies during decoding** instead of after the full match has been decoded into observation objects. `obsCount`, `missingObsCount`, and `timeRange` are computed from a separate scan of the response's `value`/`status` cell keys, so they keep describing the whole match regardless of the cap. This removes a million-object intermediate allocation on a broad, unfiltered query — it is not a speed improvement: on the reported case, network transfer is ~93% of the round trip, `JSON.parse` ~1.3%, and decoding ~5%; Eurostat serving the full payload is what dominates, not the decode loop. ([#27](https://github.com/cyanheads/eurostat-mcp-server/issues/27))
17
+ - **`eurostat_browse_themes` resolves a folder code filed under more than one TOC branch to its first placement instead of its last.** A new optional `otherPlacements` field on the tool output names the branches not taken, so an ambiguous code is visible as such rather than silently resolved. ([#32](https://github.com/cyanheads/eurostat-mcp-server/issues/32))
@@ -0,0 +1,24 @@
1
+ ---
2
+ summary: "eurostat_query_dataset stages a match past its 5,000-row inline cap onto an optional DuckDB dataframe canvas; two new tools, eurostat_dataframe_describe and eurostat_dataframe_query, read it (#8)."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.4.0 — 2026-08-04
8
+
9
+ ## Added
10
+
11
+ - **`eurostat_dataframe_describe` and `eurostat_dataframe_query`** — SQL access to a dataframe canvas. `describe` lists staged tables with row counts and column types; `query` runs a single read-only `SELECT`, rejecting statement chaining, non-`SELECT` verbs, and functions that read files or external data. Both are registered only when `CANVAS_PROVIDER_TYPE=duckdb`; otherwise they're wrapped in `disabledTool()` — invisible to `tools/list` but still named on the landing page and server card. ([#8](https://github.com/cyanheads/eurostat-mcp-server/issues/8))
12
+ - **`eurostat_query_dataset` stages a capped match onto the canvas.** When a match exceeds the 5,000-row inline cap and a canvas is configured, the whole match is written to a SQL table and the response gains `canvasId`, `tableName`, and `stagedRowCount`. Staging is skipped when the result fits inline. Passing a prior response's `canvasId` back as the new optional `canvas_id` input stages the next result onto the same canvas, so two datasets can be joined. ([#8](https://github.com/cyanheads/eurostat-mcp-server/issues/8))
13
+ - **Canvas env vars** — `CANVAS_PROVIDER_TYPE`, `CANVAS_TEMP_PATH`, `CANVAS_TTL_MS`, `CANVAS_DEFAULT_ROW_LIMIT`, documented in `.env.example`, `server.json`, and `manifest.json`. Off by default (`none`); the `@duckdb/node-api` binding ships in every install and image, so enabling the canvas needs only the one variable.
14
+
15
+ ## Changed
16
+
17
+ - **`eurostat_query_dataset`'s row source is a lazy generator** over the response's populated cells, shared by the capped inline decode and the canvas spill. The inline rows are a prefix of the staged table by construction — both walks pull from the same generator — and staging costs no additional request to Eurostat: the full response body is already in memory before decoding starts.
18
+ - **Staged columns are flat and declared, not inferred.** Each dimension contributes a `<dim>` code column and a `<dim>_label` column; the observation contributes `obs_value`, `obs_flag`, `obs_flag_label`. The schema is declared up front because DuckDB's inference reads only the leading rows, which would type an all-integer `obs_value` prefix as `BIGINT` and return it as a string.
19
+ - **Dockerfile** — the non-root `bun` user now owns `/var/lib/eurostat-mcp-server/canvas-tmp` and `/var/lib/eurostat-mcp-server/canvas-exports`, mapped to `CANVAS_TEMP_PATH` and `CANVAS_EXPORT_PATH`; the prior image had no writable path for either. A canvas-acquire failure caused by an unwritable scratch directory is now re-thrown naming `CANVAS_TEMP_PATH` instead of surfacing a bare `EACCES`.
20
+ - **`.mcpb` bundle** — `scripts/clean-mcpb.ts`'s DuckDB-stripping comment updated to describe the binding as a runtime dependency gated on `CANVAS_PROVIDER_TYPE`, not an optional peer. A bundle install still cannot run the canvas — native bindings are stripped from the bundle to keep it portable and under the registry size cap — so SQL analytics needs the npm, Docker, or from-source install.
21
+
22
+ ## Dependencies
23
+
24
+ - `@duckdb/node-api` `^1.5.5-r.3` added as a runtime dependency (powers the DataCanvas).
@@ -0,0 +1,20 @@
1
+ ---
2
+ summary: "eurostat_download_dataset reads the SDMX 2.1 TSV bulk endpoint — roughly half the bytes of eurostat_query_dataset — and stages a whole dataset on the dataframe canvas (#8)."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.5.0 — 2026-08-04
8
+
9
+ ## Added
10
+
11
+ - **`eurostat_download_dataset`** — downloads a whole dataset through the SDMX 2.1 TSV bulk endpoint (`/sdmx/2.1/data/{dataset}?format=TSV`) instead of the JSON-stat endpoint `eurostat_query_dataset` reads, and stages every observation on the dataframe canvas when one is configured. Filters take the same `{dimension_code: [value, ...]}` map as `eurostat_query_dataset`; the positional SDMX key is built server-side from the dataset's own dimension order, so arity is correct by construction and a filter naming a dimension the dataset does not have is rejected up front with the real dimension list. Narrow with `since_period`/`until_period` — there is deliberately no "last N periods", since the TSV layout keeps a column for every period regardless and `lastNObservations` only blanks the unselected cells. `preview_limit` (default 50, max 500) caps the inline echo; without a canvas only that preview is retained, and the response says so. ([#8](https://github.com/cyanheads/eurostat-mcp-server/issues/8))
12
+ - **`EurostatBulkService`** (`src/services/eurostat-bulk/`) — the streaming client behind the new tool: gzip sniffed off the response stream rather than trusted from headers (Eurostat sends no `Content-Encoding` on compressed bodies), a byte budget enforced mid-transfer since the body is `Transfer-Encoding: chunked` with no `Content-Length`, XML SOAP-fault and async-queue-envelope classification, and wide-to-long expansion of the TSV layout into one row per observation.
13
+ - **`EUROSTAT_BULK_TIMEOUT_MS`** (default `120000`) and **`EUROSTAT_BULK_MAX_BYTES`** (default `52428800`) — held separate from the existing request timeout because a bulk body streams for minutes where a metadata call answers in seconds.
14
+ - **`EurostatDataService.getDimensionOrder`** — resolves a dataset's dimension order (the JSON-stat `id` array minus `time`) from a one-period probe, the input the positional SDMX key is built from.
15
+
16
+ ## Changed
17
+
18
+ - **`eurostat_query_dataset`, both dataframe tools, `eurostat_get_dataset_info`, `eurostat_get_dimension_values`, and `eurostat_search_datasets` have their descriptions rewritten**, not appended to, to route between a dataset slice (`eurostat_query_dataset`) and a whole dataset (`eurostat_download_dataset`).
19
+ - **The two dataframe stagers write different column sets**, and `eurostat_dataframe_describe`/`eurostat_dataframe_query` now say so explicitly: `eurostat_query_dataset` gives each dimension a code column plus a `_label` companion; `eurostat_download_dataset` gives code columns only (the bulk endpoint carries no labels) plus `time`, `conf_status`, and `conf_status_label`. The two tables also disagree on `obs_flag` — JSON-stat folds a confidentiality marker into the observation status, so a confidential cell reads `obs_flag = '|C'` on a query-staged table but `obs_flag = NULL` with `conf_status = 'C'` on a bulk-staged one; join on dimension codes and `time`, not on `obs_flag`.
20
+ - **`newTableName()` moved** from `eurostat-query-dataset.tool.ts` to `src/services/canvas-accessor.ts`, so both staging tools share one table-naming helper.
@@ -0,0 +1,20 @@
1
+ ---
2
+ summary: "eurostat_query_dataset's observations[].status carries only the OBS_FLAG now, confidentiality moved to a new confStatus field (#35); a wholly-confidential slice no longer wrongly raises no_results (#36)."
3
+ breaking: true
4
+ security: false
5
+ ---
6
+
7
+ # 0.6.0 — 2026-08-04
8
+
9
+ ## Breaking
10
+
11
+ - **`eurostat_query_dataset`'s `observations[].status` no longer carries a confidentiality code.** JSON-stat publishes no `CONF_STATUS` field and instead folds it into the observation status behind a `|` — a confidential cell arrived as `status: { code: "|C", label: "|confidential" }`. The decoder now splits that separator: `status` carries only the `OBS_FLAG` half and is omitted for a cell with none, while a new sibling field `confStatus: { code, label }` carries the `CONF_STATUS` half, present only when Eurostat restricts the cell. Before: `status.code === "|C"`. After: `status` omitted, `confStatus.code === "C"`. The staged dataframe table gains `conf_status`/`conf_status_label` columns; both `eurostat_query_dataset` and `eurostat_download_dataset` now stage the same five measure columns — `obs_value`, `obs_flag`, `obs_flag_label`, `conf_status`, `conf_status_label` — under the same names with the same codes, so the two join and compare directly instead of disagreeing on what `obs_flag` holds. ([#35](https://github.com/cyanheads/eurostat-mcp-server/issues/35))
12
+
13
+ ## Changed
14
+
15
+ - **`src/services/eurostat-codelists.ts`** (new) — the `OBS_FLAG`/`CONF_STATUS` code-to-label dictionaries and the five measure column names, previously duplicated between the JSON-stat and SDMX-TSV services, now live in one module both import.
16
+ - **`eurostat_query_dataset`, `eurostat_dataframe_describe`, and `eurostat_dataframe_query` descriptions rewritten** to describe the shared measure columns instead of the `obs_flag` divergence the breaking change above removes.
17
+
18
+ ## Fixed
19
+
20
+ - **`eurostat_query_dataset` no longer rejects a slice whose every cell is confidential as `no_results`.** The guard tested the response's `value` map alone, but the decoder counts a cell as an observation when its index appears in `value` **or** `status` — a wholly-confidential slice carries every cell in `status` with no `value` entry, so it arrived as `value: {}` and was rejected even though the decoder yields it as data. The guard now derives from the same cell count (`obsCount`) the response already reports, so a rejected query and a returned one can no longer disagree about what an observation is. The `no_results` recovery hint also now names the period range, since an out-of-coverage range is the other way Eurostat answers HTTP 200 with nothing. ([#36](https://github.com/cyanheads/eurostat-mcp-server/issues/36))
@@ -0,0 +1,30 @@
1
+ ---
2
+ summary: "Adopts mcp-ts-core 0.12.3 and MCP SDK v2, reports truncated bulk previews on both output surfaces, and refreshes the build and test configuration."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.6.1 — 2026-08-21
8
+
9
+ ## Changed
10
+
11
+ - **`@cyanheads/mcp-ts-core` 0.12.3 adoption** serves MCP protocol revision 2026-07-28 alongside existing clients, advertises strict tool inputs and the error output envelope, adds stateful HTTP replay, and records failures across output validation, formatting, and enrichment.
12
+ - **Request contexts** now pass directly into framework fetch, retry, and cursor helpers without compatibility casts.
13
+ - **TypeScript and Vitest configuration** typechecks `src/` and `tests/` together while keeping build emission scoped to `src/`, with named unit, smoke, integration, and fuzz projects.
14
+ - **Runtime packaging** pins Bun 1.4.0 and omits optional framework peers from the production image while retaining the DuckDB canvas binding as a direct dependency.
15
+ - **Project guidance and metadata** syncs the framework 0.12.x skills, MCP SDK v2 conventions, community health files, bundle checks, and security contact.
16
+
17
+ ## Fixed
18
+
19
+ - **`eurostat_download_dataset` inline previews** report `truncated`, `shown`, and `cap` through enrichment whenever rows are omitted, keeping `structuredContent` and `content[]` aligned.
20
+ - **Directory tree generation** applies directory-only ignore patterns to directories, so ignored agent and workspace directories stay out of the generated tree.
21
+
22
+ ## Dependencies
23
+
24
+ - `@cyanheads/mcp-ts-core` `^0.11.1` → `^0.12.3`
25
+ - `@duckdb/node-api` `^1.5.5-r.3` → `^1.5.5-r.4`
26
+ - `@biomejs/biome` `2.5.6` → `2.5.9`
27
+ - `@types/node` `26.1.2` → `26.2.0`
28
+ - `tsc-alias` `^1.9.1` → `^1.9.2`
29
+ - `vitest` `^4.1.10` → `^4.1.11`
30
+ - `tsx` `^4.23.1` removed (the project runs TypeScript scripts with Bun directly)