brapi-mcp-server

v0.7.4 pre-1.0

A collaborative BrAPI v2.1 workspace for multi-agent research via MCP. Search studies, germplasm, genotypes, & more - across Breedbase, T3, Sweetpotatobase, & any BrAPI v2-compliant server.

brapi.caseyjhand.com/mcp
claude mcp add --transport http brapi-mcp-server https://brapi.caseyjhand.com/mcp
codex mcp add brapi-mcp-server --url https://brapi.caseyjhand.com/mcp
{
  "mcpServers": {
    "brapi-mcp-server": {
      "url": "https://brapi.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http brapi-mcp-server https://brapi.caseyjhand.com/mcp
{
  "mcpServers": {
    "brapi-mcp-server": {
      "command": "bunx",
      "args": [
        "mcp-remote",
        "https://brapi.caseyjhand.com/mcp"
      ]
    }
  }
}
{
  "mcpServers": {
    "brapi-mcp-server": {
      "type": "http",
      "url": "https://brapi.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://brapi.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

25

read 20

brapi_build_phenotype_matrix

open-world

Pull observations across one or more studies and pivot them into a germplasm × trait matrix materialized as a canvas dataframe. Returns a dataframe handle (query with 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.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_build_phenotype_matrix",
    "arguments": {
      "studies": "<studies>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "studies": {
      "minItems": 1,
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "studyDbIds to include in the matrix. At least one is required — the tool is study-anchored to avoid full-table scans."
    },
    "variables": {
      "description": "Optional subset of observationVariableDbIds to include. Omit to include all variables found in the queried studies.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "germplasm": {
      "description": "Optional subset of germplasmDbIds to include. Omit to include all germplasm found in the queried studies.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "shape": {
      "default": "wide",
      "description": "Matrix shape. `wide` — one row per germplasm, one column per variable, cell = aggregated value. `long` — one row per observation with columns: germplasmDbId, observationVariableDbId, studyDbId, value, replicateIndex. When `aggregate:\"all\"` is combined with `shape:\"wide\"`, the output falls back to long form with a replicateIndex column.",
      "type": "string",
      "enum": [
        "wide",
        "long"
      ]
    },
    "aggregate": {
      "default": "mean",
      "description": "How to aggregate replicate observations (multiple readings of the same variable on the same germplasm). `mean` and `median` attempt numeric conversion and skip non-numeric values (e.g. categorical traits). `first` keeps the first value seen. `all` keeps every replicate as a separate row (produces long-form output even when shape is \"wide\"). Default: `mean`.",
      "type": "string",
      "enum": [
        "mean",
        "median",
        "first",
        "all"
      ]
    },
    "loadLimit": {
      "description": "Cap on rows returned inline. Omit for the deployment default. Rows beyond the cap land in a dataframe; query with brapi_dataframe_query (SQL) instead of paging row-by-row.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "extraFilters": {
      "description": "Extra BrAPI filters forwarded verbatim. Valid keys vary by endpoint; brapi_describe_filters enumerates them. Named params on this tool take precedence on conflict.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "required": [
    "studies",
    "shape",
    "aggregate"
  ],
  "additionalProperties": false
}
view source ↗

brapi_server_info

Return the full orientation envelope for a registered BrAPI connection — server identity, capabilities, content counts, and notes. Re-running refreshes the cached capability scan; pass an alias to read a non-default connection.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_server_info",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias. Omit to read the connection registered under alias `default` — i.e. a prior `brapi_connect` call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "forceRefresh": {
      "default": false,
      "description": "Bypass the cached capability profile and refetch from the server.",
      "type": "boolean"
    }
  },
  "required": [
    "forceRefresh"
  ],
  "additionalProperties": false
}
view source ↗

brapi_describe_filters

List 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.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_describe_filters",
    "arguments": {
      "endpoint": "<endpoint>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "endpoint": {
      "type": "string",
      "enum": [
        "germplasm",
        "images",
        "locations",
        "observations",
        "studies",
        "variables",
        "variants"
      ],
      "description": "BrAPI endpoint to describe filters for."
    }
  },
  "required": [
    "endpoint"
  ],
  "additionalProperties": false
}
view source ↗

brapi_find_studies

open-world

Locate studies matching crop, trial type, season, location, or program. Enriches results with program/trial/location context in one call. When the upstream total exceeds loadLimit, the full result set is materialized as a dataframe — query it with brapi_dataframe_query (SQL).

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_find_studies",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "crop": {
      "description": "Filter by common crop name (single value).",
      "type": "string"
    },
    "trialTypes": {
      "description": "Filter by study types.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "seasons": {
      "description": "Filter by seasons (e.g. \"2022\").",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "locations": {
      "description": "Filter by locationDbIds (server-side identifiers, not display names).",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "programs": {
      "description": "Filter by programDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "trials": {
      "description": "Filter by trialDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "studyNames": {
      "description": "Filter by study display name.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "active": {
      "description": "Restrict to active / inactive studies.",
      "type": "boolean"
    },
    "loadLimit": {
      "description": "Cap on rows returned inline. Omit for the deployment default. Rows beyond the cap land in a dataframe; query with brapi_dataframe_query (SQL) instead of paging row-by-row.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "extraFilters": {
      "description": "Extra BrAPI filters forwarded verbatim. Valid keys vary by endpoint; brapi_describe_filters enumerates them. Named params on this tool take precedence on conflict.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "additionalProperties": false
}
view source ↗

brapi_get_study

Fetch a single study by DbId with program, trial, and location fully resolved. Response includes cheap observation/observation-unit/variable counts as drill-down signals.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_get_study",
    "arguments": {
      "studyDbId": "<studyDbId>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "studyDbId": {
      "type": "string",
      "minLength": 1,
      "description": "Study identifier."
    },
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    }
  },
  "required": [
    "studyDbId"
  ],
  "additionalProperties": false
}
view source ↗

