@cyanheads/exchange-rates-mcp-server 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +17 -13
- package/CLAUDE.md +17 -13
- package/Dockerfile +10 -0
- package/README.md +17 -13
- package/changelog/0.3.x/0.3.2.md +29 -0
- package/changelog/0.4.x/0.4.0.md +22 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/resources/definitions/fx-rates-latest.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/fx-rates-latest.resource.js +7 -2
- package/dist/mcp-server/resources/definitions/fx-rates-latest.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.js +4 -2
- package/dist/mcp-server/tools/definitions/fx-convert-currency.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.d.ts +4 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.js +52 -19
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.js +4 -2
- package/dist/mcp-server/tools/definitions/fx-get-rate.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.js +20 -6
- package/dist/mcp-server/tools/definitions/fx-get-rates.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.d.ts +2 -0
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.js +115 -82
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.js.map +1 -1
- package/dist/services/frankfurter/errors.d.ts +17 -2
- package/dist/services/frankfurter/errors.d.ts.map +1 -1
- package/dist/services/frankfurter/errors.js +26 -6
- package/dist/services/frankfurter/errors.js.map +1 -1
- package/dist/services/frankfurter/frankfurter-service.d.ts +1 -0
- package/dist/services/frankfurter/frankfurter-service.d.ts.map +1 -1
- package/dist/services/frankfurter/frankfurter-service.js +5 -3
- package/dist/services/frankfurter/frankfurter-service.js.map +1 -1
- package/dist/utils/escape-markdown-table-cell.d.ts +11 -0
- package/dist/utils/escape-markdown-table-cell.d.ts.map +1 -0
- package/dist/utils/escape-markdown-table-cell.js +19 -0
- package/dist/utils/escape-markdown-table-cell.js.map +1 -0
- package/package.json +9 -9
- package/server.json +3 -3
package/AGENTS.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** exchange-rates-mcp-server
|
|
4
|
-
**Version:** 0.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `0.12.
|
|
6
|
-
**Engines:** Bun ≥1.
|
|
4
|
+
**Version:** 0.4.0
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `0.12.8`
|
|
6
|
+
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/server` ^2.0.0
|
|
8
|
-
**Zod:** ^4.
|
|
8
|
+
**Zod:** ^4.6.0
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
11
11
|
|
|
@@ -37,6 +37,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
|
|
|
37
37
|
- **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.
|
|
38
38
|
- **Need input the caller didn't supply?** `return ctx.requestInput(...)` and read `ctx.inputs` when the handler is re-entered. Never `await` for user input mid-handler.
|
|
39
39
|
- **Secrets in env vars only** — never hardcoded.
|
|
40
|
+
- **Cut noise.** Add only what earns its place: no speculative generality, no guards for states the framework already prevents (Zod-validated params, classified errors), no abstraction until a third caller proves it, no option nothing sets.
|
|
40
41
|
- **Close the loop on issues.** When implementing work tracked by a GitHub issue, comment on the issue with what landed and close it. Do both — a comment without a close leaves stale issues open; a close without a comment leaves no record of what shipped. The comment is for future readers — state the concrete changes, not the conversation that produced them.
|
|
41
42
|
|
|
42
43
|
---
|
|
@@ -55,7 +56,7 @@ export const fxGetRate = tool('fx_get_rate', {
|
|
|
55
56
|
'Get the exchange rate for a currency pair on a given date (default: latest). ' +
|
|
56
57
|
'Returns the rate, the actual rate date, and source provenance. ' +
|
|
57
58
|
'Cross-rates are triangulated through EUR automatically.',
|
|
58
|
-
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
59
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
59
60
|
input: z.object({
|
|
60
61
|
base_currency: z.string().describe('ISO 4217 base currency code (e.g. USD).'),
|
|
61
62
|
quote_currency: z.string().describe('ISO 4217 quote currency code (e.g. EUR).'),
|
|
@@ -69,10 +70,10 @@ export const fxGetRate = tool('fx_get_rate', {
|
|
|
69
70
|
source: z.string().describe('Always "ECB via Frankfurter".'),
|
|
70
71
|
}),
|
|
71
72
|
errors: [
|
|
72
|
-
{ reason: 'unsupported_currency', code: JsonRpcErrorCode.
|
|
73
|
+
{ reason: 'unsupported_currency', code: JsonRpcErrorCode.ValidationError,
|
|
73
74
|
when: 'base_currency or quote_currency is not in the ECB currency set',
|
|
74
75
|
recovery: 'Call fx_list_currencies to get valid ISO 4217 codes.' },
|
|
75
|
-
{ reason: 'date_out_of_range', code: JsonRpcErrorCode.
|
|
76
|
+
{ reason: 'date_out_of_range', code: JsonRpcErrorCode.ValidationError,
|
|
76
77
|
when: 'date is before 1999-01-04 or in the future',
|
|
77
78
|
recovery: 'ECB data starts 1999-01-04; omit date for latest.' },
|
|
78
79
|
],
|
|
@@ -186,7 +187,7 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
186
187
|
|
|
187
188
|
Handlers throw — the framework catches, classifies, and formats.
|
|
188
189
|
|
|
189
|
-
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire (`data.recovery.hint`, mirrored into `content[]` text); override with an explicit `{ recovery: { hint: '...' } }` when dynamic runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`) bubble freely and don't need declaring.
|
|
190
|
+
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire (`data.recovery.hint`, mirrored into `content[]` text); override with an explicit `{ recovery: { hint: '...' } }` when dynamic runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring.
|
|
190
191
|
|
|
191
192
|
```ts
|
|
192
193
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
@@ -245,14 +246,16 @@ src/
|
|
|
245
246
|
fx-convert-currency.tool.ts # Convert amount between two currencies
|
|
246
247
|
fx-get-rate.tool.ts # Exchange rate for a currency pair
|
|
247
248
|
fx-get-rates.tool.ts # All rates for a base currency snapshot
|
|
248
|
-
fx-get-timeseries.tool.ts # Historical daily rates; spills to DataCanvas for long ranges
|
|
249
|
+
fx-get-timeseries.tool.ts # Historical daily rates; inline pages of 500 days, spills to DataCanvas for long ranges
|
|
249
250
|
fx-list-currencies.tool.ts # All supported ISO 4217 currencies
|
|
250
251
|
fx-dataframe-describe.tool.ts # List DataCanvas tables from a prior timeseries call
|
|
251
|
-
fx-dataframe-query.tool.ts # SQL SELECT against DataCanvas tables
|
|
252
|
+
fx-dataframe-query.tool.ts # SQL SELECT against DataCanvas tables, bounded by row_limit
|
|
252
253
|
fx-dataframe-drop.tool.ts # Remove one staged table; opt-in via FX_ENABLE_CANVAS_DROP
|
|
253
254
|
resources/definitions/
|
|
254
255
|
fx-currencies.resource.ts # fx://currencies — stable currencies reference document
|
|
255
256
|
fx-rates-latest.resource.ts # fx://rates/latest/{base} — latest rates snapshot
|
|
257
|
+
utils/
|
|
258
|
+
escape-markdown-table-cell.ts # Escapes a value for one GFM table cell (fx_dataframe_query format())
|
|
256
259
|
```
|
|
257
260
|
|
|
258
261
|
---
|
|
@@ -291,8 +294,9 @@ Available skills:
|
|
|
291
294
|
| `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
|
|
292
295
|
| `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
|
|
293
296
|
| `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
|
|
294
|
-
| `git-wrapup` | Land working-tree changes as a
|
|
295
|
-
| `release-
|
|
297
|
+
| `git-wrapup` | Land working-tree changes as a commit stack — version bump, changelog, verify, commit by concern, release commit on top. No tag, no push to main; opens the release PR when the project declares release PR mode |
|
|
298
|
+
| `release-pr-review` | Review pass on an open release PR — simplifier + correctness review, fixup commits autosquashed into the stack, PR body kept in sync. Release PR mode only |
|
|
299
|
+
| `release-and-publish` | Fast-forward merge (release PR mode) + tag + push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup` |
|
|
296
300
|
| `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
|
|
297
301
|
| `orchestrations` | Chain task skills into a gated multi-phase pipeline — build-out, QA-fix, update-ship — when you can spawn sub-agents |
|
|
298
302
|
| `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
|
|
@@ -375,7 +379,7 @@ security: false # optional — true ONLY for a source
|
|
|
375
379
|
|
|
376
380
|
`agent-notes` is an optional free-form field for maintenance agents processing the release downstream. Content here won't appear in the rendered CHANGELOG — it's consumed by agents running the `maintenance` skill. Use it for adoption instructions that don't fit the human-facing sections: new files to create, fields to populate, one-time migration steps. Omit entirely when there's nothing to say.
|
|
377
381
|
|
|
378
|
-
**Section order
|
|
382
|
+
**Section order:** the Keep a Changelog sequence — Added, Changed, Deprecated, Removed, Fixed, Security — then `Dependencies` last. Include only sections with entries — don't ship empty headers.
|
|
379
383
|
|
|
380
384
|
**Tag annotations** render as GitHub Release bodies via `--notes-from-tag`. They must be structured markdown — never a flat comma-separated string. Subject omits the version number (GitHub prepends it). See `changelog/template.md` for the full format reference.
|
|
381
385
|
|
package/CLAUDE.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** exchange-rates-mcp-server
|
|
4
|
-
**Version:** 0.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `0.12.
|
|
6
|
-
**Engines:** Bun ≥1.
|
|
4
|
+
**Version:** 0.4.0
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `0.12.8`
|
|
6
|
+
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/server` ^2.0.0
|
|
8
|
-
**Zod:** ^4.
|
|
8
|
+
**Zod:** ^4.6.0
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
11
11
|
|
|
@@ -37,6 +37,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
|
|
|
37
37
|
- **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.
|
|
38
38
|
- **Need input the caller didn't supply?** `return ctx.requestInput(...)` and read `ctx.inputs` when the handler is re-entered. Never `await` for user input mid-handler.
|
|
39
39
|
- **Secrets in env vars only** — never hardcoded.
|
|
40
|
+
- **Cut noise.** Add only what earns its place: no speculative generality, no guards for states the framework already prevents (Zod-validated params, classified errors), no abstraction until a third caller proves it, no option nothing sets.
|
|
40
41
|
- **Close the loop on issues.** When implementing work tracked by a GitHub issue, comment on the issue with what landed and close it. Do both — a comment without a close leaves stale issues open; a close without a comment leaves no record of what shipped. The comment is for future readers — state the concrete changes, not the conversation that produced them.
|
|
41
42
|
|
|
42
43
|
---
|
|
@@ -55,7 +56,7 @@ export const fxGetRate = tool('fx_get_rate', {
|
|
|
55
56
|
'Get the exchange rate for a currency pair on a given date (default: latest). ' +
|
|
56
57
|
'Returns the rate, the actual rate date, and source provenance. ' +
|
|
57
58
|
'Cross-rates are triangulated through EUR automatically.',
|
|
58
|
-
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
59
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
59
60
|
input: z.object({
|
|
60
61
|
base_currency: z.string().describe('ISO 4217 base currency code (e.g. USD).'),
|
|
61
62
|
quote_currency: z.string().describe('ISO 4217 quote currency code (e.g. EUR).'),
|
|
@@ -69,10 +70,10 @@ export const fxGetRate = tool('fx_get_rate', {
|
|
|
69
70
|
source: z.string().describe('Always "ECB via Frankfurter".'),
|
|
70
71
|
}),
|
|
71
72
|
errors: [
|
|
72
|
-
{ reason: 'unsupported_currency', code: JsonRpcErrorCode.
|
|
73
|
+
{ reason: 'unsupported_currency', code: JsonRpcErrorCode.ValidationError,
|
|
73
74
|
when: 'base_currency or quote_currency is not in the ECB currency set',
|
|
74
75
|
recovery: 'Call fx_list_currencies to get valid ISO 4217 codes.' },
|
|
75
|
-
{ reason: 'date_out_of_range', code: JsonRpcErrorCode.
|
|
76
|
+
{ reason: 'date_out_of_range', code: JsonRpcErrorCode.ValidationError,
|
|
76
77
|
when: 'date is before 1999-01-04 or in the future',
|
|
77
78
|
recovery: 'ECB data starts 1999-01-04; omit date for latest.' },
|
|
78
79
|
],
|
|
@@ -186,7 +187,7 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
186
187
|
|
|
187
188
|
Handlers throw — the framework catches, classifies, and formats.
|
|
188
189
|
|
|
189
|
-
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire (`data.recovery.hint`, mirrored into `content[]` text); override with an explicit `{ recovery: { hint: '...' } }` when dynamic runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`) bubble freely and don't need declaring.
|
|
190
|
+
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire (`data.recovery.hint`, mirrored into `content[]` text); override with an explicit `{ recovery: { hint: '...' } }` when dynamic runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring.
|
|
190
191
|
|
|
191
192
|
```ts
|
|
192
193
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
@@ -245,14 +246,16 @@ src/
|
|
|
245
246
|
fx-convert-currency.tool.ts # Convert amount between two currencies
|
|
246
247
|
fx-get-rate.tool.ts # Exchange rate for a currency pair
|
|
247
248
|
fx-get-rates.tool.ts # All rates for a base currency snapshot
|
|
248
|
-
fx-get-timeseries.tool.ts # Historical daily rates; spills to DataCanvas for long ranges
|
|
249
|
+
fx-get-timeseries.tool.ts # Historical daily rates; inline pages of 500 days, spills to DataCanvas for long ranges
|
|
249
250
|
fx-list-currencies.tool.ts # All supported ISO 4217 currencies
|
|
250
251
|
fx-dataframe-describe.tool.ts # List DataCanvas tables from a prior timeseries call
|
|
251
|
-
fx-dataframe-query.tool.ts # SQL SELECT against DataCanvas tables
|
|
252
|
+
fx-dataframe-query.tool.ts # SQL SELECT against DataCanvas tables, bounded by row_limit
|
|
252
253
|
fx-dataframe-drop.tool.ts # Remove one staged table; opt-in via FX_ENABLE_CANVAS_DROP
|
|
253
254
|
resources/definitions/
|
|
254
255
|
fx-currencies.resource.ts # fx://currencies — stable currencies reference document
|
|
255
256
|
fx-rates-latest.resource.ts # fx://rates/latest/{base} — latest rates snapshot
|
|
257
|
+
utils/
|
|
258
|
+
escape-markdown-table-cell.ts # Escapes a value for one GFM table cell (fx_dataframe_query format())
|
|
256
259
|
```
|
|
257
260
|
|
|
258
261
|
---
|
|
@@ -291,8 +294,9 @@ Available skills:
|
|
|
291
294
|
| `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
|
|
292
295
|
| `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
|
|
293
296
|
| `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
|
|
294
|
-
| `git-wrapup` | Land working-tree changes as a
|
|
295
|
-
| `release-
|
|
297
|
+
| `git-wrapup` | Land working-tree changes as a commit stack — version bump, changelog, verify, commit by concern, release commit on top. No tag, no push to main; opens the release PR when the project declares release PR mode |
|
|
298
|
+
| `release-pr-review` | Review pass on an open release PR — simplifier + correctness review, fixup commits autosquashed into the stack, PR body kept in sync. Release PR mode only |
|
|
299
|
+
| `release-and-publish` | Fast-forward merge (release PR mode) + tag + push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup` |
|
|
296
300
|
| `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
|
|
297
301
|
| `orchestrations` | Chain task skills into a gated multi-phase pipeline — build-out, QA-fix, update-ship — when you can spawn sub-agents |
|
|
298
302
|
| `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
|
|
@@ -375,7 +379,7 @@ security: false # optional — true ONLY for a source
|
|
|
375
379
|
|
|
376
380
|
`agent-notes` is an optional free-form field for maintenance agents processing the release downstream. Content here won't appear in the rendered CHANGELOG — it's consumed by agents running the `maintenance` skill. Use it for adoption instructions that don't fit the human-facing sections: new files to create, fields to populate, one-time migration steps. Omit entirely when there's nothing to say.
|
|
377
381
|
|
|
378
|
-
**Section order
|
|
382
|
+
**Section order:** the Keep a Changelog sequence — Added, Changed, Deprecated, Removed, Fixed, Security — then `Dependencies` last. Include only sections with entries — don't ship empty headers.
|
|
379
383
|
|
|
380
384
|
**Tag annotations** render as GitHub Release bodies via `--notes-from-tag`. They must be structured markdown — never a flat comma-separated string. Subject omits the version number (GitHub prepends it). See `changelog/template.md` for the full format reference.
|
|
381
385
|
|
package/Dockerfile
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
#
|
|
4
4
|
# This stage installs all dependencies (including dev), builds the TypeScript
|
|
5
5
|
# source code into JavaScript, and prepares the production assets.
|
|
6
|
+
#
|
|
7
|
+
# Pinned to $BUILDPLATFORM rather than the target platform: `bun run build` emits
|
|
8
|
+
# JavaScript, and only `dist/` crosses into the production stage, which runs its
|
|
9
|
+
# own target-arch install. Built for the target instead, the non-native leg of a
|
|
10
|
+
# `--platform linux/amd64,linux/arm64` build runs under QEMU, where bun >= 1.4
|
|
11
|
+
# aborts with a JavaScriptCore allocator assertion and fails the multi-arch push.
|
|
12
|
+
#
|
|
13
|
+
# The constraint this assumes: the build stage produces platform-independent
|
|
14
|
+
# output. A stage that compiles a native addon needs the target-arch toolchain
|
|
15
|
+
# and cannot cross-compile this way — drop the flag there.
|
|
6
16
|
# ==============================================================================
|
|
7
17
|
FROM --platform=$BUILDPLATFORM oven/bun:1.4.0 AS build
|
|
8
18
|
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/exchange-rates-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/exchange-rates-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -31,17 +31,17 @@
|
|
|
31
31
|
|
|
32
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`.
|
|
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:
|
|
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:
|
|
35
35
|
|
|
36
36
|
| Tool | Description |
|
|
37
37
|
|:-----|:------------|
|
|
38
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. Optional `symbols` filter for smaller responses; listing the base itself returns a rate of 1 for it. |
|
|
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
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
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.
|
|
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
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. 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
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. |
|
|
46
46
|
|
|
47
47
|
### `fx_list_currencies`
|
|
@@ -57,8 +57,8 @@ Enumerate all supported currencies before converting or querying.
|
|
|
57
57
|
|
|
58
58
|
Full rates snapshot for a base currency in one call.
|
|
59
59
|
|
|
60
|
-
- Returns all available quote currencies at a given date (default: latest)
|
|
61
|
-
- Optional `symbols` parameter narrows the response to specific quote currencies
|
|
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
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
63
|
- Useful for seeding bulk comparison workflows or discovering what's available
|
|
64
64
|
|
|
@@ -92,7 +92,9 @@ Historical rate series and DataCanvas SQL analytics.
|
|
|
92
92
|
`fx_get_timeseries` returns a date-keyed series (business days only — ECB publishes once per business day):
|
|
93
93
|
|
|
94
94
|
- Short ranges (≤ `FX_TIMESERIES_CANVAS_THRESHOLD_DAYS`, default 90 days) → inline `rates` map + metadata
|
|
95
|
-
- Long ranges, **when DataCanvas is enabled** →
|
|
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`
|
|
96
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
|
|
97
99
|
|
|
98
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.
|
|
@@ -100,7 +102,7 @@ The response never carries a date outside the requested range. Frankfurter snaps
|
|
|
100
102
|
Once a `canvas_id` is in hand:
|
|
101
103
|
|
|
102
104
|
1. **`fx_dataframe_describe`** — list the tables and columns on the canvas (required before `fx_dataframe_query`)
|
|
103
|
-
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
|
|
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
|
|
104
106
|
|
|
105
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`.
|
|
106
108
|
|
|
@@ -133,17 +135,18 @@ ECB FX–specific:
|
|
|
133
135
|
- Keyless access via [Frankfurter](https://www.frankfurter.dev/) — a Cloudflare-fronted ECB proxy; no API keys required
|
|
134
136
|
- Cross-rate triangulation: any pair works — USD → JPY is one upstream call, cross-rated through EUR on Frankfurter's side
|
|
135
137
|
- Weekend/holiday date semantics: `date_snapped` flag surfaces when the API returns a different date than requested
|
|
136
|
-
- ECB data covers ~30 major currencies from 1999-01-04 to present; `fx_list_currencies` always reflects the live set
|
|
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
|
|
137
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
|
|
138
140
|
- DataCanvas integration: when enabled, `fx_get_timeseries` spills long ranges to DuckDB for aggregations and trend analysis
|
|
139
141
|
- Rate provenance on every response: `rate_type: "ECB reference (mid-market)"` and `source: "ECB via Frankfurter"` — explicitly mid-market, not tradeable bid/ask
|
|
140
142
|
|
|
141
143
|
Agent-friendly output:
|
|
142
144
|
|
|
143
|
-
- Rate provenance on every response — `rate_type`, `source`, `rate_date`, and `date_snapped` so agents can reason about trust and freshness
|
|
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
|
|
144
146
|
- Structured error contracts — typed `reason` fields (`unsupported_currency`, `date_out_of_range`, `invalid_query`, …) let callers branch on failure type, not string parsing
|
|
145
147
|
- Discriminated DataCanvas output — `spilled: true` plus `canvas_id` signal when a time-series was staged for SQL follow-up rather than returned inline
|
|
146
|
-
-
|
|
148
|
+
- 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
|
+
- 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
|
|
147
150
|
|
|
148
151
|
---
|
|
149
152
|
|
|
@@ -247,7 +250,7 @@ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
|
|
|
247
250
|
|
|
248
251
|
### Prerequisites
|
|
249
252
|
|
|
250
|
-
- [Bun v1.
|
|
253
|
+
- [Bun v1.4.0](https://bun.sh/) or higher (or Node.js v24+).
|
|
251
254
|
- No API key — Frankfurter is free and keyless.
|
|
252
255
|
|
|
253
256
|
### Installation
|
|
@@ -342,6 +345,7 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
|
|
|
342
345
|
| `src/mcp-server/resources/` | Resource definitions — `fx://currencies` and `fx://rates/latest/{base}`. |
|
|
343
346
|
| `src/services/frankfurter/` | Frankfurter HTTP client, retry logic, and domain types. |
|
|
344
347
|
| `src/services/canvas/` | Module-level DataCanvas accessor for `fx_get_timeseries` spillover. |
|
|
348
|
+
| `src/utils/` | Output helpers — Markdown table-cell escaping for `fx_dataframe_query`. |
|
|
345
349
|
| `tests/` | Unit and integration tests mirroring `src/`. |
|
|
346
350
|
| `docs/` | Design document and idea notes. |
|
|
347
351
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "fx_get_rates gains date_snapped and openWorldHint: true; unsupported_currency errors across the rate tools and the rates-latest resource now list the accepted ECB code set."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.3.2 — 2026-09-12
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **`engines.bun` requires `>=1.4.0`**, matching the Dockerfile's `BUILDPLATFORM` pin already shipped in 0.3.1.
|
|
12
|
+
|
|
13
|
+
## Fixed
|
|
14
|
+
|
|
15
|
+
- **`fx_get_rates`'s `symbols` rejects an empty array** ([#10](https://github.com/cyanheads/exchange-rates-mcp-server/issues/10)) — an empty array previously matched `undefined` and silently returned every quote currency; it now fails schema validation.
|
|
16
|
+
- **`fx_get_rates` declares `openWorldHint: true`** ([#14](https://github.com/cyanheads/exchange-rates-mcp-server/issues/14)) — its handler always calls the Frankfurter API; it was the one rate tool still declaring `false`.
|
|
17
|
+
- **`fx_get_rates` gains `date_snapped`** ([#15](https://github.com/cyanheads/exchange-rates-mcp-server/issues/15)) — true when a requested historical date differs from the ECB's actual `rate_date`; `format()` renders the same weekend/holiday notice its sibling tools already show.
|
|
18
|
+
- **`unsupported_currency` errors name the accepted ECB code set** ([#17](https://github.com/cyanheads/exchange-rates-mcp-server/issues/17)) — every rejection on the four rate tools and `fx://rates/latest/{base}` now carries `rejected_codes` and `accepted_codes` on `error.data`, appended once regardless of how many codes were rejected. `quote_currency` on `fx_get_rate` and `fx_convert_currency` now points to `fx_list_currencies`, matching `base_currency`.
|
|
19
|
+
|
|
20
|
+
## Dependencies
|
|
21
|
+
|
|
22
|
+
- `@cyanheads/mcp-ts-core` 0.12.3 → 0.12.8
|
|
23
|
+
- `zod` ^4.4.3 → ^4.6.0
|
|
24
|
+
- `@biomejs/biome` 2.5.10 → 2.5.12
|
|
25
|
+
- `@types/node` 26.2.0 → 26.5.1
|
|
26
|
+
- `ignore` ^7.0.6 → ^7.0.9
|
|
27
|
+
- `tsc-alias` ^1.9.2 → ^1.9.4
|
|
28
|
+
- `vitest` ^4.1.11 → ^5.0.0
|
|
29
|
+
- `bun audit`: 10 advisories → 0
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "fx_get_timeseries pages inline results at 500 publication days and fx_dataframe_query defaults row_limit to 150 (max 10,000) — both breaking; spilled fx_get_timeseries responses name both dataframe tools, and query results escape Markdown table cells."
|
|
3
|
+
breaking: true
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.4.0 — 2026-09-12
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`fx_get_timeseries` gains `truncated` and `next_start_date`** — inline results page at 500 publication days; pass `next_start_date` back as `start_date` for the next page. ([#11](https://github.com/cyanheads/exchange-rates-mcp-server/issues/11))
|
|
12
|
+
- **`fx_dataframe_query` gains `row_limit`** (1–10,000, default 150) — passed through to DataCanvas's `query()`; a capped result's `notice` gives the `ORDER BY <column> LIMIT <n> OFFSET <m>` paging shape. ([#12](https://github.com/cyanheads/exchange-rates-mcp-server/issues/12))
|
|
13
|
+
|
|
14
|
+
## Changed
|
|
15
|
+
|
|
16
|
+
- **`fx_get_timeseries` inline results are now bounded** — a canvas-disabled or under-threshold range returns at most 500 publication days per call instead of the full series; `rate_count` stays the total for the requested range. **Breaking**: a caller relying on one call returning an unbounded series must page with `next_start_date`. ([#11](https://github.com/cyanheads/exchange-rates-mcp-server/issues/11))
|
|
17
|
+
- **`fx_dataframe_query`'s default response drops from up to 10,000 rows to 150** — `format()` no longer independently slices `content` to 50 rows, so both surfaces always carry the same row set. **Breaking**: a caller relying on more than 150 rows per call must pass a larger `row_limit` or page with `ORDER BY … LIMIT … OFFSET …`. ([#12](https://github.com/cyanheads/exchange-rates-mcp-server/issues/12))
|
|
18
|
+
- **Spilled `fx_get_timeseries` responses name both dataframe tools** — the spill `notice`, the `canvas_id`/`table_name` descriptions, `format()`, and the server `instructions` all point to `fx_dataframe_describe` before `fx_dataframe_query`. ([#16](https://github.com/cyanheads/exchange-rates-mcp-server/issues/16))
|
|
19
|
+
|
|
20
|
+
## Fixed
|
|
21
|
+
|
|
22
|
+
- **`fx_dataframe_query` escapes Markdown table cells** — a value containing `|`, `<`, `>`, `*`, `_`, a backtick, brackets, tildes, `&`, or an embedded line break no longer breaks the table or is misread as Markdown/HTML; `structuredContent` is unaffected. ([#13](https://github.com/cyanheads/exchange-rates-mcp-server/issues/13))
|
package/dist/index.js
CHANGED
|
@@ -40,7 +40,9 @@ await createApp({
|
|
|
40
40
|
'- Use fx_list_currencies first to disambiguate "dollars" (USD/AUD/CAD/HKD/SGD).\n' +
|
|
41
41
|
'- Cross-rates (e.g. USD→JPY) are triangulated through EUR automatically.\n' +
|
|
42
42
|
'- Long time-series (>90 days) spill to DataCanvas when it is enabled (CANVAS_PROVIDER_TYPE=duckdb);\n' +
|
|
43
|
-
'
|
|
43
|
+
' call fx_dataframe_describe for the staged columns, then fx_dataframe_query for SQL.\n' +
|
|
44
|
+
' Without it, long ranges return inline in pages of 500 publication days (continue from next_start_date)\n' +
|
|
45
|
+
' and the dataframe tools are not listed.',
|
|
44
46
|
setup(core) {
|
|
45
47
|
setCanvas(core.canvas);
|
|
46
48
|
},
|
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,
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-rates-latest.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/fx-rates-latest.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAKrD,eAAO,MAAM,qBAAqB;;;;;;;;
|
|
1
|
+
{"version":3,"file":"fx-rates-latest.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/fx-rates-latest.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAKrD,eAAO,MAAM,qBAAqB;;;;;;;;6BAoEhC,CAAC"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { resource, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
-
import { failureOf } from '../../../services/frankfurter/errors.js';
|
|
7
|
+
import { failureOf, unsupportedCurrencyCodesOf } from '../../../services/frankfurter/errors.js';
|
|
8
8
|
import { getFrankfurterService } from '../../../services/frankfurter/frankfurter-service.js';
|
|
9
9
|
export const fxRatesLatestResource = resource('fx://rates/latest/{base}', {
|
|
10
10
|
name: 'fx-rates-latest',
|
|
@@ -34,7 +34,12 @@ export const fxRatesLatestResource = resource('fx://rates/latest/{base}', {
|
|
|
34
34
|
catch (err) {
|
|
35
35
|
const failure = failureOf(err);
|
|
36
36
|
if (failure?.reason === 'unsupported_currency') {
|
|
37
|
-
throw validationError(`${err.message} Call fx_list_currencies
|
|
37
|
+
throw validationError(`${err.message} Call fx_list_currencies for the full currency names.`, {
|
|
38
|
+
base: params.base,
|
|
39
|
+
field: failure.field,
|
|
40
|
+
reason: failure.reason,
|
|
41
|
+
...unsupportedCurrencyCodesOf(err),
|
|
42
|
+
}, { cause: err });
|
|
38
43
|
}
|
|
39
44
|
throw err;
|
|
40
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-rates-latest.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/fx-rates-latest.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"fx-rates-latest.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/fx-rates-latest.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,+CAA+C,CAAC;AAEtF,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAAC,0BAA0B,EAAE;IACxE,IAAI,EAAE,iBAAiB;IACvB,WAAW,EACT,sEAAsE;QACtE,iFAAiF;IACnF,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mDAAmD,CAAC;KAC/E,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QAC7D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QAC3D,KAAK,EAAE,CAAC;aACL,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;aAC9B,QAAQ,CACP,0FAA0F,CAC3F;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,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG;QACvB,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;QACxC,IAAI,GAAiD,CAAC;QACtD,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACtD,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,eAAe,CACnB,GAAI,GAAa,CAAC,OAAO,uDAAuD,EAChF;oBACE,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,GAAG,0BAA0B,CAAC,GAAG,CAAC;iBACnC,EACD,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,+BAA+B,EAAE;YAC5C,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM;SACrC,CAAC,CAAC;QACH,OAAO;YACL,aAAa,EAAE,GAAG,CAAC,IAAI;YACvB,SAAS,EAAE,GAAG,CAAC,IAAI;YACnB,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,SAAS,EAAE,4BAA4B;YACvC,MAAM,EAAE,qBAAqB;SAC9B,CAAC;IACJ,CAAC;IAED,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,SAAS,EAAE;YACT,EAAE,GAAG,EAAE,uBAAuB,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,kBAAkB,EAAE;YACxF,EAAE,GAAG,EAAE,uBAAuB,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,kBAAkB,EAAE;YACxF,EAAE,GAAG,EAAE,uBAAuB,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,kBAAkB,EAAE;YACxF,EAAE,GAAG,EAAE,uBAAuB,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,kBAAkB,EAAE;SACzF;KACF,CAAC;CACH,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
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"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
-
import { failureOf } from '../../../services/frankfurter/errors.js';
|
|
7
|
+
import { failureOf, unsupportedCurrencyCodesOf } from '../../../services/frankfurter/errors.js';
|
|
8
8
|
import { ECB_START_DATE, getFrankfurterService, isIsoDate, } from '../../../services/frankfurter/frankfurter-service.js';
|
|
9
9
|
export const fxConvertCurrency = tool('fx_convert_currency', {
|
|
10
10
|
description: 'Convert an amount between any two currencies at the latest or a historical rate. ' +
|
|
@@ -22,7 +22,8 @@ export const fxConvertCurrency = tool('fx_convert_currency', {
|
|
|
22
22
|
.describe('ISO 4217 source currency code (e.g. USD). Call fx_list_currencies to get valid codes.'),
|
|
23
23
|
quote_currency: z
|
|
24
24
|
.string()
|
|
25
|
-
.describe('ISO 4217 target currency code (e.g. EUR). The amount will be expressed in this currency.'
|
|
25
|
+
.describe('ISO 4217 target currency code (e.g. EUR). The amount will be expressed in this currency. ' +
|
|
26
|
+
'Call fx_list_currencies to get valid codes.'),
|
|
26
27
|
amount: z
|
|
27
28
|
.number()
|
|
28
29
|
.positive()
|
|
@@ -109,6 +110,7 @@ export const fxConvertCurrency = tool('fx_convert_currency', {
|
|
|
109
110
|
throw ctx.fail('unsupported_currency', err.message, {
|
|
110
111
|
...ctx.recoveryFor('unsupported_currency'),
|
|
111
112
|
field: failure.field,
|
|
113
|
+
...unsupportedCurrencyCodesOf(err),
|
|
112
114
|
});
|
|
113
115
|
}
|
|
114
116
|
if (failure?.reason === 'upstream_no_data') {
|
|
@@ -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,MAAM,kCAAkC,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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"}
|
|
@@ -7,6 +7,7 @@ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
|
7
7
|
export declare const fxDataframeQuery: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
8
|
canvas_id: z.ZodString;
|
|
9
9
|
query: z.ZodString;
|
|
10
|
+
row_limit: z.ZodDefault<z.ZodNumber>;
|
|
10
11
|
}, z.core.$strip>, z.ZodObject<{
|
|
11
12
|
rows: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
12
13
|
row_count: z.ZodNumber;
|
|
@@ -27,5 +28,7 @@ export declare const fxDataframeQuery: import("@cyanheads/mcp-ts-core").ToolDefi
|
|
|
27
28
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
28
29
|
readonly when: "SQL is not a SELECT, references unknown columns, or has a syntax error.";
|
|
29
30
|
readonly recovery: "Run fx_dataframe_describe first to verify table and column names.";
|
|
30
|
-
}],
|
|
31
|
+
}], {
|
|
32
|
+
readonly notice: z.ZodOptional<z.ZodString>;
|
|
33
|
+
}>;
|
|
31
34
|
//# sourceMappingURL=fx-dataframe-query.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-dataframe-query.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-query.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAgC,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"fx-dataframe-query.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-query.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAgC,MAAM,+BAA+B,CAAC;AAa/F,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;EAwN3B,CAAC"}
|