protogrid

Search / io.github.cyanheads/brapi-mcp-server

brapi-mcp-server

R0· no sign-in

Collaborative BrAPI v2.1 MCP workspace: studies, germplasm, genotypes across Breedbase, T3, more.

v0.10.1 · active · repository · descriptor JSON · versions

An agent can connect right now, no human step.Remote endpoint, no authentication, reachable on the last probe.
Quality67needs work
Trust94of 100
Uptime, 30 days99%
Latency p50206 ms

Connect

8 clients · secrets stay placeholders
{
  "mcpServers": {
    "brapi-mcp-server": {
      "type": "http",
      "url": "https://brapi.caseyjhand.com/mcp"
    }
  }
}
claude mcp add --transport http brapi-mcp-server https://brapi.caseyjhand.com/mcp
[mcp_servers.brapi-mcp-server]
url = "https://brapi.caseyjhand.com/mcp"
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "brapi-mcp-server": {
      "type": "remote",
      "url": "https://brapi.caseyjhand.com/mcp",
      "enabled": true
    }
  }
}
{
  "mcpServers": {
    "brapi-mcp-server": {
      "type": "http",
      "url": "https://brapi.caseyjhand.com/mcp"
    }
  },
  "deeplink": "cursor://anysphere.cursor-deeplink/mcp/install?name=brapi-mcp-server&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vYnJhcGkuY2FzZXlqaGFuZC5jb20vbWNwIn0%3D"
}
{
  "servers": {
    "brapi-mcp-server": {
      "type": "http",
      "url": "https://brapi.caseyjhand.com/mcp"
    }
  }
}
{
  "mcpServers": {
    "brapi-mcp-server": {
      "httpUrl": "https://brapi.caseyjhand.com/mcp"
    }
  }
}
extensions:
  "brapi-mcp-server":
    enabled: true
    name: "brapi-mcp-server"
    type: streamable_http
    uri: "https://brapi.caseyjhand.com/mcp"
    timeout: 300

Quality 67 / 100needs work

protocol88 · weight 25
  • pass
    protocol.modernsupports 2026-07-28 (server/discover)
  • pass
    protocol.statelessanswers without a session
  • pass
    protocol.transportstreamable HTTP
  • warn
    protocol.list_ttltools/list declares ttlMs 0, so clients re-fetch it on every use
authorizationn/a · weight 15
  • n/a
    auth.prm, auth.as_metadata, auth.cimdno remote uses OAuth
  • n/a
    auth.secret_in_urlno templated URL
tool hygiene71 · weight 30
  • pass
    tools.descriptionsevery tool has a description
  • warn
    tools.description_length1 tools have descriptions over 1,024 characters, which crowds the context
  • pass
    tools.schemasevery tool has an object input schema
  • pass
    tools.annotations22 of 22 tools declare readOnlyHint or destructiveHint
  • fail
    tools.directory_hintsno tool declares all four of readOnlyHint, destructiveHint, idempotentHint and openWorldHint; missing: brapi_connect (destructiveHint); brapi_build_phenotype_matrix (destructiveHint, idempotentHint); brapi_get_germplasm (destructiveHint, openWorldHint); …
  • warn
    tools.token_costabout 12,524 tokens to load every tool
  • pass
    tools.api_dumptools are not a one-to-one API dump
stability25 · weight 15
  • warn
    stability.changes49 tool changes in 30 days
  • fail
    stability.rug_pull7 tools kept their name but changed most of their description in 30 days; review before trusting them
dependenciesn/a · weight 15

22 tools, about 12,524 tokens to load them all · tool set 62aeb8aba4f3 · tools last changed 2026-10-19 · checked 2026-10-20 13:17 UTC

