@cyanheads/exchange-rates-mcp-server 0.4.0 → 0.4.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 (40) hide show
  1. package/AGENTS.md +46 -20
  2. package/CLAUDE.md +46 -20
  3. package/Dockerfile +87 -38
  4. package/README.md +95 -76
  5. package/changelog/0.4.x/0.4.1.md +27 -0
  6. package/changelog/0.4.x/0.4.2.md +45 -0
  7. package/changelog/template.md +9 -26
  8. package/dist/index.js +9 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.d.ts.map +1 -1
  11. package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.js +4 -9
  12. package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.js.map +1 -1
  13. package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.d.ts.map +1 -1
  14. package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.js +3 -6
  15. package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.js.map +1 -1
  16. package/dist/mcp-server/tools/definitions/fx-dataframe-drop.tool.d.ts +3 -2
  17. package/dist/mcp-server/tools/definitions/fx-dataframe-drop.tool.d.ts.map +1 -1
  18. package/dist/mcp-server/tools/definitions/fx-dataframe-drop.tool.js +7 -7
  19. package/dist/mcp-server/tools/definitions/fx-dataframe-drop.tool.js.map +1 -1
  20. package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.d.ts.map +1 -1
  21. package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.js +6 -15
  22. package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.js.map +1 -1
  23. package/dist/mcp-server/tools/definitions/fx-get-rate.tool.d.ts.map +1 -1
  24. package/dist/mcp-server/tools/definitions/fx-get-rate.tool.js +4 -9
  25. package/dist/mcp-server/tools/definitions/fx-get-rate.tool.js.map +1 -1
  26. package/dist/mcp-server/tools/definitions/fx-get-rates.tool.d.ts.map +1 -1
  27. package/dist/mcp-server/tools/definitions/fx-get-rates.tool.js +4 -9
  28. package/dist/mcp-server/tools/definitions/fx-get-rates.tool.js.map +1 -1
  29. package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.d.ts.map +1 -1
  30. package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.js +19 -17
  31. package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.js.map +1 -1
  32. package/dist/services/frankfurter/errors.d.ts +6 -1
  33. package/dist/services/frankfurter/errors.d.ts.map +1 -1
  34. package/dist/services/frankfurter/errors.js +6 -2
  35. package/dist/services/frankfurter/errors.js.map +1 -1
  36. package/dist/services/frankfurter/frankfurter-service.d.ts.map +1 -1
  37. package/dist/services/frankfurter/frankfurter-service.js +12 -4
  38. package/dist/services/frankfurter/frankfurter-service.js.map +1 -1
  39. package/package.json +13 -11
  40. package/server.json +12 -26
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.4.0-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/exchange-rates-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/exchange-rates-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/exchange-rates-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.0-blueviolet.svg?style=flat-square)](https://bun.sh/)
10
+ [![Version](https://img.shields.io/badge/Version-0.4.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/exchange-rates-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.2.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/exchange-rates-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/exchange-rates-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.2-blueviolet.svg?style=flat-square)](https://bun.sh/)
11
11
 
12
12
  </div>
13
13
 
@@ -27,124 +27,138 @@
27
27
 
28
28
  ---
29
29
 
30
- ## Tools
30
+ ## Overview
31
31
 
32
- Eight tools for working with ECB FX rate data — currency lookup and disambiguation, point-in-time rates and conversions, historical time-series retrieval, and SQL analytics over the DataCanvas workspace that long time-series calls produce. Five are advertised by default; the three `fx_dataframe_*` tools need `CANVAS_PROVIDER_TYPE=duckdb`, and the destructive one among them additionally needs `FX_ENABLE_CANVAS_DROP=true`.
32
+ ECB reference exchange rates via Frankfurter — a keyless proxy covering ~30 currencies back to 1999-01-04. Convert amounts, disambiguate currency codes, and pull point-in-time or historical rates from any MCP client, with SQL analytics over long time-series when DataCanvas is enabled. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
33
33
 
34
- The three `fx_dataframe_*` tools require DataCanvas. With `CANVAS_PROVIDER_TYPE` unset (the default) they are not advertised in `tools/list` at all, so a client never sees a tool it cannot call; the HTTP landing page still lists them as disabled cards hinting `CANVAS_PROVIDER_TYPE=duckdb`, so operators can tell they exist. In that mode `fx_get_timeseries` returns every range inline, paged at 500 publication days:
34
+ ### Tools
35
35
 
36
36
  | Tool | Description |
37
- |:-----|:------------|
38
- | `fx_list_currencies` | List all ~30 ECB-supported ISO 4217 currencies with full names. Use before converting to disambiguate "dollars" (USD vs AUD vs CAD vs HKD vs SGD). |
39
- | `fx_get_rates` | Snapshot of all available rates for a base currency at latest or a historical date. Surfaces `date_snapped` when a weekend/holiday request returns the prior business-day snapshot. Optional `symbols` filter for smaller responses; listing the base itself returns a rate of 1 for it. |
40
- | `fx_get_rate` | Exchange rate for a single currency pair at latest or a historical date. Surfaces `date_snapped` when a weekend/holiday request returns the prior business-day rate. |
41
- | `fx_convert_currency` | Convert an amount between any two currencies at latest or a historical rate. Cross-rates are triangulated through EUR. Returns converted amount, rate used, rate date, and whether the date was snapped. |
42
- | `fx_get_timeseries` | Historical daily rates for a currency pair over a date range, never including a date outside it. Inline results come back in pages of 500 publication days, continued with `next_start_date`; when DataCanvas is enabled, long ranges (>90 days) spill to it with a `canvas_id` for SQL follow-up instead. |
43
- | `fx_dataframe_describe` | List DataCanvas tables and their columns from a prior `fx_get_timeseries` call. Required first step before `fx_dataframe_query`. Needs `CANVAS_PROVIDER_TYPE=duckdb`. |
44
- | `fx_dataframe_query` | Run a read-only SQL SELECT against a DataCanvas table produced by `fx_get_timeseries`. Supports aggregations, GROUP BY, window functions, and JOINs across multiple registered tables. Returns at most `row_limit` rows (default 150, max 10,000). Needs `CANVAS_PROVIDER_TYPE=duckdb`. |
45
- | `fx_dataframe_drop` | Permanently remove one staged table or view from a DataCanvas. Deletes staged analytical data only — ECB rate data is untouched and the series can be re-staged. Needs `CANVAS_PROVIDER_TYPE=duckdb` and `FX_ENABLE_CANVAS_DROP=true`; disabled otherwise. |
37
+ |:---|:---|
38
+ | `fx_list_currencies` | List all ~30 ECB-supported ISO 4217 currencies with full names |
39
+ | `fx_get_rates` | Snapshot of all rates for a base currency at latest or a historical date |
40
+ | `fx_get_rate` | Exchange rate for a single currency pair at latest or a historical date |
41
+ | `fx_convert_currency` | Convert an amount between two currencies at latest or a historical rate |
42
+ | `fx_get_timeseries` | Historical daily rates for a currency pair over a date range |
43
+ | `fx_dataframe_describe` | List DataCanvas tables and columns staged by a prior `fx_get_timeseries` call |
44
+ | `fx_dataframe_query` | Run a read-only SQL SELECT against a staged DataCanvas table |
45
+ | `fx_dataframe_drop` | Remove one staged DataCanvas table or view (opt-in, destructive) |
46
46
 
47
- ### `fx_list_currencies`
47
+ The three `fx_dataframe_*` tools need `CANVAS_PROVIDER_TYPE=duckdb` — unset, they're not advertised in `tools/list` at all, and `fx_get_timeseries` returns every range inline instead. `fx_dataframe_drop` additionally needs `FX_ENABLE_CANVAS_DROP=true`.
48
48
 
49
- Enumerate all supported currencies before converting or querying.
49
+ ### Resources
50
50
 
51
- - Returns `[{ code, name }]` for all ~30 ECB-scoped currencies
52
- - ECB coverage fluctuates as currencies enter/exit scope — always call this tool to validate user-supplied codes rather than hard-coding a list
51
+ | Resource | Description |
52
+ |:---|:---|
53
+ | `fx://currencies` | All supported currencies as a stable reference document |
54
+ | `fx://rates/latest/{base}` | Latest rates snapshot for a base currency as a stable URI |
53
55
 
54
- ---
56
+ All resource data is also reachable via tools — use `fx_list_currencies` or `fx_get_rates` for programmatic access.
55
57
 
56
- ### `fx_get_rates`
58
+ ## Capability reference
57
59
 
58
- Full rates snapshot for a base currency in one call.
60
+ ### `fx_list_currencies` <sub>tool</sub>
59
61
 
60
- - Returns all available quote currencies at a given date (default: latest), the actual `rate_date`, and `date_snapped: true` when the API silently moved a weekend/holiday request to the prior business day — always `false` when `date` is omitted
61
- - Optional `symbols` parameter narrows the response to specific quote currencies; when sent it must name at least one code — omit it to get every currency
62
- - Naming the base currency in `symbols` is valid — it is answered locally with a rate of 1 rather than sent upstream, which keeps a self-quote from failing
63
- - Useful for seeding bulk comparison workflows or discovering what's available
62
+ - No input parameters
63
+ - Returns `[{ code, name }]` for all ~30 ECB-scoped currencies, sorted alphabetically by code
64
+ - ECB coverage shifts as currencies enter or exit scope — call this to validate a user-supplied code rather than hard-coding a list
64
65
 
65
66
  ---
66
67
 
67
- ### `fx_get_rate`
68
-
69
- Point-in-time exchange rate for a single pair.
68
+ ### `fx_get_rates` <sub>tool</sub>
70
69
 
71
- - Returns the rate, the actual rate date, and `date_snapped: true` when the API silently moved a weekend/holiday request to the prior business day
72
- - Cross-rates (neither side EUR) are triangulated in a single API call — no extra round trip
73
- - A same-currency pair returns a rate of 1 without a self-quote reaching the API, but still reports the publication date the ECB actually had for that currency, so `rate_date` and `date_snapped` read the same as for any other pair
74
- - Use `fx_convert_currency` when you need the converted amount; use this tool when you only need the rate number
70
+ - `base_currency` required; `date` optional (default latest, ECB data from 1999-01-04, no future dates); optional `symbols` array narrows the response and must name at least one code
71
+ - Returns a `rates` map (quote code → rate), the actual `rate_date`, and `date_snapped: true` when a weekend/holiday request snapped to the prior business day
72
+ - Naming the base currency in `symbols` is valid — answered locally with a rate of 1 rather than sent upstream
73
+ - Typed failures: `invalid_date_format`, `unsupported_currency`, `date_out_of_range`, `upstream_no_data`
75
74
 
76
75
  ---
77
76
 
78
- ### `fx_convert_currency`
77
+ ### `fx_get_rate` <sub>tool</sub>
79
78
 
80
- Convert an amount between any two currencies.
79
+ - `base_currency`, `quote_currency` required; `date` optional (default latest, ECB data from 1999-01-04, no future dates)
80
+ - Returns `rate`, `rate_date`, and `date_snapped: true` when a weekend/holiday request snapped to the prior business day
81
+ - Cross-rates (neither side EUR) triangulate through EUR in one upstream call; a same-currency pair returns a rate of 1 without reaching the API, still dated to the real publication day
82
+ - Typed failures: `invalid_date_format`, `unsupported_currency`, `date_out_of_range`, `upstream_no_data`
83
+
84
+ ---
81
85
 
82
- - Handles EUR ↔ any, any ↔ EUR, and cross-rate (USD → JPY via EUR) in one upstream call
83
- - Returns `quote_amount`, `rate`, `rate_date`, `date_snapped`, plus `rate_type` and `source` provenance on every response
84
- - Historical conversions supported back to 1999-01-04 (ECB launch date)
86
+ ### `fx_convert_currency` <sub>tool</sub>
87
+
88
+ - `base_currency`, `quote_currency`, `amount` (must be > 0) required; `date` optional (default latest, ECB data from 1999-01-04, no future dates)
89
+ - Handles EUR↔any, any↔EUR, and cross-rate pairs (e.g. USD→JPY) in a single upstream call
90
+ - Returns `quote_amount` (rounded to 6 decimal places), `rate`, `rate_date`, `date_snapped`, plus `rate_type` and `source` provenance
91
+ - Typed failures: `invalid_date_format`, `unsupported_currency`, `date_out_of_range`, `upstream_no_data`
85
92
 
86
93
  ---
87
94
 
88
- ### `fx_get_timeseries` + `fx_dataframe_describe` / `fx_dataframe_query`
95
+ ### `fx_get_timeseries` <sub>tool</sub>
89
96
 
90
- Historical rate series and DataCanvas SQL analytics.
97
+ - `base_currency`, `quote_currency`, `start_date`, `end_date` required (ECB data from 1999-01-04, no future dates, start ≤ end); optional `canvas_id` appends to an existing canvas
98
+ - Inline results page at 500 publication days — `rate_count` is always the range total; `truncated: true` plus `next_start_date` continue the page
99
+ - Ranges over `FX_TIMESERIES_CANVAS_THRESHOLD_DAYS` (default 90 days) spill to DataCanvas when configured — response carries `spilled: true`, `canvas_id`, `table_name`; without DataCanvas they're paged inline instead
100
+ - A same-currency pair returns a rate of 1 on each real ECB publication day in range, not a synthetic Mon–Fri loop
101
+ - An empty range (only weekends/holidays) returns `rate_count: 0` with an explanatory `notice`, distinguishable from an error
91
102
 
92
- `fx_get_timeseries` returns a date-keyed series (business days only — ECB publishes once per business day):
103
+ ---
93
104
 
94
- - Short ranges (≤ `FX_TIMESERIES_CANVAS_THRESHOLD_DAYS`, default 90 days) → inline `rates` map + metadata
95
- - Long ranges, **when DataCanvas is enabled** → a preview inline + `canvas_id`, `table_name`, `spilled: true`, and a `notice` naming `fx_dataframe_describe` then `fx_dataframe_query` — the full series is registered as a DuckDB-backed table
96
- - Long ranges **without DataCanvas** → returned inline with `spilled: false`, paged (below), and a `notice` saying the threshold was crossed but no canvas was configured
97
- - Inline results are paged at 500 publication days. `rate_count` is always the total for the requested range; when a page is cut short the response carries `truncated: true` and `next_start_date`. Call again with `start_date` set to `next_start_date` and the same `end_date` for the next page — the final page has `truncated: false` and no `next_start_date`
98
- - Requesting the same currency on both sides returns a rate of 1 on each publication day in the range, taken from the ECB's real calendar rather than a synthetic Mon–Fri loop
105
+ ### `fx_dataframe_describe` <sub>tool</sub>
99
106
 
100
- The response never carries a date outside the requested range. Frankfurter snaps a range that opens on a weekend or bank holiday back to the prior publication day; those rows are dropped, so `start_date` and `end_date` always sit inside the window you asked for. A range covering only non-publication days therefore returns an empty `rates` map with `rate_count: 0` and a `notice` explaining that the ECB published nothing in that window — distinguishable from an error.
107
+ - `canvas_id` required (from a prior `fx_get_timeseries` call)
108
+ - Returns each staged table's `kind`, `row_count`, and column schema (`name`, `type`, `nullable`), plus `expires_at`
109
+ - Required first step before `fx_dataframe_query`; needs `CANVAS_PROVIDER_TYPE=duckdb` — unregistered otherwise
110
+ - `canvas_not_found` when the ID doesn't exist or has expired
101
111
 
102
- Once a `canvas_id` is in hand:
112
+ ---
103
113
 
104
- 1. **`fx_dataframe_describe`** — list the tables and columns on the canvas (required before `fx_dataframe_query`)
105
- 2. **`fx_dataframe_query`** — run arbitrary SQL SELECT against the registered table; supports aggregations, GROUP BY, window functions, JOINs across tables from multiple `fx_get_timeseries` calls. Returns at most `row_limit` rows (default 150, max 10,000) on both response surfaces; past that, `truncated: true` and a `notice` give the `ORDER BY <column> LIMIT <n> OFFSET <m>` shape for the next page (`ORDER BY` is required for stable paging). Cell values are escaped in the Markdown table so pipes, angle brackets, and line breaks stay inside their cell; `structuredContent` keeps the raw values
114
+ ### `fx_dataframe_query` <sub>tool</sub>
106
115
 
107
- The canvas uses a session-scoped TTL. To continue working with a prior series, call `fx_get_timeseries` again with the same parameters to obtain a fresh `canvas_id`.
116
+ - `canvas_id` and a read-only SQL `query` required; `row_limit` optional (1–10,000, default 150)
117
+ - Supports aggregations, GROUP BY, window functions, and JOINs across tables from multiple `fx_get_timeseries` calls
118
+ - Returns at most `row_limit` rows; `truncated: true` plus a `notice` give the `ORDER BY <column> LIMIT <n> OFFSET <m>` shape for the next page — ORDER BY is required for stable paging
119
+ - Markdown table cells are escaped so pipes, angle brackets, and line breaks stay inside their cell; `structuredContent` keeps raw values
120
+ - Needs `CANVAS_PROVIDER_TYPE=duckdb`; typed failures: `canvas_not_found`, `missing_table`, `invalid_query`
108
121
 
109
122
  ---
110
123
 
111
- ## Resources and prompts
124
+ ### `fx_dataframe_drop` <sub>tool</sub>
112
125
 
113
- | Type | Name | Description |
114
- |:-----|:-----|:------------|
115
- | Resource | `fx://currencies` | All supported currencies as a stable reference document. Injectable context for clients that support resources. |
116
- | Resource | `fx://rates/latest/{base}` | Latest rates snapshot for a base currency as a stable URI. |
126
+ - `canvas_id` and exact `table_name` (from `fx_dataframe_describe`) required
127
+ - Removes one staged table or view; ECB rate data is untouched and the series can be re-staged via `fx_get_timeseries`
128
+ - Returns `dropped: true`/`false` depending on whether the table existed
129
+ - Disabled unless `FX_ENABLE_CANVAS_DROP=true` — otherwise absent from `tools/list`, named with its enable hint only in the startup log and the HTTP landing page; also needs `CANVAS_PROVIDER_TYPE=duckdb`
117
130
 
118
- All resource data is also reachable via tools. Use `fx_list_currencies` or `fx_get_rates` for programmatic access.
131
+ ---
132
+
133
+ ### `fx://currencies` <sub>resource</sub>
134
+
135
+ - No parameters; returns `currencies`, `count`, `source` as `application/json` — the same payload as `fx_list_currencies`
136
+ - Listed as a single static resource
119
137
 
120
138
  ---
121
139
 
122
- ## Features
140
+ ### `fx://rates/latest/{base}` <sub>resource</sub>
141
+
142
+ - `base` is an ISO 4217 currency code in the URI
143
+ - Returns `base_currency`, `rate_date`, a `rates` map, `rate_type`, and `source` for the latest ECB fix
144
+ - Listed with four sample URIs (EUR, USD, GBP, JPY) as discovery hints
123
145
 
124
- Built on [`@cyanheads/mcp-ts-core`](https://www.npmjs.com/package/@cyanheads/mcp-ts-core):
146
+ ## Features
125
147
 
126
- - Declarative tool and resource definitions — single file per primitive, framework handles registration and validation
127
- - Unified error handling — handlers throw, framework catches, classifies, and formats
128
- - Typed error contracts with recovery hints — `unsupported_currency`, `date_out_of_range`, `canvas_not_found`, `missing_table`, `invalid_query`
129
- - Pluggable auth: `none`, `jwt`, `oauth`
130
- - Structured logging with optional OpenTelemetry tracing
131
- - STDIO and Streamable HTTP transports
148
+ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): stdio and Streamable HTTP transports, pluggable auth (`none` / `jwt` / `oauth`), swappable storage (`in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`), structured logging with optional OpenTelemetry tracing.
132
149
 
133
- ECB FX–specific:
150
+ ECB-specific:
134
151
 
135
152
  - Keyless access via [Frankfurter](https://www.frankfurter.dev/) — a Cloudflare-fronted ECB proxy; no API keys required
136
153
  - Cross-rate triangulation: any pair works — USD → JPY is one upstream call, cross-rated through EUR on Frankfurter's side
137
- - Weekend/holiday date semantics: `date_snapped` flag surfaces when the API returns a different date than requested
138
- - ECB data covers ~30 major currencies from 1999-01-04 to present; `fx_list_currencies` always reflects the live set, and an `unsupported_currency` rejection lists that live set inline so a caller can correct the code without a second call
139
- - Identity pairs never surface an upstream rejection: `fx_get_rate`, `fx_get_rates`, and `fx_get_timeseries` all return a rate of 1 for a currency against itself, dated to the days the ECB actually published for that currency rather than to the calendar dates requested
140
- - DataCanvas integration: when enabled, `fx_get_timeseries` spills long ranges to DuckDB for aggregations and trend analysis
141
- - Rate provenance on every response: `rate_type: "ECB reference (mid-market)"` and `source: "ECB via Frankfurter"` — explicitly mid-market, not tradeable bid/ask
154
+ - Weekend/holiday date semantics: `date_snapped` surfaces when the API returns a different date than requested
155
+ - Identity pairs never reach the upstream API: a currency against itself returns a rate of 1, dated to the day the ECB actually published for that currency rather than to the calendar date requested
156
+ - Long time-series spill to DataCanvas (DuckDB) when enabled, for SQL aggregation over the full range
142
157
 
143
158
  Agent-friendly output:
144
159
 
145
- - Rate provenance on every snapshot, rate, and conversion response — `rate_type`, `source`, `rate_date`, and `date_snapped` so agents can reason about trust and freshness
160
+ - Rate provenance on every response — `rate_type`, `source`, `rate_date`, and `date_snapped` so agents can reason about trust and freshness
146
161
  - Structured error contracts — typed `reason` fields (`unsupported_currency`, `date_out_of_range`, `invalid_query`, …) let callers branch on failure type, not string parsing
147
- - Discriminated DataCanvas output — `spilled: true` plus `canvas_id` signal when a time-series was staged for SQL follow-up rather than returned inline
148
162
  - Bounded responses — inline time-series pages continue from `next_start_date`, and SQL results cap at `row_limit`, so no call returns an unbounded payload
149
163
  - Success-path `notice` enrichment — explains an empty series, where to continue a paged series, or which tools read a staged one, so a legitimate zero-result never reads as a failure
150
164
 
@@ -290,14 +304,19 @@ All configuration is validated at startup via Zod schemas. Environment variables
290
304
  |:---------|:------------|:--------|
291
305
  | `FRANKFURTER_BASE_URL` | Frankfurter API base URL. Override for local testing or a self-hosted instance. | `https://api.frankfurter.dev/v1` |
292
306
  | `FX_TIMESERIES_CANVAS_THRESHOLD_DAYS` | Day range above which `fx_get_timeseries` spills to DataCanvas, when one is configured. | `90` |
293
- | `FX_ENABLE_CANVAS_DROP` | Enable the destructive `fx_dataframe_drop` tool. Off by default: the tool stays listed with its enable hint but is uncallable. | `false` |
307
+ | `FX_ENABLE_CANVAS_DROP` | Enable the destructive `fx_dataframe_drop` tool. Off by default: the tool is not registered and is absent from `tools/list`. | `false` |
294
308
  | `CANVAS_PROVIDER_TYPE` | Canvas engine. Set to `duckdb` to enable DataCanvas for `fx_get_timeseries` long-range spillover and to register the three `fx_dataframe_*` tools. At `none` they are skipped from `tools/list`. | `none` |
295
309
  | `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
296
310
  | `MCP_HTTP_PORT` | Port for HTTP server. | `3010` |
297
- | `MCP_SESSION_MODE` | HTTP session mode: `auto`, `stateful`, or `stateless`. `.env.example` and the Dockerfile both set `stateless` — no handler here asks the client for input mid-call, so nothing needs a session to resume. | `auto` (resolves to `stateful`) |
311
+ | `MCP_SESSION_MODE` | HTTP session mode: `auto`, `stateful`, or `stateless`. The server declares `stateless` in code — no handler here asks the client for input mid-call, so nothing needs a session to resume — and setting this variable overrides that declaration. | `stateless` |
298
312
  | `MCP_AUTH_MODE` | Auth mode: `none`, `jwt`, or `oauth`. | `none` |
299
- | `MCP_LOG_LEVEL` | Log level (RFC 5424: `debug`, `info`, `notice`, `warning`, `error`). | `info` |
313
+ | `MCP_REQUEST_STATE_KEY` | Opt-in key (≥ 32 bytes, the same on every instance) that seals the `requestState` a handler returns between rounds. No tool here returns one. | — |
314
+ | `MCP_LOG_LEVEL` | Log level (RFC 5424: `debug`, `info`, `notice`, `warning`, `error`). Also the floor for logs mirrored to the client. | `info` |
315
+ | `LOG_TOOL_FAILURE_PAYLOADS` | Log each failed tool call's arguments and result (redacted by key name only). | `false` |
316
+ | `LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES` | Per-payload cap for `LOG_TOOL_FAILURE_PAYLOADS`, in UTF-8 bytes. | `16384` |
300
317
  | `OTEL_ENABLED` | Enable [OpenTelemetry instrumentation](https://github.com/cyanheads/mcp-ts-core/tree/main/docs/telemetry). | `false` |
318
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP base URL; traces go to `/v1/traces`, metrics to `/v1/metrics`. | — |
319
+ | `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` | Opt-in OTLP log export (e.g. `http://localhost:4318/v1/logs`); the base endpoint never enables it. | — |
301
320
 
302
321
  See [`.env.example`](./.env.example) for the full list of optional overrides including storage, session, and telemetry vars.
303
322
 
@@ -331,7 +350,7 @@ docker build -t exchange-rates-mcp-server .
331
350
  docker run --rm -p 3010:3010 exchange-rates-mcp-server
332
351
  ```
333
352
 
334
- The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `/var/log/exchange-rates-mcp-server`. OpenTelemetry peer dependencies are installed by default — build with `--build-arg OTEL_ENABLED=false` to omit them. DuckDB native binaries are pre-built in the build stage and copied to production, keeping the production image free of build tools.
353
+ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `/var/log/exchange-rates-mcp-server`. OpenTelemetry peer dependencies are installed by default — build with `--build-arg OTEL_ENABLED=false` to omit them. Production dependencies, DuckDB's native binding included, are cross-installed for the target platform in a separate `deps` stage, so multi-arch builds never run Bun under emulation and the runtime image carries only `node_modules` and `dist/`.
335
354
 
336
355
  ---
337
356
 
@@ -365,7 +384,7 @@ See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rule
365
384
 
366
385
  ## Contributing
367
386
 
368
- Issues and pull requests are welcome. Run checks and tests before submitting:
387
+ Issues are welcome. Run checks and tests before submitting:
369
388
 
370
389
  ```sh
371
390
  bun run devcheck
@@ -0,0 +1,27 @@
1
+ ---
2
+ summary: "Adopts mcp-ts-core 0.13.6: declares stateless session mode in source, validates canvas_id inputs against the minted shape at argument validation, and stops putting the upstream Frankfurter request URL — which carried caller currency codes/dates plus the configured API host — on client-facing error data."
3
+ breaking: false
4
+ security: true
5
+ ---
6
+
7
+ # 0.4.1 — 2026-09-19
8
+
9
+ ## Changed
10
+
11
+ - **`sessionMode: 'stateless'` is now declared in `src/index.ts`** — the HTTP session posture no longer depends solely on `.env.example`/Dockerfile defaults; `MCP_SESSION_MODE` set in the environment still overrides it.
12
+ - **`canvas_id` inputs are validated against the minted `^[A-Za-z0-9_-]{10}$` shape** on `fx_dataframe_describe`, `fx_dataframe_query`, `fx_dataframe_drop`, and `fx_get_timeseries` — a malformed id is now rejected at argument validation instead of reaching the canvas registry, which could only report it as missing or expired.
13
+ - **Dev skill tree moved from `skills/` to `framework-skills/`** — a plugin's root `skills/` auto-loads for installers, which would hand these development skills to every agent that installs the server; not part of the published npm package.
14
+ - **`@cyanheads/mcp-ts-core` 0.12.8 → 0.13.6** — see Dependencies.
15
+
16
+ ## Security
17
+
18
+ - **The upstream Frankfurter request URL no longer reaches client-facing error data.** `structuredContent.error.data` previously carried the full request URL on an upstream failure — the caller's currency codes and dates alongside the configured `FRANKFURTER_BASE_URL` host; the error message still names the service.
19
+
20
+ ## Dependencies
21
+
22
+ - `@cyanheads/mcp-ts-core` 0.12.8 → 0.13.6
23
+ - `@duckdb/node-api` ^1.5.5-r.4 → ^1.5.5-r.5
24
+ - `zod` ^4.6.0 → ^4.6.5
25
+ - `@biomejs/biome` 2.5.12 → 2.5.14
26
+ - `tsc-alias` ^1.9.4 → ^1.9.5
27
+ - `vitest` ^5.0.0 → ^5.0.1
@@ -0,0 +1,45 @@
1
+ ---
2
+ summary: "Adopts mcp-ts-core 0.13.11: tool errors carry a request ID and their declared recovery hint, multi-arch image builds stop running Bun under emulation, and a spilled fx_get_timeseries series always stages rate as DOUBLE."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.4.2 — 2026-10-04
8
+
9
+ Advertised tool schemas are unchanged: `tools/list` (names, input/output schemas, annotations, descriptions) is byte-identical to 0.4.1.
10
+
11
+ ## Changed
12
+
13
+ - **Tool error results carry `data.requestId`** and close with `request <id>`, and a declared `errors[]` recovery hint reaches the result without a `ctx.recoveryFor` forward (0.13.10). The tools drop those forwards; the hints callers receive are unchanged.
14
+ - **Server stack traces (0.13.7) and request-context fields (0.13.8) no longer reach client-facing error `data`.**
15
+ - **Argument repair and rejections** — a JSON-stringified object, or an integer sent for a string field, is repaired instead of rejected, and argument rejections name the field paths involved (0.13.9).
16
+ - **`ctx.log` notifications to the client honor `MCP_LOG_LEVEL` and mask sensitive fields** (0.13.11).
17
+ - **DataCanvas scratch files live in a private per-process directory**, and `CANVAS_TEMP_PATH` now names its parent (0.13.9).
18
+ - **Dockerfile** — production dependencies cross-install (`--os`/`--cpu`) in a `deps` stage on `$BUILDPLATFORM`, OTel peers through `scripts/install-otel.ts`, so multi-arch builds never run Bun under emulation (0.13.10); `scripts/prune-musl-packages.ts` drops musl-only packages (0.13.11). Base images move to `oven/bun:1.4.2` (0.13.7).
19
+ - **Config docs** — `.env.example` and the README document `MCP_REQUEST_STATE_KEY` (no tool here returns `requestState`), `LOG_TOOL_FAILURE_PAYLOADS` / `LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES`, and the OTLP endpoints, log export opt-in through `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`; `.env.example` adds the log rate-limit vars.
20
+ - **Repo hygiene** — `.gitignore` and `.dockerignore` cover every `.env*` variant, `.dockerignore` excludes the MCP Registry token files, `.mcpbignore` drops `docs/idea.md`, `logs/`, and `.cache/` from the bundle, npm `files` excludes `dist/*.mcpb`, and `packageManager` moves to `bun@1.4.2`.
21
+ - **CodeQL workflow** runs one matrix job per language, uploading under `/language:<language>` so alerts raised by default setup close here once fixed.
22
+ - **Framework skills and dev scripts** (`devcheck`, `lint-mcp`, `lint-packaging`, `check-skill-versions`, `release-github`) resynced to mcp-ts-core 0.13.11; `CLAUDE.md`/`AGENTS.md` now declare gated release PRs.
23
+
24
+ ## Removed
25
+
26
+ - **`MCP_FORCE_CONSOLE_LOGGING`** is gone from the Dockerfile; nothing read it (0.13.8).
27
+
28
+ ## Fixed
29
+
30
+ - **`fx_get_timeseries` stages a spilled series with `rate` typed `DOUBLE`** ([#21](https://github.com/cyanheads/exchange-rates-mcp-server/issues/21)) — `spillover()` gets an explicit column schema, so a series whose leading rates are whole numbers no longer stages `rate` as `BIGINT` and truncates later fractional rates.
31
+ - **`server.json` npm entries** drop the `run start:*` package arguments a registry client would hand the bin and set `runtimeHint: "npx"`; the `streamable-http` entry fixes `MCP_TRANSPORT_TYPE` to `"value": "http"` so it actually starts HTTP (0.13.11).
32
+ - **`FX_ENABLE_CANVAS_DROP` docs** ([#23](https://github.com/cyanheads/exchange-rates-mcp-server/issues/23)) — `server.json` and the README said a disabled `fx_dataframe_drop` stays listed but uncallable; it is absent from `tools/list` until the flag is `true`, and the descriptions now say so.
33
+
34
+ ## Dependencies
35
+
36
+ - `@cyanheads/mcp-ts-core` 0.13.6 → ^0.13.11
37
+ - `@modelcontextprotocol/server` ^2.0.0 → ^2.2.0 (via the framework)
38
+ - `@duckdb/node-api` ^1.5.5-r.5 → ^1.5.6-r.1
39
+ - `@biomejs/biome` 2.5.14 → 2.5.15
40
+ - `@socketsecurity/bun-security-scanner` ^1.1.2 → ^1.1.3
41
+ - `@types/node` 26.5.1 → 26.6.3
42
+ - `ignore` ^7.0.9 → ^7.0.11
43
+ - `tsc-alias` ^1.9.5 → ^1.9.7
44
+ - `vitest` ^5.0.1 → ^5.0.3
45
+ - `brace-expansion` 1.1.18 → 1.1.21 and 2.1.4 → 2.1.7 (lockfile only)
@@ -6,8 +6,8 @@
6
6
 
7
7
  # Required. One-line GitHub Release-style headline. 350 character cap — a
8
8
  # ceiling, not a target. Default short and scannable. Don't pad, don't stitch
9
- # unrelated changes with commas/semicolons into an inventory — pick the
10
- # headline, like a tag's theme line. Quotes required: unquoted YAML treats
9
+ # unrelated changes with commas/semicolons into an inventory — pick the one
10
+ # headline the release is about. Quotes required: unquoted YAML treats
11
11
  # `: ` inside the value as a key separator and fails GitHub's strict parser.
12
12
  summary: ""
13
13
 
@@ -117,30 +117,13 @@ security: false
117
117
  in that unrelated item's metadata.
118
118
 
119
119
  TAG ANNOTATIONS — the annotated tag body renders as the GitHub Release body
120
- via `gh release create --notes-from-tag`. The tag is a derivative of this
121
- changelog entry — a condensed, scannable version, not a copy. Format:
122
-
123
- <theme — omit version number, GitHub prepends it>
124
- ← blank line
125
- <1-2 sentence context: what this release does>
126
- ← blank line
127
- Dependency bumps: ← section header
128
- ← blank line
129
- - `@cyanheads/mcp-ts-core` ^0.9.1 → ^0.9.6 ← bullet
130
- ← blank line
131
- Changed: ← only sections with entries
132
- ← blank line
133
- - `format()` output includes `query` in text mode
134
- ← blank line
135
- Added:
136
- ← blank line
137
- - `manifest.json` scaffolded for MCPB bundle support
138
- - Install badges (Claude Desktop, Cursor, VS Code)
139
- ← blank line
140
- <N> tests pass; `bun run devcheck` clean. ← footer
141
-
142
- Never a flat comma-separated string. Always structured markdown with
143
- sections. The tag must scan well as a rendered GitHub Release page.
120
+ via `gh release create --notes-from-tag`. It is a condensed digest of this
121
+ entry, never a copy, and its format is owned by the `release-and-publish`
122
+ skill (step 4, "Create the annotated tag"): a short subject line without the
123
+ version, flat headline bullets — no Keep-a-Changelog section headers, no
124
+ gates line — at most one deps line, issue backlinks, and the changelog link
125
+ last. In release-PR mode the `git-wrapup` skill authors those bullets as the
126
+ PR body's `## Changes` and the tag copies them.
144
127
  -->
145
128
 
146
129
  ## Added
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { createApp, disabledTool } from '@cyanheads/mcp-ts-core';
7
7
  import { config } from '@cyanheads/mcp-ts-core/config';
8
+ import { getServerConfig } from './config/server-config.js';
8
9
  import { fxCurrenciesResource, fxRatesLatestResource, } from './mcp-server/resources/definitions/index.js';
9
10
  import { fxConvertCurrency, fxDataframeDescribe, fxDataframeDrop, fxDataframeQuery, fxGetRate, fxGetRates, fxGetTimeseries, fxListCurrencies, } from './mcp-server/tools/definitions/index.js';
10
11
  import { setCanvas } from './services/canvas/canvas-accessor.js';
@@ -23,6 +24,13 @@ const canvasGate = {
23
24
  await createApp({
24
25
  name: 'exchange-rates-mcp-server',
25
26
  title: 'exchange-rates-mcp-server',
27
+ /**
28
+ * No handler here asks the caller for input mid-call, so nothing needs a session
29
+ * to resume. Declared in source rather than left to `.env.example` and the
30
+ * Dockerfile alone, which a deployment can drop; `MCP_SESSION_MODE` still wins
31
+ * when it carries a value.
32
+ */
33
+ sessionMode: 'stateless',
26
34
  tools: [
27
35
  fxListCurrencies,
28
36
  fxGetRates,
@@ -44,6 +52,7 @@ await createApp({
44
52
  ' Without it, long ranges return inline in pages of 500 publication days (continue from next_start_date)\n' +
45
53
  ' and the dataframe tools are not listed.',
46
54
  setup(core) {
55
+ getServerConfig();
47
56
  setCanvas(core.canvas);
48
57
  },
49
58
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,eAAe,EACf,gBAAgB,GACjB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,KAAK,MAAM,CAAC;AAC5D,MAAM,UAAU,GAAG;IACjB,IAAI,EAAE,6BAA6B;IACnC,MAAM,EAAE,wFAAwF;CACxF,CAAC;AAEX,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,2BAA2B;IACjC,KAAK,EAAE,2BAA2B;IAClC,KAAK,EAAE;QACL,gBAAgB;QAChB,UAAU;QACV,SAAS;QACT,iBAAiB;QACjB,eAAe;QACf,aAAa,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,YAAY,CAAC,mBAAmB,EAAE,UAAU,CAAC;QACnF,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,YAAY,CAAC,gBAAgB,EAAE,UAAU,CAAC;QAC7E,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,eAAe,EAAE,UAAU,CAAC;KAC5E;IACD,SAAS,EAAE,CAAC,oBAAoB,EAAE,qBAAqB,CAAC;IACxD,OAAO,EAAE,EAAE;IAEX,YAAY,EACV,4FAA4F;QAC5F,uEAAuE;QACvE,mFAAmF;QACnF,4EAA4E;QAC5E,uGAAuG;QACvG,yFAAyF;QACzF,4GAA4G;QAC5G,2CAA2C;IAE7C,KAAK,CAAC,IAAI;QACR,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EACL,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,eAAe,EACf,gBAAgB,GACjB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,KAAK,MAAM,CAAC;AAC5D,MAAM,UAAU,GAAG;IACjB,IAAI,EAAE,6BAA6B;IACnC,MAAM,EAAE,wFAAwF;CACxF,CAAC;AAEX,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,2BAA2B;IACjC,KAAK,EAAE,2BAA2B;IAElC;;;;;OAKG;IACH,WAAW,EAAE,WAAW;IAExB,KAAK,EAAE;QACL,gBAAgB;QAChB,UAAU;QACV,SAAS;QACT,iBAAiB;QACjB,eAAe;QACf,aAAa,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,YAAY,CAAC,mBAAmB,EAAE,UAAU,CAAC;QACnF,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,YAAY,CAAC,gBAAgB,EAAE,UAAU,CAAC;QAC7E,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,eAAe,EAAE,UAAU,CAAC;KAC5E;IACD,SAAS,EAAE,CAAC,oBAAoB,EAAE,qBAAqB,CAAC;IACxD,OAAO,EAAE,EAAE;IAEX,YAAY,EACV,4FAA4F;QAC5F,uEAAuE;QACvE,mFAAmF;QACnF,4EAA4E;QAC5E,uGAAuG;QACvG,yFAAyF;QACzF,4GAA4G;QAC5G,2CAA2C;IAE7C,KAAK,CAAC,IAAI;QACR,eAAe,EAAE,CAAC;QAClB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;CACF,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"fx-convert-currency.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-convert-currency.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AASjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqL5B,CAAC"}
1
+ {"version":3,"file":"fx-convert-currency.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-convert-currency.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AASjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8K5B,CAAC"}
@@ -86,18 +86,14 @@ export const fxConvertCurrency = tool('fx_convert_currency', {
86
86
  if (date !== 'latest') {
87
87
  /** Format first — the range comparisons below are lexicographic and would misread a malformed date. */
88
88
  if (!isIsoDate(date)) {
89
- throw ctx.fail('invalid_date_format', `date "${date}" is not a valid YYYY-MM-DD calendar date.`, { ...ctx.recoveryFor('invalid_date_format'), field: 'date' });
89
+ throw ctx.fail('invalid_date_format', `date "${date}" is not a valid YYYY-MM-DD calendar date.`, { field: 'date' });
90
90
  }
91
91
  if (date < ECB_START_DATE) {
92
- throw ctx.fail('date_out_of_range', `Date ${date} is before ECB data start ${ECB_START_DATE}.`, {
93
- ...ctx.recoveryFor('date_out_of_range'),
94
- });
92
+ throw ctx.fail('date_out_of_range', `Date ${date} is before ECB data start ${ECB_START_DATE}.`);
95
93
  }
96
94
  const today = new Date().toISOString().slice(0, 10);
97
95
  if (date > today) {
98
- throw ctx.fail('date_out_of_range', `Date ${date} is in the future.`, {
99
- ...ctx.recoveryFor('date_out_of_range'),
100
- });
96
+ throw ctx.fail('date_out_of_range', `Date ${date} is in the future.`);
101
97
  }
102
98
  }
103
99
  let resolved;
@@ -108,13 +104,12 @@ export const fxConvertCurrency = tool('fx_convert_currency', {
108
104
  const failure = failureOf(err);
109
105
  if (failure?.reason === 'unsupported_currency') {
110
106
  throw ctx.fail('unsupported_currency', err.message, {
111
- ...ctx.recoveryFor('unsupported_currency'),
112
107
  field: failure.field,
113
108
  ...unsupportedCurrencyCodesOf(err),
114
109
  });
115
110
  }
116
111
  if (failure?.reason === 'upstream_no_data') {
117
- throw ctx.fail('upstream_no_data', `The ECB published no ${input.base_currency}/${input.quote_currency} rate for ${date === 'latest' ? 'the latest business day' : date}.`, { ...ctx.recoveryFor('upstream_no_data') });
112
+ throw ctx.fail('upstream_no_data', `The ECB published no ${input.base_currency}/${input.quote_currency} rate for ${date === 'latest' ? 'the latest business day' : date}.`);
118
113
  }
119
114
  throw err;
120
115
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fx-convert-currency.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-convert-currency.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACzF,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,SAAS,GACV,MAAM,+CAA+C,CAAC;AAGvD,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC,qBAAqB,EAAE;IAC3D,WAAW,EACT,mFAAmF;QACnF,qFAAqF;QACrF,qEAAqE;QACrE,yDAAyD;IAC3D,WAAW,EAAE;QACX,YAAY,EAAE,IAAI;QAClB,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;KACpB;IACD,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,aAAa,EAAE,CAAC;aACb,MAAM,EAAE;aACR,QAAQ,CACP,uFAAuF,CACxF;QACH,cAAc,EAAE,CAAC;aACd,MAAM,EAAE;aACR,QAAQ,CACP,2FAA2F;YACzF,6CAA6C,CAChD;QACH,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,oEAAoE,CAAC;QACjF,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,wFAAwF;YACtF,6DAA6D,CAChE;KACJ,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QAC3D,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QAC5D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;QAC1E,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,CAAC,0EAA0E,CAAC;QACvF,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,CAAC,0EAA0E,CAAC;QACvF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;QAC9E,YAAY,EAAE,CAAC;aACZ,OAAO,EAAE;aACT,QAAQ,CACP,+DAA+D;YAC7D,wEAAwE,CAC3E;QACH,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,QAAQ,CACP,yFAAyF,CAC1F;QACH,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4DAA4D,CAAC;KAC1F,CAAC;IAEF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,qBAAqB;YAC7B,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,yDAAyD;YAC/D,QAAQ,EAAE,4EAA4E;SACvF;QACD;YACE,MAAM,EAAE,sBAAsB;YAC9B,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,iEAAiE;YACvE,QAAQ,EAAE,kEAAkE;SAC7E;QACD;YACE,MAAM,EAAE,mBAAmB;YAC3B,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,6CAA6C;YACnD,QAAQ,EAAE,sEAAsE;SACjF;QACD;YACE,MAAM,EAAE,kBAAkB;YAC1B,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,4EAA4E;YAClF,QAAQ,EAAE,wEAAwE;SACnF;KACF;IAED,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,QAAQ,CAAC;QAEpC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,uGAAuG;YACvG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrB,MAAM,GAAG,CAAC,IAAI,CACZ,qBAAqB,EACrB,SAAS,IAAI,4CAA4C,EACzD,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,qBAAqB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAC7D,CAAC;YACJ,CAAC;YACD,IAAI,IAAI,GAAG,cAAc,EAAE,CAAC;gBAC1B,MAAM,GAAG,CAAC,IAAI,CACZ,mBAAmB,EACnB,QAAQ,IAAI,6BAA6B,cAAc,GAAG,EAC1D;oBACE,GAAG,GAAG,CAAC,WAAW,CAAC,mBAAmB,CAAC;iBACxC,CACF,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;gBACjB,MAAM,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,QAAQ,IAAI,oBAAoB,EAAE;oBACpE,GAAG,GAAG,CAAC,WAAW,CAAC,mBAAmB,CAAC;iBACxC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,QAAsB,CAAC;QAC3B,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;QACpF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,OAAO,EAAE,MAAM,KAAK,sBAAsB,EAAE,CAAC;gBAC/C,MAAM,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAG,GAAa,CAAC,OAAO,EAAE;oBAC7D,GAAG,GAAG,CAAC,WAAW,CAAC,sBAAsB,CAAC;oBAC1C,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,GAAG,0BAA0B,CAAC,GAAG,CAAC;iBACnC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,OAAO,EAAE,MAAM,KAAK,kBAAkB,EAAE,CAAC;gBAC3C,MAAM,GAAG,CAAC,IAAI,CACZ,kBAAkB,EAClB,wBAAwB,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,cAAc,aACjE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,IAClD,GAAG,EACH,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,kBAAkB,CAAC,EAAE,CAC3C,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,IAAI,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;QAErF,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE;YACjC,IAAI,EAAE,QAAQ,CAAC,YAAY;YAC3B,KAAK,EAAE,QAAQ,CAAC,aAAa;YAC7B,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,MAAM,EAAE,WAAW;YACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,IAAI,EAAE,QAAQ,CAAC,QAAQ;YACvB,OAAO,EAAE,QAAQ,CAAC,WAAW;SAC9B,CAAC,CAAC;QAEH,OAAO;YACL,aAAa,EAAE,QAAQ,CAAC,YAAY;YACpC,cAAc,EAAE,QAAQ,CAAC,aAAa;YACtC,WAAW,EAAE,KAAK,CAAC,MAAM;YACzB,YAAY,EAAE,WAAW;YACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,SAAS,EAAE,QAAQ,CAAC,QAAQ;YAC5B,YAAY,EAAE,QAAQ,CAAC,WAAW;YAClC,SAAS,EAAE,QAAQ,CAAC,QAAQ;YAC5B,MAAM,EAAE,QAAQ,CAAC,MAAM;SACxB,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY;YAClC,CAAC,CAAC,mCAAmC,MAAM,CAAC,SAAS,qBAAqB;YAC1E,CAAC,CAAC,EAAE,CAAC;QACP,OAAO;YACL;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EACF,KAAK,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,aAAa,UAAU,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,cAAc,MAAM;oBAC3G,SAAS,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,aAAa,OAAO,MAAM,CAAC,SAAS,EAAE;oBAC/F,QAAQ;oBACR,MAAM,MAAM,CAAC,SAAS,MAAM,MAAM,CAAC,MAAM,GAAG;aAC/C;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"fx-convert-currency.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-convert-currency.tool.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fx-dataframe-describe.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-describe.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAgC,MAAM,+BAA+B,CAAC;AAG/F,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;cAsH9B,CAAC"}
1
+ {"version":3,"file":"fx-dataframe-describe.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-describe.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAgC,MAAM,+BAA+B,CAAC;AAG/F,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;cA8G9B,CAAC"}
@@ -3,6 +3,7 @@
3
3
  * @module mcp-server/tools/definitions/fx-dataframe-describe.tool
4
4
  */
5
5
  import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { CanvasIdSchema } from '@cyanheads/mcp-ts-core/canvas';
6
7
  import { JsonRpcErrorCode, McpError, serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
7
8
  import { getCanvas } from '../../../services/canvas/canvas-accessor.js';
8
9
  export const fxDataframeDescribe = tool('fx_dataframe_describe', {
@@ -16,9 +17,7 @@ export const fxDataframeDescribe = tool('fx_dataframe_describe', {
16
17
  openWorldHint: false,
17
18
  },
18
19
  input: z.object({
19
- canvas_id: z
20
- .string()
21
- .describe('Canvas ID returned by fx_get_timeseries. ' +
20
+ canvas_id: CanvasIdSchema.describe('Canvas ID returned by fx_get_timeseries. ' +
22
21
  'Re-run fx_get_timeseries to obtain a fresh canvas_id if this one has expired.'),
23
22
  }),
24
23
  output: z.object({
@@ -64,9 +63,7 @@ export const fxDataframeDescribe = tool('fx_dataframe_describe', {
64
63
  /** The canvas layer stamps a contract `reason` on its own throws — read that, don't match prose. */
65
64
  const reason = err instanceof McpError ? err.data?.reason : undefined;
66
65
  if (reason === 'canvas_not_found') {
67
- throw ctx.fail('canvas_not_found', `Canvas "${input.canvas_id}" not found or has expired.`, {
68
- ...ctx.recoveryFor('canvas_not_found'),
69
- });
66
+ throw ctx.fail('canvas_not_found', `Canvas "${input.canvas_id}" not found or has expired.`);
70
67
  }
71
68
  throw err;
72
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fx-dataframe-describe.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-describe.tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fx-dataframe-describe.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-describe.tool.ts"],"names":[],"mappings":"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"}
@@ -6,8 +6,9 @@ import { z } from '@cyanheads/mcp-ts-core';
6
6
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
7
  /**
8
8
  * Deletion is the one destructive verb on the canvas surface, so it ships
9
- * disabled: the tool stays visible in the manifest carrying its enable hint,
10
- * and answers uncallable until an operator opts in.
9
+ * disabled: `disabledTool()` keeps it out of `tools/list`, naming it with its
10
+ * enable hint only in the startup log and on the HTTP landing page, until an
11
+ * operator opts in.
11
12
  */
12
13
  export declare const fxDataframeDrop: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
13
14
  canvas_id: z.ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"fx-dataframe-drop.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-drop.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAsB,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAY,MAAM,+BAA+B,CAAC;AAoG3E;;;;GAIG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;cAKtB,CAAC"}
1
+ {"version":3,"file":"fx-dataframe-drop.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-drop.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAsB,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAY,MAAM,+BAA+B,CAAC;AA6F3E;;;;;GAKG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;cAKtB,CAAC"}