---
summary: "Cassavabase null-tolerance pass — schemas accept upstream nulls without dropping rows, walk-pedigree no longer false-flags inverse-edge backtracks as cycles, get-image flags broken upstream URLs. Plus npm scope rename to @cyanheads/brapi-mcp-server."
breaking: false
---

# 0.3.5 — 2026-04-30

A robustness pass driven by exercising the read tools against Cassavabase, which returns explicit `null` on most optional fields rather than omitting them. The headline change is that every read-tool schema now uses `nullish()` for nullable fields so sparse upstream payloads validate cleanly. Two real bugs surfaced along the way — `brapi_walk_pedigree` was double-counting inverse-edge backtracks as cycles in `direction='both'`, and `brapi_get_image` had no signal when the `imageURL` fallback returned an HTML error page instead of bytes.

## Added

- **`brapi_get_image` per-image suspect-content warnings** — when the `imageURL` fallback returns content with a non-`image/*` MIME type (typically an HTML error page from a broken CDN URL), the tool now emits a per-image `warnings[]` entry advising that the bytes were loaded but may not render. The payload is still returned so the caller can inspect it; the warning just flags that something is wrong upstream.
- **`brapi_connect` configured-alias hint in tool description** — the connect tool now scans `BRAPI_<ALIAS>_BASE_URL` env vars at module load and appends a sentence listing the pre-configured aliases to its description, so agents see the alias inventory on `tools/list` without anyone enumerating them in the prompt. The phrasing emphasizes that any other BrAPI v2 server is still reachable by passing `baseUrl` directly. Restart the server to refresh.
- **`brapi_manage_dataset` truncation column** — list-mode table now includes a `truncated` column (`yes (cap=N)` or `no`); summary mode adds a `truncated: true (cap=N rows)` line when applicable. Surfaces the producer-side cap state through both `structuredContent` and `content[]`.

## Changed

- **Optional schema fields use `nullish()` instead of `optional()`** — `brapi_find_germplasm`, `brapi_get_germplasm`, `brapi_find_studies`, `brapi_get_study`, `brapi_find_locations`, `brapi_find_variables` now accept upstream `null` on every optional field. Cassavabase serializes `subtaxa: null`, `studyCode: null`, nested `trait.traitClass: null`, etc. instead of omitting the keys; `nullish()` is `optional + nullable` so both shapes validate. Format functions correctly skip null-valued fields rather than rendering `lat=null` or `active=null`.
- **Package renamed to `@cyanheads/brapi-mcp-server`** — scoped under the `@cyanheads` npm org. README install instructions, package.json, and server.json identifiers all updated. Existing tag history retained.
- **Framework bump to `@cyanheads/mcp-ts-core ^0.8.7`** — picks up the latest framework patch.

## Fixed

- **`brapi_walk_pedigree` no longer double-counts inverse-edge backtracks as cycles in `direction='both'`** — when walking ancestors and descendants concurrently, BFS naturally re-encounters nodes via the inverse relationship as the two expansion fronts meet (e.g. expanding `g-3`'s parents then re-finding `g-3` via the parent's progeny lookup). Previous logic counted these structural symmetries as cycles, inflating `cycleCount` for every multi-root walk. The walk now checks for the inverse edge before incrementing and only counts genuine re-discoveries via a non-symmetric path.
