protein-mcp-server
Allows using Cloudflare KV, R2, and D1 as storage backends for the MCP server.
Supports OpenTelemetry tracing for observability.
Allows using Supabase as a storage backend for the MCP server.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@protein-mcp-serverList SARS-CoV-2 spike protein cryo-EM structures"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://protein.caseyjhand.com/mcp
Overview
Experimental (PDB) and predicted (AlphaFold) protein structures, federated behind one surface. Search, fetch, align, compare, and annotate structures and their ligands across RCSB, AlphaFold DB, 3D-Beacons, UniProt, InterPro, and Foldseek — all keyless. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
Tools
Tool | Description |
| Search experimental and predicted structures by free text, sequence, or organism/method/resolution filters, with optional facet breakdowns. |
| Fetch metadata and coordinate-file URLs by ID — experimental (PDB), predicted (AlphaFold), or best-available — with batch partial success and optional coordinate inlining. |
| Find sequence homologs (RCSB mmseqs2) or fold homologs (Foldseek) from a sequence, PDB ID, or UniProt accession. |
| Resolve ligand names/formulas to component IDs, find structures containing a ligand, or map binding-site residues. |
| Structurally align multiple structures (TM-align / jFATCAT) to a reference or as a full pairwise matrix. |
| Profile the PDB into distributions and trends with server-side facets — counts, histograms, timelines, and cross-tabs. |
| Fetch UniProt features and natural variants plus InterPro domain/family memberships with GO terms. |
Resources
Resource | Description |
| Experimental structure summary for a PDB entry — title, method, resolution, organism, bound ligands, and per-entity chain IDs in both the author ( |
| Predicted-structure summary for a UniProt accession from AlphaFold DB — mean pLDDT, confidence-band fractions, model URLs, and version. |
All resource data is also reachable via tools — pdb://{entry_id} mirrors protein_get_structure for source: experimental, and af://{uniprot} mirrors it for source: predicted. Many MCP clients are tool-only and don't surface resources; the summaries remain reachable through the tools.
Related MCP server: UniProt MCP Server
Capability reference
protein_search_structures tool
Free-text, protein-sequence (triggers an mmseqs2 similarity search), and organism / method / resolution filters
content_typescopes the search toexperimental,predicted, orall(default) —allis a genuine union, so computed models appear alongside PDB entriesEvery hit names its
source; sequence hits in either universe expose a chainable entryidplus the matched polymerentityId; experimental hits carry title, method, resolution, and organism enrichment, and AlphaFold models their parsed UniProt accessionstartandlimitpage through ranked results;nextStartis returned while another page remains, and an empty page past the end names the offset innoticerather than reporting no matchesOptional
facetsreturn a method / organism / release-year breakdown alongside the hits — each dimension may be listed once and reports how many matches carry no value for it; a capped dimension is named innotice, withprotein_analyze_collection(largerbucket_limit) as the route to the long tailChain hit IDs straight into
protein_get_structure
protein_get_structure tool
source: experimentalbatches PDB entry IDs (also resolving computed-model IDs likeAF_*/MA_*from search, taggedsource: predictedwith their provider);source: predictedtakes UniProt accessions for AlphaFold models with pLDDT/PAE;source: best_availabletakes UniProt accessions and returns the top federated model (highest-resolution experimental if one exists, else the best prediction)Per-ID partial success — unresolved IDs land in
failed[];requested/processeddisclose IDs dropped beyond the batch cap, and every advisory (cap, failure, overflow) joins into onenoticeRecords fetched with
source: experimental, computed models included, also carrypolymerEntities(bothauthAsymIdsandlabelAsymIds),ligands,molecularWeight, andreleaseDatecoordinateUrlslists only files that exist: BinaryCIF comes from RCSB's ModelServer, the PDB format is omitted for large mmCIF-only entries, and a computed model's files come from its provider (all three formats from AlphaFold DB, mmCIF from ModelArchive) — an AlphaFold model whose provider lookup fails keeps only its RCSB BinaryCIF, named innoticeinclude_coordsinlines coordinate content, subject to a response budget — an over-budget batch returns a per-structure size outline (re-call withsections: [ids]), and a single oversized file is withheld with a pointer to itscoordinateUrlsEvery response carries an
attributionblock naming upstream data licenses and citations
protein_find_similar tool
by: sequenceruns a synchronous RCSB mmseqs2 search;by: structureruns an asynchronous Foldseek search against experimental and predicted databases — query from a raw sequence, a PDB ID, or a UniProt accessionBoth modes accept
start/limitand reporttotalCount, echoingstartand returningnextStartwhile another page remains; an empty page past the end names the offset innotice, distinct from a search with no matchesFoldseek targets default to
pdb100+afdb50; override viadatabases(e.g.afdb-swissprot,BFVD)An async job that exceeds the poll budget returns
status: computingwith aticketId— re-call withticket_idto resume; a completed structure search returns the same ticket so a newstartpages the finished jobFoldseek searches each chain of a multichain structure as its own query: a structure response covers one query (
query, 0-based, default0) and reportsqueryCount, with anoticenaming the other queries; passquerywithticket_idto read another chain's hits from the same job. An out-of-rangequeryis rejected (query_out_of_range), not answered with an empty listStructure hits are ranked best first by
scoreacross every searched database (hits without a score last, ties by database then target) beforestart/limitpagingEach mode reads only its own controls (
sequence,max_evalue,min_identityunderby: sequence;ticket_id,databases,queryunderby: structure) — a field the selected mode can't consume is rejected, not ignoredEach hit names the engine and source database it came from
protein_track_ligands tool
mode: find_ligandresolves a name or formula to chemical component IDs with formula, weight, SMILES, and InChIKey — ranked by deposition frequency, most-common match firsttotalCountandcandidatesConsideredreport how many components matched and how many were ranked; a broad name whose matches exceed the candidate pool gets anoticeto narrow the queryA formula-shaped
querymatches on exact composition, spaced (C29 H31 N7 O) or unspaced; anything else (a component ID included) matches on name and synonymsmode: structures_with_ligandreturns PDB entries containing a ligand by exact component ID, withstart/limitpaging andnextStartwhile another page remains; a page past the end names the offset innoticeinstead of reporting no entriesmode: binding_sitereturns the protein residues lining a ligand's pocket in a structure, with contact distances; ligand instances page withstart/limitlikestructures_with_ligandPocket residues carry both mmCIF label numbering (
asymId,seqId) and author numbering (authAsymId,authSeqId) — 1IEP's imatinib pocket lists label THR93 as author THR315; the ligand instance reports its own author chain and residue numberBinding sites are experimental-only — computed from deposited coordinates; predicted models carry no bound ligands
protein_compare_structures tool
Aligns 2 to the configured cap (default 10, max 25) structures per call, via
tm-align,fatcat-rigid, orfatcat-flexible; optional per-structurechainrestricts the alignment to a single mmCIF label chainreference: firstaligns every structure to the first;reference: all_pairscomputes the full pairwise matrix; a structure repeated instructures[]is compared onceEach pair is an independent async job with per-pair partial success — a pair still computing when the poll budget elapses returns
status: computingwith a jobuuid; a failed pair degrades only its own rowRe-call with a matching
{ a, b, uuid }entry inresume[]to poll a computing pair instead of resubmitting; a resumed pair reportsa/bin the order its job was submitted, whatever the currentstructures[]order, and a resume under a differentmethodis rejectedReturns TM-score, RMSD, and aligned-residue count per pair, plus each structure's
modeledResiduesand 0–100coverage, ordered[a, b]; TM-score is normalized bya's length, so the same pair scores differently when reversed
protein_analyze_collection tool
Group by
method,organism,polymer_type,resolution,release_year, ormolecular_weightOne
group_bydimension for a breakdown, or two distinct dimensions for a cross-tab (the first nests the second); a repeated dimension is rejectedintervalsets a histogram bin width (a number, forresolutionormolecular_weight) or date-histogram period (year, the only one RCSB accepts) — applies to whichever requested dimension can consume that type; rejected when neither canScope with a free-text
query,organism,method, ormax_resolution;content_typeselects the structure universebucket_limitcaps buckets per dimension level, not per response — a cross-tab applies it separately to the parent and each nested child, up tobucket_limit × (1 + bucket_limit)buckets;noticenames every capped position andbucketsReturnedgives the realized totalEvery dimension reports
missingValueCount— matches carrying no value for that attribute (e.g. aresolutionbreakdown excludes NMR entries; computed models have neithermethodnorresolution)
protein_get_annotations tool
UniProt features (domains, binding sites, PTMs) and natural variants, plus InterPro domain/family memberships (Pfam, PROSITE, …) with associated GO terms
Provide a UniProt accession directly, or a PDB ID — resolved via the structure's sequence cross-reference
A multi-chain PDB entry can map to several accessions; the default is the deterministic lowest-author-chain pick, with alternatives listed under
ambiguity— passchain(an author chain ID) to select a specific oneincludescopes which classes are fetched (features,domains,variants,all);limitcaps each class independently (1–200, default 50), with a truncated class disclosed innoticeEvery response carries an
attributionblock naming the upstream data licenses and citations (see Upstream data licensing)
pdb://{entry_id} resource
Experimental structure summary as
application/json— title, method, resolution, organism, bound ligands, and per-entity chain IDs in both the author (authAsymIds) and mmCIF label (labelAsymIds) namespacesMirrors
protein_get_structureforsource: experimental;entry_idis a PDB entry ID (e.g.4HHB)
af://{uniprot} resource
Predicted-structure summary as
application/json— mean pLDDT, confidence-band fractions, model URLs (cif/pdb/bcif), and AlphaFold model versionuniprotaccepts a UniProt accession or an AlphaFold DB entry ID (e.g.AF-P69905-F1); mirrorsprotein_get_structureforsource: predicted
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.
PDB / AlphaFold-specific:
One federated surface over experimental (PDB) and predicted (AlphaFold / 3D-Beacons) structures — search, fetch, and compare treat both universes the same
Keyless across every upstream — RCSB, AlphaFold DB, 3D-Beacons, UniProt, InterPro, and Foldseek, no API keys to provision
Corpus analytics run on RCSB's facet engine — distributions, histograms, and cross-tabs come back as compact bucket counts, not the matching entries
Async alignment and Foldseek jobs poll within a bounded budget and hand back a job ticket (
ticketId/ per-pairuuid) instead of blocking — re-call withticket_idor aresume[]entry to poll the same job instead of resubmitting
Agent-friendly output:
Provenance on every response — each hit carries a
source(experimental/predicted), the engine and database that produced it, and effective-query / total-count echoes so agents can reason about coverageGraceful partial failure — batch fetches and pairwise comparisons return per-item rows (
failed[], per-pairstatus) instead of failing the whole request, each with actionable recovery textDiscriminated output contracts — typed
sourceandstatusunions,computingresults with resume tickets, and budget-overflow outlines let callers branch on data, not string parsing
Getting started
Public Hosted Instance
A public instance is available at https://protein.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"protein": {
"type": "streamable-http",
"url": "https://protein.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
Add the following to your MCP client configuration file. No API key is required — every upstream provider is keyless.
{
"mcpServers": {
"protein-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/protein-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"protein-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/protein-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with Docker:
{
"mcpServers": {
"protein-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/protein-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/mcpPrerequisites
Bun v1.4.0 or higher (or Node.js v24+).
No accounts or API keys — RCSB, AlphaFold DB, 3D-Beacons, UniProt, InterPro, and Foldseek are all public and keyless.
Installation
Clone the repository:
git clone https://github.com/cyanheads/protein-mcp-server.gitNavigate into the directory:
cd protein-mcp-serverInstall dependencies:
bun installConfiguration
All upstream providers are keyless, so the server runs out of the box with no configuration. Every variable below is optional.
Variable | Description | Default |
| Max wall-clock to poll an async job (alignment / Foldseek) before returning a |
|
| Cap on IDs accepted by |
|
| Cap on structures per |
|
| Default cap on buckets per |
|
| Max concurrent upstream requests for per-ID / per-pair fan-out (1–16). |
|
| Base URL for the RCSB Search API v2. |
|
| Base URL for the AlphaFold Protein Structure Database API. |
|
| Base URL for the Foldseek structural-similarity search service. |
|
| Transport: |
|
| Port for the HTTP server. |
|
| HTTP session mode: |
|
| Auth mode: |
|
| Log level (RFC 5424). |
|
| Enable OpenTelemetry instrumentation. |
|
See .env.example for the full list of provider base-URL overrides and tuning limits.
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:httpRun 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 protein-mcp-server .
docker run --rm -e MCP_TRANSPORT_TYPE=http -p 3010:3010 protein-mcp-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/protein-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| Resource definitions ( |
| Provider service layer — RCSB (search, data, facets), AlphaFold, 3D-Beacons (best-available), UniProt (incl. InterPro/GO), Structural Comparison alignment, Foldseek, and shared HTTP/identifier/concurrency helpers. |
| Unit and integration tests mirroring |
Development guide
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageRegister new tools and resources via the barrels in
src/mcp-server/*/definitions/index.tsWrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Upstream data licensing
Structure and annotation data comes from public upstream databases, each under its own license. protein_get_structure and protein_get_annotations carry an attribution block on every response — the license, citation, and homepage for each source that contributed to that specific response — so the attribution obligation travels with the data to downstream consumers rather than living only here. CC BY / CC BY-SA sources require attribution on redistribution; CC0 sources are citation-only (attribution encouraged, not required).
Source | Contributes to | License |
| CC0 1.0 Universal | |
| CC BY 4.0 | |
| CC BY 4.0 | |
| CC BY-SA 4.0 | |
| CC BY 4.0 | |
| CC BY 4.0 | |
| CC0 1.0 Universal | |
| CC BY 4.0 |
best_available federates predicted models through 3D-Beacons, so the attribution block credits the actual contributing provider (AlphaFold DB, SWISS-MODEL, BFVD, …); a provider without a curated license entry carries a See provider terms fallback pointing back to 3D-Beacons rather than a fabricated license. InterPro's own domain/family classifications are CC0; the GO terms carried alongside them are separately CC BY 4.0, so each is credited independently only when it actually contributes. Full citations for each source travel in the attribution block of the relevant tool responses. This covers upstream data licensing — the server's own code is licensed separately (see License).
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
RCSB PDB MCP — experimentally determined macromolecular structures.
Agent-to-Agent (A2A) + Model Context Protocol (MCP) hub for peptides.
Model Context Protocol server for Studex tools, notifications, and profile integrations
PDBe (Protein Data Bank in Europe, EBI) MCP.
Related MCP Servers
- FlicenseBqualityDmaintenanceA Model Context Protocol server that enhances language models with protein structure analysis capabilities, enabling detailed active site analysis and disease-related protein searches through established protein databases.219-
- FlicenseCqualityDmaintenanceA comprehensive Model Context Protocol (MCP) server providing advanced access to the UniProt protein database.2620-
- FlicenseAqualityFmaintenanceA Model Context Protocol (MCP) server that provides access to the Protein Data Bank (PDB) - the worldwide repository of information about the 3D structures of proteins, nucleic acids, and complex assemblies.526-
- FlicenseBqualityDmaintenanceA comprehensive Model Context Protocol (MCP) server that provides access to the AlphaFold Protein Structure Database through a rich set of tools and resources for protein structure prediction analysis.1935-