About ensembl-mcp-server
ensembl-mcp-server gives researchers and bioinformatics workflows access to gene, sequence, variant, homology, and cross-reference data from Ensembl REST. It combines these lookups with gene and transcript resources and a structured gene-dossier prompt.
Key features
- 01List species across Ensembl divisions
- 02Look up genes and transcript details
- 03Fetch DNA, RNA, and protein sequences
- 04Query genomic regions for features
- 05Predict variant consequences with VEP
- 06Find homologs and external cross-references
Use cases
- 01Assemble gene profiles from symbols or IDs
- 02Retrieve sequences for genes and transcripts
- 03Explore features overlapping a genomic region
- 04Assess variant effects and related annotations
MCP support
It exposes Ensembl REST lookups as MCP tools, gene, transcript, and species resources, and a gene-dossier prompt. It supports STDIO and Streamable HTTP, with a hosted endpoint.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://ensembl.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-ensembl https://ensembl.caseyjhand.com/mcp{"mcpServers":{"cyanheads-ensembl":{"type":"http","url":"https://ensembl.caseyjhand.com/mcp"}}}Open in Cursor{"servers":{"cyanheads-ensembl":{"type":"http","url":"https://ensembl.caseyjhand.com/mcp"}}}Open in VS Code{"mcpServers":{"cyanheads-ensembl":{"type":"http","url":"https://ensembl.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-ensembl":{"serverUrl":"https://ensembl.caseyjhand.com/mcp"}}}Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.
Tools
7| Parameter | Type | Required | Description |
|---|---|---|---|
| offset | integer | No | 0-based position in the name-sorted matches where the returned page starts. Default 0. Pass nextOffset from a previous response to fetch the following page; an offset at or past totalCount returns no species. |
| division | enum | No | Filter to a specific Ensembl division. EnsemblVertebrates includes human, mouse, zebrafish, and other vertebrates. EnsemblPlants covers crop and model plant genomes. EnsemblFungi, EnsemblMetazoa, EnsemblProtists cover non-vertebrate model organisms. Omit to return the endpoint default division (vertebrates).EnsemblVertebrates | EnsemblPlants | EnsemblFungi | EnsemblMetazoa | EnsemblProtists |
| max_results | integer | No | Maximum number of species to return, counted from offset. Default 50. Set to 0 to return every matching species from offset to the end, uncapped. totalCount always reports the full number of matches before this cap. |
| nameContains | string | No | Case-insensitive substring filter applied locally after fetching. Matches against species name, display name, and common name. Example: "sapiens" matches homo_sapiens; "mouse" matches mus_musculus. |
Details
From the project README@cyanheads/ensembl-mcp-server
Look up genes, fetch sequences, predict variant consequences, find orthologs, and retrieve cross-database xrefs from Ensembl REST via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://ensembl.caseyjhand.com/mcp
Overview
Gene, sequence, and variant data for vertebrates and other model organisms from the Ensembl REST API. Look up genes, fetch sequences, predict variant consequences, find orthologs, and cross-reference external databases.
Tools
| Tool | Description |
|---|---|
ensembl_list_species | List species supported by Ensembl with display name, common name, assembly, taxon ID, and division |
ensembl_lookup_gene | Resolve a gene by symbol (synonyms and former symbols included) + species or by stable ID to its Ensembl ID, genomic location, biotype, and transcript list |
ensembl_get_sequence | Fetch the DNA, cDNA, CDS, or protein sequence for a gene, transcript, protein, or genomic region |
ensembl_query_region | Find genomic features (genes, transcripts, variants, regulatory elements, exons) overlapping a chromosomal region |
ensembl_predict_variant | Predict functional consequences of a sequence variant using the Ensembl Variant Effect Predictor (VEP) |
ensembl_get_homology | Find orthologs and/or paralogs of a gene across species with percent identity and taxonomy level |
ensembl_get_xrefs | Retrieve cross-database references for a gene — HGNC, UniProt, EntrezGene, OMIM, RefSeq, Reactome, and others |
Resources
| Resource | Description |
|---|---|
ensembl://gene/{id} | Gene record by stable ID (ENSG…) — location, biotype, description, and transcript list |
ensembl://transcript/{id} | Transcript record by stable ID (ENST…) — parent gene, location, biotype, canonical flag, and length |
ensembl://species | Supported Ensembl species for the endpoint default division (vertebrates on the default endpoint) |
ensembl://species/{division} | Supported species in one division (EnsemblVertebrates, EnsemblPlants, EnsemblFungi, EnsemblMetazoa, EnsemblProtists) |
The species resources return the first 50 species by internal name; the ensembl_list_species tool pages through the rest and filters by name.
Prompts
| Prompt | Description |
|---|---|
ensembl_gene_dossier | Structured workflow for assembling a complete gene profile: symbol → ID + location → sequence → variants → orthologs → xrefs |
Capability reference
Ensembl's stable-ID endpoints answer a versioned ID (ENSG00000139618.19) as not found, so every tool and resource that takes an Ensembl stable ID drops a trailing .N from an ENS… ID before the request and returns the current version. HGVS input to ensembl_predict_variant (ENST00000380152.8:c.2T>A) keeps its version, and IDs from other sources (AT3G52430.1) are forwarded unchanged.
ensembl_list_species tool
- Optional
division(EnsemblVertebrates,EnsemblPlants,EnsemblFungi,EnsemblMetazoa,EnsemblProtists; omitted, the endpoint default — vertebrates, ~356 species on GRCh38) andnameContains, a substring match against name, display name, and common name - Returns the internal name every other tool expects (
homo_sapiens), plus display name, common name, taxon ID, assembly, and division - Sorted by internal name and paged by
offset(default0) andmax_results(default50,0uncapped);totalCountreports every match, andnextOffsetis where the next page starts when more follow
ensembl_lookup_gene tool
- Exactly one of
symbol(+species, defaulthomo_sapiens),id,ids, orsymbols(up to 1,000 submitted items; first 20 distinct trimmed queries processed);expand_transcripts(defaultfalse) adds the transcript list with biotype and canonical flag canonicalTranscriptidentifies the canonical transcript without expansion; transcript-ID lookups also returnparentGeneId. Expanded transcripts includemaneSelectRefSeq accessions when available (BRCA2:ENST00000380152.8,NM_000059.4)- A symbol that is not a current gene name falls back to synonyms and former symbols (
HER2→ERBB2), reported asmatchedAlias; a name shared by several genes (MDR1) returnsambiguouswith candidates to retry byid - A single lookup returns
gene(orambiguous); abatchreturns orderedsucceededitems carrying the submittedquery,faileditems withquery,reason(not_found,ambiguouswithcandidates, orunavailable),error, andrecovery, andomittedqueries past the processing cap. Omitted queries are never requested or reported as failed; resubmit them separately. Errors:not_found,invalid_species,no_input,conflicting_input
ensembl_get_sequence tool
- A stable ID (
ENSG…/ENST…/ENSP…) or a region (species:chr:start-end, orchr:start-endwithspecies; at most 10,000,000 bases);typeisgenomic(default),cdna,cds, orprotein—cdnaandcdsfrom a transcript ID only,proteinfrom a transcript or protein ID;expand_5prime/expand_3primeadd flanking bases - Regions take a
:1/:-1strand suffix (1:1000000-1000020:-1returns the reverse complement); the mitochondrion isMTin vertebrates (mitochondrion_genomein Drosophila,MtDNAin C. elegans), andM/chrMare rejected asinvalid_regionwhere they would not resolve to it - Returns a window set by
offset(default0) andmax_length(default10000,0uncapped);lengthis the full sequence length, andtruncated/nextOffsetsay where to resume - Errors:
not_found,type_mismatch(also a protein ID asked forgenomic/cdna/cds, or a non-coding transcript asked forprotein/cds),invalid_species,missing_species,invalid_region(also an id with a colon that is not a valid region)
ensembl_query_region tool
regionasspecies:chr:start-end, orchr:start-endwithspecies(at most 5,000,000 bases; reversed coordinates are rejected; mitochondrion naming as inensembl_get_sequence);featuredefaults to["gene"]and also acceptstranscript,variation,regulatory,exon; optional case-sensitivebiotypefilter (protein_coding,lncRNA). An empty filtered result suggests removing the filter without inferring the locus is intergenicmax_resultscaps the list (default100,0uncapped) whiletotalCountreports the true count;assemblyNamenames the coordinates' assembly, and exon rows carryparentIdandrank. Errors:invalid_region,invalid_species,missing_species
ensembl_predict_variant tool
variantas HGVS (transcript-relative or genomic), region+allele (chr:start:end:strand/allele), or a dbSNP rsID- Returns the most severe consequence, per-transcript impact (HIGH/MODERATE/LOW/MODIFIER), and colocated known variants with clinical significance. Errors:
invalid_notation,not_found,invalid_species - Requests HGVS, canonical and MANE annotations on every input route. Consequences retain
variantAllele, optionalcanonical/maneSelect, HGVS and available SIFT/PolyPhen prediction-score pairs; records retainalleleString - Colocated
clinicalSignificanceis aggregate, not a classification of the submitted allele.clinicalSignificanceByAllelepreserves explicit per-allele terms andclinicalSignificanceReferenceAlleleidentifies their reference allele; absent annotations remain omitted max_transcript_consequencesandmax_pubmed_ids_per_variant(default10each,0uncapped;include_all_colocated_pubmedlifts the PubMed cap) bound the result, whiletranscriptConsequencesTotalandpubmedTotalreport the full counts
ensembl_get_homology tool
- Exactly one of
symbol(+species, defaulthomo_sapiens) orid;typeisorthologues(default),paralogues, orall; optionaltarget_speciesfilter max_resultscaps the list (default25,0uncapped) whiletotalCountreports the true count. Errors:not_found,invalid_species(unknownspeciesortarget_species),no_input,conflicting_input- Each row retains optional
targetProteinIdforensembl_get_sequencewithtype:"protein". OptionaltargetSymbolcomes from a lookup of the returned rows' distinct gene IDs, in chunks of at most 1,000, with one five-second budget bounded by the call's remaining deadline and no retries. Missing names or failed lookups retain every primary homolog with a notice; cancellation still aborts
ensembl_get_xrefs tool
id(ENSG…/ENST…/ENSP…) required; optionaldbnamefilter (e.g.HGNC,Uniprot_gn,EntrezGene,MIM_GENE,RefSeq_mRNA,Reactome_genefor gene pathways,Reactomefor translation pathways,GO)- Default
all_levels:falsequeries the requested object's level. Setall_levels:trueto include a gene's transcript and translation references, independently ofdbname; for example, gene-levelRefSeq_mRNAmay need this or a transcript ID. Empty lists remain successful withtotalCount:0. Errors:not_found
ensembl://gene/{id} resource
idis a gene stable ID (ENSG…); a version suffix is optional and dropped- Returns location, biotype, description, and transcript list. Errors:
not_found
ensembl://transcript/{id} resource
idis a transcript stable ID (ENST…); a version suffix is optional and dropped- Returns parent gene, location, biotype, canonical flag, and length. Errors:
not_found
ensembl://species resource
- No parameters — covers the endpoint default division (vertebrates, ~356 species on the default GRCh38 endpoint)
- Returns the first 50 species by internal name with
totalCount,shown, andtruncated; a truncated body'snoticepoints toensembl_list_species(offset,max_results) for the rest - For a named division, read
ensembl://species/{division}instead
ensembl://species/{division} resource
divisionrequired:EnsemblVertebrates,EnsemblPlants,EnsemblFungi,EnsemblMetazoa, orEnsemblProtists- Returns that division's first 50 species by internal name — internal name, display name, assembly, taxon ID, and division — with
totalCount,shown, andtruncated; a truncated body'snoticepoints toensembl_list_species(division,offset,max_results) for the rest
ensembl_gene_dossier prompt
- Arguments:
gene_symbolrequired;speciesoptional (defaulthomo_sapiens) - Sequences a 7-step workflow: resolve the gene → fetch the protein sequence → find variants in the locus → predict variant consequences → find cross-species orthologs → get external database IDs → synthesize the dossier
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Ensembl-specific:
- Keyless REST API — no API key required; Ensembl REST is fully public at 55,000 req/hr
- Retries 429 responses (honoring
Retry-After) and transient 5xx errors - Upstream calls time out at 180 s per attempt and 240 s per call, so a stalled Ensembl fails instead of hanging
- Batch lookups use
POST /lookup/idandPOST /lookup/symbol/{species}to avoid N+1 round trips - GRCh37 legacy support via
ENSEMBL_BASE_URL— point the entire server athttps://grch37.rest.ensembl.orgfor clinical workflows on the older assembly - All coordinate-bearing responses echo the assembly name so agents never see a bare genomic position without assembly context
Agent-friendly output:
ensembl_get_sequencereturns bounded windows (10,000 characters by default) with the full length and anextOffsetto continueensembl_list_speciesis the discovery step for internal species names, 50 per page with anextOffset- Xref IDs from
ensembl_get_xrefsare described as inputs for protein and literature servers; theensembl_gene_dossierprompt chains 6 of the 7 tools
Getting started
Public Hosted Instance
A public instance is available at https://ensembl.caseyjhand.com/mcp — no installation required. It serves Streamable HTTP; each client takes its own config shape.
For Claude Code:
claude mcp add --transport http ensembl-mcp-server https://ensembl.caseyjhand.com/mcp
For Cline (cline_mcp_settings.json):
{
"mcpServers": {
"ensembl-mcp-server": {
"type": "streamableHttp",
"url": "https://ensembl.caseyjhand.com/mcp"
}
}
}
For Cursor (mcp.json):
{
"mcpServers": {
"ensembl-mcp-server": {
"url": "https://ensembl.caseyjhand.com/mcp"
}
}
}
Claude Desktop adds remote servers under Settings → Connectors.
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"ensembl-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/ensembl-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"ensembl-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/ensembl-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"ensembl-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/ensembl-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- No API key required — Ensembl REST is fully public.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/ensembl-mcp-server.git
- Navigate into the directory:
cd ensembl-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env if you need to override ENSEMBL_BASE_URL (e.g. for GRCh37)
Configuration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts.
| Variable | Description | Default |
|---|---|---|
ENSEMBL_BASE_URL | Ensembl REST API base URL. Override for GRCh37 (https://grch37.rest.ensembl.org) or a local mirror. | https://rest.ensembl.org |
MCP_TRANSPORT_TYPE | Transport: stdio or http | stdio |
MCP_HTTP_PORT | HTTP server port | 3010 |
MCP_HTTP_ENDPOINT_PATH | HTTP endpoint path | /mcp |
MCP_SESSION_MODE | HTTP session mode: auto, stateful, or stateless | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.) | info |
LOGS_DIR | Directory for log files (Node.js only) | <project-root>/logs |
LOG_TOOL_FAILURE_PAYLOADS | Log each failed tool call's arguments and result, redacted by key name and capped at LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). A secret inside a free-form value is not redacted. | false |
OTEL_ENABLED | Enable OpenTelemetry | false |
See .env.example for the full list of optional overrides.
Running the server
Local development
-
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:http -
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t ensembl-mcp-server .
docker run --rm -p 3010:3010 ensembl-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/ensembl-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools/resources/prompts and inits services |
src/config | Server-specific environment variable parsing and validation with Zod |
src/mcp-server/tools | Tool definitions (*.tool.ts) — 7 tools |
src/mcp-server/resources | Resource definitions (*.resource.ts) — gene, transcript, species |
src/mcp-server/prompts | Prompt definitions (*.prompt.ts) — gene dossier workflow |
src/services/ensembl | Ensembl REST API client — HTTP, rate-limit handling, retry, error normalization |
tests/ | Unit and integration tests mirroring src/ |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Register new tools and resources in the
createApp()arrays insrc/index.ts - Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.