@cyanheads/mcp-ts-core 0.8.11 → 0.8.13
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/CLAUDE.md +2 -1
- package/README.md +1 -1
- package/changelog/0.8.x/0.8.12.md +31 -0
- package/changelog/0.8.x/0.8.13.md +27 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +6 -1
- package/dist/config/index.js.map +1 -1
- package/dist/logs/combined.log +4 -4
- package/dist/logs/error.log +4 -4
- package/dist/services/canvas/core/CanvasInstance.d.ts +16 -5
- package/dist/services/canvas/core/CanvasInstance.d.ts.map +1 -1
- package/dist/services/canvas/core/CanvasInstance.js +22 -4
- package/dist/services/canvas/core/CanvasInstance.js.map +1 -1
- package/dist/services/canvas/core/CanvasRegistry.d.ts +5 -11
- package/dist/services/canvas/core/CanvasRegistry.d.ts.map +1 -1
- package/dist/services/canvas/core/CanvasRegistry.js +5 -13
- package/dist/services/canvas/core/CanvasRegistry.js.map +1 -1
- package/dist/services/canvas/core/DataCanvas.d.ts +2 -3
- package/dist/services/canvas/core/DataCanvas.d.ts.map +1 -1
- package/dist/services/canvas/core/DataCanvas.js +3 -8
- package/dist/services/canvas/core/DataCanvas.js.map +1 -1
- package/dist/services/canvas/core/IDataCanvasProvider.d.ts +24 -6
- package/dist/services/canvas/core/IDataCanvasProvider.d.ts.map +1 -1
- package/dist/services/canvas/core/IDataCanvasProvider.js +4 -4
- package/dist/services/canvas/core/canvasFactory.d.ts +7 -15
- package/dist/services/canvas/core/canvasFactory.d.ts.map +1 -1
- package/dist/services/canvas/core/canvasFactory.js +7 -16
- package/dist/services/canvas/core/canvasFactory.js.map +1 -1
- package/dist/services/canvas/core/sqlGate.d.ts +90 -60
- package/dist/services/canvas/core/sqlGate.d.ts.map +1 -1
- package/dist/services/canvas/core/sqlGate.js +231 -84
- package/dist/services/canvas/core/sqlGate.js.map +1 -1
- package/dist/services/canvas/index.d.ts +2 -2
- package/dist/services/canvas/index.d.ts.map +1 -1
- package/dist/services/canvas/index.js +1 -1
- package/dist/services/canvas/index.js.map +1 -1
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts +59 -17
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts.map +1 -1
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.js +364 -222
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.js.map +1 -1
- package/dist/services/canvas/providers/duckdb/exportWriter.d.ts +13 -25
- package/dist/services/canvas/providers/duckdb/exportWriter.d.ts.map +1 -1
- package/dist/services/canvas/providers/duckdb/exportWriter.js +15 -29
- package/dist/services/canvas/providers/duckdb/exportWriter.js.map +1 -1
- package/dist/services/canvas/providers/duckdb/schemaSniffer.d.ts +19 -26
- package/dist/services/canvas/providers/duckdb/schemaSniffer.d.ts.map +1 -1
- package/dist/services/canvas/providers/duckdb/schemaSniffer.js +30 -56
- package/dist/services/canvas/providers/duckdb/schemaSniffer.js.map +1 -1
- package/dist/services/canvas/types.d.ts +33 -6
- package/dist/services/canvas/types.d.ts.map +1 -1
- package/dist/services/canvas/types.js +1 -2
- package/dist/services/canvas/types.js.map +1 -1
- package/dist/utils/internal/requestContext.d.ts +9 -4
- package/dist/utils/internal/requestContext.d.ts.map +1 -1
- package/dist/utils/internal/requestContext.js.map +1 -1
- package/package.json +2 -2
- package/skills/api-canvas/SKILL.md +42 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/services/canvas/types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/services/canvas/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -47,7 +47,7 @@ export interface RequestContext {
|
|
|
47
47
|
* Authentication data populated by {@link requestContextService.withAuthInfo}.
|
|
48
48
|
* `undefined` when the request is unauthenticated or auth mode is `none`.
|
|
49
49
|
*/
|
|
50
|
-
auth?: AuthContext;
|
|
50
|
+
auth?: AuthContext | undefined;
|
|
51
51
|
/**
|
|
52
52
|
* Unique identifier for this request, used to correlate log entries across
|
|
53
53
|
* service boundaries. Inherited from a parent context when provided;
|
|
@@ -58,13 +58,13 @@ export interface RequestContext {
|
|
|
58
58
|
* OpenTelemetry span ID from the active span at context-creation time.
|
|
59
59
|
* `undefined` when no active span exists.
|
|
60
60
|
*/
|
|
61
|
-
spanId?: string;
|
|
61
|
+
spanId?: string | undefined;
|
|
62
62
|
/**
|
|
63
63
|
* Tenant identifier used for multi-tenancy data isolation.
|
|
64
64
|
* Resolved in priority order: `additionalContext.tenantId` →
|
|
65
65
|
* rest params → `parentContext.tenantId` → AsyncLocalStorage auth store.
|
|
66
66
|
*/
|
|
67
|
-
tenantId?: string;
|
|
67
|
+
tenantId?: string | undefined;
|
|
68
68
|
/**
|
|
69
69
|
* ISO 8601 UTC timestamp recorded at the moment this context was created.
|
|
70
70
|
*/
|
|
@@ -73,10 +73,15 @@ export interface RequestContext {
|
|
|
73
73
|
* OpenTelemetry trace ID from the active span at context-creation time.
|
|
74
74
|
* `undefined` when no active span exists.
|
|
75
75
|
*/
|
|
76
|
-
traceId?: string;
|
|
76
|
+
traceId?: string | undefined;
|
|
77
77
|
/**
|
|
78
78
|
* Additional arbitrary key-value pairs for operation-specific context.
|
|
79
79
|
* Consumers must type-check before accessing extended properties.
|
|
80
|
+
*
|
|
81
|
+
* Note: optional fields above are typed `?: T | undefined` (not just `?: T`)
|
|
82
|
+
* so the handler-facing `Context` — which carries strict-optional fields
|
|
83
|
+
* under `exactOptionalPropertyTypes` — is structurally assignable to
|
|
84
|
+
* `RequestContext`, letting services accept `ctx` directly without a cast.
|
|
80
85
|
*/
|
|
81
86
|
[key: string]: unknown;
|
|
82
87
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestContext.d.ts","sourceRoot":"","sources":["../../../src/utils/internal/requestContext.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+CAA+C,CAAC;AAa9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,WAAW;IAC1B,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,2HAA2H;IAC3H,GAAG,EAAE,MAAM,CAAC;IACZ,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"requestContext.d.ts","sourceRoot":"","sources":["../../../src/utils/internal/requestContext.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+CAA+C,CAAC;AAa9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,WAAW;IAC1B,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,2HAA2H;IAC3H,GAAG,EAAE,MAAM,CAAC;IACZ,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC/B;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE9B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE7B;;;;;;;;OAQG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE5C;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc,GAAG,SAAS,CAAC;IAErE,iFAAiF;IACjF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAmJD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,qBAAqB;IAhKhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;kCAC0B,0BAA0B,GAAQ,cAAc;IA8D7E;;;;;;;;;;;;;;;;;;;;;OAqBG;2BAES,QAAQ,kBACF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc,GACvD,cAAc;CA2C+C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestContext.js","sourceRoot":"","sources":["../../../src/utils/internal/requestContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,WAAW,IAAI,cAAc,EAAE,MAAM,iDAAiD,CAAC;AAEhG,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,kEAAkE;AAClE,SAAS,aAAa,CAAC,IAAc;IACnC,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ;QAClC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;KAClD,CAAC;AACJ,CAAC;
|
|
1
|
+
{"version":3,"file":"requestContext.js","sourceRoot":"","sources":["../../../src/utils/internal/requestContext.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/mcp-ts-core",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.13",
|
|
4
4
|
"mcpName": "io.github.cyanheads/mcp-ts-core",
|
|
5
5
|
"description": "Agent-native TypeScript framework for building MCP servers. Declarative definitions with auth, multi-backend storage, OpenTelemetry, and first-class support for Bun/Node/Cloudflare Workers.",
|
|
6
6
|
"main": "dist/core/index.js",
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
},
|
|
166
166
|
"devDependencies": {
|
|
167
167
|
"@biomejs/biome": "2.4.14",
|
|
168
|
-
"@cloudflare/workers-types": "^4.
|
|
168
|
+
"@cloudflare/workers-types": "^4.20260503.1",
|
|
169
169
|
"@duckdb/node-api": "^1.5.2-r.1",
|
|
170
170
|
"@hono/otel": "^1.1.1",
|
|
171
171
|
"@opentelemetry/exporter-metrics-otlp-http": "^0.216.0",
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
DataCanvas primitive reference — a Tier 3 SQL/analytical workspace for tabular MCP servers, backed by DuckDB. Use when registering tables from upstream APIs, running ad-hoc SQL across them, and exporting results. Covers the acquire → register → query → export flow, the token-sharing pattern for multi-agent collaboration, env config, and Cloudflare Workers fail-closed behavior.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.1"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
@@ -118,13 +118,42 @@ const joined = await instance.query(`
|
|
|
118
118
|
|
|
119
119
|
`registerAs` rejects with `Conflict` if the target name already exists — drop it first.
|
|
120
120
|
|
|
121
|
-
**Read-only enforcement** (
|
|
122
|
-
1.
|
|
123
|
-
2. Statement
|
|
124
|
-
3.
|
|
121
|
+
**Read-only enforcement** (four layers):
|
|
122
|
+
1. Text-level deny-list — pre-parse scan for file/HTTP-reading table functions (`read_csv*`, `read_json*`, `read_parquet*`, `read_text`, `read_blob`, `glob`, `iceberg_scan`, `delta_scan`, `postgres_scan`, `mysql_scan`, `sqlite_scan`, plus pre-staged spatial ones).
|
|
123
|
+
2. Statement count (must be 1) via `extractStatements`.
|
|
124
|
+
3. Statement type (must be `SELECT`) via `prepared.statementType`.
|
|
125
|
+
4. EXPLAIN-plan walk against an allowlisted set of physical operators + a denied-function rescan over plan metadata strings.
|
|
125
126
|
|
|
126
127
|
Any layer's rejection throws `ValidationError` with a structured `data.reason`. File-reading scans (`READ_CSV`, `READ_PARQUET`, `READ_JSON`), DDL (`CREATE_*`, `DROP_*`, `ALTER_*`), DML (`INSERT`, `UPDATE`, `DELETE`), exports (`COPY_TO_FILE`), and utility statements (`PRAGMA`, `ATTACH`, `LOAD`, `SET`) are all rejected.
|
|
127
128
|
|
|
129
|
+
### `instance.registerView(name, selectSql, options?)`
|
|
130
|
+
|
|
131
|
+
Register a SQL view on the canvas. The `SELECT` runs through the same four-layer gate `query()` enforces, so a malicious definition fails at registration time, not later when the view is referenced.
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
await instance.registerView(
|
|
135
|
+
'sales_by_region',
|
|
136
|
+
'SELECT region, SUM(amount) AS total FROM sales GROUP BY region',
|
|
137
|
+
);
|
|
138
|
+
// { viewName: 'sales_by_region', columns: ['region', 'total'] }
|
|
139
|
+
|
|
140
|
+
// Subsequent queries against the view inherit normal gate enforcement at execution time.
|
|
141
|
+
const result = await instance.query("SELECT total FROM sales_by_region WHERE region = 'a'");
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`CREATE OR REPLACE VIEW` semantics: re-registering the same name succeeds. Conflict with an existing base table throws `validationError({ reason: 'view_table_clash' })`.
|
|
145
|
+
|
|
146
|
+
### `instance.importFrom(sourceCanvasId, sourceTableName, options?)`
|
|
147
|
+
|
|
148
|
+
Copy a table from another canvas the caller controls into this one. The lifecycle wrapper validates tenancy on both ids before the provider sees either. Round-trips through a sandbox-rooted Parquet temp file so `TIMESTAMP`/`DATE`/`BLOB` columns survive losslessly.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const imported = await target.importFrom(source.canvasId, 'orders', { asName: 'orders_copy' });
|
|
152
|
+
// { tableName: 'orders_copy', rowCount: 2, columns: [...] }
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Idempotent on re-import (drop + create on the target). `asName` defaults to `sourceTableName`. Throws `validationError({ reason: 'import_same_canvas' })` if source and target are the same canvas — use `query({ registerAs })` to materialize within a single canvas. Throws `notFound` if the source table is missing; `validationError({ reason: 'import_view_clash' })` if the target name collides with an existing view.
|
|
156
|
+
|
|
128
157
|
### `instance.export(tableName, target, options?)`
|
|
129
158
|
|
|
130
159
|
Export a canvas table. Path-based exports are sandboxed to `CANVAS_EXPORT_PATH` (default `./.canvas-exports`). Absolute paths and `..` traversal are rejected.
|
|
@@ -141,12 +170,17 @@ await instance.export('g_with_obs', { format: 'csv', stream: writableStream });
|
|
|
141
170
|
|
|
142
171
|
```ts
|
|
143
172
|
const tables = await instance.describe();
|
|
144
|
-
// [{ name: 'germplasm', rowCount: 200, columns: [...] }, ...]
|
|
173
|
+
// [{ name: 'germplasm', kind: 'table', rowCount: 200, columns: [...] }, ...]
|
|
174
|
+
|
|
175
|
+
// Filter by kind ('table' | 'view').
|
|
176
|
+
const onlyViews = await instance.describe({ kind: 'view' });
|
|
145
177
|
|
|
146
|
-
await instance.drop('staging_table'); // false if missing
|
|
147
|
-
await instance.clear(); // returns count dropped
|
|
178
|
+
await instance.drop('staging_table'); // detects kind, emits DROP TABLE or DROP VIEW; false if missing
|
|
179
|
+
await instance.clear(); // returns count dropped (drops views before tables to avoid dependency errors)
|
|
148
180
|
```
|
|
149
181
|
|
|
182
|
+
`TableInfo.kind` discriminates `'table'` vs `'view'`. For views, `rowCount` is materialized at describe time via `COUNT(*)` — not free; treat as an approximation if the view is expensive.
|
|
183
|
+
|
|
150
184
|
### Cancellation
|
|
151
185
|
|
|
152
186
|
`registerTable`, `query`, and `export` accept `options.signal: AbortSignal`. The provider opens a fresh DuckDB connection per query/export so `connection.interrupt()` cancels exactly the in-flight work without disturbing other ops on the same canvas.
|