biothings_search
Search and understand any biological entity — gene, protein, variant, disease, drug, chemical, or pathway — from within AI coding agents.
Backed by the BioThings APIs (MyGene.info, MyVariant.info, MyChem.info, MyDisease.info, MyTaxon.info, MyGeneset.info, and other BioThings-hosted APIs), plus the UniProt and NCBI PubMed APIs. Fifteen sources in all; see Data sources.
Install
Requires Python 3.11 or newer.
pip install biothings-search
# or
uv add biothings-search
Then install the agent skills for your editor (they ship with the package):
biothings-search install-skills # this project
biothings-search install-skills --global # user-wide, all projects
biothings-search providers # list install targets
By default this writes the three locations named by the
Agent Skills specification — .agents/skills,
.claude/skills and .github/skills. Between them they cover every client below.
Naming a client that reads .agents/skills installs there rather than creating
a directory for it — saying --provider cursor tells us which agent you use, it
does not ask for a .cursor/ folder. Only Codex needs its own.
| Provider | Installs to | Notes |
|---|---|---|
agents |
.agents/skills |
Standard. Any conforming agent reads this |
claude |
.claude/skills |
Standard. Claude Code |
github |
.github/skills, ~/.copilot/skills |
Standard. GitHub Copilot, VS Code |
codex |
.codex/skills |
Codex CLI — the only client needing its own directory |
cursor |
.agents/skills |
Reads the standard path |
gemini |
.agents/skills |
Reads the standard path |
pi |
.agents/skills |
Reads the standard path |
opencode |
.agents/skills |
Reads the standard path |
openclaw |
.agents/skills |
Reads the standard path |
Quick start (CLI)
biothings-search BRCA1 # auto-detect type
biothings-search NCBIGene:695 # CURIE ID lookup
biothings-search BRCA1 TP53 aspirin # batch: multiple queries at once
biothings-search gene TP53
biothings-search variant rs28934578
biothings-search chemical aspirin
biothings-search disease "breast cancer"
biothings-search protein P04637
biothings-search taxon "Homo sapiens"
biothings-search geneset "p53 pathway"
biothings-search phenotype seizure
biothings-search paper "BRCA1 breast cancer"
biothings-search trial "BRCA1 mutation"
biothings-search anatomy liver
biothings-search cell "T cell"
biothings-search gwas "breast cancer"
biothings-search drug ibuprofen
biothings-search chebi "CHEBI:15365"
biothings-search demo # one hit per entity type
biothings-search get 672 --type gene # fetch by specific ID
biothings-search get 695 7157 672 --type gene # batch: one request, not three
biothings-search get CHEBI:15365 --type chemical --source chebi # answer from one source
biothings-search prefixes # list all supported CURIE prefixes
biothings-search sources # list the databases searched
biothings-search fields gene # list the fields a source offers
All commands accept --json / -j for machine-readable output and --size / -n.
The default of 5 suits most lookups; raise it when you need to enumerate or
post-process a set with --json. The ceiling is 1000, though each source clamps
to what it will actually serve — UniProt tops out at 500.
Asking for more than the summary
Results are normalized down to the fields most questions need — name, canonical
ID, taxon, summary. When you need more, name the source's own fields with
--fields / -f and they come back under extra, nested the way the source
returns them:
biothings-search gene BRCA1 -f genomic_pos,go.BP
biothings-search get 1017 --type gene -f genomic_pos
biothings-search gene BRCA1 -f all --json # the whole record
biothings-search fields <type> lists what a source offers, straight from the
source, so it is never out of date; --match narrows a long catalogue:
biothings-search fields gene --match genomic
biothings-search fields chemical --match drugbank
Requested fields are added to the ones the parser needs, never substituted —
-f genomic_pos still returns a named, identified hit. Fields the record does
not carry are simply absent from extra rather than reported as empty.
Every source accepts --fields, but the names are its own: BioThings sources
use dotted paths (go.BP), UniProt its query-field names (cc_disease), and
PubMed the keys of an esummary docsum (volume). Run
biothings-search fields <type> to see a source's list — it is read from the
source, so it cannot go stale. A name a source does not know is simply absent
from extra, so a fan-out never fails on whichever source happens to answer.
PubMed is the one source where --fields changes nothing about what is
fetched: E-utilities has no way to select fields and returns the whole docsum
regardless, so the option only decides how much of it is surfaced.
A shorter command
biothings-search is the only console script installed. If you want a short
form, add an alias to your shell profile:
alias bts='biothings-search' # or biothings, bt, whatever you like
An alias only applies to what you type. It is not expanded inside scripts, or when another program invokes the command — so if you write a script, a Makefile or your own agent skill that calls the short name, use a symlink instead:
ln -s "$(command -v biothings-search)" ~/.local/bin/bts
(The skills shipped with this package call biothings-search directly, so they
work either way.)
bts is deliberately not installed as a script: Debian's devscripts
package already ships a /usr/bin/bts
(the Bug Tracking System CLI), and shadowing it on every Debian and Ubuntu
machine would be a poor trade for four saved keystrokes.
MCP server (AI agent integration)
Start the server:
biothings-search serve
# or directly:
biothings-search-server
Claude Code
claude mcp add biothings biothings-search-server
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"biothings": {
"command": "biothings-search-server"
}
}
}
Cursor
Add to .cursor/mcp.json in your project (already included in this repo):
{
"mcpServers": {
"biothings": {
"command": "biothings-search-server"
}
}
}
Or add to Cursor's global MCP settings under Settings → MCP.
Windsurf
Add to Windsurf MCP settings (Settings → MCP Servers):
{
"mcpServers": {
"biothings": {
"command": "biothings-search-server"
}
}
}
VS Code (Continue.dev)
Add to .continue/config.json:
{
"mcpServers": [
{
"name": "biothings",
"command": "biothings-search-server"
}
]
}
Available MCP tools (22)
| Tool | Description |
|---|---|
search_biothing |
Universal search — auto-detects entity type |
search_biothing_batch |
Search multiple entities concurrently |
search_gene |
Genes via MyGene.info |
search_variant |
Variants via MyVariant.info |
search_chemical |
Chemicals/drugs via MyChem.info |
search_disease |
Diseases via MyDisease.info |
search_protein |
Proteins via UniProt |
search_taxon |
Taxonomy via MyTaxon.info |
search_geneset |
Gene sets/pathways via MyGeneset.info |
search_phenotype |
Phenotypes via Human Phenotype Ontology |
search_paper |
Publications via PubMed |
search_trial |
Clinical trials via ClinicalTrials.gov |
search_anatomy |
Anatomy via Uberon |
search_cell_type |
Cell types via Cell Ontology |
search_gwas |
GWAS associations via GWAS Catalog |
search_drug |
FDA-approved drugs |
search_chebi |
Chemical ontology via ChEBI |
get_entity |
Fetch entity by specific ID |
get_entities |
Fetch several entities by ID in one batched request |
list_entity_types |
List all supported types and CURIE prefixes |
list_sources |
List the databases searched and how to address each |
list_fields |
List the extra source fields available to fields |
Agent skills (slash commands)
Install skills so you can invoke them with /biothings, /biothings-gene, etc.:
biothings-search install-skills # standard locations, this project
biothings-search install-skills --global # under your home directory
biothings-search install-skills --provider cursor # add a vendor directory
biothings-search install-skills --dry-run # show what would be written
.agents/skills is the cross-client location: agents that follow the
Agent Skills standard discover skills there with no
vendor-specific setup. .claude/skills and .github/skills are the other two
locations the specification names, for Claude Code and GitHub Copilot / VS Code
respectively. Everything else is a vendor convention — the files are identical,
so an extra copy costs nothing but a directory.
Note the home locations differ for two clients: Copilot reads ~/.copilot/skills
rather than ~/.github/skills, and pi reads ~/.pi/agent/skills. --global
handles both.
Contributors regenerating the copies committed in this repo use
python scripts/build_skills.py instead; the source of truth is
src/biothings_search/skills/.
| Skill | Command |
|---|---|
| Universal search | /biothings BRCA1 |
| Gene search | /biothings-gene TP53 |
| Variant search | /biothings-variant rs28934578 |
| Chemical search | /biothings-chemical aspirin |
| Disease search | /biothings-disease "breast cancer" |
| Protein search | /biothings-protein P04637 |
| Taxon search | /biothings-taxon "Homo sapiens" |
| Geneset search | /biothings-geneset "p53 pathway" |
| Phenotype search | /biothings-phenotype seizure |
| Paper search | /biothings-paper "BRCA1 2023" |
| Trial search | /biothings-trial "BRCA1 mutation" |
| Anatomy search | /biothings-anatomy liver |
| Cell type search | /biothings-cell "T cell" |
| GWAS search | /biothings-gwas "breast cancer" |
| Drug search | /biothings-drug ibuprofen |
| ChEBI search | /biothings-chebi "CHEBI:15365" |
| Help | /biothings-help |
CURIE ID support
Queries in CURIE format (prefix:id) are resolved directly to the correct entity and API — no text search needed. Prefixes follow the Biolink Model standard (validated against 4.4.4) and are case-insensitive.
biothings-search NCBIGene:695 # → gene BTK
biothings-search UniProtKB:P04637 # → protein TP53
biothings-search DBSNP:rs28934578 # → variant
biothings-search MONDO:0007254 # → disease breast cancer
biothings-search CHEBI:15365 # → aspirin
biothings-search CL:0000084 # → T cell
biothings-search NCT:NCT00000125 # → clinical trial
biothings-search NDC:66715-6526 # → an FDA-listed drug product
Run biothings-search prefixes to see all 51 supported prefixes with their canonical ID priority.
Every prefix listed there is verified to resolve against the live API — a namespace
with no reachable backend is left out rather than advertised and silently dead.
Input is deliberately more forgiving than output. Eleven of those prefixes
(pubmed:, ensg:, chembl:, nct:, …) are conveniences that are not in the
Biolink Model; they are accepted because people type them, and never emitted.
Everything in canonical_id uses the model's own spelling.
biothings-search chebi and biothings-search gwas search those databases
specifically, but their results are typed by what they are — a ChEBI entry is a
chemical, a GWAS record is a variant — with the database in each hit's
source. That keeps canonical_id usable for linking: the same compound has
the same type and ID whether it came from ChEBI or MyChem.
Each result includes a canonical_id field — the highest-priority Biolink-standard CURIE available for that entity (e.g. NCBIGene:672 for BRCA1, UniProtKB:P04637 for TP53), following that class's id_prefixes order in the model.
One consequence worth knowing: a MyChem record contributed only by the NDC
directory is a marketed drug product rather than a small molecule, so it comes
back typed drug with an NDC: ID even from a chemical search. Biolink draws
the same line — Drug carries NDC in its id_prefixes and SmallMolecule does
not — and it is the difference between having a canonical ID and having none.
Entity type auto-detection
Bare identifiers are recognized automatically without a CURIE prefix:
| Pattern | Detected as |
|---|---|
rs28934578 |
Variant (dbSNP rsID) |
chr1:g.123A>T |
Variant (HGVS) |
ENSG00000141510 |
Gene (Ensembl) |
7157 (integer) |
Gene (Entrez ID) |
P04637 |
Protein (UniProt) |
CHEMBL25 |
Chemical (ChEMBL) |
| 27-char InChIKey | Chemical |
DB00945 |
Chemical (DrugBank) |
DOID:1612 |
Disease (DO) |
MONDO:0007254 |
Disease (MONDO) |
HP:0001250 |
Phenotype (HPO) |
GO:0006915 |
Gene set (GO) |
R-HSA-109582 |
Gene set (Reactome) |
UBERON:0002107 |
Anatomy (Uberon) |
CL:0000084 |
Cell type (CL) |
CHEBI:15365 |
ChEBI chemical |
PMID:12345678 |
Publication |
NCT00000125 |
Clinical trial |
GCST90428116 |
GWAS study |
Unknown patterns trigger a concurrent fan-out search across genes, chemicals, diseases, and proteins.
Scoping to a species
Gene, protein and gene-set searches cover every organism by default, so a symbol query returns the same gene from dozens of species. Scope it once and forget it:
export BIOTHINGS_SEARCH_SPECIES=human # or human,mouse — or a taxid
biothings-search gene BTK # human only
biothings-search gene BTK --species mouse # per-command override
biothings-search gene BTK --species all # opt back out
For an agent client, set it in the MCP server config — there is no per-call flag to reach for, and it applies to every tool:
{
"mcpServers": {
"biothings": {
"command": "biothings-search-server",
"env": { "BIOTHINGS_SEARCH_SPECIES": "human" }
}
}
}
search_biothing, search_gene, search_protein and search_geneset also
take a species argument that overrides it for one call. The other MCP tools
cover types with no species concept.
Accepts a name (human, mouse, zebrafish, fruitfly, …), an NCBI taxid
(9606), a comma-separated combination, or all. An unrecognised value fails
immediately and lists the alternatives, rather than reaching the API as an
opaque error.
Direct ID lookups are never scoped. biothings-search NCBIGene:12229
resolves the mouse record even under BIOTHINGS_SEARCH_SPECIES=human — a CURIE
names one entity, so filtering it could only ever return nothing. Only searches
are filtered. Variants, chemicals, diseases and the ontologies have no species
concept and are unaffected.
Configuration
All optional; sensible defaults apply when unset.
| Variable | Default | Purpose |
|---|---|---|
BIOTHINGS_SEARCH_SPECIES |
all |
Restrict gene/protein/geneset searches to one or more organisms: a name (human), an NCBI taxid (9606), several comma-separated (human,mouse), or all. Never applied to ID lookups. |
BIOTHINGS_TRANSLATOR_HOST |
https://biothings.transltr.io |
Host for the Translator-hosted sources (ChEBI, HPO, Uberon, Cell Ontology, GWAS, FDA, trials). Point at the CI deployment to test pre-release data. |
NCBI_API_KEY |
— | Raises the PubMed rate limit from 3 to 10 requests/second. Get one here. |
BIOTHINGS_SEARCH_EMAIL |
help@biothings.io |
Contact address sent to NCBI E-utilities. |
BIOTHINGS_SEARCH_CACHE_TTL |
300 |
Seconds a response stays cached. 0 disables caching. |
BIOTHINGS_SEARCH_CACHE_SIZE |
512 |
Maximum cached responses. |
NO_COLOR |
— | Any value disables colour, per no-color.org. Bold is kept — NO_COLOR governs colour, not weight. |
TERM |
— | TERM=dumb disables colour and bold, for a terminal that cannot render escape sequences at all. |
Colour is switched off automatically when output is not a terminal, so
biothings-search gene BRCA1 > out.txt and | grep are already plain — the two
variables above are only needed to suppress it in a terminal.
Each entity type has its own colour, so a result mixing several is readable at a
glance; biothings-search demo prints one hit per type to show them all at once.
Requests are rate-limited per host, retried on transient failures (429 and 5xx) with exponential backoff, and cached in-process, so a batch of concurrent searches will not trip an upstream limit or re-fetch what it just read.
Data sources
| Entity type | API | Coverage |
|---|---|---|
| Gene | MyGene.info | 40M+ annotations, 20K+ species |
| Variant | MyVariant.info | 900M+ human variants |
| Chemical | MyChem.info | ChEMBL, DrugBank, PubChem, FDA NDC |
| Disease | MyDisease.info | MONDO, OMIM, DO, NCIT |
| Protein | UniProt | Swiss-Prot / TrEMBL |
| Taxon | MyTaxon.info | NCBI Taxonomy |
| Gene set / Pathway | MyGeneset.info | GO, MSigDB, Reactome, WikiPathways, SMPDB |
| Phenotype | Human Phenotype Ontology | BioThings HPO API |
| Paper | PubMed | NCBI E-utilities |
| Clinical trial | ClinicalTrials.gov | BioThings CT API |
| Anatomy | Uberon | BioThings Uberon API |
| Cell type | Cell Ontology | BioThings CL API |
| GWAS | GWAS Catalog | BioThings GWAS API |
| Drug | FDA Drugs@FDA | BioThings FDA API |
| ChEBI | ChEBI | BioThings ChEBI API |
Extending with new data sources
- Subclass
BioThingsAPIinsrc/biothings_search/apis/biothings.py(orBaseAPIfor a non-BioThings source) and implement_parse_hit(), settingcanonical_idon eachSearchHit - Register in
_TYPE_TO_APIinsearch.py - Add entries to
_CURIE_MAPandCANONICAL_PREFIXESinmodels.py, verifying each prefix against the live API first - Add a CLI command in
cli.pyand an MCP tool inserver.py - Create a skill in
src/biothings_search/skills/and runpython scripts/build_skills.py - Add a fixture case in
tests/fixtures/_capture.pyand a parser test
See CONTRIBUTING.md for details.
License
Commercial use is unrestricted. The licence covers copyright only — section 6 grants no trademark rights, so "BioThings" and the service names are governed separately by TRADEMARKS.md. In short: say your software works with BioThings as much as you like; don't name your software BioThings.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file biothings_search-0.3.0.tar.gz.
File metadata
- Download URL: biothings_search-0.3.0.tar.gz
- Upload date:
- Size: 155.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eacb0e2574f468c178774fc1f486eb49ca870cecd4ccbc5e484c2cc63d92b006
|
|
| MD5 |
ba8a224ecc9f5e0f35c7265da8fa7eb8
|
|
| BLAKE2b-256 |
88eddc0369f1f70dfc3a429a826678e327013901737ce6afe4b936d63b4fd678
|
Provenance
The following attestation bundles were made for biothings_search-0.3.0.tar.gz:
Publisher:
release.yml on biothings/biothings_search
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
biothings_search-0.3.0.tar.gz -
Subject digest:
eacb0e2574f468c178774fc1f486eb49ca870cecd4ccbc5e484c2cc63d92b006 - Sigstore transparency entry: 2618802875
- Sigstore integration time:
-
Permalink:
biothings/biothings_search@14791285d470b461f1e0f0c04b933d313859065b -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/biothings
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@14791285d470b461f1e0f0c04b933d313859065b -
Trigger Event:
release
-
Statement type:
File details
Details for the file biothings_search-0.3.0-py3-none-any.whl.
File metadata
- Download URL: biothings_search-0.3.0-py3-none-any.whl
- Upload date:
- Size: 100.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c6c61ca5805cbb168594e32aef83ccdc196dad6a13cd9e7a408efe8315ec805c
|
|
| MD5 |
572e2dada7cf7cd982172ab64bdb48e6
|
|
| BLAKE2b-256 |
c22f33dd8ef6a749401794f0188776f35d8e5d87c639fc444318ac6ad9edb000
|
Provenance
The following attestation bundles were made for biothings_search-0.3.0-py3-none-any.whl:
Publisher:
release.yml on biothings/biothings_search
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
biothings_search-0.3.0-py3-none-any.whl -
Subject digest:
c6c61ca5805cbb168594e32aef83ccdc196dad6a13cd9e7a408efe8315ec805c - Sigstore transparency entry: 2618802889
- Sigstore integration time:
-
Permalink:
biothings/biothings_search@14791285d470b461f1e0f0c04b933d313859065b -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/biothings
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@14791285d470b461f1e0f0c04b933d313859065b -
Trigger Event:
release
-
Statement type: