Plant genomics MCP provides Model Context Protocol access to plant-genomics locus lookup and related analysis. It exposes 50 tools across 23 backends, supporting multiple query types including single-locus lookup, motifs, regions, variants, enrichment, and BLAST search, plus batch and cross-source synthesis.
🛠️ Key Features
50 tools across 23 backends
28 single-locus lookup tools
1 motif lookup, 1 region query
1 variant annotator
1 gene-set enrichment
1 BLAST search
12 parallel-batch tools
5 cross-source synthesis variants
🚀 Use Cases
Look up plant-genomics loci
Query genomic features by motifs or regions
Annotate variants and perform gene-set enrichment
Run BLAST searches
Execute parallel batch workflows
Combine results via cross-source synthesis
⚡ Developer Benefits
Integrates free, public sources: Ensembl Plants, Phytozome BioMart, UniProtKB, Europe PMC, QuickGO, Planteome, PlantCyc/PMN, g:Profiler, NCBI BLAST, Gramene, JASPAR, KEGG, STRING-DB, ATTED-II, ThaleMine, and BAR (Bio-Analytic Resource for Plant Biology)
⚠️ Limitations
Scope is limited to plant genomics locus lookup and the listed query/analysis types.
# Zero-install — uv fetches and runs it on demand
claude mcp add plant-genomics --scope local -- uvx plant-genomics-mcp
Other install paths (pipx, Docker, from source)
bash
# pipx — installs the CLI onto your PATH
pipx install plant-genomics-mcp
claude mcp add plant-genomics --scope local -- plant-genomics-mcp
# GHCR Docker image
docker pull ghcr.io/musharna/plant-genomics-mcp:latest
claude mcp add plant-genomics --scope local -- \
docker run --rm -i ghcr.io/musharna/plant-genomics-mcp:latest
# From source
git clone https://github.com/musharna/plant-genomics-mcp.git
cd plant-genomics-mcp
python -m venv .venv && .venv/bin/pip install -e .
claude mcp add plant-genomics --scope local -- "$(pwd)/.venv/bin/plant-genomics-mcp"
💬 Try it
Once connected, ask Claude a plain-language question — you don't have to
name any tool or remember the chain:
"Tell me everything about the Arabidopsis gene AT1G01010 — its
function, GO terms, KEGG pathways, protein-interaction partners, and
recent papers."
The server supplies the tools (here: Ensembl Plants, UniProt, QuickGO, KEGG,
STRING-DB and Europe PMC lookups); which ones get called, in what order and in
how many turns is up to the client. In the recording at the top of this page
(a narrower prompt), Claude Code picked the calls itself and returned one
combined answer. Swap in any locus and pass organism= for cross-species —
e.g. rice Os01g0100100 (oryza_sativa) — and each tool maps the organism to
that backend's own identifier.
A worked 64-call run over 114 genes in three organisms, with the 51 gaps it logged (39 since closed), is in examples/arf_family/PAGE.md.
🛠️ Tools
56 tools across 23 backends — Ensembl Plants, Phytozome BioMart,
UniProtKB, Europe PMC, QuickGO, Planteome, PlantCyc/PMN, g:Profiler,
AlphaFold DB, PDBe, InterPro, JASPAR, PANTHER, OrthoDB, AraGWAS, 1001 Genomes, NCBI BLAST,
Gramene, KEGG, STRING-DB, ATTED-II, ThaleMine, BAR.
29 single-locus + 1 motif lookup + 1 region query + 1 assembly listing + 1 release report + 1 variant annotator + 1 gene-set
enrichment + 1 BLAST search + 2 member lists + 13 parallel-batch + 5 cross-source synthesis. Most take a
TAIR-style locus (e.g. AT1G01010) plus
optional organism= (slug / scientific name / common name / NCBI taxid
— 12-plant curated coverage matrix at the pgmcp://organisms/coverage
MCP resource). All publish JSON outputSchema, EDAM ontology tags, and
behaviour annotations — every tool is readOnlyHint + openWorldHint, so
hosts can surface them without a destructive-action confirmation prompt.
Full tool matrix
#
Category
Tool
What it does
1
Gene metadata (live)
ensembl_plants_lookup_locus
Fetches gene record from Ensembl Plants REST (any plant species).
Fetches STRING-DB first-neighbor interaction partners with per-channel score.
11
Coexpression (live)
atted_coexpression
Fetches ATTED-II top-N coexpression neighbors with a score: z-score for Arabidopsis, logit score (LSmr) for the other releases.
12
Curator summary (live)
bar_gene_summary
Fetches BAR ThaleMine + GAIA-aliases curator summary for an Arabidopsis locus.
13
Expression (live)
bar_efp_expression
Fetches BAR eFP-Browser expression profile (mean ± SD per tissue) for a locus.
14
Interactions (live)
bar_aiv_interactions
Fetches BAR AIV interaction partners (Arabidopsis + rice) with confidence + papers.
15
Curator summary (live)
tair_locus_info
Silent upgrade — alias of bar_gene_summary. MCP tool name preserved for clients.
16
Metabolism (live)
plantcyc_locus_info
Walks gene → enzyme → reactions → PlantCyc/PMN pathways (free BioCyc web-services API). The metabolic-pathway view KEGG/GO lack; found=false for non-enzymatic genes. 11 species have a PGDB.
17
Sequence (live)
get_sequence
Fetches a locus's sequence (genomic / cds / cdna / protein) from Ensembl /sequence/id — the fetch half of lookup → fetch → BLAST; feed sequence to blast_sequence.
18
Region query (live)
ensembl_region_query
Lists gene/transcript/cds/exon features overlapping a genomic interval (chr:start-end) via Ensembl /overlap/region — "what's in this QTL interval" without a per-locus lookup.
19
Enrichment (live)
go_enrichment
GO + KEGG over-representation for a gene list via g:Profiler g:GOSt — "what is my DE / co-expression set enriched for?" Reports unmapped loci; optional custom background. All 12 organisms.
20
Plant ontology (live)
locus_plant_ontology
Plant Ontology (anatomy / dev-stage) + Trait Ontology annotations for a locus via Planteome (Solr) — the plant-specific ontologies GO doesn't cover. by_ontology rollup; taxon-filtered. Strong for 6 species.
21
Structure (live)
alphafold_structure
AlphaFold DB predicted 3D model for a locus (locus → UniProt → model): global mean pLDDT, per-band confidence, modelled span, and mmCIF / PDB / PAE URLs. found=false when no model is deposited. All 12 organisms.
22
Structure (live)
experimental_structures
PDBe experimentally-solved (X-ray / cryo-EM / NMR) structures for a locus (locus → UniProt): best-first PDB id, chain, method, resolution, coverage, residue span. found=false when none deposited (common for plants). All 12 organisms.
23
Domains (live)
interpro_domains
InterPro domain / family architecture (locus → UniProt): each entry's accession, name, type, source_database (Pfam included), integrated InterPro id, and residue spans, plus a count_by_type rollup. All 12 organisms.
24
TF motifs (live)
tf_binding_motifs
JASPAR curated TF DNA-binding profiles for a locus (locus → UniProt → symbol search, then UniProt-confirmed): matrix id, TF class/family, assay type (SELEX / ChIP-seq / PBM / DAP-seq), IUPAC consensus, PubMed refs, logo URL. Fuzzy name hits for other genes are quarantined in name_only_matches. Arabidopsis-heavy coverage.
25
TF motifs (live)
jaspar_motif
One JASPAR profile by matrix id (e.g. MA0570.1, or MA0570 for the newest version) including the raw position-frequency matrix — the drill-down companion to tf_binding_motifs.
26
Interactions (live)
experimental_interactions
ThaleMine CURATED EXPERIMENTAL interaction partners (BioGRID / IntAct / PSI-MI) for an Arabidopsis locus — per partner: detection method (two hybrid, pull down, ...), PSI-MI relationship type, physical vs genetic, source DB, PubMed IDs, and an evidence count. The experimental counterpart to string_interactions (predicted / text-mined). Arabidopsis only.
27
Function (live)
locus_gene_rifs
ThaleMine curated GeneRIF statements — one-sentence, manually curated descriptions of what the gene does, each tied to a PubMed ID (HY5 has 114). Citable functional context that GO terms and raw abstracts don't provide. Arabidopsis only.
28
Variation (live)
locus_variants
Natural (EVA/dbSNP) variants overlapping a locus's genomic span via Ensembl /overlap/region — id, source, consequence class, alleles, clinical significance. variant_count + truncated. All 12 organisms.
29
Variation (live)
vep_annotate
Ensembl VEP consequence prediction for a variant (region + allele, not locus) — most-severe consequence + per-transcript SO terms, IMPACT, SIFT. All 12 organisms.
30
Orthology (live)
panther_family
PANTHER protein family + subfamily (id + name), GO terms by aspect, protein class, and pathways. found=false when unmapped. All 12 organisms.
31
Orthology (live)
orthodb_orthologs
OrthoDB ortholog group (name, evolutionary rate) + cross-species member genes at the Viridiplantae level. organism_count + truncated. All 12 organisms.
32
Diversity (live)
aragwas_associations
AraGWAS genome-wide association hits per locus — score, MAF, SNP effect, phenotype/study. Arabidopsis-only.
33
Diversity (live)
arabidopsis_natural_variation
1001 Genomes natural-variation SNP effects across 1135 accessions — chr, position, effect, impact, amino-acid change, transcript + gene span. Arabidopsis-only.
34
Batch (live)
batch_* (twelve dedicated variants)
Parallel per-locus fanout for tools 1–6, 8–12, 14. Up to 50 loci per call.
35
Batch (live)
batch_locus_call
Runs any tool whose only required argument is locus (33 tools, including gene_report and the synthesis tools) over up to 50 loci; the shared args are checked against that tool's schema once, before any call.
36
Synthesis (live)
*_synth / consensus_homologs (four)
Compose 2–5 backends in parallel, return a SynthesisEnvelope with per-step status.
37
Synthesis (live)
gene_report
One-shot "tell me about this gene" dossier — annotation + xrefs + protein + domains + GO + KEGG + STRING + literature composed into a rendered Markdown result.markdown (+ structured result.sections).
38
Families (live)
entry_members
Every protein in one organism carrying an InterPro / Pfam / PANTHER entry, with the locus each maps to (entry → genes; the reverse of tools 23 and 30). UniProt total + cursor paging; reviewed-only by default.
39
Families (live)
gene_tree_members
Every gene in an Ensembl Compara gene tree — the gene_tree_id that gramene_homologs returns — with locus, protein id, species and organism; target_organism keeps one organism's members. total + limit.
40
Homology (live)
ensembl_plants_paralogs
Paralogues Ensembl Compara records for a locus — within_species_paralog and the other_paralog ("ancient paralogues") that gramene_homologs drops — closest first, with perc_id, taxonomy level and protein id. Not a family list: test membership with interpro_domains. total + limit.
41
Region query (live)
ensembl_plants_assembly
An organism's Ensembl assembly — name, GCA accession, karyotype — and every top-level seq-region with its length: the region names ensembl_region_query takes, chromosomes first, so a region walk is planned before its first call. total + limit.
42
Provenance (live)
upstream_release
The release a backend's own endpoint calls current (Ensembl, STRING, QuickGO, JASPAR, KEGG), for the backends whose answers state none; PDBe, AraGWAS and Europe PMC publish none and say why. A separate request, so read it before and after a run: equal values mean no release changed.
⚡ Quickstart
After install, the simplest call returns the Ensembl Plants record for
NAC001 — the canonical worked example used throughout examples/:
jsonc
// arguments{"locus":"AT1G01010"}// result (truncated){"id":"AT1G01010","organism":"arabidopsis_thaliana","display_name":"NAC001","biotype":"protein_coding","seq_region_name":"1","start":3631,"end":5899,"strand":1,"assembly_name":"TAIR10","description":"NAC domain containing protein 1 ..."}
A recorded Claude Code session (2026-05-24) with a narrower prompt — the
Ensembl record, UniProtKB entry and top three Europe PMC papers for
AT1G01010 — answered it in one turn (animated demo):
Full per-tool walkthroughs (with real upstream-API transcripts) live in
examples/:
v0.9 multi-organism resolver against rice + maize — per-backend routing. Captured 2026-05-24 against PyPI v1.0.4.
📚 Resources & prompts
Four read-only MCP resources + three parameterized prompts
Clients discover them via resources/list and prompts/list.
Resources (resources/read):
URI
What
pgmcp://cache/stats
Per-backend TTLCache rollup — {hits, misses, size} for each live backend.
pgmcp://organisms/phytozome
Slug → Phytozome organism_id map.
pgmcp://backends/status
Static per-backend roster — name, base_url, citation DOI, subscription_gated, kind. Nothing is probed: kind is always "live" and says nothing about whether the backend is up right now.
pgmcp://organisms/coverage
Markdown table of all 12 supported plants × 9 ID slots (ncbi_taxid / ensembl / phytozome / string / europe_pmc / kegg / atted / gprofiler / plantcyc).
Prompts (prompts/get):
Name
Required
Optional
Chains
analyze_locus
locus
organism (default arabidopsis_thaliana)
Ensembl → xrefs → UniProt → Europe PMC → QuickGO.
find_homologs
sequence
program (default blastp)
blast_sequence → per-hit resolve_locus_to_uniprot for UniProt-shaped accessions.
biological_context
locus
top_n (default 10)
Gramene → KEGG → UniProt → STRING → ATTED-II.
🔌 Transports
Transport
How to launch
stdio (default)
plant-genomics-mcp (after install) or via Docker above
streamable-HTTP
plant-genomics-mcp-http — POST JSON-RPC at http://host:port/mcp
The HTTP transport is stateless and emits JSON responses by default —
the right shape for registry indexers and remote hosting.
Self-hosting
There is no public hosted endpoint. To use the HTTP transport, run it
yourself: it is the same binary, gated by your own bearer token
(PLANT_GENOMICS_MCP_HTTP_TOKEN), with NCBI BLAST requests sent under your
own contact email.
⚙️ Configuration
Stdio needs no configuration. The two env vars that matter:
Variable
When
Effect
PLANT_GENOMICS_MCP_HTTP_TOKEN
HTTP transport only
Bearer token for /mcp; must be ≥32 chars or the HTTP server aborts at startup. Generate openssl rand -hex 32.
All env vars (HTTP bind, body cap, cache, BLAST concurrency)
Variable
Default
Effect
PLANT_GENOMICS_MCP_HTTP_HOST
127.0.0.1
HTTP bind address.
PLANT_GENOMICS_MCP_HTTP_PORT
8765
HTTP TCP port.
PLANT_GENOMICS_MCP_HTTP_MAX_BODY
2097152 (2 MiB)
Reject POSTs with Content-Length larger than this.
PLANT_GENOMICS_MCP_HTTP_STATELESS
1
0 keeps per-client session state (SSE-style).
PLANT_GENOMICS_MCP_HTTP_JSON
1
0 switches the response shape to streaming SSE events.
PLANT_GENOMICS_MCP_BLAST_CONCURRENCY
2
Max in-flight BLAST searches per process (NCBI per-IP rate limit).
PLANT_GENOMICS_MCP_CACHE_TTL
600
Per-backend TTL+LRU cache entry lifetime, in seconds. 200-only.
PLANT_GENOMICS_MCP_CACHE_SIZE
256
Max entries per backend before LRU eviction.
PLANT_GENOMICS_MCP_CACHE_DISABLED
unset
Any non-empty value makes every cache a no-op.
The cache is process-local — restart the server to drop all entries.
Long-running calls (retry storms, multi-second Phytozome BioMart POSTs)
emit MCP notifications/progress over the active session; clients opt
in via progressToken in the request _meta.
⚠️ Error model
Wire-prefix taxonomy + batch result shape
All live tools raise PlantGenomicsError subclasses; the MCP SDK
stringifies them into the wire content with a [ClassName] prefix so
clients can route on failure kind without parsing the message:
Wire prefix
When
[NotFoundError]
404 / empty BioMart row / invalid locus identifier
[RateLimitError]
429 retry budget exhausted — back off and retry
[UpstreamUnavailableError]
5xx past retry budget — service outage, try a peer backend
[PlantGenomicsError]
Other (BioMart Query ERROR: body, unexpected column count, etc.)
Batch tools return {tool, count, results, errors} where
results[locus] is the same shape as the single-locus tool and
errors[locus] is the same [ClassName] message string. Ensembl's
batch uses the native POST /lookup/id endpoint (one HTTP round-trip);
everything else fans out via asyncio.gather.
With uv, pass --extra dev — a bare uv sync omits (and removes) the test
dependencies. See CONTRIBUTING.md.
CI runs the unit suite + the stdio smoke on every push/PR (matrix:
Python 3.11, 3.12, 3.13, 3.14 — the full requires-python range), with a
dead proxy set so an ungated network call fails. A separate live-smoke job
runs two live test files (tests/test_verify_genes.py,
tests/test_arf_mcp_client.py, InterPro and PANTHER) on Python 3.12 on the
same pushes and PRs; it reports a result but is not a required check, because its result depends on
third-party services. The rest of the live suite (PLANT_GENOMICS_MCP_LIVE=1)
is not run in CI.
Drift detection.scripts/benchmark_annotations.py runs a curated corpus
of 27 loci (spanning all 12 organisms) through 12 functions — the organism
resolver plus 11 lookups across 9 of the 23 backends (ATTED-II, BAR, Ensembl
Plants, Europe PMC, Gramene, KEGG, Phytozome, STRING-DB, UniProt) — and
compares the results to a frozen snapshot of earlier results
(scripts/benchmark_annotations.expected.json), emitting PASS / DRIFT / FAIL
plus two cross-source consistency invariants. A change is detected relative to
that snapshot, not checked against an independent truth. BLAST and the
synthesis pipelines are registered in the script, but no corpus locus
exercises them. A scheduled GitHub Actions workflow
(.github/workflows/benchmark.yml) runs it weekly and pages when the same loci
fail on a re-run. Operator guide: docs/benchmarking.md.
bash
.venv/bin/python scripts/benchmark_annotations.py # full live sweep
See CHANGELOG.md for release notes, including the
v0.8 → v0.9 species=/organism_id= → organism= migration and the
v1.0.1 HTTP-token enforcement change.
MCP registry
Listed in the official MCP registry
under the namespace below (ownership-verification token for mcp-publisher):
code
mcp-name: io.github.musharna/plant-genomics-mcp
License
MIT — see LICENSE. Underlying services (Ensembl Plants,
Phytozome, TAIR, PlantCyc, BAR) have their own terms of use; consult
each before bulk querying.