brapi_find_germplasm

open-world

Find germplasm by name, synonym, accession number, PUI, crop, or free-text query. Matches across registered synonyms. When the upstream total exceeds loadLimit, the full result set is materialized as a dataframe — query it with brapi_dataframe_query (SQL) instead of paging row-by-row.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_find_germplasm",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "names": {
      "description": "Filter by germplasm display names.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "germplasmDbIds": {
      "description": "Filter by DbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "germplasmPUIs": {
      "description": "Persistent unique identifiers.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "accessionNumbers": {
      "description": "Filter by accession numbers (gene-bank catalog codes).",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "crops": {
      "description": "Filter by common crop names.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "synonyms": {
      "description": "Match registered synonyms.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "collections": {
      "description": "Filter by germplasm collection names.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "genus": {
      "description": "Botanical genus.",
      "type": "string"
    },
    "species": {
      "description": "Botanical species.",
      "type": "string"
    },
    "text": {
      "description": "Free-text query. Applied client-side as a substring match on returned rows (germplasmName, accessionNumber, defaultDisplayName, registered synonyms) — no BrAPI server reliably supports a server-side free-text filter, so combine with `crops` / `genus` / etc. to narrow the upstream pull first.",
      "type": "string"
    },
    "loadLimit": {
      "description": "Cap on rows returned inline. Omit for the deployment default. Rows beyond the cap land in a dataframe; query with brapi_dataframe_query (SQL) instead of paging row-by-row.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "extraFilters": {
      "description": "Extra BrAPI filters forwarded verbatim. Valid keys vary by endpoint; brapi_describe_filters enumerates them. Named params on this tool take precedence on conflict.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "additionalProperties": false
}
view source ↗

brapi_get_germplasm

Fetch 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.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_get_germplasm",
    "arguments": {
      "germplasmDbId": "<germplasmDbId>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "germplasmDbId": {
      "type": "string",
      "minLength": 1,
      "description": "Germplasm identifier."
    },
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    }
  },
  "required": [
    "germplasmDbId"
  ],
  "additionalProperties": false
}
view source ↗

brapi_walk_pedigree

open-world

Walk germplasm ancestry or descendancy as a deduplicated DAG, with multi-generation traversal, cycle detection, and depth limits. Returns nodes + edges plus traversal stats (depthReached, rootCount, leafCount, cycleCount, deadEndCount).

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_walk_pedigree",
    "arguments": {
      "germplasmDbIds": "<germplasmDbIds>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "germplasmDbIds": {
      "minItems": 1,
      "maxItems": 20,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1
      },
      "description": "Starting germplasm (1–20 roots). All roots are walked concurrently."
    },
    "direction": {
      "default": "ancestors",
      "description": "Which direction to walk: ancestors (parents), descendants (progeny), or both.",
      "type": "string",
      "enum": [
        "ancestors",
        "descendants",
        "both"
      ]
    },
    "maxDepth": {
      "default": 3,
      "description": "Max generations to walk per direction (default 3, cap 10).",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 10
    },
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    }
  },
  "required": [
    "germplasmDbIds",
    "direction",
    "maxDepth"
  ],
  "additionalProperties": false
}
view source ↗

brapi_germplasm_performance

open-world

