@cyanheads/brapi-mcp-server 0.7.10 → 0.7.12
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 +32 -25
- package/Dockerfile +19 -5
- package/README.md +7 -4
- package/changelog/0.7.x/0.7.11.md +43 -0
- package/changelog/0.7.x/0.7.12.md +35 -0
- package/changelog/template.md +62 -40
- package/dist/config/alias-credentials.d.ts +1 -1
- package/dist/config/alias-credentials.d.ts.map +1 -1
- package/dist/config/alias-credentials.js +24 -8
- package/dist/config/alias-credentials.js.map +1 -1
- package/dist/config/builtin-aliases.js.map +1 -1
- package/dist/config/server-config.d.ts +1 -1
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +3 -1
- package/dist/config/server-config.js.map +1 -1
- package/dist/mcp-server/resources/definitions/brapi-calls.resource.d.ts +3 -3
- package/dist/mcp-server/resources/definitions/brapi-calls.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/brapi-calls.resource.js +1 -1
- package/dist/mcp-server/resources/definitions/brapi-filters.resource.d.ts +3 -3
- package/dist/mcp-server/resources/definitions/brapi-filters.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/brapi-filters.resource.js +1 -1
- package/dist/mcp-server/resources/definitions/brapi-germplasm.resource.d.ts +6 -6
- package/dist/mcp-server/resources/definitions/brapi-germplasm.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/brapi-germplasm.resource.js +1 -1
- package/dist/mcp-server/resources/definitions/brapi-server-info.resource.d.ts +3 -3
- package/dist/mcp-server/resources/definitions/brapi-server-info.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/brapi-server-info.resource.js +1 -1
- package/dist/mcp-server/resources/definitions/brapi-study.resource.d.ts +6 -6
- package/dist/mcp-server/resources/definitions/brapi-study.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/brapi-study.resource.js +1 -1
- package/dist/mcp-server/resources/definitions/brapi-variable.resource.d.ts +6 -6
- package/dist/mcp-server/resources/definitions/brapi-variable.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/brapi-variable.resource.js +1 -1
- package/dist/mcp-server/tools/definitions/brapi-build-phenotype-matrix.tool.d.ts +19 -14
- package/dist/mcp-server/tools/definitions/brapi-build-phenotype-matrix.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-build-phenotype-matrix.tool.js +34 -0
- package/dist/mcp-server/tools/definitions/brapi-build-phenotype-matrix.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-connect.tool.d.ts +12 -12
- package/dist/mcp-server/tools/definitions/brapi-connect.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-dataframe-describe.tool.d.ts +2 -2
- package/dist/mcp-server/tools/definitions/brapi-dataframe-describe.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-dataframe-export.tool.d.ts +14 -14
- package/dist/mcp-server/tools/definitions/brapi-dataframe-export.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-dataframe-query.tool.d.ts +9 -4
- package/dist/mcp-server/tools/definitions/brapi-dataframe-query.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-dataframe-query.tool.js +31 -0
- package/dist/mcp-server/tools/definitions/brapi-dataframe-query.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-describe-filters.tool.d.ts +6 -6
- package/dist/mcp-server/tools/definitions/brapi-describe-filters.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-export-genotype-matrix.tool.d.ts +11 -11
- package/dist/mcp-server/tools/definitions/brapi-export-genotype-matrix.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.d.ts +11 -11
- package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-find-germplasm.tool.d.ts +6 -6
- 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 +6 -6
- 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 +6 -6
- 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 +6 -6
- 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 +6 -6
- 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 +7 -7
- 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 +6 -6
- package/dist/mcp-server/tools/definitions/brapi-find-variants.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-germplasm-performance.tool.d.ts +6 -6
- package/dist/mcp-server/tools/definitions/brapi-germplasm-performance.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-get-germplasm.tool.d.ts +6 -6
- package/dist/mcp-server/tools/definitions/brapi-get-germplasm.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-get-image.tool.d.ts +6 -6
- package/dist/mcp-server/tools/definitions/brapi-get-image.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-get-study.tool.d.ts +6 -6
- package/dist/mcp-server/tools/definitions/brapi-get-study.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-raw-get.tool.d.ts +6 -6
- package/dist/mcp-server/tools/definitions/brapi-raw-get.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-raw-search.tool.d.ts +7 -7
- package/dist/mcp-server/tools/definitions/brapi-raw-search.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-server-info.tool.d.ts +9 -9
- package/dist/mcp-server/tools/definitions/brapi-server-info.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-submit-observations.tool.d.ts +23 -27
- package/dist/mcp-server/tools/definitions/brapi-submit-observations.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-submit-observations.tool.js +41 -55
- package/dist/mcp-server/tools/definitions/brapi-submit-observations.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/brapi-walk-pedigree.tool.d.ts +8 -8
- package/dist/mcp-server/tools/definitions/brapi-walk-pedigree.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/index.d.ts +829 -824
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
- package/dist/mcp-server/tools/shared/find-helpers.js.map +1 -1
- package/dist/mcp-server/tools/shared/observations.js.map +1 -1
- package/dist/mcp-server/tools/shared/orientation-envelope.d.ts +12 -12
- package/dist/services/brapi-client/brapi-client.d.ts +2 -3
- package/dist/services/brapi-client/brapi-client.d.ts.map +1 -1
- package/dist/services/brapi-client/brapi-client.js +16 -19
- package/dist/services/brapi-client/brapi-client.js.map +1 -1
- package/dist/services/brapi-client/types.d.ts +2 -2
- package/dist/services/brapi-dialect/detect.d.ts +1 -1
- package/dist/services/brapi-dialect/detect.js.map +1 -1
- package/dist/services/brapi-dialect/index.d.ts +2 -2
- package/dist/services/brapi-dialect/index.js +1 -1
- package/dist/services/brapi-dialect/index.js.map +1 -1
- package/dist/services/canvas-bridge/canvas-bridge.d.ts +1 -1
- package/dist/services/canvas-bridge/canvas-bridge.d.ts.map +1 -1
- package/dist/services/canvas-bridge/canvas-bridge.js.map +1 -1
- package/dist/services/capability-registry/capability-registry.d.ts +1 -1
- package/dist/services/capability-registry/capability-registry.d.ts.map +1 -1
- package/dist/services/capability-registry/capability-registry.js +1 -1
- package/dist/services/capability-registry/capability-registry.js.map +1 -1
- package/dist/services/ontology-resolver/ontology-resolver.d.ts.map +1 -1
- package/dist/services/ontology-resolver/ontology-resolver.js.map +1 -1
- package/dist/services/reference-data-cache/reference-data-cache.d.ts +2 -2
- package/dist/services/reference-data-cache/reference-data-cache.d.ts.map +1 -1
- package/dist/services/reference-data-cache/reference-data-cache.js +1 -1
- package/dist/services/reference-data-cache/reference-data-cache.js.map +1 -1
- package/dist/services/server-registry/server-registry.d.ts.map +1 -1
- package/dist/services/server-registry/server-registry.js.map +1 -1
- package/dist/services/server-registry/types.d.ts +1 -1
- package/manifest.json +8 -6
- package/package.json +15 -14
- package/server.json +3 -3
package/CLAUDE.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** brapi-mcp-server
|
|
4
|
-
**Version:** 0.7.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.
|
|
4
|
+
**Version:** 0.7.12
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.0`
|
|
6
|
+
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` ^2.0.0 (protocol revisions 2026-07-28 and 2025-*)
|
|
6
8
|
|
|
7
9
|
> **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.
|
|
8
10
|
|
|
@@ -32,7 +34,7 @@ Tailor suggestions to what's actually missing or stale — don't recite the full
|
|
|
32
34
|
- **Logic throws, framework catches.** Tool/resource handlers are pure — throw on failure, no `try/catch`. The framework catches, classifies, and formats. Default to typed contracts: declare `errors: [...]` and throw via `ctx.fail(reason, …)` so failures carry stable `data.reason` codes for agent-client routing. Fall back to error factories (`notFound()`, `validationError()`, etc.) only for services or when no contract entry fits.
|
|
33
35
|
- **Use `ctx.log`** for request-scoped logging. No `console` calls.
|
|
34
36
|
- **Use `ctx.state`** for tenant-scoped storage. Never access persistence directly.
|
|
35
|
-
- **
|
|
37
|
+
- **Need input the caller didn't supply?** `return ctx.requestInput(...)` and read `ctx.inputs` when the handler is re-entered. Never `await` for user input mid-handler.
|
|
36
38
|
- **Secrets in env vars only** — never hardcoded.
|
|
37
39
|
- **Close the loop on issues.** When implementing work tracked by a GitHub issue, comment on the issue with what landed and close it. Do both — a comment without a close leaves stale issues open; a close without a comment leaves no record of what shipped. The comment is for future readers — state the concrete changes, not the conversation that produced them.
|
|
38
40
|
|
|
@@ -161,14 +163,16 @@ Handlers receive a unified `ctx` object. Currently used surface:
|
|
|
161
163
|
|
|
162
164
|
| Property | Description |
|
|
163
165
|
|:---------|:------------|
|
|
164
|
-
| `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. |
|
|
166
|
+
| `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. Dual-sink: Pino **and** `notifications/message` to the client, so treat it as client-visible. |
|
|
165
167
|
| `ctx.state` | Tenant-scoped KV — used by `ServerRegistry` (connection aliases), `CanvasBridge` (default canvas pointer + per-table provenance), and `CapabilityRegistry` (cached profiles). Spilled `find_*` rows live on the canvas (DuckDB), not in `ctx.state`. |
|
|
166
|
-
| `ctx.sessionId` | Mcp-Session-Id (HTTP stateful/auto); `undefined` for stdio
|
|
168
|
+
| `ctx.sessionId` | Mcp-Session-Id (HTTP stateful/auto); `undefined` for stdio, stateless HTTP unless `exposeStatelessSessionId` is opted in, and every request on protocol revision 2026-07-28, which is session-less by design. Composed into `ServerRegistry.connKey` and `CanvasBridge.defaultCanvasKey` when `BRAPI_SESSION_ISOLATION=true` (default), so concurrent HTTP sessions in the same tenant don't share connection state or canvas. Discovery / scoping key on top of tenant-keyed state — not an authorization principal. |
|
|
167
169
|
| `ctx.signal` | `AbortSignal` — threaded into every BrAPI HTTP call so client-side cancellation aborts the upstream request. |
|
|
168
170
|
| `ctx.requestId` | Unique request ID — auto-attached to every `ctx.log` entry. |
|
|
169
171
|
| `ctx.tenantId` | Tenant ID from JWT or `'default'` for stdio / HTTP+`auth=none` — outer scope on all `ctx.state` reads/writes. |
|
|
172
|
+
| `ctx.requestInput` / `ctx.inputs` | Multi-round-trip input. `brapi_submit_observations` gates apply-mode writes on a `confirm` elicitation: it reads `ctx.inputs.view('confirm')`, returns `ctx.requestInput({ inputRequests: … })` when the answer is missing, and treats a declined, cancelled, or unparseable answer as terminal (`user_declined`). `force: true` skips the round. |
|
|
173
|
+
| `ctx.enrich` | Success-path agent context. `brapi_dataframe_query` and `brapi_build_phenotype_matrix` disclose capped results with `ctx.enrich.truncated({ shown, cap, guidance })`. |
|
|
170
174
|
|
|
171
|
-
`ctx.
|
|
175
|
+
`ctx.fail(reason, …)` is the typed thrower keyed off declared `errors[]` contracts — used by 14 tools and 1 resource today. `ctx.recoveryFor(reason)` resolves the matching contract entry's recovery hint into `data.recovery.hint` so it surfaces on the wire. `ctx.content` is unused — no tool emits media blocks outside `brapi_get_image`, which returns image bytes through its own output schema.
|
|
172
176
|
|
|
173
177
|
---
|
|
174
178
|
|
|
@@ -176,7 +180,7 @@ Handlers receive a unified `ctx` object. Currently used surface:
|
|
|
176
180
|
|
|
177
181
|
Handlers throw — the framework catches, classifies, and formats.
|
|
178
182
|
|
|
179
|
-
**Default for new tools: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` to receive a typed `ctx.fail(reason, …)` keyed by the declared reason union. TypeScript catches `ctx.fail('typo')` at compile time, `data.reason` is auto-populated for observability, and the linter enforces conformance against the handler body. The `recovery` field is required descriptive metadata (≥ 5 words, lint-validated); to surface it on the wire, spread `...ctx.recoveryFor('reason')` into `data` or pass an explicit `{ recovery: { hint: '...' } }` when runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`) bubble freely and don't need declaring. Live across the BrAPI surface today: `brapi_build_phenotype_matrix`, `brapi_dataframe_describe`, `brapi_dataframe_export`, `brapi_dataframe_query`, `brapi_describe_filters`, `brapi_export_genotype_matrix`, `brapi_find_genotype_calls`, `brapi_germplasm_performance`, `brapi_get_germplasm`, `brapi_get_image`, `brapi_get_study`, `brapi_raw_get`, `brapi_raw_search`, `brapi_submit_observations`, plus the `brapi://variable/{observationVariableDbId}` resource.
|
|
183
|
+
**Default for new tools: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` to receive a typed `ctx.fail(reason, …)` keyed by the declared reason union. TypeScript catches `ctx.fail('typo')` at compile time, `data.reason` is auto-populated for observability, and the linter enforces conformance against the handler body. The `recovery` field is required descriptive metadata (≥ 5 words, lint-validated); to surface it on the wire, spread `...ctx.recoveryFor('reason')` into `data` or pass an explicit `{ recovery: { hint: '...' } }` when runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring. Live across the BrAPI surface today: `brapi_build_phenotype_matrix`, `brapi_dataframe_describe`, `brapi_dataframe_export`, `brapi_dataframe_query`, `brapi_describe_filters`, `brapi_export_genotype_matrix`, `brapi_find_genotype_calls`, `brapi_germplasm_performance`, `brapi_get_germplasm`, `brapi_get_image`, `brapi_get_study`, `brapi_raw_get`, `brapi_raw_search`, `brapi_submit_observations`, plus the `brapi://variable/{observationVariableDbId}` resource.
|
|
180
184
|
|
|
181
185
|
```ts
|
|
182
186
|
errors: [
|
|
@@ -257,7 +261,7 @@ src/
|
|
|
257
261
|
brapi-build-phenotype-matrix.tool.ts # Germplasm × trait matrix from studies; materialized as canvas dataframe
|
|
258
262
|
brapi-germplasm-performance.tool.ts # Per-variable aggregates (n, mean, median, sd) for a single germplasm
|
|
259
263
|
brapi-export-genotype-matrix.tool.ts # Genotype calls → germplasm × variant dataframe + VCF-lite / PLINK serialization
|
|
260
|
-
brapi-submit-observations.tool.ts # Two-phase observation write — preview / apply (POST + PUT)
|
|
264
|
+
brapi-submit-observations.tool.ts # Two-phase observation write — preview / apply (POST + PUT) behind a confirmation round trip
|
|
261
265
|
brapi-raw-get.tool.ts # Last-resort GET passthrough with routing nudge
|
|
262
266
|
brapi-raw-search.tool.ts # Last-resort POST /search passthrough with async polling
|
|
263
267
|
shared/
|
|
@@ -297,9 +301,9 @@ src/
|
|
|
297
301
|
|
|
298
302
|
## Skills
|
|
299
303
|
|
|
300
|
-
Skills are modular instructions in `skills/` at the project root. Read them directly when a task matches — e.g., `skills/add-tool/SKILL.md` when adding a tool.
|
|
304
|
+
Skills are modular instructions in `framework-skills/` at the project root. Read them directly when a task matches — e.g., `framework-skills/add-tool/SKILL.md` when adding a tool. Keep development skills out of root `skills/`: plugin hosts load that directory for installing agents.
|
|
301
305
|
|
|
302
|
-
**Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, Codex: `.codex/skills/`, shared: `.agents/skills/`, others: equivalent). This makes skills available as context without needing to reference `skills/` paths manually. After framework updates, run the `maintenance` skill — it re-syncs the agent directory automatically (Phase B).
|
|
306
|
+
**Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, Codex: `.codex/skills/`, shared: `.agents/skills/`, others: equivalent). This makes skills available as context without needing to reference `framework-skills/` paths manually. After framework updates, run the `maintenance` skill — it re-syncs the agent directory automatically (Phase B).
|
|
303
307
|
|
|
304
308
|
Available skills:
|
|
305
309
|
|
|
@@ -317,10 +321,12 @@ Available skills:
|
|
|
317
321
|
| `tool-defs-analysis` | Read-only audit of MCP definition language across the surface — voice, leaks, defaults, recovery hints, output descriptions |
|
|
318
322
|
| `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
|
|
319
323
|
| `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
|
|
324
|
+
| `techniques` | Catalog of response/data-shaping techniques — overflow handling, payload shaping, retrieval patterns |
|
|
320
325
|
| `devcheck` | Lint, format, typecheck, audit |
|
|
321
326
|
| `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
|
|
322
|
-
| `git-wrapup` | Land working-tree changes as a versioned commit
|
|
323
|
-
| `release-
|
|
327
|
+
| `git-wrapup` | Land working-tree changes as a versioned commit stack; opens a release PR when the project declares release PR mode. |
|
|
328
|
+
| `release-pr-review` | Review an open release PR, land fixups, and keep its body current. Release PR mode only. |
|
|
329
|
+
| `release-and-publish` | Tag + push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup`. |
|
|
324
330
|
| `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
|
|
325
331
|
| `orchestrations` | Chain task skills into a gated multi-phase pipeline — build-out, QA-fix, update-ship — when you can spawn sub-agents |
|
|
326
332
|
| `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
|
|
@@ -329,7 +335,7 @@ Available skills:
|
|
|
329
335
|
| `api-linter` | Definition lint rule reference (`format-parity`, `schema-*`, `name-*`, `server-json-*`, …) |
|
|
330
336
|
| `api-canvas` | DataCanvas: register tabular data, run SQL, export, plus the `spillover()` helper for big result sets — Tier 3 opt-in |
|
|
331
337
|
| `api-config` | AppConfig, parseConfig, env vars |
|
|
332
|
-
| `api-context` | Context interface, logger, state,
|
|
338
|
+
| `api-context` | Context interface, RequestContext, logger, state, multi-round-trip input |
|
|
333
339
|
| `api-errors` | McpError, JsonRpcErrorCode, error patterns |
|
|
334
340
|
| `api-mirror` | MirrorService: persistent SQLite-backed local mirror of a bulk upstream dataset with FTS5 — Tier 3 opt-in |
|
|
335
341
|
| `api-services` | LLM, Speech, Graph services |
|
|
@@ -338,7 +344,7 @@ Available skills:
|
|
|
338
344
|
| `api-utils` | Formatting, parsing, security, pagination, scheduling, telemetry helpers |
|
|
339
345
|
| `api-workers` | Cloudflare Workers runtime |
|
|
340
346
|
|
|
341
|
-
**Chaining skills into pipelines.** When the user wants a multi-phase effort — build this server out, QA-and-fix the surface, update-and-ship — *and you can spawn sub-agents*, `skills/orchestrations/SKILL.md` sequences the task skills above into a gated pipeline with verification at each step. Read it to drive the run. Optional: skip it if you can't orchestrate sub-agents, and ignore it entirely if you were *spawned* as one — you've already been scoped to a single phase.
|
|
347
|
+
**Chaining skills into pipelines.** When the user wants a multi-phase effort — build this server out, QA-and-fix the surface, update-and-ship — *and you can spawn sub-agents*, `framework-skills/orchestrations/SKILL.md` sequences the task skills above into a gated pipeline with verification at each step. Read it to drive the run. Optional: skip it if you can't orchestrate sub-agents, and ignore it entirely if you were *spawned* as one — you've already been scoped to a single phase.
|
|
342
348
|
|
|
343
349
|
When you complete a skill's checklist, check the boxes and add a completion timestamp at the end (e.g., `Completed: 2026-03-11`).
|
|
344
350
|
|
|
@@ -354,13 +360,14 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
354
360
|
| `bun run rebuild` | Clean + build |
|
|
355
361
|
| `bun run clean` | Remove build artifacts |
|
|
356
362
|
| `bun run devcheck` | Lint + format + typecheck + security + changelog sync |
|
|
357
|
-
| `bun run audit:
|
|
363
|
+
| `bun run audit:fix` | Upgrade vulnerable packages within existing ranges with `bun audit fix`; try before `bun update <name>` and `bun dedupe`. |
|
|
364
|
+
| `bun run audit:refresh` | Delete `bun.lock`, reinstall, re-audit. Last resort after in-place fixes; re-resolves ranged dependencies, including the framework. |
|
|
358
365
|
| `bun run list-skills` | Print the skill index for this project (name, version, description) |
|
|
359
366
|
| `bun run tree` | Generate `docs/tree.md` |
|
|
360
367
|
| `bun run format` | Auto-fix formatting via Biome |
|
|
361
368
|
| `bun run lint:mcp` | Validate MCP tool / resource / prompt definitions against the spec |
|
|
362
369
|
| `bun run lint:packaging` | Verify env var alignment between `manifest.json` and `server.json` |
|
|
363
|
-
| `bun run bundle` | Build and
|
|
370
|
+
| `bun run bundle` | Build, pack, and clean a `.mcpb` for one-click Claude Desktop install |
|
|
364
371
|
| `bun run test` | Vitest suite |
|
|
365
372
|
| `bun run start` | Production mode — defers transport selection to `MCP_TRANSPORT_TYPE` (stdio default) |
|
|
366
373
|
| `bun run start:stdio` | Production mode (stdio) — requires prior `bun run build` |
|
|
@@ -372,7 +379,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
372
379
|
|
|
373
380
|
## Bundling
|
|
374
381
|
|
|
375
|
-
`bun run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. MCPB is stdio-only — HTTP deployments are unaffected. To opt out, delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly when `manifest.json` is absent.
|
|
382
|
+
`bun run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips two classes of `node_modules/**` content that root-anchored `.mcpbignore` patterns cannot reach: dependency-shipped agent docs (`framework-skills/`, `skills/`, `.claude/`, `.agents/`, `SKILL.md`) and platform-specific native bindings, which would otherwise lock the bundle to the platform it was packed on. The bundle therefore ships portable without the DuckDB native — `@duckdb/node-api` is loaded lazily, so canvas tools report an actionable install hint and every other tool works normally. MCPB is stdio-only — HTTP deployments are unaffected. To opt out, delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly when `manifest.json` is absent.
|
|
376
383
|
|
|
377
384
|
**Adding an env var requires both files:** `server.json` (registry discovery, `environmentVariables[]`) and `manifest.json` (bundle install UX, `mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies the env var names match.
|
|
378
385
|
|
|
@@ -388,20 +395,20 @@ Each per-version file opens with YAML frontmatter:
|
|
|
388
395
|
---
|
|
389
396
|
summary: One-line headline, ≤350 chars # required — powers the rollup index
|
|
390
397
|
breaking: false # optional — true flags breaking changes
|
|
391
|
-
security: false # optional — true
|
|
398
|
+
security: false # optional — true ONLY for a source-code security fix, never a dependency CVE bump
|
|
392
399
|
---
|
|
393
400
|
|
|
394
401
|
# 0.1.0 — YYYY-MM-DD
|
|
395
402
|
...
|
|
396
403
|
```
|
|
397
404
|
|
|
398
|
-
`breaking: true` renders a `· ⚠️ Breaking` badge — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames). `security: true` renders a `· 🛡️ Security` badge and pairs with a `## Security` body section. When both are set, badges render `· ⚠️ Breaking · 🛡️ Security`.
|
|
405
|
+
`breaking: true` renders a `· ⚠️ Breaking` badge — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames). `security: true` renders a `· 🛡️ Security` badge and pairs with a `## Security` body section — set it only for a security fix in this server's *own source code*, never for a routine dependency or transitive CVE bump (record those under `## Dependencies`). When both are set, badges render `· ⚠️ Breaking · 🛡️ Security`.
|
|
399
406
|
|
|
400
407
|
`agent-notes` is an optional free-form field for maintenance agents processing the release downstream. Content here won't appear in the rendered CHANGELOG — it's consumed by agents running the `maintenance` skill. Use it for adoption instructions that don't fit the human-facing sections: new files to create, fields to populate, one-time migration steps. Omit entirely when there's nothing to say.
|
|
401
408
|
|
|
402
|
-
**Section order** (Keep a Changelog): Added, Changed, Deprecated, Removed, Fixed, Security. Include only sections with entries — don't ship empty headers.
|
|
409
|
+
**Section order** (Keep a Changelog): Added, Changed, Deprecated, Removed, Fixed, Security, then Dependencies. Include only sections with entries — don't ship empty headers.
|
|
403
410
|
|
|
404
|
-
**Tag annotations** render as GitHub Release bodies via `--notes-from-tag`.
|
|
411
|
+
**Tag annotations** render as GitHub Release bodies via `--notes-from-tag`. Subject omits the version number (GitHub prepends it). Follow `framework-skills/release-and-publish/SKILL.md` for the tag format.
|
|
405
412
|
|
|
406
413
|
---
|
|
407
414
|
|
|
@@ -425,7 +432,7 @@ import { getMyService } from '@/services/my-domain/my-service.js';
|
|
|
425
432
|
- [ ] JSDoc `@fileoverview` + `@module` on every file
|
|
426
433
|
- [ ] `ctx.log` for logging, `ctx.state` for storage — no `console`, no direct persistence access
|
|
427
434
|
- [ ] Handlers throw on failure — error factories or plain `Error`, no try/catch
|
|
428
|
-
- [ ] `format()` renders all data the LLM needs — different clients forward different surfaces (
|
|
435
|
+
- [ ] `format()` renders all data the LLM needs — different clients forward different surfaces (Claude Code → `structuredContent`, Claude Desktop → `content[]`); both must carry the same data
|
|
429
436
|
- [ ] BrAPI tool: resolves connection via `ServerRegistry.get(ctx, alias ?? DEFAULT_ALIAS)` before touching the client
|
|
430
437
|
- [ ] BrAPI tool: gates the call with `CapabilityRegistry.ensure(...)` — never fires against an endpoint the server didn't advertise
|
|
431
438
|
- [ ] BrAPI tool: raw / domain / output schemas reviewed against real upstream sparsity (most `/germplasm` and `/studies` fields are optional in the wild)
|
|
@@ -434,7 +441,7 @@ import { getMyService } from '@/services/my-domain/my-service.js';
|
|
|
434
441
|
- [ ] Tests include at least one sparse upstream payload (fields omitted) alongside the happy path
|
|
435
442
|
- [ ] Registered in the `tools` array of `createApp()` in `src/index.ts`
|
|
436
443
|
- [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
|
|
437
|
-
- [ ] `.codex-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; `interface.displayName` =
|
|
438
|
-
- [ ] `.codex-plugin/mcp.json` updated — server name key
|
|
439
|
-
- [ ] `.claude-plugin/plugin.json` populated —
|
|
444
|
+
- [ ] `.codex-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; `interface.displayName` = the unscoped repo name; `interface.shortDescription` from `package.json` description
|
|
445
|
+
- [ ] `.codex-plugin/mcp.json` updated — server name key is the unscoped repo name; user-supplied variables are listed in `env_vars`, never set to empty strings in `env`
|
|
446
|
+
- [ ] `.claude-plugin/plugin.json` populated — metadata from `package.json`; inline `mcpServers` entry keyed by the unscoped repo name; user-supplied variables declared under `userConfig` and referenced as `${user_config.<option>}`
|
|
440
447
|
- [ ] `bun run devcheck` passes
|
package/Dockerfile
CHANGED
|
@@ -3,8 +3,16 @@
|
|
|
3
3
|
#
|
|
4
4
|
# This stage installs all dependencies (including dev), builds the TypeScript
|
|
5
5
|
# source code into JavaScript, and prepares the production assets.
|
|
6
|
+
#
|
|
7
|
+
# Pinned to BUILDPLATFORM, not the target platform. `bun run build` emits
|
|
8
|
+
# platform-independent JavaScript and only `dist/` is copied forward, so this
|
|
9
|
+
# stage has no reason to run under emulation — and under QEMU it does not run
|
|
10
|
+
# at all: Bun's JavaScriptCore aborts with a spurious MemoryExhaustion
|
|
11
|
+
# assertion (~21 MB peak), so a cross-arch build of this stage fails outright
|
|
12
|
+
# on an arm64 host. Building natively also removes emulation from the slowest
|
|
13
|
+
# stage of a multi-arch build.
|
|
6
14
|
# ==============================================================================
|
|
7
|
-
FROM oven/bun:1.
|
|
15
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.0 AS build
|
|
8
16
|
|
|
9
17
|
WORKDIR /usr/src/app
|
|
10
18
|
|
|
@@ -33,7 +41,7 @@ RUN bun run build
|
|
|
33
41
|
# application. It uses a slim base image and only includes production
|
|
34
42
|
# dependencies and build artifacts.
|
|
35
43
|
# ==============================================================================
|
|
36
|
-
FROM oven/bun:1.
|
|
44
|
+
FROM oven/bun:1.4.0-slim AS production
|
|
37
45
|
|
|
38
46
|
WORKDIR /usr/src/app
|
|
39
47
|
|
|
@@ -54,8 +62,14 @@ COPY package.json bun.lock ./
|
|
|
54
62
|
|
|
55
63
|
# Install only production dependencies, ignoring any lifecycle scripts (like 'prepare')
|
|
56
64
|
# that are not needed in the final production image.
|
|
65
|
+
# `--omit=peer` drops the framework's optional peer tiers (test runner, service
|
|
66
|
+
# SDKs, parsers) that Bun would otherwise auto-install. Anything this server
|
|
67
|
+
# actually imports belongs in its own `dependencies` — @duckdb/node-api among
|
|
68
|
+
# them — so nothing needed at runtime is lost. The two `bun add` steps below
|
|
69
|
+
# carry the same flag; without it, they re-resolve the graph and pull every
|
|
70
|
+
# optional peer back in.
|
|
57
71
|
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
58
|
-
bun install --production --frozen-lockfile --ignore-scripts
|
|
72
|
+
bun install --production --omit=peer --frozen-lockfile --ignore-scripts
|
|
59
73
|
|
|
60
74
|
# Conditionally install OpenTelemetry optional peer dependencies (Tier 3).
|
|
61
75
|
# These are not bundled by default to keep the base image lean. Enable at build time
|
|
@@ -63,7 +77,7 @@ RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
|
63
77
|
ARG OTEL_ENABLED=true
|
|
64
78
|
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
65
79
|
if [ "$OTEL_ENABLED" = "true" ]; then \
|
|
66
|
-
bun add @hono/otel \
|
|
80
|
+
bun add --omit=dev --omit=peer --ignore-scripts @hono/otel \
|
|
67
81
|
@opentelemetry/instrumentation-http \
|
|
68
82
|
@opentelemetry/exporter-metrics-otlp-http \
|
|
69
83
|
@opentelemetry/exporter-trace-otlp-http \
|
|
@@ -82,7 +96,7 @@ RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
|
82
96
|
ARG CANVAS_ENABLED=true
|
|
83
97
|
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
84
98
|
if [ "$CANVAS_ENABLED" = "true" ]; then \
|
|
85
|
-
bun add @duckdb/node-api; \
|
|
99
|
+
bun add --omit=dev --omit=peer @duckdb/node-api; \
|
|
86
100
|
fi
|
|
87
101
|
|
|
88
102
|
# Copy the compiled application code from the build stage
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
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://modelcontextprotocol.io/) [](./LICENSE) [](https://www.typescriptlang.org/) [](https://bun.sh/) [](./CHANGELOG.md)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
|
|
67
67
|
| Tool | Description |
|
|
68
68
|
|:-----|:------------|
|
|
69
|
-
| `brapi_submit_observations` | Two-phase observation write — `mode: preview` validates; `mode: apply`
|
|
69
|
+
| `brapi_submit_observations` | Two-phase observation write — `mode: preview` validates; `mode: apply` asks the caller to confirm, then fans POST + PUT in parallel. Additive only — no destructive deletion. |
|
|
70
70
|
|
|
71
71
|
### Escape hatches
|
|
72
72
|
|
|
@@ -118,6 +118,8 @@ Within one (tenant, session), dataframes act as a self-cleaning shared notebook:
|
|
|
118
118
|
|
|
119
119
|
**Default (isolated) shape.** Under `MCP_AUTH_MODE=none` + HTTP stateful (the default), each MCP session carves its own connection state and its own canvas. Two researchers connected to the same host don't see each other's `brapi_connect` aliases, exchanged SGN/OAuth tokens, or spilled `df_<uuid>` rows. Stdio always behaves as one session (single-process, no concurrency).
|
|
120
120
|
|
|
121
|
+
**Clients on MCP revision 2026-07-28.** That revision is session-less on every transport — requests carry no `Mcp-Session-Id` — so `ctx.sessionId` is undefined and a client negotiating it falls back to the shared tenant workspace even under `MCP_SESSION_MODE=stateful`. Session isolation applies to 2025-era clients; deployments that need a hard boundary for 2026-era clients should carve tenants with `MCP_AUTH_MODE=jwt`/`oauth`.
|
|
122
|
+
|
|
121
123
|
**Shared-workspace shape.** Set `BRAPI_SESSION_ISOLATION=false` for cross-session collaboration in one tenant — multiple MCP sessions then share connection state and one default canvas, the way pre-0.5.3 deployments behaved. Useful when planning, analysis, and writeup agents run as separate MCP clients but operate as one researcher on shared upstream credentials.
|
|
122
124
|
|
|
123
125
|
**On privileged data.** The `df_<uuid>` name is a capability token within a canvas — not row-level access control. Anyone holding the name within the same (tenant, session) bucket can read its rows. Under default isolation, that bucket is one MCP session. Under `BRAPI_SESSION_ISOLATION=false`, the bucket widens to the whole tenant (all callers under `auth=none`, or one user's sessions under `jwt`/`oauth`). Treat dataframe names like authenticated share links — pass within the bucket, not externally. The 24h TTL caps blast radius; the provenance trail (originating tool, baseUrl, query) supports audit. Belt-and-braces: `brapi_dataframe_describe` requires an explicit `dataframe` name on shared-trust HTTP (no list-all enumeration), and `brapi_dataframe_query` rejects system-catalog reads (`information_schema`, `pg_catalog`, `sqlite_master`, `duckdb_*`) — so a caller without a known `df_<uuid>` name can't fish through either surface.
|
|
@@ -192,7 +194,7 @@ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
|
|
|
192
194
|
|
|
193
195
|
No env vars are required — the six built-in aliases (`bti-cassava`, `bti-sweetpotato`, `bti-breedbase-demo`, `t3-wheat`, `t3-oat`, `t3-barley`) resolve out-of-the-box, and agents can connect to any other BrAPI v2 URL at runtime via `brapi_connect`. **For credentialed servers, prefer env vars over agent input** so passwords / tokens / API keys stay out of the LLM context — see [Per-alias credentials](#per-alias-credentials).
|
|
194
196
|
|
|
195
|
-
**Prerequisites:** [Bun v1.
|
|
197
|
+
**Prerequisites:** [Bun v1.4.0+](https://bun.sh/) or Node.js v24+. [`@duckdb/node-api`](https://www.npmjs.com/package/@duckdb/node-api) is a required dependency — supported on Linux/macOS/Windows × x64 plus Linux/macOS arm64 (no Windows arm64; no Cloudflare Workers).
|
|
196
198
|
|
|
197
199
|
---
|
|
198
200
|
|
|
@@ -223,7 +225,7 @@ Every variable is optional.
|
|
|
223
225
|
| `BRAPI_CANVAS_DROP_ENABLED` | Opt-in for `brapi_dataframe_drop` registration. Off by default; dataframes expire via TTL when left unmanaged. | `false` |
|
|
224
226
|
| `BRAPI_EXPORT_DIR` | Directory for `brapi_dataframe_export` output files. Setting a path is the opt-in (no separate enable flag); unset leaves the tool out of `tools/list`. Stdio-only — the tool stays disabled under HTTP transport regardless of this value. Bridged to the framework's `CANVAS_EXPORT_PATH` automatically. | — |
|
|
225
227
|
| `BRAPI_CANVAS_MAX_ROWS` / `BRAPI_CANVAS_QUERY_TIMEOUT_MS` | Per-query response row cap and wall-clock timeout for `brapi_dataframe_query`. | `10000` / `30000` |
|
|
226
|
-
| `MCP_TRANSPORT_TYPE` / `MCP_HTTP_PORT` / `MCP_SESSION_MODE` | Transport (`stdio` \| `http`), HTTP port, session mode
|
|
228
|
+
| `MCP_TRANSPORT_TYPE` / `MCP_HTTP_PORT` / `MCP_SESSION_MODE` | Transport (`stdio` \| `http`), HTTP port, session mode: `stateful` retains 2025 client sessions for observation-write confirmation; `stateless` cannot perform that confirmation round; `auto` (framework default) resolves to stateful for HTTP. Docker and the env example pin `stateful`. | `stdio` / `3010` / `stateful` |
|
|
227
229
|
| `MCP_AUTH_MODE` / `MCP_LOG_LEVEL` / `STORAGE_PROVIDER_TYPE` / `OTEL_ENABLED` | Auth mode (`none` \| `jwt` \| `oauth`), log level, storage backend, OpenTelemetry. | `none` / `info` / `in-memory` / `false` |
|
|
228
230
|
| `BRAPI_SESSION_ISOLATION` | When `true`, scope ServerRegistry connection state and the CanvasBridge default canvas to `ctx.sessionId` (HTTP stateful/auto). Concurrent callers under `MCP_AUTH_MODE=none` operate in isolated workspaces. Set `false` for the shared-workspace collaboration model. No effect on stdio. | `true` |
|
|
229
231
|
|
|
@@ -326,6 +328,7 @@ Defaults to HTTP transport, stateful session mode (engages the `mcp-session-id`
|
|
|
326
328
|
- **Multi-user with institutional SSO.** `MCP_AUTH_MODE=jwt` (HS256, `MCP_AUTH_SECRET_KEY`) or `oauth` (JWKS, `OAUTH_ISSUER_URL` + `OAUTH_AUDIENCE`). Each user's `tid` claim carves a tenant — the outer scope. `BRAPI_SESSION_ISOLATION=true` (default) then sub-scopes inside each tenant for users running parallel sessions, and JWT/OAuth identity binding gives real session-hijack protection on top.
|
|
327
329
|
- **One researcher, parallel agents.** If multiple agents (planner, analyst, writeup) connect as separate MCP clients but should share one workspace, set `BRAPI_SESSION_ISOLATION=false` and rely on shared trust. This is the shared-workspace shape.
|
|
328
330
|
- **Stdio.** Always one session; isolation is moot. The flag has no effect.
|
|
331
|
+
- **Clients on MCP revision 2026-07-28.** Session-less by protocol, so they land in the shared tenant workspace whatever `BRAPI_SESSION_ISOLATION` says. Only the per-user-credentials shape isolates them.
|
|
329
332
|
|
|
330
333
|
**Belt-and-braces under shared trust.** Even with `BRAPI_SESSION_ISOLATION=false`, `brapi_dataframe_describe` requires an explicit `dataframe` name on HTTP (no list-all enumeration), and `brapi_dataframe_query` rejects system-catalog reads (`information_schema`, `pg_catalog`, `sqlite_master`, `duckdb_*`). The dataframe name is the capability token; possession proves it.
|
|
331
334
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Adopts @cyanheads/mcp-ts-core ^0.12.3 (MCP SDK v2): every HTTP endpoint serves protocol revision 2026-07-28 alongside the 2025 era, undeclared tool arguments are rejected instead of stripped, and brapi_submit_observations' apply-mode confirmation becomes a multi-round-trip input_required result."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.7.11 — 2026-08-22
|
|
8
|
+
|
|
9
|
+
The wire-level changes below arrive with the framework and apply across the whole tool surface; this server changes no contract of its own.
|
|
10
|
+
|
|
11
|
+
## Added
|
|
12
|
+
|
|
13
|
+
- **`brapi_dataframe_query` and `brapi_build_phenotype_matrix` disclose truncation** — `truncated` / `shown` / `cap` / `notice` in `structuredContent` and the `content[]` trailer. `dataframe_query`'s `cap` is the ceiling that actually bound, and the notice names which lever produced it (`preview` or `rowLimit`).
|
|
14
|
+
|
|
15
|
+
## Changed
|
|
16
|
+
|
|
17
|
+
- **Undeclared top-level tool arguments are rejected by name** instead of silently stripped, and every `inputSchema` advertises `additionalProperties: false`. A nested `z.object()` still strips.
|
|
18
|
+
- **Advertised schemas are JSON Schema 2020-12**, and every `outputSchema` declares the error envelope — clients that validate `structuredContent` without checking `isError` stop rejecting error results.
|
|
19
|
+
- **Protocol revision 2026-07-28 is served on every HTTP endpoint**, alongside the 2025 era.
|
|
20
|
+
- **`brapi_submit_observations` `mode: apply` confirmation is a multi-round-trip `input_required` result.** A 2026-07-28 client re-invokes the tool with the answer; a 2025-era client is fulfilled through the SDK's legacy shim on its live session. `force: true` is unchanged.
|
|
21
|
+
- **Per-session isolation does not apply to 2026-07-28 clients** — that revision is session-less, so `ctx.sessionId` is undefined and those callers share the tenant workspace whatever `BRAPI_SESSION_ISOLATION` says. `MCP_SESSION_MODE` stays pinned `stateful`; `.env.example` and the README env row now carry the reason.
|
|
22
|
+
- **`ctx.log` lines also reach the client** as `notifications/message` at their RFC 5424 level — treat log text as client-visible.
|
|
23
|
+
- **Docker** — Bun 1.4.0 in both stages, the build stage pinned to `$BUILDPLATFORM` (Bun's JavaScriptCore aborts under emulated amd64), and the production install omits the framework's optional peer tiers. `bundle` packs via `npx -y @anthropic-ai/mcpb`.
|
|
24
|
+
|
|
25
|
+
## Removed
|
|
26
|
+
|
|
27
|
+
- **`elicit_unavailable`** — apply mode no longer probes for client elicitation support, so the reason is gone from `brapi_submit_observations`' error contract. A declined, cancelled, or malformed answer returns `user_declined`.
|
|
28
|
+
|
|
29
|
+
## Fixed
|
|
30
|
+
|
|
31
|
+
- **Singleton `GET` 404s log at debug**, not as incidents — every caller catches them and reports an absent record. Upstream status now reads from the canonical `error.data.status`.
|
|
32
|
+
|
|
33
|
+
## Dependencies
|
|
34
|
+
|
|
35
|
+
- `@cyanheads/mcp-ts-core` ^0.10.14 → ^0.12.3
|
|
36
|
+
- `@duckdb/node-api` ^1.5.4-r.1 → ^1.5.5-r.4
|
|
37
|
+
- `@biomejs/biome` ^2.5.0 → ^2.5.9
|
|
38
|
+
- `@types/node` ^26.1.1 → ^26.2.0
|
|
39
|
+
- `tsc-alias` ^1.9.1 → ^1.9.2
|
|
40
|
+
- `typescript` ^6.0.3 → ^7.0.2
|
|
41
|
+
- `vitest` ^4.1.10 → ^4.1.11
|
|
42
|
+
- `packageManager` bun@1.3.14 → bun@1.4.0
|
|
43
|
+
- Skills and `scripts/` resynced from the framework.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Adopts @cyanheads/mcp-ts-core ^0.13.0: empty and unsubstituted ${…} env values read as unset across every BRAPI_* path, async-search cancellation and poll deadlines classify as RequestCancelled and Timeout, and the framework skill tree moves out of the plugin-loaded skills/ directory."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.7.12 — 2026-09-13
|
|
8
|
+
|
|
9
|
+
A framework-adoption release; this server changes no tool contract of its own.
|
|
10
|
+
|
|
11
|
+
## Changed
|
|
12
|
+
|
|
13
|
+
- **Plugin manifests declare their user config** — `.claude-plugin/plugin.json` gains a `userConfig` block, and it and `manifest.json` reference every option as `${user_config.<key>}`; `.codex-plugin/mcp.json` forwards `BRAPI_DEFAULT_BASE_URL` through `env_vars` rather than setting it to an empty string, which would replace a value the operator exported (mcp-ts-core 0.13.0).
|
|
14
|
+
- **Tool argument rejections classify as `InvalidParams` (-32602)** instead of `ValidationError`, carrying the same structured error envelope and message text (mcp-ts-core 0.12.7).
|
|
15
|
+
- **HTTP transport** — a trailing slash on `MCP_PUBLIC_URL` no longer doubles in advertised links (mcp-ts-core 0.12.8); the landing page's curl snippet sends a handshake `initialize` accepts, and a cancelled request's SSE stream closes immediately rather than at keep-alive (mcp-ts-core 0.12.9).
|
|
16
|
+
- **`MCP_RESPONSE_VERBOSITY` and `OAUTH_PROXY_*` are no longer recognized** by framework config (mcp-ts-core 0.12.8). Neither is set by this server's Docker image or `.env.example`.
|
|
17
|
+
- **Records logged from `setup()` survive startup** — buffered and replayed once the logger initializes, or drained to stderr when startup fails, instead of dropped (mcp-ts-core 0.12.5).
|
|
18
|
+
- **The framework skill tree moved from `skills/` to `framework-skills/`** — plugin hosts auto-load a root `skills/`, which handed this server's development skills to every installing agent. `.mcpbignore`, the agent protocol, and `docs/tree.md` follow the path; no runtime surface changed (mcp-ts-core 0.13.0).
|
|
19
|
+
- **Bun engines floor raised to `>=1.4.0`** (mcp-ts-core 0.12.9), and `audit:fix` runs `bun audit fix` — the previous script ran a read-only audit and changed nothing (mcp-ts-core 0.13.0).
|
|
20
|
+
|
|
21
|
+
## Fixed
|
|
22
|
+
|
|
23
|
+
- **An unsubstituted `${…}` env value no longer registers a phantom alias or fails URL validation** — `BRAPI_<ALIAS>_*` credentials and the `BRAPI_*` server config both read empty strings and whole-value placeholders as unset through `parseEnvConfig`, so a builtin alias is no longer shadowed by its own unfilled placeholder. A URL containing a literal `${…}` segment is still preserved (mcp-ts-core 0.13.0).
|
|
24
|
+
- **A cancelled async search throws `RequestCancelled` (-32011) and an exhausted poll deadline throws `Timeout`** — they were `InternalError` and `ServiceUnavailable`. Neither issues a further poll, and both the `structuredContent.error` envelope and the `content[]` trailer carry the same message.
|
|
25
|
+
- **An upstream 500 reaches the client's reclassifier again** — no HTTP status maps to `InternalError` now, so a singleton `GET` that an upstream answers 500 for an unknown DbId maps to `NotFound` without retrying, an ordinary 500 retries, and a 501 carries `data.retryable: false` so an unimplemented method is not retried (mcp-ts-core 0.12.4).
|
|
26
|
+
|
|
27
|
+
## Dependencies
|
|
28
|
+
|
|
29
|
+
- `@cyanheads/mcp-ts-core` ^0.12.3 → ^0.13.0
|
|
30
|
+
- `zod` ^4.4.3 → ^4.6.1
|
|
31
|
+
- `@biomejs/biome` ^2.5.9 → ^2.5.13
|
|
32
|
+
- `@types/node` ^26.2.0 → ^26.5.1
|
|
33
|
+
- `ignore` ^7.0.6 → ^7.0.9
|
|
34
|
+
- `tsc-alias` ^1.9.2 → ^1.9.4
|
|
35
|
+
- `vitest` ^4.1.11 → ^5.0.0
|
package/changelog/template.md
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
# to author a new release. Set that file's H1 to `# <version> — YYYY-MM-DD`
|
|
5
5
|
# with a concrete date.
|
|
6
6
|
|
|
7
|
-
# Required. One-line GitHub Release-style headline. 350 character cap
|
|
8
|
-
# Default short and scannable. Don't pad, don't stitch
|
|
9
|
-
#
|
|
10
|
-
#
|
|
7
|
+
# Required. One-line GitHub Release-style headline. 350 character cap — a
|
|
8
|
+
# ceiling, not a target. Default short and scannable. Don't pad, don't stitch
|
|
9
|
+
# unrelated changes with commas/semicolons into an inventory — pick the
|
|
10
|
+
# headline, like a tag's theme line. Quotes required: unquoted YAML treats
|
|
11
|
+
# `: ` inside the value as a key separator and fails GitHub's strict parser.
|
|
11
12
|
summary: ""
|
|
12
13
|
|
|
13
14
|
# Set `true` when consumers must change code to upgrade: API removals,
|
|
@@ -24,9 +25,10 @@ security: false
|
|
|
24
25
|
|
|
25
26
|
# Optional free-form notes for maintenance agents processing this release.
|
|
26
27
|
# Not rendered in CHANGELOG — consumed by agents running `maintenance` on
|
|
27
|
-
# downstream servers.
|
|
28
|
-
#
|
|
29
|
-
#
|
|
28
|
+
# downstream servers. ADOPTION STEPS ONLY — new files to create, fields to
|
|
29
|
+
# populate, one-time migration steps. Never a second rendering of the body:
|
|
30
|
+
# if a body bullet already says it, name the bullet's symbol instead of
|
|
31
|
+
# re-explaining. Omit the field entirely when there's nothing to say.
|
|
30
32
|
# agent-notes: |
|
|
31
33
|
# <instructions for downstream maintenance agents>
|
|
32
34
|
---
|
|
@@ -41,17 +43,54 @@ security: false
|
|
|
41
43
|
each bullet with the symbol or concept name in **bold** so they can skip
|
|
42
44
|
what's irrelevant and zoom in on what's not.
|
|
43
45
|
|
|
44
|
-
Tone: terse, fact-dense, not verbose.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
Tone: terse, fact-dense, not verbose. Bullet shape: **symbol** + what
|
|
47
|
+
changed + at most one consumer-facing caveat. One sentence by default, two
|
|
48
|
+
when the second carries weight — a bullet past ~40 words or three sentences
|
|
49
|
+
is wrong. The depth lives one hop away: the linked issue carries the why,
|
|
50
|
+
the commit diff carries the how. The changelog names what changed and what
|
|
51
|
+
a consumer does about it; a reader who wants mechanism opens the link.
|
|
52
|
+
|
|
53
|
+
Model length on THIS guide, never on the previous entry — entries modeled
|
|
54
|
+
on entries compound.
|
|
55
|
+
|
|
56
|
+
Cut (each has shipped as a wall of text; these are the cruft):
|
|
57
|
+
- History/justification narration — how the bug worked, why the old
|
|
58
|
+
behavior was wrong. One short clause at most; the issue carries the story.
|
|
59
|
+
- Design-rationale defense — "chosen over Y because…", "guarding the
|
|
60
|
+
getter is not enough…". That is the author arguing with a reviewer;
|
|
61
|
+
reviewers read the PR, not the changelog.
|
|
62
|
+
- Defensive unchanged-clauses — "X is unchanged", "byte-identical to
|
|
63
|
+
<prev>". Keep one only where its absence would cause a real misread,
|
|
64
|
+
as a short parenthetical.
|
|
65
|
+
- Edge-case inventories — marker lists, not-flagged lists, escape tables.
|
|
66
|
+
Tests and the issue carry those.
|
|
67
|
+
- Mechanism walkthroughs (JSDoc, CLAUDE.md/AGENTS.md, or the relevant
|
|
68
|
+
skill own those), ceremonial framings ("This release introduces…"),
|
|
69
|
+
backwards-compat paragraphs, file-by-file test enumerations. Prefer
|
|
70
|
+
code/symbol names over English re-explanations.
|
|
71
|
+
|
|
72
|
+
Verified ≠ included: the every-claim-verified-from-the-diff rule bounds
|
|
73
|
+
the TRUTH of what you write, never the AMOUNT.
|
|
74
|
+
|
|
75
|
+
Example — same fact, right size:
|
|
76
|
+
|
|
77
|
+
TOO LONG: **`fetchWithTimeout`'s `timeoutMs` bounds the whole exchange**
|
|
78
|
+
(#341). `fetch` resolves once headers arrive and the deadline was
|
|
79
|
+
cleared as the helper returned, so a peer that answered promptly and
|
|
80
|
+
then stalled the stream held the request open indefinitely. A 2xx
|
|
81
|
+
carrying a body now comes back as a passthrough wrapper that disarms
|
|
82
|
+
the deadline when the body closes, errors, or is cancelled; …
|
|
83
|
+
[+90 more words of mechanism and edge cases]
|
|
84
|
+
|
|
85
|
+
RIGHT: **`fetchWithTimeout`'s `timeoutMs` now bounds the whole
|
|
86
|
+
exchange, not just the headers** (#341). A stalled body aborts with
|
|
87
|
+
the same `Timeout` error; the returned `Response` is a wrapper, so
|
|
88
|
+
identity assertions (`toBe(response)`) no longer hold.
|
|
52
89
|
|
|
53
90
|
Narrative intro: skip by default. Add one short sentence only when the
|
|
54
|
-
release theme genuinely needs framing the bullets can't carry.
|
|
91
|
+
release theme genuinely needs framing the bullets can't carry. When many
|
|
92
|
+
bullets share one upgrade consequence, state it ONCE — intro line or
|
|
93
|
+
agent-notes — never per bullet.
|
|
55
94
|
|
|
56
95
|
Sections: Keep a Changelog order — Added, Changed, Deprecated, Removed,
|
|
57
96
|
Fixed, Security. Include only sections with entries; delete the rest
|
|
@@ -78,30 +117,13 @@ security: false
|
|
|
78
117
|
in that unrelated item's metadata.
|
|
79
118
|
|
|
80
119
|
TAG ANNOTATIONS — the annotated tag body renders as the GitHub Release body
|
|
81
|
-
via `gh release create --notes-from-tag`.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
Dependency bumps: ← section header
|
|
89
|
-
← blank line
|
|
90
|
-
- `@cyanheads/mcp-ts-core` ^0.9.1 → ^0.9.6 ← bullet
|
|
91
|
-
← blank line
|
|
92
|
-
Changed: ← only sections with entries
|
|
93
|
-
← blank line
|
|
94
|
-
- `format()` output includes `query` in text mode
|
|
95
|
-
← blank line
|
|
96
|
-
Added:
|
|
97
|
-
← blank line
|
|
98
|
-
- `manifest.json` scaffolded for MCPB bundle support
|
|
99
|
-
- Install badges (Claude Desktop, Cursor, VS Code)
|
|
100
|
-
← blank line
|
|
101
|
-
<N> tests pass; `bun run devcheck` clean. ← footer
|
|
102
|
-
|
|
103
|
-
Never a flat comma-separated string. Always structured markdown with
|
|
104
|
-
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"): the entry's `summary:` as the
|
|
123
|
+
theme line without the version, flat headline bullets — no Keep-a-Changelog
|
|
124
|
+
section headers, no gates line — at most one deps line, issue backlinks,
|
|
125
|
+
and the changelog link last. In release-PR mode the `git-wrapup` skill
|
|
126
|
+
authors that digest as the PR body's `## Changes` and the tag copies it.
|
|
105
127
|
-->
|
|
106
128
|
|
|
107
129
|
## Added
|
|
@@ -26,7 +26,7 @@ export interface AliasCredentials {
|
|
|
26
26
|
}
|
|
27
27
|
/** Compute the env-var prefix for an alias. `my-server` → `BRAPI_MY_SERVER_`. */
|
|
28
28
|
export declare function aliasEnvPrefix(alias: string): string;
|
|
29
|
-
/** Read
|
|
29
|
+
/** Read alias env vars; empty strings and whole-value host placeholders are unset. */
|
|
30
30
|
export declare function readAliasCredentials(alias: string, env?: NodeJS.ProcessEnv): AliasCredentials;
|
|
31
31
|
/**
|
|
32
32
|
* Pick a `ConnectAuth` from the credential bundle. Returns `undefined` when no
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alias-credentials.d.ts","sourceRoot":"","sources":["../../src/config/alias-credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"alias-credentials.d.ts","sourceRoot":"","sources":["../../src/config/alias-credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAEjF;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA6BD,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,sFAAsF;AACtF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,gBAAgB,CAalB;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,MAAM,GACZ,WAAW,GAAG,SAAS,CAwCzB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CAAE,EACvE,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,oBAAoB,CAwBtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,GAAG,SAAS,CAAC;CAC3B;AAID;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,eAAe,EAAE,CA4CjG;AAaD;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,MAAM,CAmB9E"}
|