@cyanheads/brapi-mcp-server 0.3.5
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 +391 -0
- package/Dockerfile +99 -0
- package/LICENSE +201 -0
- package/README.md +590 -0
- package/changelog/0.1.x/0.1.0.md +19 -0
- package/changelog/0.1.x/0.1.1.md +27 -0
- package/changelog/0.1.x/0.1.2.md +22 -0
- package/changelog/0.2.x/0.2.0.md +35 -0
- package/changelog/0.2.x/0.2.1.md +36 -0
- package/changelog/0.3.x/0.3.0.md +38 -0
- package/changelog/0.3.x/0.3.1.md +40 -0
- package/changelog/0.3.x/0.3.2.md +29 -0
- package/changelog/0.3.x/0.3.3.md +19 -0
- package/changelog/0.3.x/0.3.4.md +33 -0
- package/changelog/0.3.x/0.3.5.md +24 -0
- package/changelog/template.md +51 -0
- package/dist/config/alias-credentials.d.ts +82 -0
- package/dist/config/alias-credentials.d.ts.map +1 -0
- package/dist/config/alias-credentials.js +159 -0
- package/dist/config/alias-credentials.js.map +1 -0
- package/dist/config/server-config.d.ts +39 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +128 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +85 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/prompts/definitions/brapi-eda-study.prompt.d.ts +14 -0
- package/dist/mcp-server/prompts/definitions/brapi-eda-study.prompt.d.ts.map +1 -0
- package/dist/mcp-server/prompts/definitions/brapi-eda-study.prompt.js +75 -0
- package/dist/mcp-server/prompts/definitions/brapi-eda-study.prompt.js.map +1 -0
- package/dist/mcp-server/prompts/definitions/brapi-meta-analysis.prompt.d.ts +16 -0
- package/dist/mcp-server/prompts/definitions/brapi-meta-analysis.prompt.d.ts.map +1 -0
- package/dist/mcp-server/prompts/definitions/brapi-meta-analysis.prompt.js +109 -0
- package/dist/mcp-server/prompts/definitions/brapi-meta-analysis.prompt.js.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-calls.resource.d.ts +11 -0
- package/dist/mcp-server/resources/definitions/brapi-calls.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-calls.resource.js +46 -0
- package/dist/mcp-server/resources/definitions/brapi-calls.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-dataset.resource.d.ts +13 -0
- package/dist/mcp-server/resources/definitions/brapi-dataset.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-dataset.resource.js +26 -0
- package/dist/mcp-server/resources/definitions/brapi-dataset.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-filters.resource.d.ts +19 -0
- package/dist/mcp-server/resources/definitions/brapi-filters.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-filters.resource.js +45 -0
- package/dist/mcp-server/resources/definitions/brapi-filters.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-germplasm.resource.d.ts +18 -0
- package/dist/mcp-server/resources/definitions/brapi-germplasm.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-germplasm.resource.js +34 -0
- package/dist/mcp-server/resources/definitions/brapi-germplasm.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-server-info.resource.d.ts +11 -0
- package/dist/mcp-server/resources/definitions/brapi-server-info.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-server-info.resource.js +28 -0
- package/dist/mcp-server/resources/definitions/brapi-server-info.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-study.resource.d.ts +18 -0
- package/dist/mcp-server/resources/definitions/brapi-study.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/brapi-study.resource.js +34 -0
- package/dist/mcp-server/resources/definitions/brapi-study.resource.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-connect.tool.d.ts +82 -0
- package/dist/mcp-server/tools/definitions/brapi-connect.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-connect.tool.js +106 -0
- package/dist/mcp-server/tools/definitions/brapi-connect.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-describe-filters.tool.d.ts +41 -0
- package/dist/mcp-server/tools/definitions/brapi-describe-filters.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-describe-filters.tool.js +88 -0
- package/dist/mcp-server/tools/definitions/brapi-describe-filters.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.d.ts +74 -0
- package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.js +386 -0
- package/dist/mcp-server/tools/definitions/brapi-find-genotype-calls.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-germplasm.tool.d.ts +72 -0
- package/dist/mcp-server/tools/definitions/brapi-find-germplasm.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-germplasm.tool.js +290 -0
- package/dist/mcp-server/tools/definitions/brapi-find-germplasm.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-images.tool.d.ts +65 -0
- package/dist/mcp-server/tools/definitions/brapi-find-images.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-images.tool.js +243 -0
- package/dist/mcp-server/tools/definitions/brapi-find-images.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-locations.tool.d.ts +63 -0
- package/dist/mcp-server/tools/definitions/brapi-find-locations.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-locations.tool.js +278 -0
- package/dist/mcp-server/tools/definitions/brapi-find-locations.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-observations.tool.d.ts +74 -0
- package/dist/mcp-server/tools/definitions/brapi-find-observations.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-observations.tool.js +288 -0
- package/dist/mcp-server/tools/definitions/brapi-find-observations.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-studies.tool.d.ts +69 -0
- package/dist/mcp-server/tools/definitions/brapi-find-studies.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-studies.tool.js +243 -0
- package/dist/mcp-server/tools/definitions/brapi-find-studies.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-variables.tool.d.ts +86 -0
- package/dist/mcp-server/tools/definitions/brapi-find-variables.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-variables.tool.js +337 -0
- package/dist/mcp-server/tools/definitions/brapi-find-variables.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-variants.tool.d.ts +59 -0
- package/dist/mcp-server/tools/definitions/brapi-find-variants.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-find-variants.tool.js +248 -0
- package/dist/mcp-server/tools/definitions/brapi-find-variants.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-get-germplasm.tool.d.ts +59 -0
- package/dist/mcp-server/tools/definitions/brapi-get-germplasm.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-get-germplasm.tool.js +306 -0
- package/dist/mcp-server/tools/definitions/brapi-get-germplasm.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-get-image.tool.d.ts +57 -0
- package/dist/mcp-server/tools/definitions/brapi-get-image.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-get-image.tool.js +291 -0
- package/dist/mcp-server/tools/definitions/brapi-get-image.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-get-study.tool.d.ts +75 -0
- package/dist/mcp-server/tools/definitions/brapi-get-study.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-get-study.tool.js +323 -0
- package/dist/mcp-server/tools/definitions/brapi-get-study.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-manage-dataset.tool.d.ts +87 -0
- package/dist/mcp-server/tools/definitions/brapi-manage-dataset.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-manage-dataset.tool.js +296 -0
- package/dist/mcp-server/tools/definitions/brapi-manage-dataset.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-raw-get.tool.d.ts +35 -0
- package/dist/mcp-server/tools/definitions/brapi-raw-get.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-raw-get.tool.js +148 -0
- package/dist/mcp-server/tools/definitions/brapi-raw-get.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-raw-search.tool.d.ts +33 -0
- package/dist/mcp-server/tools/definitions/brapi-raw-search.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-raw-search.tool.js +126 -0
- package/dist/mcp-server/tools/definitions/brapi-raw-search.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-server-info.tool.d.ts +51 -0
- package/dist/mcp-server/tools/definitions/brapi-server-info.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-server-info.tool.js +41 -0
- package/dist/mcp-server/tools/definitions/brapi-server-info.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-submit-observations.tool.d.ts +117 -0
- package/dist/mcp-server/tools/definitions/brapi-submit-observations.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-submit-observations.tool.js +574 -0
- package/dist/mcp-server/tools/definitions/brapi-submit-observations.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-walk-pedigree.tool.d.ts +52 -0
- package/dist/mcp-server/tools/definitions/brapi-walk-pedigree.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/brapi-walk-pedigree.tool.js +420 -0
- package/dist/mcp-server/tools/definitions/brapi-walk-pedigree.tool.js.map +1 -0
- package/dist/mcp-server/tools/shared/connect-auth-schema.d.ts +29 -0
- package/dist/mcp-server/tools/shared/connect-auth-schema.d.ts.map +1 -0
- package/dist/mcp-server/tools/shared/connect-auth-schema.js +55 -0
- package/dist/mcp-server/tools/shared/connect-auth-schema.js.map +1 -0
- package/dist/mcp-server/tools/shared/find-helpers.d.ts +143 -0
- package/dist/mcp-server/tools/shared/find-helpers.d.ts.map +1 -0
- package/dist/mcp-server/tools/shared/find-helpers.js +319 -0
- package/dist/mcp-server/tools/shared/find-helpers.js.map +1 -0
- package/dist/mcp-server/tools/shared/orientation-envelope.d.ts +97 -0
- package/dist/mcp-server/tools/shared/orientation-envelope.d.ts.map +1 -0
- package/dist/mcp-server/tools/shared/orientation-envelope.js +254 -0
- package/dist/mcp-server/tools/shared/orientation-envelope.js.map +1 -0
- package/dist/mcp-server/tools/shared/raw-routing-hints.d.ts +10 -0
- package/dist/mcp-server/tools/shared/raw-routing-hints.d.ts.map +1 -0
- package/dist/mcp-server/tools/shared/raw-routing-hints.js +46 -0
- package/dist/mcp-server/tools/shared/raw-routing-hints.js.map +1 -0
- package/dist/services/brapi-client/brapi-client.d.ts +76 -0
- package/dist/services/brapi-client/brapi-client.d.ts.map +1 -0
- package/dist/services/brapi-client/brapi-client.js +320 -0
- package/dist/services/brapi-client/brapi-client.js.map +1 -0
- package/dist/services/brapi-client/index.d.ts +9 -0
- package/dist/services/brapi-client/index.d.ts.map +1 -0
- package/dist/services/brapi-client/index.js +7 -0
- package/dist/services/brapi-client/index.js.map +1 -0
- package/dist/services/brapi-client/types.d.ts +82 -0
- package/dist/services/brapi-client/types.d.ts.map +1 -0
- package/dist/services/brapi-client/types.js +8 -0
- package/dist/services/brapi-client/types.js.map +1 -0
- package/dist/services/brapi-filters/catalog.d.ts +14 -0
- package/dist/services/brapi-filters/catalog.d.ts.map +1 -0
- package/dist/services/brapi-filters/catalog.js +490 -0
- package/dist/services/brapi-filters/catalog.js.map +1 -0
- package/dist/services/brapi-filters/index.d.ts +8 -0
- package/dist/services/brapi-filters/index.d.ts.map +1 -0
- package/dist/services/brapi-filters/index.js +7 -0
- package/dist/services/brapi-filters/index.js.map +1 -0
- package/dist/services/brapi-filters/types.d.ts +23 -0
- package/dist/services/brapi-filters/types.d.ts.map +1 -0
- package/dist/services/brapi-filters/types.js +9 -0
- package/dist/services/brapi-filters/types.js.map +1 -0
- package/dist/services/capability-registry/capability-registry.d.ts +51 -0
- package/dist/services/capability-registry/capability-registry.d.ts.map +1 -0
- package/dist/services/capability-registry/capability-registry.js +234 -0
- package/dist/services/capability-registry/capability-registry.js.map +1 -0
- package/dist/services/capability-registry/index.d.ts +9 -0
- package/dist/services/capability-registry/index.d.ts.map +1 -0
- package/dist/services/capability-registry/index.js +7 -0
- package/dist/services/capability-registry/index.js.map +1 -0
- package/dist/services/capability-registry/types.d.ts +67 -0
- package/dist/services/capability-registry/types.d.ts.map +1 -0
- package/dist/services/capability-registry/types.js +9 -0
- package/dist/services/capability-registry/types.js.map +1 -0
- package/dist/services/dataset-store/dataset-store.d.ts +35 -0
- package/dist/services/dataset-store/dataset-store.d.ts.map +1 -0
- package/dist/services/dataset-store/dataset-store.js +190 -0
- package/dist/services/dataset-store/dataset-store.js.map +1 -0
- package/dist/services/dataset-store/index.d.ts +8 -0
- package/dist/services/dataset-store/index.d.ts.map +1 -0
- package/dist/services/dataset-store/index.js +7 -0
- package/dist/services/dataset-store/index.js.map +1 -0
- package/dist/services/dataset-store/types.d.ts +65 -0
- package/dist/services/dataset-store/types.d.ts.map +1 -0
- package/dist/services/dataset-store/types.js +8 -0
- package/dist/services/dataset-store/types.js.map +1 -0
- package/dist/services/ontology-resolver/index.d.ts +8 -0
- package/dist/services/ontology-resolver/index.d.ts.map +1 -0
- package/dist/services/ontology-resolver/index.js +7 -0
- package/dist/services/ontology-resolver/index.js.map +1 -0
- package/dist/services/ontology-resolver/ontology-resolver.d.ts +49 -0
- package/dist/services/ontology-resolver/ontology-resolver.d.ts.map +1 -0
- package/dist/services/ontology-resolver/ontology-resolver.js +99 -0
- package/dist/services/ontology-resolver/ontology-resolver.js.map +1 -0
- package/dist/services/ontology-resolver/types.d.ts +38 -0
- package/dist/services/ontology-resolver/types.d.ts.map +1 -0
- package/dist/services/ontology-resolver/types.js +8 -0
- package/dist/services/ontology-resolver/types.js.map +1 -0
- package/dist/services/reference-data-cache/index.d.ts +9 -0
- package/dist/services/reference-data-cache/index.d.ts.map +1 -0
- package/dist/services/reference-data-cache/index.js +7 -0
- package/dist/services/reference-data-cache/index.js.map +1 -0
- package/dist/services/reference-data-cache/reference-data-cache.d.ts +31 -0
- package/dist/services/reference-data-cache/reference-data-cache.d.ts.map +1 -0
- package/dist/services/reference-data-cache/reference-data-cache.js +131 -0
- package/dist/services/reference-data-cache/reference-data-cache.js.map +1 -0
- package/dist/services/reference-data-cache/types.d.ts +42 -0
- package/dist/services/reference-data-cache/types.d.ts.map +1 -0
- package/dist/services/reference-data-cache/types.js +9 -0
- package/dist/services/reference-data-cache/types.js.map +1 -0
- package/dist/services/server-registry/index.d.ts +9 -0
- package/dist/services/server-registry/index.d.ts.map +1 -0
- package/dist/services/server-registry/index.js +7 -0
- package/dist/services/server-registry/index.js.map +1 -0
- package/dist/services/server-registry/server-registry.d.ts +57 -0
- package/dist/services/server-registry/server-registry.d.ts.map +1 -0
- package/dist/services/server-registry/server-registry.js +210 -0
- package/dist/services/server-registry/server-registry.js.map +1 -0
- package/dist/services/server-registry/types.d.ts +43 -0
- package/dist/services/server-registry/types.d.ts.map +1 -0
- package/dist/services/server-registry/types.js +10 -0
- package/dist/services/server-registry/types.js.map +1 -0
- package/package.json +86 -0
- package/server.json +99 -0
package/README.md
ADDED
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>@cyanheads/brapi-mcp-server</h1>
|
|
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>19 Tools • 6 Resources • 2 Prompts</div>
|
|
5
|
+
</p>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div align="center">
|
|
9
|
+
|
|
10
|
+
[](https://www.npmjs.com/package/@cyanheads/brapi-mcp-server) [](./CHANGELOG.md) [](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [](https://modelcontextprotocol.io/)
|
|
11
|
+
|
|
12
|
+
[](./LICENSE) [](https://www.typescriptlang.org/) [](https://bun.sh/) [](./CHANGELOG.md)
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Tools
|
|
19
|
+
|
|
20
|
+
Nineteen 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 additive write surface for observations, and raw passthrough escape hatches.
|
|
21
|
+
|
|
22
|
+
### Orient
|
|
23
|
+
|
|
24
|
+
| Tool Name | Description |
|
|
25
|
+
|:----------|:------------|
|
|
26
|
+
| `brapi_connect` | Connect to a BrAPI v2 server, authenticate, cache the capability profile, and return the full orientation envelope inline. |
|
|
27
|
+
| `brapi_server_info` | Return the full orientation envelope for a registered BrAPI connection — identity, capabilities, content counts, notes. |
|
|
28
|
+
| `brapi_describe_filters` | List valid filter names for a BrAPI endpoint — powers dynamic discovery for `extraFilters` on any `find_*` tool. |
|
|
29
|
+
|
|
30
|
+
### Retrieve
|
|
31
|
+
|
|
32
|
+
| Tool Name | Description |
|
|
33
|
+
|:----------|:------------|
|
|
34
|
+
| `brapi_find_studies` | Locate studies matching crop / trial type / season / location / program filters, with per-field distributions and dataset spillover. |
|
|
35
|
+
| `brapi_get_study` | Fetch a single study with program / trial / location FKs resolved and companion counts for observations, units, and variables. |
|
|
36
|
+
| `brapi_find_germplasm` | Find germplasm by name, synonym, accession, crop, or free-text query, with distributions and dataset spillover. |
|
|
37
|
+
| `brapi_get_germplasm` | Fetch a single germplasm with attributes, direct parents, and companion counts (studies, parents, direct descendants). |
|
|
38
|
+
| `brapi_walk_pedigree` | Walk germplasm ancestry or descendancy as a deduplicated DAG (BFS) with cycle detection, depth limits, and traversal stats. |
|
|
39
|
+
| `brapi_find_variables` | Find observation variables (traits) by name, class, ontology, or free-text; ranked client-side via `OntologyResolver` when `text` is supplied. |
|
|
40
|
+
| `brapi_find_observations` | Pull observation records filtered by study, germplasm, variable, season, or observation unit. Dataset spillover. |
|
|
41
|
+
| `brapi_find_images` | Filter images by observation unit / study / ontology term / MIME type — metadata only, bytes via `brapi_get_image`. |
|
|
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
|
+
| `brapi_find_locations` | Find research stations / field sites by country / type / abbreviation, with optional client-side bounding-box filter. |
|
|
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. Default 100k cap (hard cap 500k); rows beyond `loadLimit` spill to DatasetStore. |
|
|
46
|
+
|
|
47
|
+
### Orchestrate
|
|
48
|
+
|
|
49
|
+
| Tool Name | Description |
|
|
50
|
+
|:----------|:------------|
|
|
51
|
+
| `brapi_manage_dataset` | Lifecycle for `find_*` spillover datasets — list, summary, load (paged rows with column projection), delete. |
|
|
52
|
+
|
|
53
|
+
### Write
|
|
54
|
+
|
|
55
|
+
| Tool Name | Description |
|
|
56
|
+
|:----------|:------------|
|
|
57
|
+
| `brapi_submit_observations` | Submit new (POST) or updated (PUT) observation rows for a study. Default `mode: preview` validates only; `mode: apply` elicits confirmation, fans POST + PUT in parallel, and reports the post-write count. Additive — no observation is destroyed. |
|
|
58
|
+
|
|
59
|
+
### Escape hatches
|
|
60
|
+
|
|
61
|
+
| Tool Name | Description |
|
|
62
|
+
|:----------|:------------|
|
|
63
|
+
| `brapi_raw_get` | Passthrough to any BrAPI `GET /{path}` the curated tools don't cover. Emits a routing nudge when a goal-shaped tool exists for the target. |
|
|
64
|
+
| `brapi_raw_search` | Passthrough to any BrAPI `POST /search/{noun}` with async polling handled transparently. Same routing nudge pattern. |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### `brapi_connect`
|
|
69
|
+
|
|
70
|
+
Session bootstrap. Authenticates to a BrAPI v2 server, registers the connection under a named alias, loads the capability profile via `CapabilityRegistry`, and inlines the full orientation envelope in the response. One call fully orients the agent.
|
|
71
|
+
|
|
72
|
+
- `baseUrl` and `auth` are optional — when omitted they fall back to `BRAPI_<ALIAS>_*`, then `BRAPI_DEFAULT_*` env vars. Agents can call `brapi_connect({ alias: 'cassava' })` with nothing else and credentials never enter the LLM context (see [Per-alias credentials](#per-alias-credentials))
|
|
73
|
+
- Tagged-union auth input: `none`, `sgn` (session-token exchange), `oauth2` (accepted at schema level, rejected at runtime pending client-credentials flow), `bearer`, `api_key`
|
|
74
|
+
- Multiple concurrent connections per session via distinct aliases
|
|
75
|
+
- Forces a fresh capability load on every connect — the agent expects current state
|
|
76
|
+
- Returns the same envelope as `brapi_server_info` — server identity, auth status, capability profile (supported/missing calls), content summary, server-specific notes
|
|
77
|
+
|
|
78
|
+
> **Alias discovery.** Configured aliases are appended to this tool's description at server startup, so agents see the inventory on `tools/list` without anyone having to spell them out in the prompt. Restart the server after changing `BRAPI_<ALIAS>_*` env vars to refresh. Pre-configured aliases are shortcuts only — any other BrAPI v2 server is reachable by passing `baseUrl` directly.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### `brapi_server_info`
|
|
83
|
+
|
|
84
|
+
On-demand orientation envelope for any registered alias. Useful for refreshing capability data after a long session or switching between aliases.
|
|
85
|
+
|
|
86
|
+
- Defaults to the most recent `brapi_connect` alias when `alias` is omitted
|
|
87
|
+
- `forceRefresh: true` bypasses the cached capability profile
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### `brapi_describe_filters`
|
|
92
|
+
|
|
93
|
+
Static filter catalog drawn from the BrAPI v2.1 spec — name, type, description, and example per filter. Use it before constructing `extraFilters` on any `find_*` tool.
|
|
94
|
+
|
|
95
|
+
- Covers `studies`, `germplasm`, `variables`, `observations`, `images`, `variants`, `locations`
|
|
96
|
+
- Catalog entries reflect the v2.1 spec; individual servers may implement subsets (the capability profile from `brapi_connect` tells you which)
|
|
97
|
+
- Response includes `specReference` link and the full list of available endpoints for discovery
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### `brapi_find_studies`
|
|
102
|
+
|
|
103
|
+
Locate studies with filters on crop, trial type, season, location, program, free text. Pulls an initial page (capped at `loadLimit`) and, when the upstream total exceeds `loadLimit`, spills the full union into `DatasetStore` and returns a dataset handle.
|
|
104
|
+
|
|
105
|
+
- Distributions computed across the full row set (`programName`, `studyType`, `seasons`, `locationName`, `commonCropName`)
|
|
106
|
+
- Refinement hint suggests which field to narrow when results exceed `loadLimit`
|
|
107
|
+
- `extraFilters` escape hatch for server-specific filter keys (discover via `brapi_describe_filters`)
|
|
108
|
+
- Warnings surface when `extraFilters` collides with named inputs
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### `brapi_get_study`
|
|
113
|
+
|
|
114
|
+
Fetch a single study by `studyDbId` with FKs resolved via `ReferenceDataCache` and cheap `pageSize=0` probes for observation / observation-unit / variable counts.
|
|
115
|
+
|
|
116
|
+
- Resolves `programDbId`, `trialDbId`, `locationDbId` into full records in one call
|
|
117
|
+
- Companion counts signal where to drill next without a full page pull
|
|
118
|
+
- Warnings when the upstream server doesn't support count probes
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### `brapi_find_germplasm`
|
|
123
|
+
|
|
124
|
+
Find germplasm by name, synonym, accession number, PUI, crop, or free-text. Matches across registered synonyms per BrAPI semantics.
|
|
125
|
+
|
|
126
|
+
- Distributions across `commonCropName`, `genus`, `species`, `collection`, `countryOfOriginCode`
|
|
127
|
+
- Dataset spillover identical to `brapi_find_studies`
|
|
128
|
+
- Refinement hint identifies the highest-cardinality dimension for narrowing
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### `brapi_get_germplasm`
|
|
133
|
+
|
|
134
|
+
Fetch a single germplasm with attributes, direct parents, and three companion counts (studies the germplasm appeared in, direct parents, direct descendants) — the counts signal where pedigree traversal could go next.
|
|
135
|
+
|
|
136
|
+
- Pulls `/germplasm/{id}`, `/germplasm/{id}/attributes`, `/germplasm/{id}/pedigree`, and `/germplasm/{id}/progeny` in one call
|
|
137
|
+
- Warnings when the upstream server omits any of those sub-endpoints
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### `brapi_walk_pedigree`
|
|
142
|
+
|
|
143
|
+
Walk germplasm ancestry or descendancy as a deduplicated DAG. BrAPI only exposes one generation per call, so this tool BFS-expands from each root, breaks cycles, and enforces a 1000-node safety cap.
|
|
144
|
+
|
|
145
|
+
- `direction`: `ancestors` (parents), `descendants` (progeny), or `both`
|
|
146
|
+
- Up to 20 roots per call, depth capped at 10 (default 3)
|
|
147
|
+
- Returns nodes + edges plus traversal stats (`depthReached`, `leafCount`, `cycleCount`, `deadEndCount`, `truncated`)
|
|
148
|
+
- Warnings when the server doesn't expose `/germplasm/{id}/pedigree` or `/progeny`
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### `brapi_find_variables`
|
|
153
|
+
|
|
154
|
+
Find observation variables (traits) by name, trait class, ontology term, or free-text. When `text` is supplied, results are re-ranked client-side via `OntologyResolver`; otherwise falls back to upstream order.
|
|
155
|
+
|
|
156
|
+
- Distributions across `ontologyDbId`, `traitClass`, `scaleName`
|
|
157
|
+
- Ontology candidates (top 10) surfaced separately when `text` is supplied, with source attribution (`puiMatch` / `nameMatch` / `synonymMatch` / `traitClassMatch`)
|
|
158
|
+
- Dataset spillover and `extraFilters` passthrough identical to other `find_*` tools
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### `brapi_find_observations`
|
|
163
|
+
|
|
164
|
+
Pull observation records filtered by study, germplasm, variable, season, observation unit, observation level, or timestamp range.
|
|
165
|
+
|
|
166
|
+
- Distributions across `observationVariableName`, `studyName`, `germplasmName`, `observationLevel`, `season`
|
|
167
|
+
- Dataset spillover when the upstream total exceeds `loadLimit` — handle passes to `brapi_manage_dataset`
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### `brapi_find_images`
|
|
172
|
+
|
|
173
|
+
Filter images by observation unit, observation, study, descriptive ontology term, file name, or MIME type. Returns metadata only — use `brapi_get_image` for bytes.
|
|
174
|
+
|
|
175
|
+
- Distributions across `mimeType`, `studyName`, `observationUnitName`, `descriptiveOntologyTerms`
|
|
176
|
+
- Dataset spillover for large result sets
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
### `brapi_get_image`
|
|
181
|
+
|
|
182
|
+
Fetch image bytes for up to 5 `imageDbIds` and return them inline as `type: image` content blocks. Hard cap of 20 MB per image.
|
|
183
|
+
|
|
184
|
+
- Prefers BrAPI `/images/{id}/imagecontent`; falls back to the `imageURL` field when the server doesn't implement imagecontent
|
|
185
|
+
- Relative `imageURL`s resolve against the registered base URL; absolute URLs pass through (no auth attached to the fallback)
|
|
186
|
+
- Per-image error reporting — partial success is surfaced cleanly
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
### `brapi_find_locations`
|
|
191
|
+
|
|
192
|
+
Find research stations / field sites by country, abbreviation, type, or location ID.
|
|
193
|
+
|
|
194
|
+
- Optional client-side bounding-box filter (`bbox: {minLat, maxLat, minLon, maxLon}`) applied after the upstream fetch (BrAPI has no spec-level bbox filter)
|
|
195
|
+
- Distributions across `countryCode` and `locationType`
|
|
196
|
+
- All four corners required to activate `bbox`; mismatched values produce a warning and the filter is skipped
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### `brapi_find_variants`
|
|
201
|
+
|
|
202
|
+
Find variant records by variant set, reference sequence, or genomic region.
|
|
203
|
+
|
|
204
|
+
- Genomic region uses 1-based inclusive `start` / exclusive `end` per the BrAPI spec
|
|
205
|
+
- Distributions across `variantType`, `referenceName`, `variantSetDbId`
|
|
206
|
+
- Warns when `start >= end`
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### `brapi_find_genotype_calls`
|
|
211
|
+
|
|
212
|
+
Pull genotype calls for a germplasm × variant set. Handles BrAPI's async-search pattern (`POST /search/calls` → `GET /search/calls/{id}`) transparently.
|
|
213
|
+
|
|
214
|
+
- Requires at least one filter (`variantSetDbId`, `germplasmDbIds`, `callSetDbIds`, `variantDbIds`) — unfiltered pulls are rejected
|
|
215
|
+
- Default cap of 100,000 calls per call (hard cap 500,000); `truncated: true` flags when the cap was hit
|
|
216
|
+
- Rows beyond `loadLimit` (default 200) spill to `DatasetStore` for export via `brapi_manage_dataset`
|
|
217
|
+
- Echoes server-reported genotype-encoding (`expandHomozygotes`, `unknownString`, `sepPhased`, `sepUnphased`) so the agent can interpret the values
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### `brapi_manage_dataset`
|
|
222
|
+
|
|
223
|
+
Consolidated lifecycle tool for datasets produced by `find_*` spillovers.
|
|
224
|
+
|
|
225
|
+
- `mode: list` — enumerate datasets with source / query / rowCount / expiration
|
|
226
|
+
- `mode: summary` — per-dataset metadata and provenance
|
|
227
|
+
- `mode: load` — paged rows (up to 1000 per page) with optional column projection
|
|
228
|
+
- `mode: delete` — drop metadata and payload
|
|
229
|
+
- Export (CSV / Parquet) is deferred until the write surface lands
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
### `brapi_raw_get`
|
|
234
|
+
|
|
235
|
+
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.
|
|
236
|
+
|
|
237
|
+
- Rejects absolute URLs in `path` — cross-origin smuggling via the registered base URL is blocked
|
|
238
|
+
- Emits a `suggestion` field when a goal-shaped tool covers the target endpoint (e.g. calling `raw_get /studies` nudges you to `brapi_find_studies`)
|
|
239
|
+
- Does not enrich results, resolve foreign keys, or compute distributions — prefer curated tools when they apply
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
### `brapi_raw_search`
|
|
244
|
+
|
|
245
|
+
Last-resort passthrough to any BrAPI `POST /search/{noun}`. Handles the 202 / async-poll pattern transparently.
|
|
246
|
+
|
|
247
|
+
- Same routing-nudge behavior as `brapi_raw_get`
|
|
248
|
+
- Returns `kind: sync | async` and the `searchResultsDbId` when the server took the async path
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### `brapi_submit_observations`
|
|
253
|
+
|
|
254
|
+
Two-phase write for observation rows. Default `mode: preview` validates rows against the study's variables and returns a routing breakdown; `mode: apply` elicits user confirmation when the client supports it, then POSTs new rows and PUTs rows carrying `observationDbId` in parallel.
|
|
255
|
+
|
|
256
|
+
- POST/PUT routing keyed on per-row `observationDbId` presence — mixed batches in one call
|
|
257
|
+
- Pre-flight pulls `/studies/{id}/observationvariables` to flag rows whose variable isn't exposed by the study (warning, not rejection — the upstream is the source of truth)
|
|
258
|
+
- Apply mode requires `ctx.elicit` confirmation OR an explicit `force: true` flag (rejected with `Forbidden` otherwise)
|
|
259
|
+
- Post-write probe re-fetches `/studies/{id}/observations?pageSize=0` to surface the new total in the response
|
|
260
|
+
- `latestObservationTimestamp` echoes the most recent `observationTimeStamp` across the accepted rows
|
|
261
|
+
- Additive only — destructive deletion is not exposed; corrections route through PUT
|
|
262
|
+
- Auth scope: `brapi:write:observations` (HTTP deployments only)
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Resources
|
|
267
|
+
|
|
268
|
+
Six MCP resources mirror the curated tool surface for clients that prefer URI-addressable access. Tool-only clients lose nothing — every resource has a corresponding tool path.
|
|
269
|
+
|
|
270
|
+
| URI template | Description |
|
|
271
|
+
|:-------------|:------------|
|
|
272
|
+
| `brapi://server/info` | Orientation envelope for the default connection (mirror of `brapi_server_info`). |
|
|
273
|
+
| `brapi://calls` | Raw capability profile — supported services, their methods/versions, declared crops. |
|
|
274
|
+
| `brapi://study/{studyDbId}` | Single study with FKs resolved (mirror of `brapi_get_study`). |
|
|
275
|
+
| `brapi://germplasm/{germplasmDbId}` | Single germplasm with attributes and parents (mirror of `brapi_get_germplasm`). |
|
|
276
|
+
| `brapi://dataset/{datasetId}` | Metadata + provenance for a persisted dataset (paged rows via `brapi_manage_dataset` mode `load`). |
|
|
277
|
+
| `brapi://filters/{endpoint}` | Filter catalog for a BrAPI endpoint (mirror of `brapi_describe_filters`). |
|
|
278
|
+
|
|
279
|
+
All resources use the default connection. Multi-server workflows route through the tool surface where alias is an explicit input.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Prompts
|
|
284
|
+
|
|
285
|
+
Two prompt templates package multi-step BrAPI workflows so the agent can pick them off the shelf.
|
|
286
|
+
|
|
287
|
+
| Name | Args | Purpose |
|
|
288
|
+
|:-----|:-----|:--------|
|
|
289
|
+
| `brapi_eda_study` | `studyDbId`, `alias?` | Exploratory-data-analysis playbook for a single study — orient, variables, coverage, missing data, outliers, pedigree side-quest, structured report. |
|
|
290
|
+
| `brapi_meta_analysis` | `germplasmDbIds` (CSV), `traitName`, `alias?` | Cross-study meta-analysis playbook — trait resolution, study discovery, harmonization, per-germplasm × per-study summary, across-study summary, pedigree context. |
|
|
291
|
+
|
|
292
|
+
Pure templates — they generate the user message a downstream LLM consumes. No side effects.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Features
|
|
297
|
+
|
|
298
|
+
Built on [`@cyanheads/mcp-ts-core`](https://www.npmjs.com/package/@cyanheads/mcp-ts-core):
|
|
299
|
+
|
|
300
|
+
- Declarative tool, resource, and prompt definitions — single file per primitive, framework handles registration and validation
|
|
301
|
+
- Unified error handling — handlers throw, framework catches, classifies, and formats
|
|
302
|
+
- Pluggable auth: `none`, `jwt`, `oauth`
|
|
303
|
+
- Swappable storage backends: `in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`
|
|
304
|
+
- Structured logging with optional OpenTelemetry tracing
|
|
305
|
+
- STDIO and Streamable HTTP transports
|
|
306
|
+
|
|
307
|
+
BrAPI-specific:
|
|
308
|
+
|
|
309
|
+
- **Multi-server session** — `ServerRegistry` maps aliases to live BrAPI connections, so one agent session can span Breedbase, T3, and Sweetpotatobase in parallel
|
|
310
|
+
- **Capability-aware calls** — `CapabilityRegistry` caches the `/serverinfo` profile per connection and guards every tool call against unsupported endpoints before they hit the wire
|
|
311
|
+
- **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
|
|
312
|
+
- **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
|
|
313
|
+
- **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
|
|
314
|
+
- **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
|
|
315
|
+
- **Free-text variable ranking** — `OntologyResolver` scores variable records against a query (PUI / name / synonym / trait-class) so `find_variables text:"..."` returns ranked candidates even when the server has no `/ontologies` endpoint
|
|
316
|
+
- **Dynamic filter discovery** — static v2.1 filter catalog plus an `extraFilters` passthrough lets agents drive any server-specific filter without schema churn
|
|
317
|
+
- **Auth variants in one schema** — tagged-union connection auth covers none / bearer / api-key / SGN session-token exchange in a single input shape
|
|
318
|
+
- **Typed error contracts** — every declared failure mode carries a stable `data.reason`, an HTTP-style `code`, and a `recovery.hint` mirrored onto the wire, so agent clients can route errors deterministically (e.g. `unknown_alias` → re-run `brapi_connect`, `dataset_not_found` → drop the stale handle)
|
|
319
|
+
- **Last-resort escape hatches** — `brapi_raw_get` and `brapi_raw_search` pass through to any endpoint with routing nudges pointing at the curated tool when one exists
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Getting started
|
|
324
|
+
|
|
325
|
+
Add the following to your MCP client configuration file.
|
|
326
|
+
|
|
327
|
+
```json
|
|
328
|
+
{
|
|
329
|
+
"mcpServers": {
|
|
330
|
+
"brapi": {
|
|
331
|
+
"type": "stdio",
|
|
332
|
+
"command": "bunx",
|
|
333
|
+
"args": ["@cyanheads/brapi-mcp-server@latest"],
|
|
334
|
+
"env": {
|
|
335
|
+
"MCP_TRANSPORT_TYPE": "stdio",
|
|
336
|
+
"MCP_LOG_LEVEL": "info"
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Or with npx (no Bun required):
|
|
344
|
+
|
|
345
|
+
```json
|
|
346
|
+
{
|
|
347
|
+
"mcpServers": {
|
|
348
|
+
"brapi": {
|
|
349
|
+
"type": "stdio",
|
|
350
|
+
"command": "npx",
|
|
351
|
+
"args": ["-y", "@cyanheads/brapi-mcp-server@latest"],
|
|
352
|
+
"env": {
|
|
353
|
+
"MCP_TRANSPORT_TYPE": "stdio",
|
|
354
|
+
"MCP_LOG_LEVEL": "info"
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Or with Docker:
|
|
362
|
+
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"mcpServers": {
|
|
366
|
+
"brapi": {
|
|
367
|
+
"type": "stdio",
|
|
368
|
+
"command": "docker",
|
|
369
|
+
"args": [
|
|
370
|
+
"run", "-i", "--rm",
|
|
371
|
+
"-e", "MCP_TRANSPORT_TYPE=stdio",
|
|
372
|
+
"ghcr.io/cyanheads/brapi-mcp-server:latest"
|
|
373
|
+
]
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
For Streamable HTTP, set the transport and start the server:
|
|
380
|
+
|
|
381
|
+
```sh
|
|
382
|
+
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
|
|
383
|
+
# Server listens at http://localhost:3010/mcp
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
No environment variables are required for the public BrAPI test server — agents can open connections at runtime via `brapi_connect`. **For credentialed servers, prefer env vars over agent input**: set `BRAPI_DEFAULT_*` for a default connection, or `BRAPI_<ALIAS>_*` per registered alias, so passwords / tokens / API keys stay out of the LLM context. See [Per-alias credentials](#per-alias-credentials).
|
|
387
|
+
|
|
388
|
+
### Prerequisites
|
|
389
|
+
|
|
390
|
+
- [Bun v1.3.11](https://bun.sh/) or higher (or Node.js v22+).
|
|
391
|
+
- 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.
|
|
392
|
+
|
|
393
|
+
### Installation
|
|
394
|
+
|
|
395
|
+
1. **Clone the repository:**
|
|
396
|
+
|
|
397
|
+
```sh
|
|
398
|
+
git clone https://github.com/cyanheads/brapi-mcp-server.git
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
2. **Navigate into the directory:**
|
|
402
|
+
|
|
403
|
+
```sh
|
|
404
|
+
cd brapi-mcp-server
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
3. **Install dependencies:**
|
|
408
|
+
|
|
409
|
+
```sh
|
|
410
|
+
bun install
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
4. **Configure environment:**
|
|
414
|
+
|
|
415
|
+
```sh
|
|
416
|
+
cp .env.example .env
|
|
417
|
+
# edit .env and set required vars
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Configuration
|
|
423
|
+
|
|
424
|
+
Every variable is optional — agents can configure connections entirely at runtime via `brapi_connect`. Set the `BRAPI_DEFAULT_*` variables if you want a default connection without an explicit `brapi_connect` call.
|
|
425
|
+
|
|
426
|
+
| Variable | Description | Default |
|
|
427
|
+
|:---------|:------------|:--------|
|
|
428
|
+
| `BRAPI_DEFAULT_BASE_URL` | Default BrAPI v2 base URL including path prefix (e.g. `https://test-server.brapi.org/brapi/v2`). | — |
|
|
429
|
+
| `BRAPI_DEFAULT_USERNAME` | Default SGN-family username for session-token auth. | — |
|
|
430
|
+
| `BRAPI_DEFAULT_PASSWORD` | Default SGN-family password. | — |
|
|
431
|
+
| `BRAPI_DEFAULT_OAUTH_CLIENT_ID` | Default OAuth2 client ID (e.g. CGIAR-family servers). | — |
|
|
432
|
+
| `BRAPI_DEFAULT_OAUTH_CLIENT_SECRET` | Default OAuth2 client secret. | — |
|
|
433
|
+
| `BRAPI_DEFAULT_API_KEY` | Default static API key. | — |
|
|
434
|
+
| `BRAPI_DEFAULT_API_KEY_HEADER` | Header name carrying the static API key. | `Authorization` |
|
|
435
|
+
| `BRAPI_LOAD_LIMIT` | In-context row cap before `find_*` tools spill to `DatasetStore`. | `200` |
|
|
436
|
+
| `BRAPI_MAX_CONCURRENT_REQUESTS` | Per-connection concurrency cap for parallel upstream fan-out. | `4` |
|
|
437
|
+
| `BRAPI_RETRY_MAX_ATTEMPTS` | Max retries on 429/5xx before surfacing the error. | `3` |
|
|
438
|
+
| `BRAPI_RETRY_BASE_DELAY_MS` | Base delay for exponential backoff between retries. | `500` |
|
|
439
|
+
| `BRAPI_REQUEST_TIMEOUT_MS` | Per-request HTTP timeout. | `30000` |
|
|
440
|
+
| `BRAPI_SEARCH_POLL_TIMEOUT_MS` | Total budget for async `/search/{noun}/{id}` polling. | `60000` |
|
|
441
|
+
| `BRAPI_SEARCH_POLL_INTERVAL_MS` | Interval between async-search status checks. | `1000` |
|
|
442
|
+
| `BRAPI_DATASET_TTL_SECONDS` | TTL for spilled datasets. | `86400` |
|
|
443
|
+
| `BRAPI_DATASET_STORE_DIR` | Filesystem path for `DatasetStore` payloads when filesystem storage is active. | — |
|
|
444
|
+
| `BRAPI_REFERENCE_CACHE_TTL_SECONDS` | TTL for reference-data cache entries (programs, trials, locations, crops). | `3600` |
|
|
445
|
+
| `BRAPI_ALLOW_PRIVATE_IPS` | Allow connecting to RFC 1918 / loopback targets. Dev-only. | `false` |
|
|
446
|
+
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
447
|
+
| `MCP_HTTP_PORT` | Port for HTTP server. | `3010` |
|
|
448
|
+
| `MCP_AUTH_MODE` | Auth mode: `none`, `jwt`, or `oauth`. | `none` |
|
|
449
|
+
| `MCP_LOG_LEVEL` | Log level (RFC 5424). | `info` |
|
|
450
|
+
| `STORAGE_PROVIDER_TYPE` | Storage backend. | `in-memory` |
|
|
451
|
+
| `OTEL_ENABLED` | Enable OpenTelemetry. | `false` |
|
|
452
|
+
|
|
453
|
+
Per-alias overrides follow the `BRAPI_<ALIAS>_*` pattern — see [Per-alias credentials](#per-alias-credentials).
|
|
454
|
+
|
|
455
|
+
See [`.env.example`](./.env.example) for the full list of optional overrides.
|
|
456
|
+
|
|
457
|
+
### Per-alias credentials
|
|
458
|
+
|
|
459
|
+
`brapi_connect` resolves `baseUrl` and `auth` from env vars when the agent omits them, so credentials never enter the LLM context. Three layers of precedence:
|
|
460
|
+
|
|
461
|
+
1. **Explicit agent input** — always wins.
|
|
462
|
+
2. **Per-alias env vars** — `BRAPI_<ALIAS>_*` where the alias name is uppercased and hyphens become underscores (`my-server` → `BRAPI_MY_SERVER_*`).
|
|
463
|
+
3. **Default env vars** — `BRAPI_DEFAULT_*`, only consulted when the alias differs from `default`.
|
|
464
|
+
|
|
465
|
+
Each alias carries **one** credential family — auth mode is derived from which fields are set:
|
|
466
|
+
|
|
467
|
+
| Vars set | Resolved `mode` |
|
|
468
|
+
|:---------|:----------------|
|
|
469
|
+
| `_USERNAME` + `_PASSWORD` | `sgn` (Breedbase `/token` exchange) |
|
|
470
|
+
| `_BEARER_TOKEN` | `bearer` |
|
|
471
|
+
| `_API_KEY` (+ optional `_API_KEY_HEADER`) | `api_key` |
|
|
472
|
+
| `_OAUTH_CLIENT_ID` + `_OAUTH_CLIENT_SECRET` (+ optional `_OAUTH_TOKEN_URL`) | `oauth2` |
|
|
473
|
+
| _(none set)_ | `none` |
|
|
474
|
+
|
|
475
|
+
Mixing families within a single alias raises a `ValidationError` naming the conflict.
|
|
476
|
+
|
|
477
|
+
```sh
|
|
478
|
+
# .env — register Cassavabase as alias 'cassava'
|
|
479
|
+
BRAPI_CASSAVA_BASE_URL=https://cassavabase.org/brapi/v2
|
|
480
|
+
BRAPI_CASSAVA_USERNAME=alice
|
|
481
|
+
BRAPI_CASSAVA_PASSWORD=...
|
|
482
|
+
|
|
483
|
+
# Register a static-API-key server as alias 'prod'
|
|
484
|
+
BRAPI_PROD_BASE_URL=https://my-brapi.example.com/brapi/v2
|
|
485
|
+
BRAPI_PROD_API_KEY=...
|
|
486
|
+
BRAPI_PROD_API_KEY_HEADER=X-API-Key
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Then the agent calls `brapi_connect({ alias: 'cassava' })` — no `baseUrl`, no `auth`, no secrets in the prompt.
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## Running the server
|
|
494
|
+
|
|
495
|
+
### Local development
|
|
496
|
+
|
|
497
|
+
- **Hot-reload dev mode** (run `tsx --watch` directly):
|
|
498
|
+
|
|
499
|
+
```sh
|
|
500
|
+
MCP_TRANSPORT_TYPE=stdio bunx tsx --watch src/index.ts
|
|
501
|
+
MCP_TRANSPORT_TYPE=http bunx tsx --watch src/index.ts
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
- **Build and run the production version:**
|
|
505
|
+
|
|
506
|
+
```sh
|
|
507
|
+
bun run rebuild
|
|
508
|
+
bun run start # transport selected via MCP_TRANSPORT_TYPE (stdio default)
|
|
509
|
+
# or pin the transport explicitly:
|
|
510
|
+
bun run start:stdio
|
|
511
|
+
bun run start:http
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
- **Run checks and tests:**
|
|
515
|
+
|
|
516
|
+
```sh
|
|
517
|
+
bun run devcheck # Lint, format, typecheck, security, changelog sync
|
|
518
|
+
bun run test # Vitest suite
|
|
519
|
+
bun run lint:mcp # Validate MCP definitions against spec
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Docker
|
|
523
|
+
|
|
524
|
+
```sh
|
|
525
|
+
docker build -t brapi-mcp-server .
|
|
526
|
+
docker run --rm -p 3010:3010 brapi-mcp-server
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `/var/log/brapi-mcp-server`. OpenTelemetry peer dependencies are installed by default — build with `--build-arg OTEL_ENABLED=false` to omit them.
|
|
530
|
+
|
|
531
|
+
### Multi-user HTTP deployments
|
|
532
|
+
|
|
533
|
+
`ctx.state` — where `ServerRegistry` (connection aliases + resolved bearer tokens), `DatasetStore` (spilled `find_*` rows), and `CapabilityRegistry` (cached `/serverinfo` profiles) live — is **scoped by `tenantId`, not by MCP session id**. Tenant resolution:
|
|
534
|
+
|
|
535
|
+
| Mode | Resolved `tenantId` |
|
|
536
|
+
|:-----|:--------------------|
|
|
537
|
+
| `MCP_TRANSPORT_TYPE=stdio` (any auth) | `default` |
|
|
538
|
+
| `MCP_TRANSPORT_TYPE=http` + `MCP_AUTH_MODE=none` (default) | `default` for every connected client |
|
|
539
|
+
| `MCP_TRANSPORT_TYPE=http` + `MCP_AUTH_MODE=jwt` or `oauth` | JWT `tid` claim, fail-closed if absent |
|
|
540
|
+
|
|
541
|
+
In HTTP + `none`, every client shares one bucket: connection aliases registered by one user (including the access token resolved from an SGN `/token` exchange) are reachable to any other connected user. For shared HTTP deployments, set `MCP_AUTH_MODE=jwt` (HS256, `MCP_AUTH_SECRET_KEY`) or `oauth` (JWKS, `OAUTH_ISSUER_URL` + `OAUTH_AUDIENCE`) so each caller's `tid` carves its own state.
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## Project structure
|
|
546
|
+
|
|
547
|
+
| Directory | Purpose |
|
|
548
|
+
|:----------|:--------|
|
|
549
|
+
| `src/index.ts` | `createApp()` entry point — registers 19 tools, 6 resources, 2 prompts, and inits the seven services. |
|
|
550
|
+
| `src/config` | Server-specific environment variable parsing with Zod. |
|
|
551
|
+
| `src/mcp-server/tools` | Tool definitions (`*.tool.ts`) and shared helpers (`orientation-envelope`, `find-helpers`, `connect-auth-schema`, `raw-routing-hints`). |
|
|
552
|
+
| `src/mcp-server/resources` | Resource definitions (`*.resource.ts`) — URI-addressable mirrors of curated tool data. |
|
|
553
|
+
| `src/mcp-server/prompts` | Prompt definitions (`*.prompt.ts`) — multi-step BrAPI workflow templates. |
|
|
554
|
+
| `src/services/brapi-client` | HTTP client with retry, concurrency capping, async-search polling, private-IP guard, and binary fetch. |
|
|
555
|
+
| `src/services/brapi-filters` | Static BrAPI v2.1 filter catalog. |
|
|
556
|
+
| `src/services/capability-registry` | Per-connection capability profile cache. |
|
|
557
|
+
| `src/services/dataset-store` | Tenant-scoped dataset handles for spilled `find_*` results. |
|
|
558
|
+
| `src/services/ontology-resolver` | Free-text → ontology-candidate matcher powering `brapi_find_variables` ranking. |
|
|
559
|
+
| `src/services/reference-data-cache` | Cache for programs, trials, locations, crops. |
|
|
560
|
+
| `src/services/server-registry` | Alias → live BrAPI connection map with auth resolution. |
|
|
561
|
+
| `tests/` | Unit and integration tests mirroring `src/`. |
|
|
562
|
+
| `docs/design.md` | End-to-end surface design (current + planned tools). |
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
## Development guide
|
|
567
|
+
|
|
568
|
+
See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rules. The short version:
|
|
569
|
+
|
|
570
|
+
- Handlers throw, framework catches — no `try/catch` in tool logic
|
|
571
|
+
- Use `ctx.log` for request-scoped logging, `ctx.state` for tenant-scoped storage
|
|
572
|
+
- Register new tools in the `tools` array of `createApp()` in `src/index.ts`
|
|
573
|
+
- Wrap upstream calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
## Contributing
|
|
578
|
+
|
|
579
|
+
Issues and pull requests are welcome. Run checks and tests before submitting:
|
|
580
|
+
|
|
581
|
+
```sh
|
|
582
|
+
bun run devcheck
|
|
583
|
+
bun run test
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
---
|
|
587
|
+
|
|
588
|
+
## License
|
|
589
|
+
|
|
590
|
+
Apache-2.0 — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Initial scaffold from @cyanheads/mcp-ts-core with complete MCP surface design — 19 tools and 6 resources for BrAPI v2.1 find/get, pedigree traversal, writes, filter discovery, and dataset lifecycle."
|
|
3
|
+
breaking: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 0.1.0 — 2026-04-23
|
|
7
|
+
|
|
8
|
+
Initial scaffold and design for a TypeScript MCP server exposing BrAPI v2.1 to LLMs as a goal-oriented plant-breeding workbench. Implementation lands in subsequent releases.
|
|
9
|
+
|
|
10
|
+
## Added
|
|
11
|
+
|
|
12
|
+
- Project scaffold from `@cyanheads/mcp-ts-core` — skills, TypeScript config, Biome, Vitest, devcheck, Dockerfile, agent protocol files, changelog structure.
|
|
13
|
+
- Design doc at [`docs/design.md`](docs/design.md) covering:
|
|
14
|
+
- 19-tool MCP surface organized by axis — orient (`connect`, `server_info`, `describe_filters`), retrieve (`find_*`/`get_*`, `walk_pedigree`), orchestrate (`submit_observations`, `manage_dataset`), and escape hatches (`raw_get`, `raw_search`).
|
|
15
|
+
- 6 resources (server info, study, germplasm, dataset, calls, filters) — tool-only clients lose nothing (primary entities have paired `get_*` tools; reference data via `find_*`; niche lookups via `raw_get`).
|
|
16
|
+
- 2 prompt templates — EDA framework for a single study, meta-analysis across germplasm + trait.
|
|
17
|
+
- Service layer: `BrapiClient`, `CapabilityRegistry`, `ReferenceDataCache`, `DatasetStore`, `OntologyResolver`, `ServerRegistry`.
|
|
18
|
+
- Workflow analysis (server_info, find_studies, walk_pedigree, submit_observations), response companions (orient-combine, filter distributions, traversal stats, post-action state), design decisions, known limitations, and a compatibility matrix adapted from [Plant-Phenomics-Lab/Breedbase-Client](https://github.com/Plant-Phenomics-Lab/Breedbase-Client).
|
|
19
|
+
- Echo tool/resource/prompt starter definitions from the framework (placeholder — replaced during implementation).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Phase 3 tool surface — 7 read-side BrAPI tools (connect, server_info, describe_filters, find/get studies & germplasm) plus ServerRegistry for session-scoped multi-server workflows and a static BrAPI v2.1 filter catalog."
|
|
3
|
+
breaking: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 0.1.1 — 2026-04-23
|
|
7
|
+
|
|
8
|
+
Phase 3 of the BrAPI MCP surface lands the first read-side tools end-to-end and the final service needed to run them. Agents can now connect to a BrAPI v2 server, orient against the capability profile, and drive studies / germplasm workflows without hitting `raw_get`.
|
|
9
|
+
|
|
10
|
+
## Added
|
|
11
|
+
|
|
12
|
+
- **`ServerRegistry` service** (`src/services/server-registry/`) — session-scoped alias map that resolves connection auth (none / bearer / api_key / sgn-password-exchange) and persists each registration under the tenant's `ctx.state`. OAuth2 is accepted at the schema level but rejected at runtime pending a proper client-credentials flow.
|
|
13
|
+
- **BrAPI filter catalog** (`src/services/brapi-filters/`) — static v2.1 filter descriptors for `studies`, `germplasm`, `variables`, `observations`, `images`, `variants`, and `locations`, each paired with a spec-reference URL. Drives dynamic discovery for the `extraFilters` passthrough.
|
|
14
|
+
- **Phase 3 tools** — 7 read-side tools registered in `createApp()`:
|
|
15
|
+
- `brapi_connect` — authenticate, register an alias, load the capability profile, and inline the orientation envelope.
|
|
16
|
+
- `brapi_server_info` — on-demand orientation envelope for any registered alias (`forceRefresh` bypasses cache).
|
|
17
|
+
- `brapi_describe_filters` — filter catalog lookup per endpoint with a discovery list of every available endpoint.
|
|
18
|
+
- `brapi_find_studies` / `brapi_find_germplasm` — single-page fetch with distributions, refinement hints, and `DatasetStore` spillover when the upstream total exceeds `loadLimit` (capped at 50k rows / 50 pages per call).
|
|
19
|
+
- `brapi_get_study` — single study with program / trial / location FKs resolved via `ReferenceDataCache` plus `pageSize=0` probes for observation / observation-unit / variable counts.
|
|
20
|
+
- `brapi_get_germplasm` — single germplasm with attributes, direct parents, and companion counts (study count, parent count, direct descendant count).
|
|
21
|
+
- **Shared tool helpers** — `connect-auth-schema.ts` (Zod discriminated union mirroring `ConnectAuth`), `orientation-envelope.ts` (the shared envelope builder + markdown formatter for `brapi_connect` and `brapi_server_info`), and `find-helpers.ts` (alias / loadLimit / extraFilters input fragments, `mergeFilters`, `computeDistribution`, `loadInitialPage`, `spillToDataset`).
|
|
22
|
+
- **End-to-end tool tests** — `tests/tools/` covers every tool handler against a dependency-injected fetcher, plus a dedicated `ServerRegistry` unit test suite covering alias validation, URL normalization, and SGN token exchange.
|
|
23
|
+
|
|
24
|
+
## Changed
|
|
25
|
+
|
|
26
|
+
- **Dependencies** — `@cyanheads/mcp-ts-core` ^0.6.14 → ^0.6.15; `@biomejs/biome` ^2.4.7 → ^2.4.13; `tsx` ^4.19.0 → ^4.21.0; `typescript` ^5.9.3 → ^6.0.3; `vitest` ^4.1.0 → ^4.1.5.
|
|
27
|
+
- **`skills/security-pass`** — synced to v1.1 with mcp-ts-core 0.6.15 (expanded to cover resources, prompts, descriptions, sampling / roots / elicit response validation, HTTP deployment surface, constant-time comparisons, and parse size/depth limits).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Docs and metadata polish for publish — full README, LICENSE, project tree; BrAPI-specific CLAUDE.md; richer package.json keywords/engines, server.json env vars, and Dockerfile OCI labels."
|
|
3
|
+
breaking: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 0.1.2 — 2026-04-23
|
|
7
|
+
|
|
8
|
+
Finalize project documentation and package metadata in preparation for the first npm / MCP Registry publish. No runtime changes.
|
|
9
|
+
|
|
10
|
+
## Added
|
|
11
|
+
|
|
12
|
+
- **`README.md`** — full project README covering the 7-tool surface, feature highlights, install / Docker / npx / bunx usage, configuration matrix, local development commands, and project structure.
|
|
13
|
+
- **`LICENSE`** — Apache-2.0 full text.
|
|
14
|
+
- **`bunfig.toml`** — Bun install config (`auto = "fallback"`, `frozenLockfile = false`).
|
|
15
|
+
- **`docs/tree.md`** — generated directory tree (via `bun run tree`).
|
|
16
|
+
|
|
17
|
+
## Changed
|
|
18
|
+
|
|
19
|
+
- **`CLAUDE.md`** — rewritten from the generic scaffold into a BrAPI-specific agent protocol. Tool example is now `brapi_connect`, `find_*` spillover pattern documented, `ServerConfigSchema` shows the real `BRAPI_*` env vars, structure tree matches the six services and seven tools actually registered, commands table uses `bun run`, and the definition checklist gates BrAPI-specific invariants (`ServerRegistry.get`, `CapabilityRegistry.ensure`, dataset spillover).
|
|
20
|
+
- **`package.json`** — added `mcpName` (`io.github.cyanheads/brapi-mcp-server`), `author`, expanded `keywords` (brapi, plant-breeding, bioinformatics, agriculture, phenotyping, genotyping, llm-tools, typescript), `engines.bun >=1.2.0`, and `packageManager: bun@1.3.11`. Description tightened to match the README headline.
|
|
21
|
+
- **`server.json`** — description aligned with `package.json`, `BRAPI_DEFAULT_BASE_URL` added to both stdio and HTTP package environment variable lists, `packageArguments` compacted to one-line objects.
|
|
22
|
+
- **`Dockerfile`** — populated the `org.opencontainers.image.description` label and added `org.opencontainers.image.source` pointing at the GitHub repo.
|