---
summary: "Surface complete — adds brapi_submit_observations write tool, six brapi:// resources, two workflow prompts (eda_study, meta_analysis), POST/PUT methods on BrapiClient, and full test backfill (101 → 191 tests)."
breaking: false
---

# 0.3.0 — 2026-04-25

Closes the MVP design surface from `docs/design.md`. The read side (18 tools, 6 services) shipped in 0.1.x / 0.2.x; this release adds the only write tool, the additive resource layer for URI-addressable clients, two workflow prompts that package the canonical multi-step BrAPI flows, and backfills tests for every untested handler.

## Added

- **`brapi_submit_observations` tool** — additive write surface for observation rows. Two-phase: `mode: preview` (default) validates rows against the study's `observationvariables` and reports a `routing` breakdown (POST for new, PUT for rows carrying `observationDbId`); `mode: apply` elicits user confirmation via `ctx.elicit`, fans the rows out to POST + PUT in parallel, then re-probes `studies/{id}/observations?pageSize=0` to return the post-write total. Apply requires `ctx.elicit` support OR an explicit `force: true` flag (rejected with `Forbidden` otherwise). Per-row warnings flag unknown variables, empty values, and missing FK fields. Auth scope: `brapi:write:observations`.
- **Six MCP resources** under the `brapi://` scheme — additive layer for URI-addressable clients. Each mirrors an existing tool's payload through the default connection:
  - `brapi://server/info` — orientation envelope (mirror of `brapi_server_info`).
  - `brapi://calls` — raw capability profile from `CapabilityRegistry`.
  - `brapi://study/{studyDbId}` — single study with FKs resolved (mirror of `brapi_get_study`).
  - `brapi://germplasm/{germplasmDbId}` — single germplasm with attributes + parents (mirror of `brapi_get_germplasm`).
  - `brapi://dataset/{datasetId}` — dataset metadata + provenance (rows via `brapi_manage_dataset`).
  - `brapi://filters/{endpoint}` — static filter catalog (mirror of `brapi_describe_filters`).
- **Two MCP prompts** — multi-step workflow templates that package the canonical BrAPI flows into ready-to-fire user messages:
  - `brapi_eda_study(studyDbId, alias?)` — exploratory-data-analysis playbook for one study (orient → variables → coverage → missing → outliers → pedigree → report).
  - `brapi_meta_analysis(germplasmDbIds, traitName, alias?)` — cross-study trait meta-analysis (resolve trait → discover studies → harmonize → per-germplasm × per-study summary → across-study summary → pedigree side-quest → report).
- **`BrapiClient.post()` / `BrapiClient.put()`** — generic JSON request helpers shared by the new write tool. Same retry policy, HTTP error reclassification, and SSRF guard as `get()`.

## Changed

- **`brapi_raw_get` cross-origin guard** — `rejectCrossOrigin()` now runs against the raw `input.path` before `normalizePath` adds the leading `/`. Previous order let `https://evil/leak` slip past the regex (the leading slash blocked the `/^https?:\/\//` match) and instead concatenate into the registered baseUrl path, where the URL constructor escaped it benignly. Defense-in-depth restored.
- **README** — version badge bumped, surface counters updated to `19 Tools · 6 Resources · 2 Prompts`, new sections for resources and prompts, write-tool entry in the tools table, project structure expanded with `mcp-server/resources/` and `mcp-server/prompts/`.

## Fixed

- **State key validation** — switched every service prefix from colon-separated to slash-separated (`brapi:conn:` → `brapi/conn/`, `brapi:capability:` → `brapi/capability/`, `brapi:ds:meta:` / `brapi:ds:rows:` → `brapi/ds/meta/` / `brapi/ds/rows/`, `brapi:ref:…` → `brapi/ref/…`). `@cyanheads/mcp-ts-core` 0.7.x storage rejects keys outside `/^[a-zA-Z0-9_.\-/]+$/`, which broke every state-using tool at runtime in HTTP mode (`ServerRegistry.register`, `CapabilityRegistry`, `DatasetStore`, `ReferenceDataCache`). Unit tests passed because `createMockContext` skips key validation; field-testing the HTTP transport surfaced the regression. Also updated the matching state-key assertions in `tests/tools/brapi-connect.tool.test.ts`.

## Verified

- `bun run devcheck` — all 11 sub-checks pass (lint, format, typecheck, MCP definitions, framework antipatterns, docs/skills/changelog sync, secrets, deps audit, outdated).
- `bun run test` — 191/191 pass across 32 test files (+90 new tests covering the 12 previously untested tools, 6 resources, and 2 prompts).
- `bun run lint:mcp` — `All definitions valid.` (19 tools, 6 resources, 2 prompts).