Aggregate a single germplasm's observations across every study it appears in, returning per-variable summary statistics (n, mean, median, sd, min, max), the contributing studies, and seasons. Study-anchored: discovers the germplasm's studies first (with a dialect-honor cross-check), then pulls observations per study — avoids the unanchored germplasm-only pull that stalls on SGN/Breedbase. For the underlying observation matrix, use brapi_build_phenotype_matrix.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_germplasm_performance",
    "arguments": {
      "germplasmDbId": "<germplasmDbId>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "germplasmDbId": {
      "type": "string",
      "minLength": 1,
      "description": "The germplasmDbId to summarize performance for."
    },
    "variables": {
      "description": "Optional subset of observationVariableDbIds to aggregate. Omit to include every variable observed for the germplasm.",
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  },
  "required": [
    "germplasmDbId"
  ],
  "additionalProperties": false
}
view source ↗

brapi_find_variables

open-world

Find observation variables (traits) by name, trait class, ontology term, or free-text query. Free-text queries are ranked against the returned set and may resolve to ontology URIs when the server advertises them. When the upstream total exceeds loadLimit, the full result set is materialized as a dataframe — query it with brapi_dataframe_query (SQL).

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_find_variables",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "variables": {
      "description": "Filter by observationVariableDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "variableNames": {
      "description": "Filter by exact observationVariableNames.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "variablePUIs": {
      "description": "Filter by persistent ontology URIs.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "traitClasses": {
      "description": "Filter by trait class.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "ontologies": {
      "description": "Filter by ontologyDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "studies": {
      "description": "Filter by studyDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "methods": {
      "description": "Filter by methodDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "scales": {
      "description": "Filter by scaleDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "crop": {
      "description": "Filter by common crop name (single value).",
      "type": "string"
    },
    "text": {
      "description": "Free-text query. Ranks the **full upstream union** (the spilled dataframe when one is produced, otherwise the first page) via the ontology resolver, then fills the in-context window up to loadLimit with matches first and unmatched rows for context. Use exact filters (`variables`, `variableNames`, `variablePUIs`, `traitClasses`, `ontologies`) to actually narrow the upstream pull. Differs from `brapi_find_germplasm.text`, which drops unmatched rows.",
      "type": "string"
    },
    "loadLimit": {
      "description": "Cap on rows returned inline. Omit for the deployment default. Rows beyond the cap land in a dataframe; query with brapi_dataframe_query (SQL) instead of paging row-by-row.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "extraFilters": {
      "description": "Extra BrAPI filters forwarded verbatim. Valid keys vary by endpoint; brapi_describe_filters enumerates them. Named params on this tool take precedence on conflict.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "additionalProperties": false
}
view source ↗

brapi_find_observations

open-world

Pull observation records filtered by study, germplasm, variable, season, or observation unit. When the upstream total exceeds loadLimit, the full result set is materialized as a dataframe — query it with brapi_dataframe_query (SQL).

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_find_observations",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "studies": {
      "description": "Filter by studyDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "germplasm": {
      "description": "Filter by germplasmDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "variables": {
      "description": "Filter by observationVariableDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "observationUnits": {
      "description": "Filter by observationUnitDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "observations": {
      "description": "Filter by observationDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "seasons": {
      "description": "Filter by seasonDbIds (e.g. \"2022\").",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "programs": {
      "description": "Filter by programDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "trials": {
      "description": "Filter by trialDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "observationLevels": {
      "description": "Observation unit level (plot, plant, field, etc.).",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "timestampFrom": {
      "description": "ISO 8601 start of the observation-time window.",
      "type": "string"
    },
    "timestampTo": {
      "description": "ISO 8601 end of the observation-time window.",
      "type": "string"
    },
    "loadLimit": {
      "description": "Cap on rows returned inline. Omit for the deployment default. Rows beyond the cap land in a dataframe; query with brapi_dataframe_query (SQL) instead of paging row-by-row.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "extraFilters": {
      "description": "Extra BrAPI filters forwarded verbatim. Valid keys vary by endpoint; brapi_describe_filters enumerates them. Named params on this tool take precedence on conflict.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "additionalProperties": false
}
view source ↗

brapi_find_images

open-world

Filter 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. When the upstream total exceeds loadLimit, the full result set is materialized as a dataframe — query it with brapi_dataframe_query (SQL).

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_find_images",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "images": {
      "description": "Filter by imageDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "observationUnits": {
      "description": "Filter by observationUnitDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "observations": {
      "description": "Filter by observationDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "studies": {
      "description": "Filter by studyDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "imageFileNames": {
      "description": "Filter by uploaded file name.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "mimeTypes": {
      "description": "Filter by MIME type — e.g. \"image/jpeg\", \"image/png\".",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "descriptiveOntologyTerms": {
      "description": "Filter by ontology tags (e.g. \"CO_334:plot\").",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "loadLimit": {
      "description": "Cap on rows returned inline. Omit for the deployment default. Rows beyond the cap land in a dataframe; query with brapi_dataframe_query (SQL) instead of paging row-by-row.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "extraFilters": {
      "description": "Extra BrAPI filters forwarded verbatim. Valid keys vary by endpoint; brapi_describe_filters enumerates them. Named params on this tool take precedence on conflict.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "additionalProperties": false
}
view source ↗

brapi_get_image

open-world

Fetch 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. No filesystem side-effects.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_get_image",
    "arguments": {
      "imageDbIds": "<imageDbIds>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "imageDbIds": {
      "minItems": 1,
      "maxItems": 5,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1
      },
      "description": "1–5 image identifiers."
    },
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    }
  },
  "required": [
    "imageDbIds"
  ],
  "additionalProperties": false
}
view source ↗