Tool changes

  • brapi_raw_searchchangedoutput schema
  • brapi_raw_getchangedoutput schema
  • brapi_export_genotype_matrixchangeddescription, output schema
    before

    Pull genotype calls for a germplasm × variant set and pivot them into a matrix. `format` controls the output: `matrix-json` registers a wide germplasm × variant canvas dataframe for SQL analysis; `vcf-lite` returns VCF-subset text (in the `vcf` field) and also registers the dataframe; `plink` returns .ped/.map text (in the `ped`/`map` fields) and also registers the dataframe. vcf-lite/plink pull /variants metadata for CHROM/POS/REF/ALT (`.`/`0` when the server lacks them). Read the dataframe with brapi_dataframe_describe and brapi_dataframe_query (SQL). Column names are SQL-safe identifiers; `variantColumnLegend` maps them back to original variant IDs.

    after · 57% of words in common

    Pull genotype calls for a germplasm × variant set and pivot them into a matrix. `matrix-json` registers a wide canvas dataframe; `vcf-lite` adds VCF-subset text in `vcf`; `plink` adds .ped/.map text in `ped`/`map`. Text formats pull /variants metadata and convert zero-based BrAPI start to one-based positions; missing/invalid positions use `.`/`0`. Read the dataframe with brapi_dataframe_describe and brapi_dataframe_query (SQL). `variantColumnLegend` maps SQL-safe columns to original variant IDs.

  • brapi_find_genotype_callschangedoutput schema
  • brapi_find_variantschangedoutput schema
  • brapi_find_locationschangedoutput schema
  • brapi_find_imageschangedoutput schema
  • brapi_find_observationschangedoutput schema
  • brapi_find_variableschangedinput schema, output schema
  • brapi_germplasm_performancechangedoutput schema

Showing the latest 10. Full history: list_changes · trend: quality JSON.

Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed. How it is computed.

Trust 94 / 100

provenance80
liveness100
freshness100
hygiene100

+repository +namespace-matches-repo +reachable +uptime-99% +updated-1d-ago

Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed. How it is computed.

Dependencies

@cyanheads/[email protected] npmthis version is not known to the dependency resolver

@cyanheads/[email protected] npmthis version is not known to the dependency resolver

Dependency graphs from deps.dev; advisories from OSV.dev, including the GitHub Advisory Database and the PyPI Advisory Database; all CC BY 4.0. The graph is what a clean install of this version resolves today; nothing was installed or run. How it is checked.

Endpoints

remoteauthreachableuptime 30dp50protocollast ok
https://brapi.caseyjhand.com/mcp streamable-httpnoneyes99%206 ms2026-07-282026-10-20
packageregistryversionruntimesecrets
@cyanheads/brapi-mcp-servernpm0.10.1npx
@cyanheads/brapi-mcp-servernpm0.10.1npx

Tools (22)

