@cyanheads/brapi-mcp-server 0.4.9 → 0.4.10
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 +1 -1
- package/README.md +58 -8
- package/changelog/0.4.x/0.4.10.md +30 -0
- package/dist/config/server-config.d.ts +7 -0
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +28 -0
- package/dist/config/server-config.js.map +1 -1
- package/dist/index.js +14 -6
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-dataframe-describe.tool.d.ts +39 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-describe.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-describe.tool.js +107 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-describe.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-drop.tool.d.ts +23 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-drop.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-drop.tool.js +55 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-drop.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-query.tool.d.ts +38 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-query.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-query.tool.js +162 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-query.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.d.ts +8 -4
- package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.js +14 -17
- package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-find-germplasm.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-germplasm.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-find-images.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-images.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-find-locations.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-locations.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-find-observations.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-observations.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-find-studies.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-studies.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-find-variables.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-variables.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-find-variants.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-variants.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-manage-dataset.tool.d.ts +2 -0
- package/dist/mcp-server/tools/definitions/brapi-manage-dataset.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-manage-dataset.tool.js +10 -0
- package/dist/mcp-server/tools/definitions/brapi-manage-dataset.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/index.d.ts +75 -2
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/index.js +15 -0
- package/dist/mcp-server/tools/definitions/index.js.map +1 -1
- package/dist/mcp-server/tools/shared/find-helpers.d.ts +1 -0
- package/dist/mcp-server/tools/shared/find-helpers.d.ts.map +1 -1
- package/dist/mcp-server/tools/shared/find-helpers.js +9 -0
- package/dist/mcp-server/tools/shared/find-helpers.js.map +1 -1
- package/dist/mcp-server/tools/shared/raw-routing-hints.js +1 -1
- package/dist/mcp-server/tools/shared/raw-routing-hints.js.map +1 -1
- package/dist/services/canvas-bridge/canvas-bridge.d.ts +100 -0
- package/dist/services/canvas-bridge/canvas-bridge.d.ts.map +1 -0
- package/dist/services/canvas-bridge/canvas-bridge.js +320 -0
- package/dist/services/canvas-bridge/canvas-bridge.js.map +1 -0
- package/dist/services/canvas-bridge/index.d.ts +8 -0
- package/dist/services/canvas-bridge/index.d.ts.map +1 -0
- package/dist/services/canvas-bridge/index.js +7 -0
- package/dist/services/canvas-bridge/index.js.map +1 -0
- package/dist/services/canvas-bridge/types.d.ts +45 -0
- package/dist/services/canvas-bridge/types.d.ts.map +1 -0
- package/dist/services/canvas-bridge/types.js +11 -0
- package/dist/services/canvas-bridge/types.js.map +1 -0
- package/dist/services/dataset-store/dataset-store.d.ts +12 -3
- package/dist/services/dataset-store/dataset-store.d.ts.map +1 -1
- package/dist/services/dataset-store/dataset-store.js +22 -4
- package/dist/services/dataset-store/dataset-store.js.map +1 -1
- package/dist/services/dataset-store/types.d.ts +7 -0
- package/dist/services/dataset-store/types.d.ts.map +1 -1
- package/package.json +11 -2
- package/server.json +3 -3
package/CLAUDE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** brapi-mcp-server
|
|
4
|
-
**Version:** 0.4.
|
|
4
|
+
**Version:** 0.4.10
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core)
|
|
6
6
|
|
|
7
7
|
> **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.
|
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<h1>@cyanheads/brapi-mcp-server</h1>
|
|
3
3
|
<p><b>BrAPI v2.1 MCP server — studies, germplasm, observations, genotypes, images, and pedigrees across Breedbase, T3, Sweetpotatobase, and any BrAPI-compliant server.</b>
|
|
4
|
-
<div>
|
|
4
|
+
<div>22 Tools • 6 Resources • 2 Prompts</div>
|
|
5
5
|
</p>
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](https://www.npmjs.com/package/@cyanheads/brapi-mcp-server) [](https://www.npmjs.com/package/@cyanheads/brapi-mcp-server) [](./CHANGELOG.md) [](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [](https://modelcontextprotocol.io/)
|
|
11
11
|
|
|
12
12
|
[](./LICENSE) [](https://www.typescriptlang.org/) [](https://bun.sh/) [](./CHANGELOG.md)
|
|
13
13
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
## Tools
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Twenty-two tools grouped by shape — connection tools bootstrap a session, `find_*` tools return a summarized page plus distributions and spill overflow rows into the DatasetStore, `get_*` tools fetch a single record with companion counts, plus pedigree walking, dataset lifecycle, an opt-in SQL/analytical workspace over spilled rows, an additive write surface for observations, and raw passthrough escape hatches.
|
|
21
21
|
|
|
22
22
|
### Orient
|
|
23
23
|
|
|
@@ -42,7 +42,7 @@ Nineteen tools grouped by shape — connection tools bootstrap a session, `find_
|
|
|
42
42
|
| `brapi_get_image` | Fetch image bytes for up to 5 imageDbIds inline as `type: image` content blocks. Prefers `/images/{id}/imagecontent`, falls back to `imageURL`. |
|
|
43
43
|
| `brapi_find_locations` | Find research stations / field sites by country / type / abbreviation, with optional client-side bounding-box filter. |
|
|
44
44
|
| `brapi_find_variants` | Find variant records by variant set, reference, or genomic region (1-based inclusive / exclusive). |
|
|
45
|
-
| `brapi_find_genotype_calls` | Pull genotype calls across a germplasm × variant set via async-search polling.
|
|
45
|
+
| `brapi_find_genotype_calls` | Pull genotype calls across a germplasm × variant set via async-search polling. Upstream pull bounded by deployment policy (`BRAPI_GENOTYPE_CALLS_MAX_PULL`, default 100k, max 500k); rows beyond `loadLimit` spill to DatasetStore. |
|
|
46
46
|
|
|
47
47
|
### Orchestrate
|
|
48
48
|
|
|
@@ -50,6 +50,14 @@ Nineteen tools grouped by shape — connection tools bootstrap a session, `find_
|
|
|
50
50
|
|:----------|:------------|
|
|
51
51
|
| `brapi_manage_dataset` | Lifecycle for `find_*` spillover datasets — list, summary, load (paged rows with column projection), delete. |
|
|
52
52
|
|
|
53
|
+
### Analyze
|
|
54
|
+
|
|
55
|
+
| Tool Name | Description |
|
|
56
|
+
|:----------|:------------|
|
|
57
|
+
| `brapi_dataframe_query` | Run SELECT SQL across in-memory dataframes (DuckDB-backed). Spilled `find_*` datasets auto-register as `ds_<datasetId>` dataframes. Use `registerAs` to chain. Read-only — multi-statement, non-SELECT, file-reads, and exports are rejected. **Opt-in via `CANVAS_PROVIDER_TYPE=duckdb` + `BRAPI_CANVAS_ENABLED=true`** — omitted from `tools/list` otherwise. |
|
|
58
|
+
| `brapi_dataframe_describe` | List dataframes with column schema, row counts, and originating-dataset provenance for `ds_*` entries. |
|
|
59
|
+
| `brapi_dataframe_drop` | Drop a dataframe by name. Idempotent — `dropped: false` for unknown names. Underlying DatasetStore dataset is unaffected. |
|
|
60
|
+
|
|
53
61
|
### Write
|
|
54
62
|
|
|
55
63
|
| Tool Name | Description |
|
|
@@ -212,8 +220,8 @@ Find variant records by variant set, reference sequence, or genomic region.
|
|
|
212
220
|
Pull genotype calls for a germplasm × variant set. Handles BrAPI's async-search pattern (`POST /search/calls` → `GET /search/calls/{id}`) transparently.
|
|
213
221
|
|
|
214
222
|
- Requires at least one filter (`variantSetDbId`, `germplasmDbIds`, `callSetDbIds`, `variantDbIds`) — unfiltered pulls are rejected
|
|
215
|
-
-
|
|
216
|
-
- Rows beyond `loadLimit` (default 200) spill to `DatasetStore` for
|
|
223
|
+
- Upstream pull bounded by deployment policy (`BRAPI_GENOTYPE_CALLS_MAX_PULL`, default 100,000, hard ceiling 500,000) — protects upstream from unbounded sequential paginated GETs. `truncated: true` flags when the cap was hit; agents narrow the filters and re-pull, or query the spilled dataframe
|
|
224
|
+
- Rows beyond `loadLimit` (default 200) spill to `DatasetStore` for paged follow-up via `brapi_manage_dataset`, or SQL-queryable access via `brapi_dataframe_query`
|
|
217
225
|
- Echoes server-reported genotype-encoding (`expandHomozygotes`, `unknownString`, `sepPhased`, `sepUnphased`) so the agent can interpret the values
|
|
218
226
|
|
|
219
227
|
---
|
|
@@ -230,6 +238,40 @@ Consolidated lifecycle tool for datasets produced by `find_*` spillovers.
|
|
|
230
238
|
|
|
231
239
|
---
|
|
232
240
|
|
|
241
|
+
### `brapi_dataframe_query`
|
|
242
|
+
|
|
243
|
+
Run SQL across in-memory dataframes — a SQL/analytical workspace backed by the framework's DuckDB-powered DataCanvas. Spilled `find_*` datasets auto-register as `ds_<datasetId>` dataframes; describe them via `brapi_dataframe_describe` before composing a query.
|
|
244
|
+
|
|
245
|
+
> **Off by default.** Both gates must be on: `CANVAS_PROVIDER_TYPE=duckdb` (framework-side) and `BRAPI_CANVAS_ENABLED=true` (server-side, default true). Requires the optional `@duckdb/node-api` peer dep. Not available on Cloudflare Workers — DuckDB has no V8-isolate build.
|
|
246
|
+
|
|
247
|
+
- Read-only enforcement via the framework's three-layer SQL gate (single statement → SELECT only → plan-walk allowlist), plus a server-side deny-list for `read_json*` / `read_parquet*` / `iceberg_scan` / `delta_scan` that bypass the canvas
|
|
248
|
+
- `registerAs` materializes the result as a new dataframe — full result lives in the workspace, response carries a bounded `preview` slice plus the full `rowCount`
|
|
249
|
+
- `BRAPI_CANVAS_MAX_ROWS` (default 10,000) caps response materialization; raising `rowLimit` past this is silently capped — use `registerAs` instead
|
|
250
|
+
- `BRAPI_CANVAS_QUERY_TIMEOUT_MS` (default 30,000) wraps the query in a wall-clock cap on top of `ctx.signal`
|
|
251
|
+
- Per-tenant default workspace cached in `ctx.state` — agents never see the underlying canvasId
|
|
252
|
+
- SQL-gate rejections translate to a typed `sql_rejected` reason, preserving the granular gate code on `data.gateReason`
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
### `brapi_dataframe_describe`
|
|
257
|
+
|
|
258
|
+
List the dataframes available in the current workspace (or describe one by name) with column schema, row counts, and originating-dataset provenance.
|
|
259
|
+
|
|
260
|
+
- `ds_*`-prefixed dataframes carry full provenance: originating tool (`source`), `baseUrl`, original `query`, `createdAt`, `expiresAt`
|
|
261
|
+
- User-derived dataframes (created via `brapi_dataframe_query({ registerAs })`) show structural info only
|
|
262
|
+
- Pass `tableName` to scope to one entry; omit to list all
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
### `brapi_dataframe_drop`
|
|
267
|
+
|
|
268
|
+
Release a dataframe by name. Idempotent — returns `dropped: false` rather than failing when the name is unknown.
|
|
269
|
+
|
|
270
|
+
- Drops the dataframe and its provenance metadata; the underlying DatasetStore dataset is untouched
|
|
271
|
+
- Use `brapi_manage_dataset mode=delete` to drop both the dataset and its dataframe in one call
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
233
275
|
### `brapi_raw_get`
|
|
234
276
|
|
|
235
277
|
Last-resort passthrough to any BrAPI `GET /{path}` the curated tools don't cover (e.g. `/samples`, `/methods`, `/scales`, `/crosses`). Returns the raw upstream envelope plus pagination metadata.
|
|
@@ -313,6 +355,7 @@ BrAPI-specific:
|
|
|
313
355
|
- **Tolerant capability discovery** — if `/serverinfo` is unavailable or sparse, discovery falls back to `/calls` and returns a partial orientation envelope with explicit notes
|
|
314
356
|
- **Find-route planning** — curated `find_*` tools prefer GET list endpoints, then fall back to POST `/search/{noun}` when only search is advertised
|
|
315
357
|
- **Dataset spillover** — `find_*` tools cap in-context rows at `loadLimit` and transparently persist larger unions (up to 50k rows / 50 pages) as handles in `DatasetStore`; `brapi_manage_dataset` pages / projects / deletes them
|
|
358
|
+
- **Dataframes (Tier 3, opt-in)** — spilled `find_*` rows auto-register as DuckDB-backed dataframes named `ds_<datasetId>`; agents run SELECT SQL across them via `brapi_dataframe_query`, with read-only enforcement and a per-tenant workspace. Gated by `CANVAS_PROVIDER_TYPE=duckdb` + `BRAPI_CANVAS_ENABLED=true`; requires the optional `@duckdb/node-api` peer dep. Not available on Cloudflare Workers.
|
|
316
359
|
- **Async-search transparency** — `brapi_find_genotype_calls` and `brapi_raw_search` handle the `POST /search/{noun}` → `GET /search/{noun}/{id}` 202-retry pattern without the agent needing to know
|
|
317
360
|
- **Pedigree DAG walks** — `brapi_walk_pedigree` BFS-traverses ancestry or descendancy with cycle detection, depth limits, and traversal stats — BrAPI only exposes one generation per call
|
|
318
361
|
- **Image content** — `brapi_get_image` fetches image bytes inline as MCP `type: image` blocks, preferring `/images/{id}/imagecontent` and falling back to the metadata `imageURL` field
|
|
@@ -394,6 +437,7 @@ No environment variables are required for the public BrAPI test server — agent
|
|
|
394
437
|
|
|
395
438
|
- [Bun v1.3.11](https://bun.sh/) or higher (or Node.js v22+).
|
|
396
439
|
- A BrAPI v2 endpoint to point at — the public [test server](https://test-server.brapi.org/brapi/v2) works out of the box; production servers typically need credentials.
|
|
440
|
+
- *(Optional)* [`@duckdb/node-api`](https://www.npmjs.com/package/@duckdb/node-api) — required only to enable the dataframe surface (`CANVAS_PROVIDER_TYPE=duckdb`). Listed as an optional peer dep so the bare install stays light. Linux/macOS/Windows × x64 plus Linux/macOS arm64 supported (Windows arm64 is unsupported by DuckDB upstream). Not available on Cloudflare Workers.
|
|
397
441
|
|
|
398
442
|
### Installation
|
|
399
443
|
|
|
@@ -449,6 +493,11 @@ Every variable is optional — agents can configure connections entirely at runt
|
|
|
449
493
|
| `BRAPI_REFERENCE_CACHE_TTL_SECONDS` | TTL for reference-data cache entries (programs, trials, locations, crops). | `3600` |
|
|
450
494
|
| `BRAPI_ALLOW_PRIVATE_IPS` | Allow connecting to RFC 1918 / loopback targets. Dev-only. | `false` |
|
|
451
495
|
| `BRAPI_ENABLE_WRITES` | Opt-in flag for the write surface (`brapi_submit_observations`). Off by default — the tool is omitted from `tools/list` unless the operator opts in for this deployment. | `false` |
|
|
496
|
+
| `BRAPI_GENOTYPE_CALLS_MAX_PULL` | Hard ceiling on rows pulled from the upstream BrAPI server in a single `brapi_find_genotype_calls` invocation. Bounds total page count per query — protects upstream from unbounded pagination loops. Maximum 500,000. | `100000` |
|
|
497
|
+
| `CANVAS_PROVIDER_TYPE` | Framework-side switch for the `DataCanvas` primitive. Set to `duckdb` to enable the dataframe surface. Fails closed on Cloudflare Workers. | `none` |
|
|
498
|
+
| `BRAPI_CANVAS_ENABLED` | Server-side gate for `brapi_dataframe_*` tools. Effective only when `CANVAS_PROVIDER_TYPE=duckdb`. | `true` |
|
|
499
|
+
| `BRAPI_CANVAS_MAX_ROWS` | Hard cap on rows materialized into a `brapi_dataframe_query` response. Use `registerAs` to keep larger result sets in the workspace. | `10000` |
|
|
500
|
+
| `BRAPI_CANVAS_QUERY_TIMEOUT_MS` | Per-query wall-clock timeout for `brapi_dataframe_query`. | `30000` |
|
|
452
501
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
453
502
|
| `MCP_HTTP_PORT` | Port for HTTP server. | `3010` |
|
|
454
503
|
| `MCP_AUTH_MODE` | Auth mode: `none`, `jwt`, or `oauth`. | `none` |
|
|
@@ -558,15 +607,16 @@ In HTTP + `none`, every client shares one bucket: connection aliases registered
|
|
|
558
607
|
|
|
559
608
|
| Directory | Purpose |
|
|
560
609
|
|:----------|:--------|
|
|
561
|
-
| `src/index.ts` | `createApp()` entry point — registers
|
|
610
|
+
| `src/index.ts` | `createApp()` entry point — registers 22 tools, 6 resources, 2 prompts, and inits the eight services. |
|
|
562
611
|
| `src/config` | Server-specific environment variable parsing with Zod. |
|
|
563
612
|
| `src/mcp-server/tools` | Tool definitions (`*.tool.ts`) and shared helpers (`orientation-envelope`, `find-helpers`, `connect-auth-schema`, `raw-routing-hints`). |
|
|
564
613
|
| `src/mcp-server/resources` | Resource definitions (`*.resource.ts`) — URI-addressable mirrors of curated tool data. |
|
|
565
614
|
| `src/mcp-server/prompts` | Prompt definitions (`*.prompt.ts`) — multi-step BrAPI workflow templates. |
|
|
566
615
|
| `src/services/brapi-client` | HTTP client with retry, concurrency capping, async-search polling, private-IP guard, and binary fetch. |
|
|
567
616
|
| `src/services/brapi-filters` | Static BrAPI v2.1 filter catalog. |
|
|
617
|
+
| `src/services/canvas-bridge` | Bridge over the framework's `DataCanvas` primitive — per-tenant default-workspace resolution, dataframe naming, provenance tracking. |
|
|
568
618
|
| `src/services/capability-registry` | Per-connection capability profile cache. |
|
|
569
|
-
| `src/services/dataset-store` | Tenant-scoped dataset handles for spilled `find_*` results. |
|
|
619
|
+
| `src/services/dataset-store` | Tenant-scoped dataset handles for spilled `find_*` results. Auto-registers rows as dataframes when the canvas-bridge is enabled. |
|
|
570
620
|
| `src/services/ontology-resolver` | Free-text → ontology-candidate matcher powering `brapi_find_variables` ranking. |
|
|
571
621
|
| `src/services/reference-data-cache` | Cache for programs, trials, locations, crops. |
|
|
572
622
|
| `src/services/server-registry` | Alias → live BrAPI connection map with auth resolution. |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Dataframe surface (Tier 3, opt-in) — spilled find_* rows auto-register as DuckDB-backed dataframes; agents run SELECT SQL across them via brapi_dataframe_query/describe/drop. Genotype-call cap promoted to operator policy."
|
|
3
|
+
breaking: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 0.4.10 — 2026-05-03
|
|
7
|
+
|
|
8
|
+
A SQL/analytical workspace lands on top of the existing dataset surface. When `find_*` tools spill to `DatasetStore`, the rows now also auto-register as `ds_<datasetId>` dataframes on the framework's DuckDB-backed `DataCanvas` — agents query them with SELECT SQL via `brapi_dataframe_query`, describe schemas via `brapi_dataframe_describe`, and drop them via `brapi_dataframe_drop`. The whole surface is Tier 3: optional peer dep `@duckdb/node-api`, gated behind `CANVAS_PROVIDER_TYPE=duckdb` and `BRAPI_CANVAS_ENABLED=true`. Bare installs and Cloudflare Workers are unaffected. Separately, `brapi_find_genotype_calls` retires its per-call `maxCalls` input in favor of a deployment-side `BRAPI_GENOTYPE_CALLS_MAX_PULL` operator policy.
|
|
9
|
+
|
|
10
|
+
## Added
|
|
11
|
+
|
|
12
|
+
- **`brapi_dataframe_query`** — run SELECT SQL across in-memory dataframes. Read-only enforcement uses the framework's three-layer SQL gate (single statement → SELECT only → plan-walk allowlist) plus a server-side deny-list for `read_json*` / `read_parquet*` / `iceberg_scan` / `delta_scan` table functions that bypass the canvas. `registerAs` materializes the result as a new dataframe; the response carries a bounded `preview` slice plus the full `rowCount`. Per-tenant default workspace cached in `ctx.state` — agents never see the underlying canvasId. Typed `sql_rejected` reason preserves the granular gate code on `data.gateReason`.
|
|
13
|
+
- **`brapi_dataframe_describe`** — list dataframes (or one by name) with column schema, row count, and originating-dataset provenance for `ds_*` entries (source tool, baseUrl, original query, createdAt, expiresAt). User-derived dataframes from `registerAs` show structural info only.
|
|
14
|
+
- **`brapi_dataframe_drop`** — release a dataframe by name. Idempotent — `dropped: false` rather than failing for unknown names. The underlying `DatasetStore` dataset is untouched; `brapi_manage_dataset mode=delete` drops both.
|
|
15
|
+
- **`CanvasBridge` service** (`src/services/canvas-bridge/`) — owns the three concerns the framework leaves to the consumer: per-tenant default canvas resolution (cached in `ctx.state`, refreshed on stale-id `NotFound`), SQL-safe table naming for UUID-shaped dataset IDs (`ds_<datasetId_with_underscores>`), and originating-dataset provenance tracking. `isEnabled()` is the single gate every dataframe tool checks. `composeSignal()` wraps `ctx.signal` with a wall-clock cap using the manual-AbortController pattern (avoids `AbortSignal.timeout()` realm-mismatch issues in Bun stdio).
|
|
16
|
+
- **`DatasetStore` ↔ canvas integration** — `create()` auto-registers spilled rows on the canvas when the bridge is enabled; the resulting dataframe name surfaces on `DatasetMetadata.dataframe`. `delete()` mirrors the drop. Both directions are best-effort — failure logs a warning but never breaks the dataset op. Dataset handles, `brapi_manage_dataset` summary/list output, and `find_*` formatters all surface `dataframe: <name>` when present so agents can pivot directly into SQL.
|
|
17
|
+
- **5 new env vars**:
|
|
18
|
+
- `BRAPI_GENOTYPE_CALLS_MAX_PULL` (default 100,000, max 500,000) — operator policy ceiling on rows pulled in a single `brapi_find_genotype_calls` invocation.
|
|
19
|
+
- `CANVAS_PROVIDER_TYPE` (framework, default `none`) — set to `duckdb` to enable the canvas service. Fails closed on Cloudflare Workers.
|
|
20
|
+
- `BRAPI_CANVAS_ENABLED` (server, default `true`) — server-side gate for the `brapi_dataframe_*` surface. Effective only when the framework canvas is active.
|
|
21
|
+
- `BRAPI_CANVAS_MAX_ROWS` (default 10,000) — hard cap on rows materialized into a `brapi_dataframe_query` response. Larger result sets must use `registerAs`.
|
|
22
|
+
- `BRAPI_CANVAS_QUERY_TIMEOUT_MS` (default 30,000) — per-query wall-clock timeout layered on top of `ctx.signal`.
|
|
23
|
+
- **Optional peer dependency `@duckdb/node-api ^1.5.0`** — listed under `peerDependenciesMeta.optional: true` so bare installs stay light. Linux/macOS/Windows × x64 plus Linux/macOS arm64 supported (Windows arm64 unsupported by DuckDB upstream).
|
|
24
|
+
- **`api-canvas` and `code-simplifier` skills** synced from the framework upgrade. `api-config`, `api-workers`, `add-tool`, `design-mcp-server`, `security-pass`, and the `report-issue-*` pair gained canvas-aware sections.
|
|
25
|
+
|
|
26
|
+
## Changed
|
|
27
|
+
|
|
28
|
+
- **`brapi_find_genotype_calls` cap is deployment-side now** — the per-call `maxCalls` input is removed (Zod silently strips it; no wire break for callers still passing it). The cap reads from `BRAPI_GENOTYPE_CALLS_MAX_PULL` instead, so the upstream-protection budget is set by the operator, not the agent. Truncation warning, output `truncated` doc, and the `raw_search` routing nudge updated to point at the new env var. Recovery hint when truncated: narrow the filters and re-pull, or query the spilled dataframe.
|
|
29
|
+
- **Framework bump** — `@cyanheads/mcp-ts-core` `^0.8.8` → `^0.8.10`. Picks up the `DataCanvas` primitive, `core.canvas` wiring on `CoreServices`, and the canvas-related env-var schemas.
|
|
30
|
+
- **`src/index.ts`** registers the dataframe tools conditionally on `serverConfig.canvasEnabled`, mirroring the existing `enableWrites` gate. Tools are omitted from `tools/list` when the gate is off so agents don't see capabilities they can't use.
|
|
@@ -35,6 +35,13 @@ declare const ServerConfigSchema: z.ZodObject<{
|
|
|
35
35
|
true: "true";
|
|
36
36
|
false: "false";
|
|
37
37
|
}>>, z.ZodTransform<boolean, "true" | "false">>;
|
|
38
|
+
genotypeCallsMaxPull: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
39
|
+
canvasEnabled: z.ZodPipe<z.ZodDefault<z.ZodEnum<{
|
|
40
|
+
true: "true";
|
|
41
|
+
false: "false";
|
|
42
|
+
}>>, z.ZodTransform<boolean, "true" | "false">>;
|
|
43
|
+
canvasMaxRows: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
44
|
+
canvasQueryTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
38
45
|
}, z.core.$strip>;
|
|
39
46
|
export type ServerConfig = z.infer<typeof ServerConfigSchema>;
|
|
40
47
|
export declare function getServerConfig(): ServerConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C,QAAA,MAAM,kBAAkB
|
|
1
|
+
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwItB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,CA4B9C;AAED,uDAAuD;AACvD,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
|
@@ -107,6 +107,30 @@ const ServerConfigSchema = z.object({
|
|
|
107
107
|
.default('false')
|
|
108
108
|
.transform((v) => v === 'true')
|
|
109
109
|
.describe('Opt-in flag for the write surface (`brapi_submit_observations`). Off by default — the tool is omitted from `tools/list` unless the operator opts in for this deployment.'),
|
|
110
|
+
genotypeCallsMaxPull: z.coerce
|
|
111
|
+
.number()
|
|
112
|
+
.int()
|
|
113
|
+
.positive()
|
|
114
|
+
.max(500_000)
|
|
115
|
+
.default(100_000)
|
|
116
|
+
.describe('Hard ceiling on rows pulled from the upstream BrAPI server in a single brapi_find_genotype_calls invocation. Bounds total page count per query — protects the upstream from unbounded pagination loops. Default 100,000 (≈10 pages at the standard pageSize=10,000); maximum 500,000 (≈50 pages, matching the per-query budget of other find_* tools).'),
|
|
117
|
+
canvasEnabled: z
|
|
118
|
+
.enum(['true', 'false'])
|
|
119
|
+
.default('true')
|
|
120
|
+
.transform((v) => v === 'true')
|
|
121
|
+
.describe('Gate the brapi_dataframe_* tool surface. Effective only when the framework canvas service is also configured (CANVAS_PROVIDER_TYPE=duckdb). Default true — set false to keep the dependency installed but the tools hidden.'),
|
|
122
|
+
canvasMaxRows: z.coerce
|
|
123
|
+
.number()
|
|
124
|
+
.int()
|
|
125
|
+
.positive()
|
|
126
|
+
.default(10_000)
|
|
127
|
+
.describe('Hard upper bound on rows materialized into a brapi_dataframe_query response. Larger result sets must use registerAs to keep the full set in the workspace.'),
|
|
128
|
+
canvasQueryTimeoutMs: z.coerce
|
|
129
|
+
.number()
|
|
130
|
+
.int()
|
|
131
|
+
.positive()
|
|
132
|
+
.default(30_000)
|
|
133
|
+
.describe('Per-query wall-clock timeout for brapi_dataframe_query.'),
|
|
110
134
|
});
|
|
111
135
|
let _config;
|
|
112
136
|
export function getServerConfig() {
|
|
@@ -131,6 +155,10 @@ export function getServerConfig() {
|
|
|
131
155
|
searchPollIntervalMs: 'BRAPI_SEARCH_POLL_INTERVAL_MS',
|
|
132
156
|
allowPrivateIps: 'BRAPI_ALLOW_PRIVATE_IPS',
|
|
133
157
|
enableWrites: 'BRAPI_ENABLE_WRITES',
|
|
158
|
+
genotypeCallsMaxPull: 'BRAPI_GENOTYPE_CALLS_MAX_PULL',
|
|
159
|
+
canvasEnabled: 'BRAPI_CANVAS_ENABLED',
|
|
160
|
+
canvasMaxRows: 'BRAPI_CANVAS_MAX_ROWS',
|
|
161
|
+
canvasQueryTimeoutMs: 'BRAPI_CANVAS_QUERY_TIMEOUT_MS',
|
|
134
162
|
});
|
|
135
163
|
return _config;
|
|
136
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import { createApp } from '@cyanheads/mcp-ts-core';
|
|
|
10
10
|
import { getServerConfig } from './config/server-config.js';
|
|
11
11
|
import { initBrapiClient } from './services/brapi-client/index.js';
|
|
12
12
|
import { initBrapiDialectRegistry } from './services/brapi-dialect/index.js';
|
|
13
|
+
import { initCanvasBridge } from './services/canvas-bridge/index.js';
|
|
13
14
|
import { initCapabilityRegistry } from './services/capability-registry/index.js';
|
|
14
15
|
import { initDatasetStore } from './services/dataset-store/index.js';
|
|
15
16
|
import { initOntologyResolver } from './services/ontology-resolver/index.js';
|
|
@@ -23,11 +24,17 @@ import { brapiFiltersResource } from './mcp-server/resources/definitions/brapi-f
|
|
|
23
24
|
import { brapiGermplasmResource } from './mcp-server/resources/definitions/brapi-germplasm.resource.js';
|
|
24
25
|
import { brapiServerInfoResource } from './mcp-server/resources/definitions/brapi-server-info.resource.js';
|
|
25
26
|
import { brapiStudyResource } from './mcp-server/resources/definitions/brapi-study.resource.js';
|
|
26
|
-
import { readOnlyToolDefinitions, writeToolDefinitions, } from './mcp-server/tools/definitions/index.js';
|
|
27
|
+
import { dataframeToolDefinitions, readOnlyToolDefinitions, writeToolDefinitions, } from './mcp-server/tools/definitions/index.js';
|
|
27
28
|
const serverConfig = getServerConfig();
|
|
28
|
-
const tools =
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
const tools = [
|
|
30
|
+
...readOnlyToolDefinitions,
|
|
31
|
+
// Dataframe surface gated by BRAPI_CANVAS_ENABLED. The framework canvas
|
|
32
|
+
// itself is gated by CANVAS_PROVIDER_TYPE — when that's not `duckdb`, the
|
|
33
|
+
// bridge returns `isEnabled() === false` and the tools fail with a typed
|
|
34
|
+
// `dataframe_disabled` error directing the operator to set both env vars.
|
|
35
|
+
...(serverConfig.canvasEnabled ? dataframeToolDefinitions : []),
|
|
36
|
+
...(serverConfig.enableWrites ? writeToolDefinitions : []),
|
|
37
|
+
];
|
|
31
38
|
await createApp({
|
|
32
39
|
tools,
|
|
33
40
|
resources: [
|
|
@@ -39,12 +46,13 @@ await createApp({
|
|
|
39
46
|
brapiFiltersResource,
|
|
40
47
|
],
|
|
41
48
|
prompts: [brapiEdaStudy, brapiMetaAnalysis],
|
|
42
|
-
setup() {
|
|
49
|
+
setup(core) {
|
|
50
|
+
const canvasBridge = initCanvasBridge(core.canvas, serverConfig);
|
|
43
51
|
initBrapiClient(serverConfig);
|
|
44
52
|
initCapabilityRegistry(serverConfig);
|
|
45
53
|
initBrapiDialectRegistry();
|
|
46
54
|
initReferenceDataCache(serverConfig);
|
|
47
|
-
initDatasetStore(serverConfig);
|
|
55
|
+
initDatasetStore(serverConfig, canvasBridge);
|
|
48
56
|
initServerRegistry(serverConfig);
|
|
49
57
|
initOntologyResolver();
|
|
50
58
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,4DAA4D,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,gEAAgE,CAAC;AACnG,OAAO,EAAE,kBAAkB,EAAE,MAAM,4DAA4D,CAAC;AAChG,OAAO,EAAE,oBAAoB,EAAE,MAAM,8DAA8D,CAAC;AACpG,OAAO,EAAE,oBAAoB,EAAE,MAAM,8DAA8D,CAAC;AACpG,OAAO,EAAE,sBAAsB,EAAE,MAAM,gEAAgE,CAAC;AACxG,OAAO,EAAE,uBAAuB,EAAE,MAAM,kEAAkE,CAAC;AAC3G,OAAO,EAAE,kBAAkB,EAAE,MAAM,4DAA4D,CAAC;AAChG,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,yCAAyC,CAAC;AAEjD,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;AAEvC,MAAM,KAAK,GAAG,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,4DAA4D,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,gEAAgE,CAAC;AACnG,OAAO,EAAE,kBAAkB,EAAE,MAAM,4DAA4D,CAAC;AAChG,OAAO,EAAE,oBAAoB,EAAE,MAAM,8DAA8D,CAAC;AACpG,OAAO,EAAE,oBAAoB,EAAE,MAAM,8DAA8D,CAAC;AACpG,OAAO,EAAE,sBAAsB,EAAE,MAAM,gEAAgE,CAAC;AACxG,OAAO,EAAE,uBAAuB,EAAE,MAAM,kEAAkE,CAAC;AAC3G,OAAO,EAAE,kBAAkB,EAAE,MAAM,4DAA4D,CAAC;AAChG,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,yCAAyC,CAAC;AAEjD,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;AAEvC,MAAM,KAAK,GAAG;IACZ,GAAG,uBAAuB;IAC1B,wEAAwE;IACxE,0EAA0E;IAC1E,yEAAyE;IACzE,0EAA0E;IAC1E,GAAG,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/D,GAAG,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC;CAC3D,CAAC;AAEF,MAAM,SAAS,CAAC;IACd,KAAK;IACL,SAAS,EAAE;QACT,uBAAuB;QACvB,kBAAkB;QAClB,kBAAkB;QAClB,sBAAsB;QACtB,oBAAoB;QACpB,oBAAoB;KACrB;IACD,OAAO,EAAE,CAAC,aAAa,EAAE,iBAAiB,CAAC;IAC3C,KAAK,CAAC,IAAI;QACR,MAAM,YAAY,GAAG,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACjE,eAAe,CAAC,YAAY,CAAC,CAAC;QAC9B,sBAAsB,CAAC,YAAY,CAAC,CAAC;QACrC,wBAAwB,EAAE,CAAC;QAC3B,sBAAsB,CAAC,YAAY,CAAC,CAAC;QACrC,gBAAgB,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAC7C,kBAAkB,CAAC,YAAY,CAAC,CAAC;QACjC,oBAAoB,EAAE,CAAC;IACzB,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `brapi_dataframe_describe` — list dataframes (or describe one)
|
|
3
|
+
* with column schema, row count, and originating-dataset provenance.
|
|
4
|
+
* Auto-registered dataset dataframes (`ds_<datasetId>`) carry full source
|
|
5
|
+
* metadata (originating tool, baseUrl, query, expiry); user-derived dataframes
|
|
6
|
+
* created via `brapi_dataframe_query({ registerAs })` only show structural info.
|
|
7
|
+
*
|
|
8
|
+
* @module mcp-server/tools/definitions/brapi-dataframe-describe.tool
|
|
9
|
+
*/
|
|
10
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
11
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
12
|
+
export declare const brapiDataframeDescribe: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
13
|
+
dataframe: z.ZodOptional<z.ZodString>;
|
|
14
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
15
|
+
tables: z.ZodArray<z.ZodObject<{
|
|
16
|
+
name: z.ZodString;
|
|
17
|
+
rowCount: z.ZodNumber;
|
|
18
|
+
columns: z.ZodArray<z.ZodObject<{
|
|
19
|
+
name: z.ZodString;
|
|
20
|
+
type: z.ZodString;
|
|
21
|
+
nullable: z.ZodOptional<z.ZodBoolean>;
|
|
22
|
+
}, z.core.$strip>>;
|
|
23
|
+
approxSizeBytes: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
provenance: z.ZodOptional<z.ZodObject<{
|
|
25
|
+
datasetId: z.ZodString;
|
|
26
|
+
source: z.ZodString;
|
|
27
|
+
baseUrl: z.ZodString;
|
|
28
|
+
query: z.ZodUnknown;
|
|
29
|
+
createdAt: z.ZodString;
|
|
30
|
+
expiresAt: z.ZodString;
|
|
31
|
+
}, z.core.$strip>>;
|
|
32
|
+
}, z.core.$strip>>;
|
|
33
|
+
}, z.core.$strip>, readonly [{
|
|
34
|
+
readonly reason: "dataframe_disabled";
|
|
35
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
36
|
+
readonly when: "Dataframe surface is gated off by env (CANVAS_PROVIDER_TYPE != duckdb or BRAPI_CANVAS_ENABLED=false)";
|
|
37
|
+
readonly recovery: "Set CANVAS_PROVIDER_TYPE=duckdb and BRAPI_CANVAS_ENABLED=true on the deployment, or use brapi_manage_dataset to enumerate datasets directly.";
|
|
38
|
+
}]>;
|
|
39
|
+
//# sourceMappingURL=brapi-dataframe-describe.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brapi-dataframe-describe.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/brapi-dataframe-describe.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAgDjE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCjC,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `brapi_dataframe_describe` — list dataframes (or describe one)
|
|
3
|
+
* with column schema, row count, and originating-dataset provenance.
|
|
4
|
+
* Auto-registered dataset dataframes (`ds_<datasetId>`) carry full source
|
|
5
|
+
* metadata (originating tool, baseUrl, query, expiry); user-derived dataframes
|
|
6
|
+
* created via `brapi_dataframe_query({ registerAs })` only show structural info.
|
|
7
|
+
*
|
|
8
|
+
* @module mcp-server/tools/definitions/brapi-dataframe-describe.tool
|
|
9
|
+
*/
|
|
10
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
11
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
12
|
+
import { getCanvasBridge } from '../../../services/canvas-bridge/index.js';
|
|
13
|
+
const ColumnSchema = z.object({
|
|
14
|
+
name: z.string().describe('Column name.'),
|
|
15
|
+
type: z.string().describe('SQL column type (VARCHAR, INTEGER, DOUBLE, BOOLEAN, etc.).'),
|
|
16
|
+
nullable: z.boolean().optional().describe('True when NULL values are allowed.'),
|
|
17
|
+
});
|
|
18
|
+
const ProvenanceSchema = z.object({
|
|
19
|
+
datasetId: z
|
|
20
|
+
.string()
|
|
21
|
+
.describe('Originating dataset ID — pass to brapi_manage_dataset to operate on the underlying rows.'),
|
|
22
|
+
source: z.string().describe('Tool/operation that produced the dataset (e.g. find_observations).'),
|
|
23
|
+
baseUrl: z.string().describe('BrAPI base URL the dataset was pulled from.'),
|
|
24
|
+
query: z.unknown().describe('Original filter map / search body.'),
|
|
25
|
+
createdAt: z.string().describe('ISO 8601 dataset creation time.'),
|
|
26
|
+
expiresAt: z.string().describe('ISO 8601 expiry — when the dataframe will be evicted.'),
|
|
27
|
+
});
|
|
28
|
+
const DescribedTableSchema = z.object({
|
|
29
|
+
name: z.string().describe('Dataframe name. Use this in SQL queries.'),
|
|
30
|
+
rowCount: z.number().int().nonnegative().describe('Rows currently registered.'),
|
|
31
|
+
columns: z
|
|
32
|
+
.array(ColumnSchema.describe('Column declaration.'))
|
|
33
|
+
.describe('Schema in declaration order.'),
|
|
34
|
+
approxSizeBytes: z.number().int().nonnegative().optional().describe('Approximate size in bytes.'),
|
|
35
|
+
provenance: ProvenanceSchema.optional().describe('Originating dataset provenance — present only for auto-registered dataframes (`ds_*`).'),
|
|
36
|
+
});
|
|
37
|
+
const OutputSchema = z.object({
|
|
38
|
+
tables: z
|
|
39
|
+
.array(DescribedTableSchema.describe('Dataframe description.'))
|
|
40
|
+
.describe('All described dataframes.'),
|
|
41
|
+
});
|
|
42
|
+
const InputSchema = z.object({
|
|
43
|
+
dataframe: z
|
|
44
|
+
.string()
|
|
45
|
+
.min(1)
|
|
46
|
+
.optional()
|
|
47
|
+
.describe('When set, return only the named dataframe. Omit to list all dataframes.'),
|
|
48
|
+
});
|
|
49
|
+
export const brapiDataframeDescribe = tool('brapi_dataframe_describe', {
|
|
50
|
+
description: 'List dataframes (or describe one) with columns, row counts, and originating-dataset provenance. Use this to discover what dataframes are available before writing a brapi_dataframe_query.',
|
|
51
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
52
|
+
errors: [
|
|
53
|
+
{
|
|
54
|
+
reason: 'dataframe_disabled',
|
|
55
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
56
|
+
when: 'Dataframe surface is gated off by env (CANVAS_PROVIDER_TYPE != duckdb or BRAPI_CANVAS_ENABLED=false)',
|
|
57
|
+
recovery: 'Set CANVAS_PROVIDER_TYPE=duckdb and BRAPI_CANVAS_ENABLED=true on the deployment, or use brapi_manage_dataset to enumerate datasets directly.',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
input: InputSchema,
|
|
61
|
+
output: OutputSchema,
|
|
62
|
+
async handler(input, ctx) {
|
|
63
|
+
const bridge = getCanvasBridge();
|
|
64
|
+
if (!bridge.isEnabled()) {
|
|
65
|
+
throw ctx.fail('dataframe_disabled', 'brapi_dataframe_describe is unavailable — dataframes are not enabled on this deployment.', { ...ctx.recoveryFor('dataframe_disabled') });
|
|
66
|
+
}
|
|
67
|
+
const describeOpts = {};
|
|
68
|
+
if (input.dataframe !== undefined)
|
|
69
|
+
describeOpts.tableName = input.dataframe;
|
|
70
|
+
const tables = await bridge.describe(ctx, describeOpts);
|
|
71
|
+
return { tables };
|
|
72
|
+
},
|
|
73
|
+
format: (result) => [{ type: 'text', text: renderDescribe(result.tables) }],
|
|
74
|
+
});
|
|
75
|
+
function renderDescribe(tables) {
|
|
76
|
+
const lines = [];
|
|
77
|
+
lines.push(`# ${tables.length} dataframe(s)`);
|
|
78
|
+
if (tables.length === 0) {
|
|
79
|
+
lines.push('');
|
|
80
|
+
lines.push('_No dataframes. Run a find_* tool that spills to a dataset, or use brapi_dataframe_query with `registerAs` to materialize one._');
|
|
81
|
+
return lines.join('\n');
|
|
82
|
+
}
|
|
83
|
+
for (const table of tables) {
|
|
84
|
+
lines.push('');
|
|
85
|
+
lines.push(`## \`${table.name}\``);
|
|
86
|
+
lines.push(`- rowCount: ${table.rowCount}`);
|
|
87
|
+
if (table.approxSizeBytes !== undefined) {
|
|
88
|
+
lines.push(`- approxSizeBytes: ${table.approxSizeBytes}`);
|
|
89
|
+
}
|
|
90
|
+
lines.push(`- columns: ${table.columns.length}`);
|
|
91
|
+
for (const col of table.columns) {
|
|
92
|
+
const nullable = col.nullable === undefined ? '' : ` (nullable: ${col.nullable})`;
|
|
93
|
+
lines.push(` - ${col.name}: ${col.type}${nullable}`);
|
|
94
|
+
}
|
|
95
|
+
if (table.provenance) {
|
|
96
|
+
lines.push('- provenance:');
|
|
97
|
+
lines.push(` - datasetId: \`${table.provenance.datasetId}\``);
|
|
98
|
+
lines.push(` - source: ${table.provenance.source}`);
|
|
99
|
+
lines.push(` - baseUrl: ${table.provenance.baseUrl}`);
|
|
100
|
+
lines.push(` - createdAt: ${table.provenance.createdAt}`);
|
|
101
|
+
lines.push(` - expiresAt: ${table.provenance.expiresAt}`);
|
|
102
|
+
lines.push(` - query: \`${JSON.stringify(table.provenance.query)}\``);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return lines.join('\n');
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=brapi-dataframe-describe.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brapi-dataframe-describe.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/brapi-dataframe-describe.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `brapi_dataframe_drop` — release a single dataframe by name.
|
|
3
|
+
* Idempotent (returns `dropped: false` for unknown names rather than failing).
|
|
4
|
+
* Drops the dataframe and any provenance metadata stored alongside it. The
|
|
5
|
+
* originating dataset is unaffected — use `brapi_manage_dataset mode=delete`
|
|
6
|
+
* to drop both.
|
|
7
|
+
*
|
|
8
|
+
* @module mcp-server/tools/definitions/brapi-dataframe-drop.tool
|
|
9
|
+
*/
|
|
10
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
11
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
12
|
+
export declare const brapiDataframeDrop: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
13
|
+
dataframe: z.ZodString;
|
|
14
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
15
|
+
dataframe: z.ZodString;
|
|
16
|
+
dropped: z.ZodBoolean;
|
|
17
|
+
}, z.core.$strip>, readonly [{
|
|
18
|
+
readonly reason: "dataframe_disabled";
|
|
19
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
20
|
+
readonly when: "Dataframe surface is gated off by env (CANVAS_PROVIDER_TYPE != duckdb or BRAPI_CANVAS_ENABLED=false)";
|
|
21
|
+
readonly recovery: "Set CANVAS_PROVIDER_TYPE=duckdb and BRAPI_CANVAS_ENABLED=true on the deployment, or use brapi_manage_dataset for the underlying dataset.";
|
|
22
|
+
}]>;
|
|
23
|
+
//# sourceMappingURL=brapi-dataframe-drop.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brapi-dataframe-drop.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/brapi-dataframe-drop.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAmBjE,eAAO,MAAM,kBAAkB;;;;;;;;;;GAqC7B,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `brapi_dataframe_drop` — release a single dataframe by name.
|
|
3
|
+
* Idempotent (returns `dropped: false` for unknown names rather than failing).
|
|
4
|
+
* Drops the dataframe and any provenance metadata stored alongside it. The
|
|
5
|
+
* originating dataset is unaffected — use `brapi_manage_dataset mode=delete`
|
|
6
|
+
* to drop both.
|
|
7
|
+
*
|
|
8
|
+
* @module mcp-server/tools/definitions/brapi-dataframe-drop.tool
|
|
9
|
+
*/
|
|
10
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
11
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
12
|
+
import { getCanvasBridge } from '../../../services/canvas-bridge/index.js';
|
|
13
|
+
const InputSchema = z.object({
|
|
14
|
+
dataframe: z
|
|
15
|
+
.string()
|
|
16
|
+
.min(1)
|
|
17
|
+
.describe('Dataframe to drop. Use brapi_dataframe_describe to discover names. Returns dropped:false (no error) when the name is unknown.'),
|
|
18
|
+
});
|
|
19
|
+
const OutputSchema = z.object({
|
|
20
|
+
dataframe: z.string().describe('The dataframe name that was requested for drop.'),
|
|
21
|
+
dropped: z
|
|
22
|
+
.boolean()
|
|
23
|
+
.describe('True when the dataframe existed and was removed; false when it did not exist.'),
|
|
24
|
+
});
|
|
25
|
+
export const brapiDataframeDrop = tool('brapi_dataframe_drop', {
|
|
26
|
+
description: 'Drop a dataframe by name. Idempotent — returns dropped:false rather than failing when the name is unknown. The underlying dataset is untouched (use brapi_manage_dataset mode=delete to drop both).',
|
|
27
|
+
annotations: { readOnlyHint: false, idempotentHint: true, openWorldHint: false },
|
|
28
|
+
errors: [
|
|
29
|
+
{
|
|
30
|
+
reason: 'dataframe_disabled',
|
|
31
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
32
|
+
when: 'Dataframe surface is gated off by env (CANVAS_PROVIDER_TYPE != duckdb or BRAPI_CANVAS_ENABLED=false)',
|
|
33
|
+
recovery: 'Set CANVAS_PROVIDER_TYPE=duckdb and BRAPI_CANVAS_ENABLED=true on the deployment, or use brapi_manage_dataset for the underlying dataset.',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
input: InputSchema,
|
|
37
|
+
output: OutputSchema,
|
|
38
|
+
async handler(input, ctx) {
|
|
39
|
+
const bridge = getCanvasBridge();
|
|
40
|
+
if (!bridge.isEnabled()) {
|
|
41
|
+
throw ctx.fail('dataframe_disabled', 'brapi_dataframe_drop is unavailable — dataframes are not enabled on this deployment.', { ...ctx.recoveryFor('dataframe_disabled') });
|
|
42
|
+
}
|
|
43
|
+
const dropped = await bridge.drop(ctx, input.dataframe);
|
|
44
|
+
return { dataframe: input.dataframe, dropped };
|
|
45
|
+
},
|
|
46
|
+
format: (result) => [
|
|
47
|
+
{
|
|
48
|
+
type: 'text',
|
|
49
|
+
text: result.dropped
|
|
50
|
+
? `# Dropped \`${result.dataframe}\`\n- dropped: true`
|
|
51
|
+
: `# No-op — \`${result.dataframe}\` not found\n- dropped: false`,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=brapi-dataframe-drop.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brapi-dataframe-drop.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/brapi-dataframe-drop.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAEpE,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,+HAA+H,CAChI;CACJ,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;IACjF,OAAO,EAAE,CAAC;SACP,OAAO,EAAE;SACT,QAAQ,CAAC,+EAA+E,CAAC;CAC7F,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC,sBAAsB,EAAE;IAC7D,WAAW,EACT,qMAAqM;IACvM,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;IAChF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,oBAAoB;YAC5B,IAAI,EAAE,gBAAgB,CAAC,kBAAkB;YACzC,IAAI,EAAE,sGAAsG;YAC5G,QAAQ,EACN,0IAA0I;SAC7I;KACO;IACV,KAAK,EAAE,WAAW;IAClB,MAAM,EAAE,YAAY;IAEpB,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;YACxB,MAAM,GAAG,CAAC,IAAI,CACZ,oBAAoB,EACpB,sFAAsF,EACtF,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,oBAAoB,CAAC,EAAE,CAC7C,CAAC;QACJ,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QACxD,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC;QAClB;YACE,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM,CAAC,OAAO;gBAClB,CAAC,CAAC,eAAe,MAAM,CAAC,SAAS,qBAAqB;gBACtD,CAAC,CAAC,eAAe,MAAM,CAAC,SAAS,gCAAgC;SACpE;KACF;CACF,CAAC,CAAC"}
|