Reported issues for brapi-mcp-server
Pod holds 24 of 46 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.
Back to brapi-mcp-server.
Most discussed
feat(loadLimit): decouple in-context cap from upstream pageSize
loadLimit does three jobs and the entanglement leaks into agent behavior:
- In-context row cap returned to the LLM
- Spillover trigger threshold (
maybeSpillreturns first-page only whentotalCount ≤ loadLimit) - Upstream
pageSizefor both first call and every spillover page (spillToCanvasinsrc/mcp-server/tools/shared/find-helpers.ts)
Footgun
An agent that lowers loadLimit to "see fewer rows inline" silently shrinks dataframe spillover capacity proportionally — `loadLimit
Read the thread · 2026-05-05 · closed · 5 comments
Add brapi_germplasm_performance tool — aggregate observations across studies
Use case
"How does line X-401 perform across the germplasm pool's history?" is the breeder's primary question. Today this requires N find_observations calls + manual aggregation, and is easy to get wrong on dialects that drop the germplasm filter (returning the global aggregate instead of the per-germplasm one).
Dependency
Blocked by #8. This issue depends on what brapi_build_phenotype_matrix outputs. The implementation path and final shape are confirmed after #8 lands.
T
Read the thread · 2026-05-01 · closed · 5 comments
Dialect detection: URL pattern matching + verified-flag per mapping
Motivation
Today detectDialectFromName only matches on serverInfo.serverName (and organizationName). Two real-world failure modes:
- Generic server names. Some SGN-family deployments report
serverName: 'BrAPI'or omit it entirely. We catch "Boyce Thompson Institute" viaorganizationNamebut miss anything else hosted on*.cassavabase.org,*.sweetpotatobase.org,*.yambase.org, etc. - Mapping confidence is invisible.
PLURAL_TO_SINGULARincassavabase-dialect.tsmi
Read the thread · 2026-05-01 · closed · 5 comments
bug(find_observations): Sweetpotatobase study spillover can run past client timeout
Server version
0.7.2
mcp-ts-core version
^0.9.21
Runtime
Bun
Runtime version
Bun ≥ 1.3.0
Transport
stdio / direct handler validation
Description
brapi_find_observations({ studies: ["1131"] }) against Sweetpotatobase is not an all_filters_dropped dialect failure on the current tree. The Breedbase dialect rewrites studyDbIds to studyDbId, and the upstream GET route returns the expected 1,221 observations.
The rough edge is spillover latency: at the forme
Read the thread · 2026-05-02 · closed · 4 comments
feat(walk_pedigree): spill large pedigree results to canvas dataframe(s)
brapi_walk_pedigree is the only walking tool in this server that does not follow the find_* spillover pattern. When a pedigree walk returns thousands of nodes (cassavabase descendant walks easily hit this), the full nodes[] and edges[] arrays are returned inline regardless of size. Two related problems:
- The
MAX_NODES = 1000cap is loose. The check (src/mcp-server/tools/definitions/brapi-walk-pedigree.tool.ts:198) runs at the start of each depth iteration, but a single depth c
Read the thread · 2026-05-02 · closed · 4 comments
bug(get_*): upstream 5xx on missing DbId surfaces as transport error + 4-retry storm; not_found contract never fires
Server version
0.5.3
mcp-ts-core version
0.8.17
Runtime
Bun
Runtime version
Bun 1.3.11
Transport
HTTP (Streamable HTTP)
OS
macOS 25.1.0
Description
Singleton GET tools — brapi_get_study, brapi_get_germplasm, plus the brapi://study/{id} and brapi://germplasm/{id} resources — surface upstream-server bugs as opaque transport errors when the upstream returns 5xx for a missing DbId. On Breedbase (one of the built-in aliases), /studies/{nonexistent} r
Read the thread · 2026-05-06 · closed · 3 comments
bug(error-contracts): data.recovery.hint missing on the wire for several declared-contract throws
Server version
0.5.3
mcp-ts-core version
0.8.17
Runtime
Bun
Runtime version
Bun 1.3.11
Transport
HTTP (Streamable HTTP)
OS
macOS 25.1.0
Description
Several tools declare typed error contracts with a recovery field but throw via ctx.fail(reason, ...) without spreading ctx.recoveryFor(reason) into the data payload. The framework requires the spread to opt the contract recovery onto the wire (see node_modules/@cyanheads/mcp-ts-core/CLAUDE.md "Err
Read the thread · 2026-05-06 · closed · 3 comments
Dialect: add normalizeRow hook for null-vs-omitted shape coercion
Motivation
CassavaBase returns null for many optional fields where the BrAPI v2.1 spec says the field should be omitted entirely. Today every BrAPI tool's row schema absorbs this with .nullish() — repeated across dozens of fields and growing every time we discover a new sparse upstream shape.
That's a structural smell:
- The same defensive change has to be applied in every schema.
- Renderer code has to repeat
if (g.value)guards row-by-row to avoid'lat=null'style output. - Future
Read the thread · 2026-05-01 · closed · 3 comments
Most recent
bug(builtin-aliases): t3-wheat / t3-oat / t3-barley now answer 401 on /serverinfo
Server version
0.7.10 (reproduces on the 0.7.11 tree)
mcp-ts-core version
0.12.3
Runtime
Bun
Runtime version
Bun 1.4.0
Transport
stdio
Description
The three built-in T3 aliases in src/config/builtin-aliases.ts (t3-wheat, t3-oat, t3-barley) are documented as no-auth public endpoints in .env.example and the README. All three hosts now answer HTTP 401 on GET /brapi/v2/serverinfo anonymously:
curl -s -o /dev/null -w '%{http_code}' https://wheat.tri
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/52) · 2026-08-22 · open · 0 comments
### bug(brapi-client): singleton HTTP 500 bypasses the Breedbase not-found reclassification
### Server version
0.7.10 (reproduces on the 0.7.11 tree)
### mcp-ts-core version
0.12.3
### Runtime
Bun
### Runtime version
Bun 1.4.0
### Transport
http
### Description
`reclassifyHttpError` in `src/services/brapi-client/brapi-client.ts` documents that a 5xx on a singleton `/{noun}/{id}` fetch is treated as `NotFound`, because Breedbase answers HTTP 500 for an unknown DbId. The guard at the top of the function returns early unless `err.code === JsonRpcErrorCode.ServiceUnavailable`, b
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/51) · 2026-08-22 · open · 0 comments
### feat(dataframe): name the dataframe tools in responses that stage a dataframe
Thirteen tools stage rows as a canvas dataframe and hand back a `df_XXXXX_XXXXX` handle, but nothing in the response payload tells the agent to reach that data with `brapi_dataframe_describe` and `brapi_dataframe_query`. The handle is an opaque generated name; an agent that receives one without a pointer either reports the truncation and stops, or re-runs the producing tool with narrower filters — re-fetching rows that are already staged one SQL query away.
The gap is in the **runtime response*
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/50) · 2026-08-13 · open · 0 comments
### feat(isolation): fail closed on credentialed connection state when no session key exists
Under `BRAPI_SESSION_ISOLATION=true` (the default), both the connection registry and the canvas bridge key their state on `ctx.sessionId`, and when it is absent both fall back silently to the shared per-tenant namespace (`scopePrefix()` in `src/services/server-registry/server-registry.ts`, `DEFAULT_CANVAS_KEY` in `src/services/canvas-bridge/canvas-bridge.ts`). For the connection registry that shared namespace holds `RegisteredServer` entries whose `resolvedAuth` is the live upstream credential h
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/49) · 2026-07-27 · open · 0 comments
### feat(observations): parallelize per-study pulls in germplasm_performance and build_phenotype_matrix
`brapi_germplasm_performance` and `brapi_build_phenotype_matrix` both collect observations study-by-study through a sequential `for` loop around the shared `pullStudyObservations` helper — one full HTTP round trip (plus the `/observationunits` fallback) per study, awaited before starting the next. Neither tool bounds concurrency. `BRAPI_MAX_CONCURRENT_REQUESTS` (default 4, documented in README/.env.example as a "per-connection concurrency cap") is declared in `server-config.ts` but isn't read by
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/48) · 2026-07-16 · closed · 1 comment
### bug(dataframe_describe): renders every column name uncapped
### Server version
0.7.6
### mcp-ts-core version
^0.10.14
### Runtime
Bun
### Runtime version
Bun 1.3.14
### Transport
HTTP JSON-RPC
### Description
`brapi_dataframe_describe` renders one line per column with no size bound. For a dataframe with a normal shape (a `find_*` spillover, ~18 columns) that is correct and cheap. For a genotype matrix, one column is registered per variant, so a wide matrix makes the tool emit a column name per variant into `content[]`.
Related: #46
### Steps
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/47) · 2026-07-16 · closed · 1 comment
### feat(export_genotype_matrix): bound columnCount, not just total calls
`brapi_export_genotype_matrix` bounds the total genotype calls it pulls (`maxCalls`, clamped to `BRAPI_GENOTYPE_CALLS_MAX_PULL`), but nothing bounds how those calls distribute across the germplasm × variant grid. A schema-legal skew — one germplasm × `maxCalls` variants — makes `columnCount` equal the entire call budget, and every per-variant output scales with it.
Related: #42, #45
## Proposal
Bound `columnCount` directly, mirroring the `maxCalls` clamp #45 established: a deployment-level ce
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/46) · 2026-07-16 · closed · 1 comment
### bug(export_genotype_matrix): maxCalls is unbounded and bypasses the deployment call ceiling
### Server version
0.7.6
### mcp-ts-core version
^0.10.9
### Runtime
Bun
### Runtime version
Bun 1.3.14
### Transport
HTTP
### Description
`brapi_export_genotype_matrix`'s `maxCalls` input carries no `.max()` bound and is never clamped against the deployment's `genotypeCallsMaxPull` config ceiling. A caller can pass an arbitrarily large `maxCalls` and the tool honors it, so the documented "hard ceiling" is advisory only.
`brapi_find_genotype_calls` does not have this gap — it uses th
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/45) · 2026-07-16 · closed · 1 comment
### bug(docker): HEALTHCHECK uses curl, which the bun slim base image does not ship
### Server version
0.7.6
### mcp-ts-core version
^0.10.9
### Runtime
Bun
### Runtime version
Bun 1.3.14
### Transport
HTTP
### Description
The `Dockerfile` `HEALTHCHECK` probes `/healthz` with `curl -f`, but the `oven/bun:*-slim` production base ships neither `curl` nor `wget`. The probe can never succeed, so a container run from the published image reports `unhealthy` for its entire lifetime even while the server is serving correctly.
Any orchestrator that gates on container health
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/44) · 2026-07-16 · closed · 1 comment
### feat(germplasm_performance): add a retrieval path when study discovery hits the cap
### Server version
0.7.6
### mcp-ts-core version
^0.10.14
### Runtime
Bun
### Description
`brapi_germplasm_performance` caps automatic study discovery at `STUDY_DISCOVERY_CAP = 200`. When that cap is hit, the response warns that aggregates may be incomplete and suggests narrowing with a study-specific phenotype matrix, but the tool does not expose a continuation cursor, an offset, or a dataframe/list handle that lets an agent retrieve the omitted study slice.
That leaves a truncation pat
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/43) · 2026-07-05 · closed · 1 comment
### bug(export_genotype_matrix): content[] previews VCF/PLINK text and column legend
### Server version
0.7.6
### mcp-ts-core version
^0.10.9
### Runtime
Bun
### Runtime version
Bun 1.3.14
### Transport
HTTP JSON-RPC / direct formatter check
### Description
`brapi_export_genotype_matrix` puts generated VCF/PLINK serializations in `structuredContent`, but `format()` emits only a preview and tells clients to read `structuredContent.<field>`. Content-only clients lose generated rows.
The same formatter caps the variant column legend at 20 remappings.
### Steps to repro
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/42) · 2026-07-05 · closed · 1 comment
### bug(format): shared renderers omit full distributions and large passthrough fields from content[]
### Server version
0.7.6
### mcp-ts-core version
^0.10.9
### Runtime
Bun
### Runtime version
Bun 1.3.14
### Transport
HTTP JSON-RPC
### Description
Several shared format helpers render summaries in `content[]` for fields that are complete in `structuredContent`. Content-only clients cannot recover those values because the text points to `structuredContent`, which those clients do not read.
This breaks parity between the two result surfaces. Both surfaces are used by different AI clie
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/41) · 2026-07-05 · closed · 1 comment
### bug(get_study): variableCount/observationCount report server-wide totals, not study-scoped
### Server version
0.7.4
### mcp-ts-core version
0.10.6 (`^0.10.6`)
### Runtime
Bun
### Transport
HTTP (Streamable HTTP)
### Description
`brapi_get_study` returns companion counts (`variableCount`, `observationCount`) that are **server-wide totals, not scoped to the study**. The enrichment scopes them with a `studyDbIds` filter, which the `brapi-test` dialect drops upstream (the response even carries the `dropped filter 'studyDbIds'` warning), so the counts silently collapse to the glob
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/40) · 2026-06-18 · closed · 1 comment
### bug(dataframe_query): every query fails on internal probe — "Ambiguous reference to column name table_name"
### Server version
0.7.4
### mcp-ts-core version
0.10.6 (`^0.10.6`)
### Runtime
Bun
### Transport
HTTP (Streamable HTTP)
### Description
Every `brapi_dataframe_query` call fails *before* the user SQL runs — including `SELECT 1`. The handler issues an internal pre-flight probe against the DuckDB catalog whose `WHERE` clause references an unqualified `table_name`, which DuckDB rejects as ambiguous. Named `brapi_dataframe_describe` hits the same wall (the no-arg list mode returns the inten
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/39) · 2026-06-18 · closed · 1 comment
### bug(submit_observations): apply mode hard-blocked — ctx.elicit never defined at runtime (upstream mcp-ts-core#211)
`brapi_submit_observations` apply mode requires an elicitation confirm and correctly fails closed when the client lacks it: `elicit_unavailable` (Forbidden) unless `force=true`. Upstream cyanheads/mcp-ts-core#211 means `ctx.elicit` is `undefined` on every production request regardless of client capability — the framework's capability detection sniffs methods the SDK never attaches.
Net effect today: apply mode returns `elicit_unavailable` on **all** clients, including elicit-capable ones. The r
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/38) · 2026-06-10 · closed · 1 comment
### bug(find_variants): dataframe spillover throws on reserved-word column "end"
`brapi_find_variants` throws `Canvas column name "end" is a reserved SQL keyword. Choose another name.` whenever its result spills to a canvas dataframe. BrAPI `/variants` records carry an `end` field (variant end position), and the generic `find_*` spillover path registers rows under their raw upstream keys as DuckDB column names — `end` is a reserved word, so `assertValidIdentifier` rejects it at `registerTable` and the whole call fails (no dataframe is produced).
### Reproduce
Against the B
[Read the thread](https://github.com/cyanheads/brapi-mcp-server/issues/37) · 2026-06-02 · closed · 2 comments
The remaining reports are on [the project's issue tracker](https://github.com/cyanheads/brapi-mcp-server/issues).