brapi_build_phenotype_matrixread-onlyPull observations across one or more studies and pivot them into a germplasm × trait matrix materialized as a canvas dataframe. Returns a dataframe handle (read it with brapi_dataframe_describe and brapi_dataframe_query) plus a summary of dimensions and aggregate method. Long-form output is suitable for downstream GROUP BY analysis by study, germplasm, or variable. A study whose pull fails is named in warnings and the rest still build the matrix; the call fails only when every study failed.
brapi_connectOpen a connection to a BrAPI v2 server, authenticate, and return the full orientation envelope (server identity, capability profile, content summary, suggested next tools). Other BrAPI tools connect an alias the server has a URL configured for (a built-in or operator-configured alias, or `default` on a deployment with a default server) on first use; call this to connect any other server by `baseUrl`, to pass `auth`, or to re-point an alias. Supports multiple concurrent connections via named aliases. Credentials can be configured server-side and omitted from this call. When a request carries no MCP session on a deployment without per-user auth, aliases live in one namespace shared by every such caller: re-registering an alias re-points their later calls to it. Built-in known servers (callable with no `baseUrl` or `auth` — public BrAPI v2 endpoints): `bti-breedbase-demo`, `bti-cassava`, `bti-sweetpotato`. Operator-configured aliases on this deployment (credentials and/or baseUrl read from server env vars): `default`, `cassava`. Aliases are shortcuts only; any other BrAPI v2 server is reachable by passing `baseUrl` directly.
brapi_dataframe_describeread-onlyStart here after a spillover. Lists dataframes (or describes one) with columns, row counts, and originating-source provenance. The dataframe name appears inline on every find_* response that spilled (`result.dataframe.tableName`) — pass it as `dataframe` to inspect schema and provenance before writing the first brapi_dataframe_query. On a shared HTTP endpoint without per-caller auth, listing without a name is available only where each MCP session has its own workspace, and never to a request without a session; pass a known name instead.
brapi_dataframe_queryRun SQL across in-memory dataframes. Dataframes auto-populate when find_* tools spill (named `df_<uuid>`) — the dataframe name appears inline on every find_* response that spilled (`result.dataframe.tableName`), so the typical flow is find_* → read the name → query here. Use brapi_dataframe_describe to inspect schema and provenance for a known name. SELECT only — writes/DDL/COPY/PRAGMA/ATTACH/file-reads are rejected. Use SQL as the paging idiom: `LIMIT/OFFSET` to walk results, projection to trim columns, aggregation to summarize. Use `registerAs` to chain — the result lands as a new dataframe.
brapi_describe_filtersread-onlyList the valid filter names for a BrAPI endpoint (studies, germplasm, observations, variables, images, variants, locations) — companion lookup for the `extraFilters` passthrough on any `find_*` tool. Entries reflect the BrAPI v2.1 spec; individual servers may implement subsets.
brapi_export_genotype_matrixread-onlyPull genotype calls for a germplasm × variant set and pivot them into a matrix. `matrix-json` registers a wide canvas dataframe; `vcf-lite` adds VCF-subset text in `vcf`; `plink` adds .ped/.map text in `ped`/`map`. Text formats pull /variants metadata and convert zero-based BrAPI start to one-based positions; missing/invalid positions use `.`/`0`. Read the dataframe with brapi_dataframe_describe and brapi_dataframe_query (SQL). `variantColumnLegend` maps SQL-safe columns to original variant IDs.
brapi_find_genotype_callsread-onlyPull genotype calls for a germplasm × variant set. Filter to bound cost — at minimum, set `variantSetDbId` or `germplasmDbIds`. The upstream pull is capped by deployment policy; when the pull is truncated, narrow the filters. results[] holds the leading calls up to `loadLimit` and a 24,000-byte budget; when it holds fewer than were collected, every collected call is materialized as a dataframe — read it with brapi_dataframe_describe and brapi_dataframe_query (SQL) instead of paging row-by-row.
brapi_find_germplasmread-onlyFind germplasm by name, synonym, accession number, PUI, crop, or free-text query. Matches across registered synonyms. results[] holds the leading matches up to loadLimit and a 24,000-byte budget; when it holds fewer rows than matched, the matched set is materialized as a dataframe — read it with brapi_dataframe_describe and brapi_dataframe_query (SQL) instead of paging row-by-row.
brapi_find_imagesread-onlyFilter images by observation unit, observation, study, descriptive ontology term, file name, or MIME type. Returns metadata only — use brapi_get_image to fetch bytes inline. results[] holds the leading matches up to loadLimit and a 24,000-byte budget; when it holds fewer rows than matched, the matched set is materialized as a dataframe — read it with brapi_dataframe_describe and brapi_dataframe_query (SQL).
brapi_find_locationsread-onlyFind research stations / field sites by country, abbreviation, type, location ID, or free-text. Countries filter by ISO 3166-1 alpha-3 code via countryCodes, or by free-form English country name via countryNames (resolved client-side to alpha-3 — "Uganda" → "UGA"). Optional bbox parameter restricts rows to a latitude/longitude window. When no first-page row falls inside it under the spec GeoJSON [lon, lat, alt] reading and a row carries a Point geometry, bbox is retried with axes swapped; if that matches, the swapped reading is used (non-conformant servers store [lat, lon, alt]) with a warning and `coordinateAxisOrder: "swapped"`. results[] holds the leading matches up to loadLimit and a 24,000-byte budget; when it holds fewer rows than matched, the matched set is materialized as a dataframe — read it with brapi_dataframe_describe and brapi_dataframe_query (SQL).
brapi_find_observationsread-onlyPull observation records filtered by study, germplasm, variable, season, or observation unit. Without a studies, trials, observationUnits, or observations anchor, a GET query first runs a one-row count probe and skips the bulk pull (warnings says so) when the probe fails or reports more than 5,000 matches. results[] holds the leading matches up to loadLimit and a 24,000-byte budget; when those bounds cut it short, the matched set is materialized as a dataframe — read it with brapi_dataframe_describe and brapi_dataframe_query (SQL).
brapi_find_studiesread-onlyLocate studies matching crop, trial type, season, location, or program. Enriches results with program/trial/location context in one call. results[] holds the leading matches up to loadLimit and a 24,000-byte budget; when it holds fewer rows than matched, the matched set is materialized as a dataframe — read it with brapi_dataframe_describe and brapi_dataframe_query (SQL).
brapi_find_variablesread-onlyFind observation variables (traits) by name, trait class, ontology term, or free-text query. Free-text queries are ranked against every fetched row by PUI, name, synonym, and trait text; a candidate carries the ontology PUI of its row as termId when the row has one. results[] holds the leading rows up to loadLimit and a 24,000-byte budget; when it holds fewer rows than matched, the matched set is materialized as a dataframe — read it with brapi_dataframe_describe and brapi_dataframe_query (SQL).
brapi_find_variantsread-onlyFind variant records by variant set, reference sequence, or genomic region (start/end, 0-based inclusive / exclusive per the BrAPI spec; servers may differ). results[] holds the leading matches up to loadLimit and a 24,000-byte budget; when it holds fewer rows than matched, the matched set is materialized as a dataframe — read it with brapi_dataframe_describe and brapi_dataframe_query (SQL).
brapi_germplasm_performanceread-onlyAggregate a single germplasm's observations across studies, returning per-variable statistics (n, mean, median, sd, min, max), contributing studies, seasons, and collection coverage. SGN/Breedbase uses advertised germplasm-scoped observation units with embedded measurements, including zeros. Other servers discover up to 200 studies before pulling per study. Pass studyDbIds to skip discovery and restrict collection to known studies. Per-study observation limits, page limits, failures, and incomplete scans appear in coverage and warnings. For the underlying matrix, use brapi_build_phenotype_matrix.
brapi_get_germplasmread-onlyFetch a single germplasm by DbId with attributes and direct parents. Response companions report study count, direct parent count, and direct descendant count — signals for pedigree depth and observation coverage.
brapi_get_imageread-onlyFetch image bytes for up to 5 imageDbIds and return them inline as `type: image` content blocks. Falls back to the metadata `imageURL` when the server lacks dedicated image-content delivery or that request fails. No filesystem side-effects.
brapi_get_studyread-onlyFetch a single study by DbId with its program, trial, and location records resolved where those lookups succeed. Response includes cheap observation/observation-unit/variable counts as drill-down signals.
brapi_raw_getread-onlyPassthrough to BrAPI GET /{path} without foreign-key resolution. List results (result array or result.data) return a leading preview within loadLimit and a 24,000-byte budget on each serialized row representation; an oversized first row returns no inline rows. Omitted fetched rows remain in a dataframe readable with brapi_dataframe_describe and brapi_dataframe_query. Explicit params.page/pageSize fetches only that upstream page, staging it if trimmed. Non-list results and envelope siblings are preserved. Emits a suggestion when a curated tool covers the endpoint.
brapi_raw_searchread-onlyPassthrough to BrAPI POST /search/{noun}, polling async search IDs. Sends loadLimit as the initial pageSize unless body.page/pageSize drives explicit paging. List previews fit loadLimit and a 24,000-byte budget on each serialized row representation; an oversized first row returns no inline rows. Every fetched row omitted inline stays in a dataframe readable with brapi_dataframe_describe and brapi_dataframe_query. Explicit paging fetches only the requested page, staging it if trimmed. Non-list results and envelope siblings are preserved; no distributions or foreign-key resolution.
brapi_server_inforead-onlyReturn the full orientation envelope for a BrAPI connection — server identity, capabilities, content counts, suggested finders, and notes. Pass forceRefresh to refetch the cached capability scan; pass an alias to read a non-default connection.
brapi_walk_pedigreeread-onlyWalk germplasm ancestry or descendancy as a deduplicated DAG with cycle detection and depth limits. leafCount counts graph terminals, confirmedLeafCount counts successfully verified leaves, and frontier records unresolved directions. Nodes and edges each fit loadLimit and a 24,000-byte preview budget; trimmed discovered graphs and already-fetched omitted relatives are staged for brapi_dataframe_describe and brapi_dataframe_query (SQL). Diagrams describe only the discovered graph, never unvisited relatives.

