API and data

A read-only JSON API over the same engine that renders the pages, a Python client, and an MCP server for AI agents. No key is needed. Field names may change between snapshots.

A first request

GET /api/claims?q=drought&pageSize=1

Every response says what it is

Responses carry human_reviewed, abstract_display and the data_sha256 of the snapshot, so a client can tell which snapshot it is reading.

{
  "human_reviewed": 0,
  "abstract_display": "all_public",
  "data_sha256": "9d9680926d1bfc948c6b3f235c0575e6630535abdf000e01b4a56e3ff26820f6"
}

Endpoints

  • GET/api/claimsSearch claims. Same parameters and ranking as the Search page.
  • GET/api/claims/{id}One claim with its paper record.
  • GET/api/papersSearch papers (scope judgment included).
  • GET/api/papers/{id}One paper, the block text the model read, and its claims.
  • GET/api/facetsBrowse trees and the vocabulary of every filter.
  • GET/api/statsCounters, distributions, fill rates, first-pass checks. /api/corpus/stats is an alias.
  • POST/mcpModel Context Protocol server for AI agents (see below).

Search parameters

Lexical BM25. All words must match; when no document holds them all, documents with any of the words are returned and match = "any_term". A DOI, DOI URL, OpenAlex id or claim id typed as q resolves directly (match = "identifier"). In the claims scope, a phrase of q that names an organism of the taxa layer — a spelling the layer placed on one NCBI taxon, or a backbone name of a taxon, its species or its genus — also matches the claims whose taxon or interactor lies in that species (subspecies, varieties, formae speciales and pathovars included — unlike the interacting view, which lists those separately), in that genus, or, for a name above the genus such as Fungi, on that very taxon; the response lists them in organisms with their rank.

qFree text, at most 300 characters; or a DOI / OpenAlex id / claim id.
kind, bucket, pol, stat, es, origin, roleClaim filters; values from /api/facets → vocab.
taxon, gene, interactorKey of a verbatim browse entry (from /api/facets → views).
decade, oa=1, doi=1, paperFilters on the claim’s paper.
label, reason, statusPaper search only.
groupClaims only: none | kind | bucket | taxon | decade | paper. Groups are paged; each carries its first 3 claims.
sortrelevance | newest | oldest | cited (citation count of the paper in the OpenAlex snapshot).
page, pageSizepageSize ≤ 100; default 10 for claims, 25 for papers.
curl '/api/claims?q=drought&kind=observation&sort=newest&pageSize=5'

Python client

The plantclaims package wraps the endpoints in functions and returns their JSON unchanged. It needs Python 3.8 or later and nothing beyond the standard library.

pip install https://plantclaims.org/sdk/plantclaims-0.1.1-py3-none-any.whl
import plantclaims

hits = plantclaims.search_claims("wheat stripe rust resistance", page_size=5)
for hit in hits["results"]:
    print(hit["claim"]["statement"], hit["paper"]["doi"])

# every matching claim, page after page
for hit in plantclaims.iter_claims("Fusarium head blight", stat="significant", limit=200):
    ...

paper = plantclaims.get_paper("W2945897111")   # or a DOI
vocab = plantclaims.facets()["vocab"]         # the values every filter accepts

MCP server for AI agents

POST /mcp speaks the Model Context Protocol (Streamable HTTP), so an AI assistant searches PlantClaims while it answers. It runs the same search as this site and the API. No key is needed and every tool is read-only.

https://plantclaims.org/mcp
search_claimsClaims ranked as on the Search page, with filters for kind, polarity, statistics, origin, research area and decade.
get_claimOne claim: every field, the evidence quotes and its paper.
search_papersPapers with their scope label and number of claims.
get_paperOne paper by OpenAlex id or DOI: metadata, abstract and claims.
list_filtersThe values each filter accepts.
statsSize of the dataset and the snapshot hash.

Claude Code