brapi_find_locations

open-world

Find research stations / field sites by country, abbreviation, type, location ID, or free-text. Optional bbox parameter restricts rows to a latitude/longitude window. When the spec-correct GeoJSON [lon, lat, alt] reading produces zero matches and at least one row carries a Point geometry, the bbox filter retries once with axes swapped (handles non-conformant servers that store [lat, lon, alt]) and surfaces a warning + `coordinateAxisOrder: "swapped"`. When the upstream total exceeds loadLimit, the full result set is materialized as a dataframe — query it with brapi_dataframe_query (SQL).

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_find_locations",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "locations": {
      "description": "Filter by locationDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "locationNames": {
      "description": "Filter by display name.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "countryCodes": {
      "description": "ISO 3166-1 alpha-3 country codes.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "locationTypes": {
      "description": "Location type — e.g. \"Research Station\", \"Field\".",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "abbreviations": {
      "description": "Short location abbreviations.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "bbox": {
      "description": "Optional post-fetch bounding box. All four corners must be set to activate the filter.",
      "type": "object",
      "properties": {
        "minLat": {
          "description": "Minimum latitude in WGS84 decimal degrees.",
          "type": "number",
          "minimum": -90,
          "maximum": 90
        },
        "maxLat": {
          "description": "Maximum latitude in WGS84 decimal degrees.",
          "type": "number",
          "minimum": -90,
          "maximum": 90
        },
        "minLon": {
          "description": "Minimum longitude in WGS84 decimal degrees.",
          "type": "number",
          "minimum": -180,
          "maximum": 180
        },
        "maxLon": {
          "description": "Maximum longitude in WGS84 decimal degrees.",
          "type": "number",
          "minimum": -180,
          "maximum": 180
        }
      },
      "additionalProperties": false
    },
    "loadLimit": {
      "description": "Cap on rows returned inline. Omit for the deployment default. Rows beyond the cap land in a dataframe; query with brapi_dataframe_query (SQL) instead of paging row-by-row.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "extraFilters": {
      "description": "Extra BrAPI filters forwarded verbatim. Valid keys vary by endpoint; brapi_describe_filters enumerates them. Named params on this tool take precedence on conflict.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "additionalProperties": false
}
view source ↗

brapi_find_variants

open-world

Find variant records by variant set, reference sequence, or genomic region (start/end, 1-based inclusive / exclusive). When the upstream total exceeds loadLimit, the full result set is materialized as a dataframe — query it with brapi_dataframe_query (SQL).

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_find_variants",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "variantSets": {
      "description": "Filter by variantSetDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "variants": {
      "description": "Filter by variantDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "references": {
      "description": "Filter by referenceDbIds.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "referenceName": {
      "description": "Reference display name (e.g. \"chr01\", \"chr1\").",
      "type": "string"
    },
    "start": {
      "description": "Inclusive 1-based start.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "end": {
      "description": "Exclusive 1-based end.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "loadLimit": {
      "description": "Cap on rows returned inline. Omit for the deployment default. Rows beyond the cap land in a dataframe; query with brapi_dataframe_query (SQL) instead of paging row-by-row.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "extraFilters": {
      "description": "Extra BrAPI filters forwarded verbatim. Valid keys vary by endpoint; brapi_describe_filters enumerates them. Named params on this tool take precedence on conflict.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "additionalProperties": false
}
view source ↗

brapi_find_genotype_calls

open-world

