Releases: cyanheads/oecd-mcp-server
Release list
v0.3.0: unified upstream and flow-ref error contracts
unified upstream and flow-ref error contracts
- Every tool and the
oecd://dataflow/{agency_id}/{flow_id}resource declaredata.reasonanddata.recovery.hintfor OECD upstream failures via a sharedupstreamRefusal()reader (#29) oecd_get_dimension_valuesand the dataflow resource report an unparseableflow_refasinvalid_flow_ref(ValidationError) instead ofdataflow_not_found/ a bareNotFound(#27, #28)upstream_errorno longer declaresretryable—data.retryableis omitted rather than sent astrueoecd_list_agenciesandoecd_search_datasetsno longer restate every remaining failure asupstream_error; undeclared codes now bubble as themselves
v0.2.2: redirects refused at the OECD fetch boundary
redirects refused at the OECD fetch boundary
- fetchOecd issues every request with redirect: manual and refuses any 3xx as a terminal, non-retried Forbidden — the origin externalServiceRoot() pins a delegated root to previously bound only the first hop (#26)
- oecd_list_agencies, oecd_search_datasets, oecd_get_dataset_info, oecd_get_dimension_values, oecd_query_dataset declare upstream_redirect (Forbidden, not retryable) and report the boundary's own sentence instead of an undeclared Forbidden or a retryable upstream_error
- docs: redirect-refusal decision record in docs/design.md, README OECD_BASE_URL note, three drifted rows in the tools table corrected
v0.2.1: Delegated dataflows and version-pinned codelists
Delegated dataflows and version-pinned codelists
- Follow the 27 dataflows OECD catalogues on the public root but defines on sti-public, dcd-public, or archive, for structure, codes, and observations (#23)
- Read codelists and concept schemes at the root and version the datastructure actually references, instead of the configured root's latest (#24)
- Check for a delegated root before spending the observation retry budget on a 500/404, instead of after three attempts and backoff (#25)
- NoRecordsFound bodies read as an empty result, alongside the existing NoResultsFound handling
- field-test skill doc fix: debug-level upstream traces land in the file log sinks, not mcp_log (2.8 → 2.9)
v0.2.0: Dataflow reference resolution, dot-segment identifier fix
Dataflow reference resolution, dot-segment identifier fix
Fixes the 8 dataflows OECD publishes without a datastructure prefix and
the 49 whose id prefix names a datastructure OECD does not keep in sync
— both were unreachable or 404ing. Dimension names and agency
directorates now resolve from OECD's concept and agency schemes instead
of repeating the id.
- BREAKING: oecd_get_dimension_values pages results (50 by default,
limit up to 500) instead of returning the whole codelist; a
1,164-code dimension no longer ships 66 KB to structuredContent (#6) - Security: a flow_ref of "." or ".." — plain or percent-encoded —
normalized past identifier validation to an unrelated collection
endpoint, returning the wrong dataflow's structure as if it were the
one requested; identifiers now require a leading letter or digit - Dataflow references resolve through the id OECD actually catalogues,
with a datastructure fallback for id/DSD mismatches (#20, #22) - oecd_list_agencies reports each agency's directorate; oecd_get_dataset_info,
the oecd://dataflow resource, and dimension descriptions carry concept
names instead of the raw id (#13, #16) - oecd_dataframe_query maps a missing table to a table_not_found reason
instead of a generic invalid_sql (#17)
v0.1.5: UNIT_MULT scaling fix, full inline rendering, typed upstream-failure classification
UNIT_MULT scaling fix, full inline rendering, typed upstream-failure classification
- Value scaling corrected: a GDP figure previously returned as 26054.614
now returns 26054614000000, applying UNIT_MULT as OECD intends. Every
row carries value_scale, the divisor back to the published figure (#9) - Every declared observation attribute (OBS_STATUS, PRICE_BASE, DECIMALS,
UNIT_MULT, ...) is now a column instead of being dropped (#9) - format() renders the full result up to a shared preview budget instead
of a 10-row cap, on both the DataCanvas and no-canvas paths; a no-canvas
cap now discloses itself via content_table_capped (#11, #19) - oecd_query_dataset gained typed reasons for a 422/400 rejection, a
request-rate or download-size throttle, a timeout, and an exhausted
5xx, each with its own recovery (#7, #10, #18, #21) - Internal: shared fetchOecd HTTP boundary extracted for both SDMX
services; explicit canvas schema so sparse attribute columns register
v0.1.4: oecd_search_datasets description matching + offset paging, retry fixes
oecd_search_datasets description matching + offset paging, retry fixes
- oecd_search_datasets matches descriptions as well as names (matched_in), returns a 240-char truncated description, and adds offset paging past limit (#14, #15)
- oecd_search_datasets: agency_not_found contract entry for an unknown agency_id, no longer misreported as a retryable outage (#12)
- Structure-service retries reclassify 404 as terminal NotFound, restate any 5xx as retryable, and stop a 429 Retry-After: 0 from collapsing the backoff
- enrichment.totalCount on oecd_search_datasets is optional, fixing an output-validation failure on fully-returned searches (#5)
- README and design docs: stale PISA references and dead example agency IDs corrected against the live catalog (#8)
- Dockerfile production stage installs prod deps instead of copying dev node_modules (888 MB -> 664 MB)
- deps: @cyanheads/mcp-ts-core ^0.10.6 -> ^0.11.1 (+ dev-dep bumps, bun 1.3.14)
v0.1.3: mcp-ts-core ^0.10.6 adoption
mcp-ts-core ^0.10.6 adoption
Framework upgrade to 0.10.x with the tool-surface and packaging changes it brings.
Added:
oecd_search_datasetsdiscloses the full match count (enrichment.totalCount) when the limit caps the returned listoecd_dataframe_querydenies system-catalog introspection from caller SQL (denySystemCatalogs: true)- Container
HEALTHCHECKon/healthz,APP_VERSIONOCI label, writable.cache/.mirrordata dirs
Changed:
createApp()sets explicitname/title=oecd-mcp-server- Error contracts
invalid_sql/invalid_flow_ref/invalid_keymigrateInvalidParams→ValidationError bundlecleans the.mcpb(clean-mcpb.ts): prunes dev deps, strips dependency-shipped agent docs
Dependency bumps:
@cyanheads/mcp-ts-core^0.9.21 → ^0.10.6@biomejs/biome^2.4.16 → ^2.5.0@types/node^25.9.2 → ^25.9.3
61 tests pass; bun run devcheck clean.
v0.1.2: DX fixes across 4 tools
DX fixes across 4 tools
Corrects four agent-facing gaps identified during initial field testing.
Fixed:
- oecd_search_datasets description no longer leaks the caching implementation detail (#1)
- oecd_query_dataset response echoes effective query parameters (flow_ref, key, period range) in both structuredContent and content[] (#2)
- oecd_get_dimension_values returns a notice field when a dimension has no codelist, directing the caller to oecd_query_dataset for discovery (#3)
- oecd_dataframe_describe / oecd_dataframe_query canvas-not-configured path uses a declared canvas_disabled contract (ServiceUnavailable, typed data.reason) instead of an undeclared factory call (#4)
Dependency bumps:
@types/node^25.9.1 → ^25.9.2
61 tests pass; bun run devcheck clean.
v0.1.1: First public release — OECD SDMX MCP server
First public release — OECD SDMX MCP server
7 MCP tools + 1 resource over 1,500+ OECD statistical datasets via SDMX. Keyless; no API key required. Optional DataCanvas SQL support for large result sets via DuckDB.
Added:
- oecd_list_agencies, oecd_search_datasets, oecd_get_dataset_info, oecd_get_dimension_values — SDMX structure tools
- oecd_query_dataset — fetch observations; large result sets spill to DataCanvas (CANVAS_PROVIDER_TYPE=duckdb)
- oecd_dataframe_describe, oecd_dataframe_query — DataCanvas SQL tools
- oecd://dataflow/{agency_id}/{flow_id} resource — dimension metadata as JSON
- Dockerfile with node_modules copy for @duckdb/node-api native binary preservation
Security:
- SDMX_ID_SAFE regex — validates agencyId, dsdId, dfId against /^[A-Za-z0-9._-]+$/ before URL construction
- SDMX_KEY_SAFE regex — validates dimension key against /^[A-Za-z0-9._+%-]*$/ before URL path insertion
- Error sanitization — removed url from serviceUnavailable context, stripped body content from 400/parse-error messages
60 tests pass; bun run devcheck clean.