claude mcp add --transport http plantclaims https://plantclaims.org/mcp

Claude.ai and Claude Desktop

Settings → Connectors → Add custom connector, with the URL above.

Cursor and other clients

{
  "mcpServers": {
    "plantclaims": {
      "url": "https://plantclaims.org/mcp"
    }
  }
}

Every answer marks the claims as candidates extracted by a language model and gives the quote, the paper DOI and the claim URL to cite.

Claim object

{
  "basis": "measured",
  "buckets": [
    "B6"
  ],
  "dir_inf": false,
  "es": "observed",
  "ev": [
    {
      "block": "abstract",
      "end": 456,
      "id": "e0",
      "match": "exact_raw",
      "quote": "A total of 80 useful plants belonging to 45 families and 69 genera were collected from 20 randomly selected agroforestry plots",
      "start": 330
    }
  ],
  "fields": {
    "outcome": {
      "ev": [
        "e0"
      ],
      "v": "80 useful plants belonging to 45 families and 69 genera"
    },
    "setting": {
      "ev": [
        "e0"
      ],
      "v": "20 randomly selected agroforestry plots"
    },
    "taxon": {
      "ev": [
        "e0"
      ],
      "v": "useful plants"
    }
  },
  "id": "claim-7cf07de1a324da14",
  "kind": "observation",
  "missing": {},
  "origin": "original_result",
  "paper": "W1422251141",
  "pol": "not_applicable",
  "pos": 0,
  "rev": "rev-7cf07de1a324da142c526929065cfac0554915f17e7f08a3336c905d1d0ef327",
  "rsr": null,
  "schema": "claims-v0.9",
  "stat": "not_reported",
  "statement": "A total of 80 useful plants belonging to 45 families and 69 genera were collected from 20 randomly selected agroforestry plots.",
  "tax": {
    "taxon": {
      "ids": [],
      "src": "program",
      "st": "unresolved"
    }
  }
}

Paper object

{
  "abstract_chars": 615,
  "answered_by": "claude-sonnet-5-5",
  "attempt": 1,
  "author_ids": [
    "A5015148354",
    "A5027681900",
    "A5108350097"
  ],
  "authors": [
    "Sourabh Deb",
    "A. Arunachalam",
    "AK Das"
  ],
  "channel": "interactive",
  "cited_by": 33,
  "claims": {
    "accepted": 4,
    "proposed": 4,
    "quarantined": 0,
    "review": 0
  },
  "cleaning": "clean-v0.1",
  "doi": null,
  "era": "y2000_09",
  "funders_n": 0,
  "group": "Forestry",
  "id": "W1422251141",
  "j": {
    "buckets": [
      "B6"
    ],
    "buckets_source": "union_of_accepted_claims_excluding_cited_background",
    "input_issues": [],
    "label": "core",
    "missing_reason": null,
    "next_action": "human_review",
    "question": "which plants are used for food, medicine and other purposes in traditional agroforests",
    "rationale": "Ethnobotanical survey of useful plants in traditional agroforests of the Nyishi community.",
    "reason": "direct_plant_research",
    "subject": "useful plants of Nyishi agroforestry plots"
  },
  "language": "en",
  "n_authors": 3,
  "oa": {
    "display": "source_link_only",
    "is_oa": true,
    "license": "cc-by-nc-nd",
    "status": "green"
  },
  "pmid": null,
  "schema": "claims-v0.9",
  "status": "claims_extracted",
  "subfield": "Forestry",
  "title": "Indigenous knowledge of Nyishi tribes on traditional agroforestry systems",
  "topic": "African Botany and Ecology Studies",
  "type": "article",
  "url": "http://nopr.niscair.res.in/bitstream/123456789/2973/1/IJTK%208%281%29%2041-46.pdf",
  "venue": "Indian Journal of Traditional Knowledge",
  "year": 2009,
  "year_suspect": false
}

Text and offsets