Pull 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 or query the spilled dataframe. `loadLimit` bounds the rows returned inline; the full collected set is materialized as a dataframe — query it with brapi_dataframe_query (SQL) instead of paging row-by-row.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_find_genotype_calls",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "variantSetDbId": {
      "description": "Scope calls to a single variant set. Strongly recommended.",
      "type": "string",
      "minLength": 1
    },
    "variantSetDbIds": {
      "description": "Alternative: multiple variant sets at once.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "germplasmDbIds": {
      "description": "Restrict to these germplasm (call sets).",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "callSetDbIds": {
      "description": "Restrict to these call sets directly.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "variantDbIds": {
      "description": "Restrict to specific variants.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "callFormat": {
      "description": "Requested call-encoding format, when the server honors it.",
      "type": "string",
      "enum": [
        "VCF",
        "FLAPJACK",
        "DARTSEQ",
        "JSON"
      ]
    },
    "loadLimit": {
      "description": "Cap on rows returned inline. Omit for the deployment default. When the collected set exceeds this, the full result lands in a dataframe and only the first `loadLimit` rows return inline — query the dataframe with brapi_dataframe_query (SQL) for the rest. Upstream pageSize is fixed for genotype calls, so this knob only affects the inline preview here (no spillover capacity tradeoff).",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    }
  },
  "additionalProperties": false
}
view source ↗

brapi_export_genotype_matrix

open-world

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). Column names are SQL-safe identifiers; `variantColumnLegend` maps them back to original variant IDs.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_export_genotype_matrix",
    "arguments": {
      "variantSetDbId": "<variantSetDbId>",
      "format": "<format>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "germplasmDbIds": {
      "description": "Restrict to these germplasm. Omit to pull all germplasm in the variant set (use with caution on large sets).",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "variantSetDbId": {
      "type": "string",
      "minLength": 1,
      "description": "Variant set to pull calls for. Required."
    },
    "format": {
      "type": "string",
      "enum": [
        "plink",
        "vcf-lite",
        "matrix-json"
      ],
      "description": "Output format. `matrix-json` registers a wide canvas dataframe only. `vcf-lite` returns VCF-subset text and registers the dataframe. `plink` returns .ped/.map text and registers the dataframe."
    },
    "maxCalls": {
      "description": "Override the deployment-level pull cap (BRAPI_GENOTYPE_CALLS_MAX_PULL). Useful for large panels where the default is too low.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "variantSetDbId",
    "format"
  ],
  "additionalProperties": false
}
view source ↗

brapi_dataframe_describe

Start 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. Listing without a name is unavailable when this server runs as a shared HTTP endpoint without per-caller auth; pass a known name instead.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_dataframe_describe",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "dataframe": {
      "description": "When set, return only the named dataframe. Omit to list all dataframes.",
      "type": "string",
      "minLength": 1
    }
  },
  "additionalProperties": false
}
view source ↗

brapi_raw_get

open-world

Passthrough to any BrAPI GET /{path} endpoint. Returns the raw upstream envelope without enrichment or foreign-key resolution. Emits a `suggestion` field when a curated tool exists for the same data. Spills to a canvas dataframe when the upstream advertises more rows than `loadLimit` AND the result is a list shape (`result` array or `result.data` envelope); inline `result` is unchanged. Skips spillover when the caller drives paging via `params.page` / `params.pageSize`.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_raw_get",
    "arguments": {
      "path": "<path>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "path": {
      "type": "string",
      "minLength": 1,
      "description": "Endpoint path — e.g. \"/samples\", \"/methods\". Leading \"/\" is optional."
    },
    "params": {
      "description": "Query parameters to append. Arrays are repeated per BrAPI convention.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {
        "anyOf": [
          {
            "type": "string"
          },
          {
            "type": "number"
          },
          {
            "type": "boolean"
          },
          {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "number"
                }
              ]
            }
          }
        ]
      }
    },
    "loadLimit": {
      "description": "Cap on rows returned inline. Omit for the deployment default. Rows beyond the cap land in a dataframe; query with brapi_dataframe_query (SQL) instead of paging row-by-row.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "path"
  ],
  "additionalProperties": false
}
view source ↗

write 2

brapi_connect

open-world

Open a connection to a BrAPI v2 server, authenticate, and return the full orientation envelope (server identity, capability profile, content summary). Required handshake before other BrAPI tools. Supports multiple concurrent connections via named aliases. Credentials can be configured server-side and omitted from this call. Built-in known servers (callable with no `baseUrl` or `auth` — public BrAPI v2 endpoints): `bti-breedbase-demo`, `bti-cassava`, `bti-sweetpotato`, `t3-barley`, `t3-oat`, `t3-wheat`. 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.