Schemas: list_tools.

Similar MCP servers

More from io.github.cyanheads

And 140 more from this publisher.

Official server.json
{
  "name": "io.github.cyanheads/brapi-mcp-server",
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
  "remotes": [
    {
      "url": "https://brapi.caseyjhand.com/mcp",
      "type": "streamable-http"
    }
  ],
  "version": "0.10.1",
  "packages": [
    {
      "version": "0.10.1",
      "transport": {
        "type": "stdio"
      },
      "identifier": "@cyanheads/brapi-mcp-server",
      "runtimeHint": "npx",
      "registryType": "npm",
      "registryBaseUrl": "https://registry.npmjs.org",
      "environmentVariables": [
        {
          "name": "BRAPI_DEFAULT_BASE_URL",
          "format": "string",
          "description": "Default BrAPI v2 base URL. Optional — connections can be opened at runtime via the brapi_connect tool instead."
        },
        {
          "name": "BRAPI_ENABLE_WRITES",
          "format": "string",
          "default": "false",
          "description": "Opt-in flag for the write surface (brapi_submit_observations). Off by default — the tool is omitted from tools/list unless the operator opts in."
        },
        {
          "name": "BRAPI_PAGE_SIZE",
          "format": "string",
          "default": "1000",
          "description": "Upstream pageSize used during canvas spillover walks (decoupled from BRAPI_LOAD_LIMIT). Dataframe ceiling = pageSize × 50 pages, capped at 50,000 rows."
        },
        {
          "name": "MCP_LOG_LEVEL",
          "format": "string",
          "default": "info",
          "description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn')."
        }
      ]
    },
    {
      "version": "0.10.1",
      "transport": {
        "url": "http://localhost:3010/mcp",
        "type": "streamable-http"
      },
      "identifier": "@cyanheads/brapi-mcp-server",
      "runtimeHint": "npx",
      "registryType": "npm",
      "registryBaseUrl": "https://registry.npmjs.org",
      "environmentVariables": [
        {
          "name": "MCP_TRANSPORT_TYPE",
          "value": "http",
          "format": "string",
          "description": "Selects the HTTP transport."
        },
        {
          "name": "BRAPI_DEFAULT_BASE_URL",
          "format": "string",
          "description": "Default BrAPI v2 base URL. Optional — connections can be opened at runtime via the brapi_connect tool instead."
        },
        {
          "name": "BRAPI_ENABLE_WRITES",
          "format": "string",
          "default": "false",
          "description": "Opt-in flag for the write surface (brapi_submit_observations). Off by default — the tool is omitted from tools/list unless the operator opts in."
        },
        {
          "name": "BRAPI_PAGE_SIZE",
          "format": "string",
          "default": "1000",
          "description": "Upstream pageSize used during canvas spillover walks (decoupled from BRAPI_LOAD_LIMIT). Dataframe ceiling = pageSize × 50 pages, capped at 50,000 rows."
        },
        {
          "name": "MCP_HTTP_HOST",
          "format": "string",
          "default": "127.0.0.1",
          "description": "The hostname for the HTTP server."
        },
        {
          "name": "MCP_HTTP_PORT",
          "format": "string",
          "default": "3010",
          "description": "The port to run the HTTP server on."
        },
        {
          "name": "MCP_HTTP_ENDPOINT_PATH",
          "format": "string",
          "default": "/mcp",
          "description": "The endpoint path for the MCP server."
        },
        {
          "name": "MCP_AUTH_MODE",
          "format": "string",
          "default": "none",
          "description": "Authentication mode to use: 'none', 'jwt', or 'oauth'."
        },
        {
          "name": "MCP_LOG_LEVEL",
          "format": "string",
          "default": "info",
          "description": "Sets the minimum log level for output (e.g., 'debug', 'info', 'warn')."
        }
      ]
    }
  ],
  "repository": {
    "url": "https://github.com/cyanheads/brapi-mcp-server",
    "source": "github"
  },
  "description": "Collaborative BrAPI v2.1 MCP workspace: studies, germplasm, genotypes across Breedbase, T3, more."
}