Evidence start/end are Unicode code-point offsets into the block text returned by /api/papers/{id} (text.title, text.abstract). That text is exactly what the model read and may contain literal tags and entities such as <i> or &lt;; the API returns it unchanged, the pages render the inline markup. When the snapshot is exported as licensed_only, text.abstract is null unless the paper’s licence allows display; quotes are always present.

Normalised organisms

claim.tax[field] (field = taxon, interactor or interactor_2 — the second interacting organism of claims-v0.8) holds the NCBI Taxonomy ids the field value was matched to (ids; a list value has several), the match status (st: resolved, partly_resolved, unresolved, none) and its source (src: program = exact-name rules, judge = the judging model for what the rules left). sp lists judged species names that NCBI Taxonomy lacks — the ids then hold the genus; txt lists names not placed. /api/facets vocab.taxa gives name, rank, group, family and genus per id, plus common (the common name shown: the NCBI common name the claims write most, else GenBank's) and syn (NCBI scientific synonyms, searchable); taxon nodes list written (other spellings the claims used); the views organism and interacting have three levels — the group (plant, fungus, oomycete, bacterium, archaeon, virus, animal, other), the family (its taxid, or unranked) and the taxon by id — and search accepts organism_group / organism_family / organism and interacting_group / interacting_family / interacting. The organism view files a subspecies, variety or cultivar group under its species (node.sub lists them); the interacting view keeps every taxon as it is. The literal values in fields are unchanged.

Normalised genes

claim.gen.gene lists the parts of the gene value in order (a list value has several). Each part has l (label: the symbol, without a species prefix the program verified), t (type: gene, symbol, qtl_marker, gene_family, sequence_feature, untyped), st (status: resolved = one NCBI Gene entry of that symbol in the species; ambiguous = several; placed = no entry, grouped by the symbol; typed / untyped / no_organism = no gene entry) and, for parts placed on a gene, sp (NCBI Taxonomy id of the species or organism) and k (the entry key of /browse/genes/{sp}/{k}); id is the NCBI Gene id when resolved; w is the part as written when it differs from l. The species comes from the claim's normalised organism. Placement is by program rules only; nobody has reviewed it.

Numbers and units

claim.vx is the exporter's reading of the value field (the literal stays in fields.value.v): n lists the magnitudes in order, u the unit as written, shape says single, range, list, mean_sd (sd holds the spread written after ±) or unparsed; approx marks a hedge such as "about" or "up to", extra marks a literal that says more than a magnitude (a cultivar name, "of the total"). From the claims-v0.7 schema on there is no separate unit field: the model writes the value with its unit and this reading separates them. It is a program's reading, not checked by a person.

Chemical entities

A part of the gene value that the gene rules could not place and whose name matches ChEBI (the Chemical Entities of Biological Interest database) has t = metabolite or compound_class (a ChEBI entity without a molecular formula, such as flavonoid), k = the entry key of /browse/compounds/{k} and, when one entity matched, c = its ChEBI id; no sp, because a compound is not tied to a species. ChEBI data are licensed under CC BY 4.0; the ChEBI name, URL and release are credited in the footer.

Scientific names

it holds [start, end) code-point spans of scientific names (genus rank and below) that the exporter recognised in a text by matching it against NCBI Taxonomy: paper.it for the title, claim.it.st for the statement, claim.it.ev[evidence id] for each quote, claim.it.f[field] for a field value, and text.it.title / text.it.abstract for the blocks of /api/papers/{id}. The pages set these spans in italics; the API leaves the text unchanged. Rank words, authorities and the hybrid sign are outside the spans; a genus on its own is included only when the paper’s texts or its claims’ normalised organisms corroborate it. A mechanical display annotation, recomputed at every export (manifest latin_names names the rules and the pinned index).

Errors

400 with {"error": "…"} for an unknown filter value or a page out of range; 404 for an unknown id. Results are empty, not an error, when nothing matches.