write
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_connect",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "baseUrl": {
      "description": "BrAPI v2 base URL (absolute URL) including any path prefix — e.g. https://test-server.brapi.org/brapi/v2. Omit to use the configured default for this alias.",
      "type": "string"
    },
    "auth": {
      "description": "Auth payload. Omit to use credentials configured server-side for this alias (or no auth when none are configured).",
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "mode": {
              "type": "string",
              "const": "none",
              "description": "No authentication."
            }
          },
          "required": [
            "mode"
          ],
          "additionalProperties": false,
          "description": "No-auth variant — public BrAPI endpoints."
        },
        {
          "type": "object",
          "properties": {
            "mode": {
              "type": "string",
              "const": "bearer",
              "description": "Pre-obtained bearer token."
            },
            "token": {
              "type": "string",
              "minLength": 1,
              "description": "Pre-obtained access token, sent verbatim with each BrAPI request."
            }
          },
          "required": [
            "mode",
            "token"
          ],
          "additionalProperties": false,
          "description": "Bearer-token variant — caller already has an access token."
        },
        {
          "type": "object",
          "properties": {
            "mode": {
              "type": "string",
              "const": "api_key",
              "description": "Static API key in a custom header."
            },
            "apiKey": {
              "type": "string",
              "minLength": 1,
              "description": "API key issued by the BrAPI server."
            },
            "headerName": {
              "description": "HTTP header to send the API key in. Defaults to `Authorization`.",
              "type": "string"
            }
          },
          "required": [
            "mode",
            "apiKey"
          ],
          "additionalProperties": false,
          "description": "API-key variant — static key sent in a configurable header."
        },
        {
          "type": "object",
          "properties": {
            "mode": {
              "type": "string",
              "const": "sgn",
              "description": "Breedbase/SGN username+password; exchanged for a bearer token at /token."
            },
            "username": {
              "type": "string",
              "minLength": 1,
              "description": "SGN account username."
            },
            "password": {
              "type": "string",
              "minLength": 1,
              "description": "Password for the SGN/Breedbase username supplied above."
            }
          },
          "required": [
            "mode",
            "username",
            "password"
          ],
          "additionalProperties": false,
          "description": "SGN variant — username/password exchanged at /token for a session bearer."
        },
        {
          "type": "object",
          "properties": {
            "mode": {
              "type": "string",
              "const": "oauth2",
              "description": "OAuth2 client-credentials flow; exchanged for an access token at connect time."
            },
            "clientId": {
              "type": "string",
              "minLength": 1,
              "description": "OAuth2 client identifier registered with the upstream IdP."
            },
            "clientSecret": {
              "type": "string",
              "minLength": 1,
              "description": "OAuth2 client secret paired with the clientId."
            },
            "tokenUrl": {
              "description": "OAuth2 token endpoint (absolute URL). Defaults derived from the base URL when omitted.",
              "type": "string"
            }
          },
          "required": [
            "mode",
            "clientId",
            "clientSecret"
          ],
          "additionalProperties": false,
          "description": "OAuth2 client-credentials variant."
        }
      ]
    },
    "alias": {
      "default": "default",
      "description": "Alias for this connection. Use distinct aliases to register multiple BrAPI servers in one session.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    }
  },
  "required": [
    "alias"
  ],
  "additionalProperties": false
}
view source ↗

brapi_dataframe_query

Run 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.

write
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "brapi_dataframe_query",
    "arguments": {
      "sql": "<sql>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "sql": {
      "type": "string",
      "minLength": 1,
      "description": "SELECT statement against dataframes. Single statement only — writes, DDL, file reads, and exports are rejected. Use brapi_dataframe_describe to discover available dataframes. SQL is the primary paging idiom: use `LIMIT/OFFSET` to walk a large dataframe, projection to trim columns, and aggregation (`COUNT`, `GROUP BY`, `AVG`) to summarize without materializing every row."
    },
    "registerAs": {
      "description": "Persist the result as a new dataframe under this name. The response still returns at most `preview` rows; the full result remains queryable as a new dataframe. Conflicts with an existing dataframe name fail — drop first via brapi_dataframe_drop. Identifier rules: letters, digits, and underscores; must start with a letter or underscore; max 63 characters.",
      "type": "string",
      "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,62}$"
    },
    "preview": {
      "description": "Cap the number of rows returned in this response (1–1000). When omitted, the deployment-wide response cap applies. Lower this with `registerAs` when you only need a sample to verify the query.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 1000
    },
    "rowLimit": {
      "description": "Hard cap on rows materialized into the response, bounded by the deployment-wide response cap. For larger result sets, use `registerAs` to keep the full result queryable instead of raising this.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    }
  },
  "required": [
    "sql"
  ],
  "additionalProperties": false
}
view source ↗

