@cyanheads/exchange-rates-mcp-server 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +44 -17
- package/CLAUDE.md +44 -17
- package/README.md +90 -72
- package/changelog/0.4.x/0.4.0.md +22 -0
- package/changelog/0.4.x/0.4.1.md +27 -0
- package/changelog/template.md +9 -26
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.js +2 -3
- package/dist/mcp-server/tools/definitions/fx-dataframe-describe.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-drop.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fx-dataframe-drop.tool.js +2 -3
- package/dist/mcp-server/tools/definitions/fx-dataframe-drop.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 +54 -22
- package/dist/mcp-server/tools/definitions/fx-dataframe-query.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 -86
- package/dist/mcp-server/tools/definitions/fx-get-timeseries.tool.js.map +1 -1
- package/dist/services/frankfurter/errors.d.ts +6 -1
- package/dist/services/frankfurter/errors.d.ts.map +1 -1
- package/dist/services/frankfurter/errors.js +6 -2
- package/dist/services/frankfurter/errors.js.map +1 -1
- package/dist/services/frankfurter/frankfurter-service.d.ts.map +1 -1
- package/dist/services/frankfurter/frankfurter-service.js +12 -4
- 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 +8 -7
- package/server.json +3 -3
|
@@ -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))
|
|
@@ -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
|
package/changelog/template.md
CHANGED
|
@@ -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
|
|
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`.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
@@ -23,6 +23,13 @@ const canvasGate = {
|
|
|
23
23
|
await createApp({
|
|
24
24
|
name: 'exchange-rates-mcp-server',
|
|
25
25
|
title: 'exchange-rates-mcp-server',
|
|
26
|
+
/**
|
|
27
|
+
* No handler here asks the caller for input mid-call, so nothing needs a session
|
|
28
|
+
* to resume. Declared in source rather than left to `.env.example` and the
|
|
29
|
+
* Dockerfile alone, which a deployment can drop; `MCP_SESSION_MODE` still wins
|
|
30
|
+
* when it carries a value.
|
|
31
|
+
*/
|
|
32
|
+
sessionMode: 'stateless',
|
|
26
33
|
tools: [
|
|
27
34
|
fxListCurrencies,
|
|
28
35
|
fxGetRates,
|
|
@@ -40,7 +47,9 @@ await createApp({
|
|
|
40
47
|
'- Use fx_list_currencies first to disambiguate "dollars" (USD/AUD/CAD/HKD/SGD).\n' +
|
|
41
48
|
'- Cross-rates (e.g. USD→JPY) are triangulated through EUR automatically.\n' +
|
|
42
49
|
'- Long time-series (>90 days) spill to DataCanvas when it is enabled (CANVAS_PROVIDER_TYPE=duckdb);\n' +
|
|
43
|
-
'
|
|
50
|
+
' call fx_dataframe_describe for the staged columns, then fx_dataframe_query for SQL.\n' +
|
|
51
|
+
' Without it, long ranges return inline in pages of 500 publication days (continue from next_start_date)\n' +
|
|
52
|
+
' and the dataframe tools are not listed.',
|
|
44
53
|
setup(core) {
|
|
45
54
|
setCanvas(core.canvas);
|
|
46
55
|
},
|
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;
|
|
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;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,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;
|
|
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;;;;;;;;;;;;;;;;;;;;cAoH9B,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:
|
|
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({
|
|
@@ -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":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"fx-dataframe-describe.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-describe.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAuB,MAAM,+BAA+B,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC/F,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAEjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC,uBAAuB,EAAE;IAC/D,WAAW,EACT,sFAAsF;QACtF,qGAAqG;QACrG,gGAAgG;QAChG,mDAAmD;IACrD,WAAW,EAAE;QACX,YAAY,EAAE,IAAI;QAClB,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,KAAK;KACrB;IACD,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,SAAS,EAAE,cAAc,CAAC,QAAQ,CAChC,2CAA2C;YACzC,+EAA+E,CAClF;KACF,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6DAA6D,CAAC;QAC7F,MAAM,EAAE,CAAC;aACN,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;YAChD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YACtD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;YACvE,OAAO,EAAE,CAAC;iBACP,KAAK,CACJ,CAAC;iBACE,MAAM,CAAC;gBACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;gBACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oDAAoD,CAAC;gBAC/E,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;aAC1E,CAAC;iBACD,QAAQ,CAAC,6BAA6B,CAAC,CAC3C;iBACA,QAAQ,CAAC,+BAA+B,CAAC;SAC7C,CAAC;aACD,QAAQ,CAAC,8CAA8C,CAAC,CAC5D;aACA,QAAQ,CAAC,uDAAuD,CAAC;QACpE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;KACxF,CAAC;IAEF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,kBAAkB;YAC1B,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,+CAA+C;YACrD,QAAQ,EAAE,uDAAuD;SAClE;KACF;IAED,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,kBAAkB,CAAC,6DAA6D,CAAC,CAAC;QAC1F,CAAC;QAED,IAAI,QAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,oGAAoG;YACpG,MAAM,MAAM,GACV,GAAG,YAAY,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,IAAwC,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;YAC9F,IAAI,MAAM,KAAK,kBAAkB,EAAE,CAAC;gBAClC,MAAM,GAAG,CAAC,IAAI,CACZ,kBAAkB,EAClB,WAAW,KAAK,CAAC,SAAS,6BAA6B,EACvD;oBACE,GAAG,GAAG,CAAC,WAAW,CAAC,kBAAkB,CAAC;iBACvC,CACF,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAE7C,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE;YAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS;YACzB,UAAU,EAAE,UAAU,CAAC,MAAM;SAC9B,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,SAAS,EAAE,CAAC,CAAC,QAAQ;YACrB,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7B,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,KAAK;aAC9B,CAAC,CAAC;SACJ,CAAC,CAAC,CAAC;QAEJ,OAAO;YACL,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM;YACN,UAAU,EAAE,QAAQ,CAAC,SAAS;SAC/B,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,MAAM,CAAC,SAAS,0BAA0B,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,KAAK,GAAa,CAAC,cAAc,MAAM,CAAC,SAAS,kBAAkB,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC;QAChG,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC;YAC7D,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;gBAC5B,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAClF,CAAC;QACH,CAAC;QACD,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -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;
|
|
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;AAkG3E;;;;GAIG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;cAKtB,CAAC"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @module mcp-server/tools/definitions/fx-dataframe-drop.tool
|
|
4
4
|
*/
|
|
5
5
|
import { disabledTool, tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { CanvasIdSchema } from '@cyanheads/mcp-ts-core/canvas';
|
|
6
7
|
import { JsonRpcErrorCode, McpError } from '@cyanheads/mcp-ts-core/errors';
|
|
7
8
|
import { getServerConfig } from '../../../config/server-config.js';
|
|
8
9
|
import { getCanvas } from '../../../services/canvas/canvas-accessor.js';
|
|
@@ -19,9 +20,7 @@ const fxDataframeDropDefinition = tool('fx_dataframe_drop', {
|
|
|
19
20
|
openWorldHint: false,
|
|
20
21
|
},
|
|
21
22
|
input: z.object({
|
|
22
|
-
canvas_id:
|
|
23
|
-
.string()
|
|
24
|
-
.describe('Canvas ID returned by fx_get_timeseries. ' +
|
|
23
|
+
canvas_id: CanvasIdSchema.describe('Canvas ID returned by fx_get_timeseries. ' +
|
|
25
24
|
'Re-run fx_get_timeseries to obtain a fresh canvas_id if this one has expired.'),
|
|
26
25
|
table_name: z
|
|
27
26
|
.string()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-dataframe-drop.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-drop.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAEjE,MAAM,yBAAyB,GAAG,IAAI,CAAC,mBAAmB,EAAE;IAC1D,WAAW,EACT,oFAAoF;QACpF,yFAAyF;QACzF,2DAA2D;QAC3D,gEAAgE;QAChE,iEAAiE;IACnE,WAAW,EAAE;QACX,YAAY,EAAE,KAAK;QACnB,eAAe,EAAE,IAAI;QACrB,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,KAAK;KACrB;IACD,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,SAAS,EAAE,CAAC
|
|
1
|
+
{"version":3,"file":"fx-dataframe-drop.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-drop.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;
|
|
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;AAMjD,OAAO,EAAE,gBAAgB,EAAgC,MAAM,+BAA+B,CAAC;AAa/F,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;EAsN3B,CAAC"}
|
|
@@ -3,8 +3,18 @@
|
|
|
3
3
|
* @module mcp-server/tools/definitions/fx-dataframe-query.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';
|
|
9
|
+
import { escapeMarkdownTableCell } from '../../../utils/escape-markdown-table-cell.js';
|
|
10
|
+
/**
|
|
11
|
+
* Rows returned when the caller sets no row_limit. Every returned row renders on both
|
|
12
|
+
* response surfaces (~125 B/row serialized for the staged date/rate table), so 150 rows
|
|
13
|
+
* is ~19 KB on the wire — inside the framework's 24 KB outline budget, where 200 is not.
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_ROW_LIMIT = 150;
|
|
16
|
+
/** DataCanvas's own materialization ceiling — raising row_limit can never exceed an unbounded query. */
|
|
17
|
+
const MAX_ROW_LIMIT = 10_000;
|
|
8
18
|
export const fxDataframeQuery = tool('fx_dataframe_query', {
|
|
9
19
|
description: 'Run a read-only SQL SELECT against DataCanvas tables staged by fx_get_timeseries. ' +
|
|
10
20
|
'Supports aggregations, GROUP BY, window functions, and JOINs across multiple registered tables. ' +
|
|
@@ -17,34 +27,49 @@ export const fxDataframeQuery = tool('fx_dataframe_query', {
|
|
|
17
27
|
openWorldHint: false,
|
|
18
28
|
},
|
|
19
29
|
input: z.object({
|
|
20
|
-
canvas_id:
|
|
21
|
-
.string()
|
|
22
|
-
.describe('Canvas ID returned by fx_get_timeseries. ' +
|
|
30
|
+
canvas_id: CanvasIdSchema.describe('Canvas ID returned by fx_get_timeseries. ' +
|
|
23
31
|
'Re-run fx_get_timeseries to obtain a fresh canvas_id if this one has expired.'),
|
|
24
32
|
query: z
|
|
25
33
|
.string()
|
|
26
34
|
.describe('Read-only SQL SELECT statement. Reference tables by the names returned by fx_dataframe_describe ' +
|
|
27
35
|
'or the table_name field from fx_get_timeseries. ' +
|
|
28
36
|
"Example: SELECT date, rate FROM fx_usd_eur WHERE date > '2024-01-01' ORDER BY date"),
|
|
37
|
+
row_limit: z
|
|
38
|
+
.number()
|
|
39
|
+
.int()
|
|
40
|
+
.min(1)
|
|
41
|
+
.max(MAX_ROW_LIMIT)
|
|
42
|
+
.default(DEFAULT_ROW_LIMIT)
|
|
43
|
+
.describe(`Most rows to return (1–${MAX_ROW_LIMIT}, default ${DEFAULT_ROW_LIMIT}). When the query ` +
|
|
44
|
+
'produces more, truncated is true — page with ORDER BY <column> LIMIT <n> OFFSET <m> in the ' +
|
|
45
|
+
'SQL, or aggregate, rather than raising this toward the maximum.'),
|
|
29
46
|
}),
|
|
30
47
|
output: z.object({
|
|
31
48
|
rows: z
|
|
32
49
|
.array(z
|
|
33
50
|
.record(z.string(), z.unknown())
|
|
34
51
|
.describe('One result row — column-name → value pairs matching the SELECT columns.'))
|
|
35
|
-
.describe(
|
|
52
|
+
.describe(`Result rows, at most row_limit (default ${DEFAULT_ROW_LIMIT}). Each key is a column name from the query.`),
|
|
36
53
|
row_count: z
|
|
37
54
|
.number()
|
|
38
|
-
.describe('Rows returned
|
|
39
|
-
'not the full result size.
|
|
55
|
+
.describe('Rows returned — always the length of rows. When truncated is true this equals row_limit, ' +
|
|
56
|
+
'not the full result size.'),
|
|
40
57
|
truncated: z
|
|
41
58
|
.boolean()
|
|
42
|
-
.describe('True when the query produced more rows than
|
|
43
|
-
'
|
|
59
|
+
.describe('True when the query produced more rows than row_limit and rows holds only the first ' +
|
|
60
|
+
'row_limit of them. Fetch the rest with ORDER BY <column> LIMIT <n> OFFSET <m> — ORDER BY is ' +
|
|
61
|
+
'required for deterministic paging — or aggregate to shrink the result.'),
|
|
44
62
|
canvas_id: z
|
|
45
63
|
.string()
|
|
46
64
|
.describe('The canvas ID used — pass to a subsequent fx_dataframe_query or fx_dataframe_describe call.'),
|
|
47
65
|
}),
|
|
66
|
+
enrichment: {
|
|
67
|
+
notice: z
|
|
68
|
+
.string()
|
|
69
|
+
.optional()
|
|
70
|
+
.describe('Present when truncated is true: how many rows came back and the ORDER BY … LIMIT … OFFSET ' +
|
|
71
|
+
'query shape that fetches the next page.'),
|
|
72
|
+
},
|
|
48
73
|
errors: [
|
|
49
74
|
{
|
|
50
75
|
reason: 'canvas_not_found',
|
|
@@ -86,7 +111,10 @@ export const fxDataframeQuery = tool('fx_dataframe_query', {
|
|
|
86
111
|
}
|
|
87
112
|
let result;
|
|
88
113
|
try {
|
|
89
|
-
result = await instance.query(input.query, {
|
|
114
|
+
result = await instance.query(input.query, {
|
|
115
|
+
rowLimit: input.row_limit,
|
|
116
|
+
signal: ctx.signal,
|
|
117
|
+
});
|
|
90
118
|
}
|
|
91
119
|
catch (err) {
|
|
92
120
|
const reason = reasonOf(err);
|
|
@@ -116,21 +144,28 @@ export const fxDataframeQuery = tool('fx_dataframe_query', {
|
|
|
116
144
|
}
|
|
117
145
|
throw err;
|
|
118
146
|
}
|
|
147
|
+
const truncated = result.truncated ?? false;
|
|
119
148
|
ctx.log.info('Executed dataframe query', {
|
|
120
149
|
canvasId: input.canvas_id,
|
|
121
150
|
rowCount: result.rowCount,
|
|
122
|
-
truncated
|
|
151
|
+
truncated,
|
|
123
152
|
});
|
|
153
|
+
if (truncated) {
|
|
154
|
+
ctx.enrich.notice(`The query produced more than ${input.row_limit} rows; rows holds the first ${input.row_limit}. ` +
|
|
155
|
+
`For the next page re-run it with ORDER BY <column> LIMIT ${input.row_limit} OFFSET ${input.row_limit} ` +
|
|
156
|
+
'(raise OFFSET by the limit each page). ORDER BY is required: without it DuckDB does not ' +
|
|
157
|
+
'guarantee the same row order across pages. Aggregating or filtering shrinks the result instead.');
|
|
158
|
+
}
|
|
124
159
|
return {
|
|
125
160
|
rows: result.rows,
|
|
126
161
|
row_count: result.rowCount,
|
|
127
|
-
truncated
|
|
162
|
+
truncated,
|
|
128
163
|
canvas_id: input.canvas_id,
|
|
129
164
|
};
|
|
130
165
|
},
|
|
131
166
|
format: (result) => {
|
|
132
167
|
const capNote = result.truncated
|
|
133
|
-
? '\n⚠️ *truncated:
|
|
168
|
+
? '\n⚠️ *truncated: yes — the query produced more rows than row_limit; only these were returned.*'
|
|
134
169
|
: '\n*truncated: no*';
|
|
135
170
|
if (result.rows.length === 0) {
|
|
136
171
|
return [
|
|
@@ -141,19 +176,16 @@ export const fxDataframeQuery = tool('fx_dataframe_query', {
|
|
|
141
176
|
];
|
|
142
177
|
}
|
|
143
178
|
const cols = Object.keys(result.rows[0] ?? {});
|
|
144
|
-
const
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
.
|
|
148
|
-
.map((r) =>
|
|
149
|
-
|
|
150
|
-
const total = result.truncated ? `${result.row_count}+ (capped)` : `${result.row_count}`;
|
|
151
|
-
const note = result.row_count > shown ? `\n*Showing ${shown} of ${total} rows*` : `\n*${total} rows*`;
|
|
152
|
-
const table = [header, sep, ...rowLines].join('\n');
|
|
179
|
+
const toRow = (cells) => `| ${cells.map(escapeMarkdownTableCell).join(' | ')} |`;
|
|
180
|
+
const table = [
|
|
181
|
+
toRow(cols),
|
|
182
|
+
`| ${cols.map(() => '---').join(' | ')} |`,
|
|
183
|
+
...result.rows.map((r) => toRow(cols.map((c) => String(r[c] ?? '')))),
|
|
184
|
+
].join('\n');
|
|
153
185
|
return [
|
|
154
186
|
{
|
|
155
187
|
type: 'text',
|
|
156
|
-
text: `${table}
|
|
188
|
+
text: `${table}\n*${result.row_count} rows* · canvas \`${result.canvas_id}\`${capNote}`,
|
|
157
189
|
},
|
|
158
190
|
];
|
|
159
191
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-dataframe-query.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-query.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"fx-dataframe-query.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-dataframe-query.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,8 @@ export declare const fxGetTimeseries: import("@cyanheads/mcp-ts-core").ToolDefin
|
|
|
17
17
|
end_date: z.ZodString;
|
|
18
18
|
rates: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
19
19
|
rate_count: z.ZodNumber;
|
|
20
|
+
truncated: z.ZodBoolean;
|
|
21
|
+
next_start_date: z.ZodOptional<z.ZodString>;
|
|
20
22
|
rate_type: z.ZodString;
|
|
21
23
|
source: z.ZodString;
|
|
22
24
|
spilled: z.ZodBoolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx-get-timeseries.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-timeseries.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"fx-get-timeseries.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fx-get-timeseries.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAkBjE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuX1B,CAAC"}
|