disabled 3

brapi_dataframe_drop

Drop a dataframe by name. Idempotent — returns dropped:false rather than failing when the name is unknown. Dataframes also expire via TTL automatically; explicit drop is only needed when the operator wants to free workspace memory immediately.

disabledwould be write

Disabled. Dataframe drop is gated off (BRAPI_CANVAS_DROP_ENABLED=false).

Set BRAPI_CANVAS_DROP_ENABLED=true to enable explicit drop. Dataframes also expire via TTL when left unmanaged.
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "dataframe": {
      "type": "string",
      "minLength": 1,
      "description": "Dataframe to drop. Use brapi_dataframe_describe to discover names. Returns dropped:false (no error) when the name is unknown."
    }
  },
  "required": [
    "dataframe"
  ],
  "additionalProperties": false
}
view source ↗

brapi_dataframe_export

Export a dataframe to disk (CSV, Parquet, or JSON) under BRAPI_EXPORT_DIR and return the absolute path of a file the human can open in Excel, Tad, DuckDB CLI, etc. Source dataframes are immutable after spillover, so re-exporting the same df_<uuid> is byte-stable. Use `columns` for thin projection or `sql` for filtering/aggregation; for repeated derived views, query with registerAs first then export the derived dataframe.

disabledwould be write

Disabled. Dataframe export requires stdio transport.

File paths must resolve on the same machine as the user — run the server with MCP_TRANSPORT_TYPE=stdio to enable.
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "dataframe": {
      "type": "string",
      "minLength": 1,
      "description": "Dataframe to export. Use brapi_dataframe_describe to discover names. Source identity for the export — paired-drop cleanup keys off this name when brapi_dataframe_drop later removes it."
    },
    "format": {
      "type": "string",
      "enum": [
        "csv",
        "parquet",
        "json"
      ],
      "description": "Output format. CSV opens in Excel / Tad; Parquet preserves typed columns and is small on disk; JSON is line-delimited."
    },
    "filename": {
      "description": "Optional filename inside BRAPI_EXPORT_DIR. Path separators (\"/\", \"\\\") and \"..\" segments are rejected. Re-using a name overwrites the existing file. Omit to get a timestamp-suffixed default that never collides.",
      "type": "string",
      "minLength": 1
    },
    "columns": {
      "description": "Optional thin projection — exports only these columns. Mutually exclusive with `sql`. For filtering or aggregation, run brapi_dataframe_query with registerAs first, then export that derived dataframe.",
      "minItems": 1,
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,62}$",
        "description": "Column name to project — letters, digits, underscores; must start with a letter or underscore; max 63 chars."
      }
    },
    "sql": {
      "description": "Optional SELECT statement that defines what to export — same SQL gate as brapi_dataframe_query (SELECT only, single statement, plan-walk allowlist). Mutually exclusive with `columns`. The dataframe input still identifies the source for paired-drop cleanup.",
      "type": "string",
      "minLength": 1
    }
  },
  "required": [
    "dataframe",
    "format"
  ],
  "additionalProperties": false
}
view source ↗

brapi_submit_observations

open-world

Submit observations for a study. Default mode `preview` validates rows against the study variables and returns a routing breakdown without writing. Mode `apply` elicits confirmation when supported, then creates new rows or updates existing ones based on observationDbId presence. Additive only — no observation is destroyed.

disabledwould be write
scope observations

Disabled. Writes are disabled (BRAPI_ENABLE_WRITES=false).

Set BRAPI_ENABLE_WRITES=true to enable observation submission.
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "alias": {
      "description": "Connection alias registered via brapi_connect. Omit to read the connection registered under alias `default` — i.e. a prior brapi_connect call that did not specify an alias. Calls that used a non-default alias must pass that same alias here.",
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "studyDbId": {
      "type": "string",
      "minLength": 1,
      "description": "Study the observations are submitted against."
    },
    "observations": {
      "minItems": 1,
      "maxItems": 5000,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "observationDbId": {
            "description": "Server-assigned identifier of an existing observation. When present, the row updates that observation; when absent, the row creates a new one.",
            "type": "string",
            "minLength": 1
          },
          "observationUnitDbId": {
            "type": "string",
            "minLength": 1,
            "description": "FK to the observation unit (plot / plant / sample) the value applies to. Required."
          },
          "observationVariableDbId": {
            "type": "string",
            "minLength": 1,
            "description": "FK to the observation variable (trait) being measured. Required."
          },
          "value": {
            "type": "string",
            "description": "Recorded measurement value, stringified per BrAPI convention. Empty strings are flagged as warnings."
          },
          "collector": {
            "description": "Name or ID of the person who collected the value.",
            "type": "string"
          },
          "observationTimeStamp": {
            "description": "ISO 8601 timestamp the observation was taken.",
            "type": "string"
          },
          "season": {
            "description": "Season block. Most servers tolerate either seasonDbId or year+label.",
            "type": "object",
            "properties": {
              "seasonDbId": {
                "description": "Server-side season identifier.",
                "type": "string"
              },
              "year": {
                "description": "Calendar year (e.g. \"2024\").",
                "type": "string"
              },
              "season": {
                "description": "Season label (e.g. \"wet\", \"dry\", \"Q1\").",
                "type": "string"
              }
            },
            "additionalProperties": false
          },
          "geoCoordinates": {
            "description": "Optional GeoJSON Feature carrying lon/lat for this observation.",
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "const": "Feature",
                "description": "GeoJSON feature type (always \"Feature\")."
              },
              "geometry": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "Point",
                    "description": "GeoJSON geometry type (always \"Point\")."
                  },
                  "coordinates": {
                    "minItems": 2,
                    "maxItems": 2,
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "description": "[longitude, latitude] in WGS84 decimal degrees."
                  }
                },
                "required": [
                  "type",
                  "coordinates"
                ],
                "additionalProperties": false,
                "description": "GeoJSON point geometry."
              }
            },
            "required": [
              "type",
              "geometry"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "observationUnitDbId",
          "observationVariableDbId",
          "value"
        ],
        "additionalProperties": false,
        "description": "One observation row. observationDbId presence routes to PUT vs POST."
      },
      "description": "1 – 5000 observation rows. Mixed POST + PUT routing is supported."
    },
    "mode": {
      "default": "preview",
      "description": "`preview` (default) validates only; `apply` writes after eliciting confirmation when supported.",
      "type": "string",
      "enum": [
        "preview",
        "apply"
      ]
    },
    "force": {
      "default": false,
      "description": "Bypass elicitation in apply mode. Use only when the client lacks ctx.elicit support and explicit user authorization for the write has been recorded out-of-band.",
      "type": "boolean"
    }
  },
  "required": [
    "studyDbId",
    "observations",
    "mode",
    "force"
  ],
  "additionalProperties": false
}
view source ↗

Resources

6

Orientation envelope for the default BrAPI connection — identity, capabilities, content counts, notes. Same payload as the brapi_server_info tool.

uri brapi://server/info mime application/json

Capability profile for the default BrAPI connection — supported services, their HTTP methods, declared versions, and crops list. Mirrors what /serverinfo + /calls returned at the last load.

uri brapi://calls mime application/json

Single-study resource on the default BrAPI connection — same payload as the brapi_get_study tool, addressable by URI.

uri brapi://study/{studyDbId} mime application/json

Single-germplasm resource on the default BrAPI connection — same payload as the brapi_get_germplasm tool, addressable by URI.

uri brapi://germplasm/{germplasmDbId} mime application/json

Single observation-variable resource on the default BrAPI connection — the canonical /variables/{id} record (trait, scale, method, ontology), addressable by URI. The single-record equivalent of brapi_find_variables.

uri brapi://variable/{observationVariableDbId} mime application/json

BrAPI filter catalog for a single endpoint (name, type, description, example per filter). Mirrors the brapi_describe_filters tool.

uri brapi://filters/{endpoint} mime application/json

Prompts

2

Run an exploratory-data-analysis pass over a single BrAPI study — structure, variables, coverage, outliers, missing data — using the curated brapi_* tools.

  • studyDbIdrequired — Target studyDbId. Locate via brapi_find_studies if unknown.
  • alias — Connection alias registered via brapi_connect. Omit to use the default connection.

Run a cross-study meta-analysis on a germplasm × trait combination — resolve trait, find studies, pull observations, harmonize scales, summarize across studies.

  • germplasmDbIdsrequired — Comma-separated germplasmDbIds (e.g. "germplasm-1,germplasm-2"). The meta-analysis will collect every observation of the target trait on these germplasm across all reachable studies.
  • traitNamerequired — Target trait name or free-text query — e.g. "dry matter content", "Plant height". Resolved to one or more observation variables via brapi_find_variables.
  • alias — Connection alias registered via brapi_connect. Omit to use the default connection. For multi-server meta-analyses, run this prompt once per registered alias and merge.