About protein-mcp-server
protein-mcp-server brings experimental and predicted protein structures and annotations together for structural biology and protein research. It supports structure search, similarity lookup, alignment, ligand tracking, and collection statistics, with source attribution.
Key features
- 01Search experimental and predicted structures
- 02Fetch structure metadata and coordinates
- 03Find sequence or structural homologs
- 04Track ligands and binding sites
- 05Compare multiple protein structures
- 06Retrieve UniProt and InterPro annotations
Use cases
- 01Filter structures by sequence or organism
- 02Compare protein models and inspect similarity
- 03Find structures containing a ligand and its binding site
MCP support
As an MCP server, it exposes tools for protein structure search and retrieval, similarity analysis, ligand tracking, structure comparison, and annotation, plus PDB and AlphaFold resources. It supports STDIO and Streamable HTTP.
Configuration
Local server config is the same for every client. Copy it into your client’s MCP config file.
npx -y protein-mcp-serverMCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODESecretAuthentication mode to use: 'none', 'jwt', or 'oauth'.Local servers need a runtime on your machine (e.g. Node.js 18+). Config file locations differ by client; see your client’s docs.
Tools
6Saved tool list · updated 2w ago
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum number of results to return (1-100, default 25). |
| query | string | Yes | Search query for protein name, PDB ID, keyword, or description (e.g., "kinase", "hemoglobin", "1ABC"). |
| offset | integer | No | Offset for pagination (default 0). |
| organism | string | No | Filter by source organism scientific name (e.g., "Homo sapiens", "Escherichia coli"). |
| maxResolution | number | No | Maximum resolution in Angstroms (e.g., 2.0 for high-resolution structures). |
| minResolution | number | No | Minimum resolution in Angstroms. |
| experimentalMethod | enum | No | Filter by experimental method used to determine the structure.X-RAY DIFFRACTION | SOLUTION NMR | ELECTRON MICROSCOPY | NEUTRON DIFFRACTION | FIBER DIFFRACTION | SOLID-STATE NMR | THEORETICAL MODEL |
Details
From the project README@cyanheads/protein-mcp-server
Federated protein structure & annotation across experimental (PDB) and predicted (AlphaFold) models via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://protein.caseyjhand.com/mcp
Overview
Experimental (PDB) and predicted (AlphaFold) protein structures behind one surface. Search, fetch, align, and annotate structures and their ligands across RCSB, AlphaFold DB, 3D-Beacons, UniProt, InterPro, and Foldseek. No API key required.
Tools
| Tool | Description |
|---|---|
protein_search_structures | Search experimental and predicted structures by text, sequence, or organism/method/resolution, with optional facets |
protein_get_structure | Fetch metadata and coordinate URLs for experimental, predicted, or best-available structures |
protein_find_similar | Find sequence homologs (RCSB mmseqs2) or fold homologs (Foldseek) |
protein_track_ligands | Resolve ligands to component IDs, find structures containing one, or map its binding site |
protein_compare_structures | Align structures with TM-align or jFATCAT, against a reference or all pairs |
protein_analyze_collection | Profile the PDB as counts, histograms, timelines, and cross-tabs |
protein_get_annotations | Fetch UniProt features and variants plus InterPro domains with GO terms |
Resources
| Resource | Description |
|---|---|
pdb://{entry_id} | Experimental structure summary for a PDB entry |
af://{uniprot} | AlphaFold DB predicted-structure summary for a UniProt accession |
Both resources are also reachable through protein_get_structure, for clients that don't surface resources.
Capability reference
protein_search_structures tool
- At least one of
query,sequence(an mmseqs2 search;min_identity/max_evalueapply only with it),organism,method, ormax_resolution;content_typeisexperimental,predicted, orall(default); up to 100 hits per page (default 25) vialimit/start - A
sequenceneeds at least 10 residues; whitespace is stripped and case normalized, and an invalid one fails asinvalid_sequence. Each hit names itssourceand an entryidyou can pass to other tools - Optional
facets(method,organism,polymer_type,resolution,release_year,molecular_weight) add a breakdown capped atPROTEIN_FACET_BUCKET_CAPbuckets per dimension
protein_get_structure tool
source: experimental(default) takes PDB entry IDs and theAF_*/MA_*computed-model IDs search returns (these come back assource: predicted);predictedtakes UniProt accessions for AlphaFold models with pLDDT/PAE;best_availabletakes UniProt accessions and returns the highest-resolution experimental structure, else the best prediction. Up toPROTEIN_MAX_BATCH_IDSIDs per call (default 25)- Unresolved IDs land in
failed[], andrequested/processedshow IDs dropped past the cap; the call fails asall_failedwhen nothing resolves andmixed_id_typeswhen the IDs don't fitsource. Records includecoordinateUrlsfor the files that exist include_coordsinlines coordinate text within a size budget; an over-budget batch returns anoverflowoutline to re-call withsections: [ids]
protein_find_similar tool
by: sequenceruns a synchronous RCSB mmseqs2 search fromsequence,pdb_id, oruniprot, filtered bymax_evalue/min_identity;by: structureruns an async Foldseek search frompdb_idoruniprotagainstpdb100+afdb50unlessdatabasessays otherwise. A field only the other mode reads fails asmode_mismatched_field; up to 100 hits per page (default 25)- Sequences follow the same rules as
protein_search_structures, and a directsequencewins over identifiers. Hits name theirsource(anddatabasefor structure hits), ranked byscore; responses reporttotalCountandnextStart - A structure job still running at the poll budget returns
status: computingwith aticketId; re-call withticket_idto resume it. A multichain structure is searched one chain at a time viaquery(0-based, default 0) out ofqueryCount
protein_track_ligands tool
modeisfind_ligand(query: a name or formula),structures_with_ligand(comp_id), orbinding_site(pdb_id, optionalcomp_id); a missing mode input fails asmissing_param.limitis 1–100 (default 25), andstartpages the last two modesfind_ligandreturns component IDs with formula, weight, SMILES, and InChIKey, ranked bydepositionCount, withtotalCountandcandidatesConsideredshowing when the candidate pool was cut short;structures_with_ligandlists entries highest resolution firstbinding_sitereturns pocket residues with contact distances, numbered in both label (asymId,seqId) and author (authAsymId,authSeqId) namespaces; it works on experimental structures only
protein_compare_structures tool
- 2 structures up to
PROTEIN_MAX_COMPARE_STRUCTURES(default 10, max 25), each apdb_idwith an optional label-namespacechain;methodistm-align(default),fatcat-rigid, orfatcat-flexible;referenceisfirst(default) orall_pairs;timeout_s(5–120) sets the per-pair poll budget - Each pair row has a
status(complete,computing,failed),tmScore,rmsd,alignedResidues,modeledResidues, andcoverage; TM-score is normalized bya's length, so reversing a pair changes it.similarityScoreandsequenceSimilarityappear when the upstream supplies them - A computing pair returns its job
uuid; re-call with{ a, b, uuid }inresume[]to poll it instead of resubmitting. A mismatchedmethodor pair fails asresume_method_mismatchorresume_job_mismatch
protein_analyze_collection tool
group_bytakes one ofmethod,organism,polymer_type,resolution,release_year,molecular_weight, or two distinct ones for a cross-tab; scope withquery,organism,method,max_resolution, andcontent_type(defaultexperimental).intervalsets a numeric bin width forresolution/molecular_weightor"year"forrelease_year- Returns
totalandbucketsReturned; buckets carrylabelandcount(numeric bins addrangeFrom/rangeTo), and every dimension reportsmissingValueCount bucket_limit(1–500, defaultPROTEIN_FACET_BUCKET_CAP) caps each dimension separately;truncatedandnoticesay where results were cut
protein_get_annotations tool
- A
uniprotaccession, or apdb_idresolved through its UniProt cross-reference (authorchainpicks one accession);includeisfeatures,domains,variants, orall(default);limitpages each class separately (1–200, default 50), with independent zero-basedfeatures_offset,variants_offset, anddomains_offset(default 0) - Returns UniProt features and natural variants plus InterPro domains with GO terms; a PDB entry mapping to several accessions uses the lowest author chain and lists the rest in
ambiguity - Each requested class carries
featuresTotal,variantsTotal, ordomainsTotal; a page with more records setstruncatedand names the next offset innotice - Failures are typed as
missing_identifier,invalid_accession,no_uniprot_mapping, orchain_not_found
pdb://{entry_id} resource
entry_idis a PDB entry ID (e.g.4HHB); returnsapplication/jsonwith title, methods, resolution, organisms, ligands, andpolymerEntitiescarrying bothauthAsymIdsandlabelAsymIds- Same data as
protein_get_structurewithsource: experimental
af://{uniprot} resource
uniprotis a UniProt accession or an AlphaFold DB entry ID (e.g.AF-P69905-F1); returnsapplication/jsonwithmeanPlddt,confidenceBuckets,cifUrl/pdbUrl/bcifUrl, andmodelVersion- Same data as
protein_get_structurewithsource: 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:
- Search, fetch, and comparison treat experimental (PDB) and predicted (AlphaFold DB, ModelArchive, 3D-Beacons providers) structures the same way
- Keyless across RCSB, AlphaFold DB, 3D-Beacons, UniProt, InterPro, and Foldseek
- Collection analytics run on RCSB's facet engine and return bucket counts, not matching entries
- Foldseek and alignment jobs poll for up to
PROTEIN_ASYNC_POLL_TIMEOUT_MS(default 30 s), then hand back a resume handle (ticketId, per-pairuuid) instead of blocking - Chain namespaces stay separate:
authAsymIdsfeedprotein_get_annotationschain,labelAsymIdsfeedprotein_compare_structureschain
Agent-friendly output:
- Provenance: every hit names its
source(experimental/predicted) and the engine or database behind it, andprotein_get_structureandprotein_get_annotationscarry anattributionblock (see Upstream data licensing) - Graceful partial failure:
failed[]rows and per-pairstatuskeep one bad ID or pair from failing the request - Paging and advisories: paged tools return
totalCountandnextStart, astartpast the end is flagged innoticeseparately from zero matches, and every advisory joins into that onenotice
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-mcp-server": {
"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 needed.
{
"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/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- No accounts or API keys: every upstream is public.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/protein-mcp-server.git
- Navigate into the directory:
cd protein-mcp-server
- Install dependencies:
bun install
- Configure environment (optional):
cp .env.example .env
# every variable has a working default
Configuration
Every variable is optional.
| Variable | Description | Default |
|---|---|---|
PROTEIN_ASYNC_POLL_TIMEOUT_MS | Poll budget for an async alignment or Foldseek job before it returns computing (min 1000). | 30000 |
PROTEIN_MAX_BATCH_IDS | Max IDs per protein_get_structure call (1–100). | 25 |
PROTEIN_MAX_COMPARE_STRUCTURES | Max structures per protein_compare_structures call (2–25). | 10 |
PROTEIN_FACET_BUCKET_CAP | Buckets per dimension for protein_search_structures facets, and the protein_analyze_collection default (1–500). | 50 |
PROTEIN_FANOUT_CONCURRENCY | Max concurrent upstream requests for per-ID and per-pair fan-out (1–16). | 5 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. Overrides the stateless mode the server declares in code. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
OTEL_ENABLED | Enable OpenTelemetry. | false |
Each upstream's base URL can also be pointed at a mirror: RCSB_SEARCH_BASE_URL, RCSB_DATA_BASE_URL, RCSB_FILES_BASE_URL, RCSB_MODELS_BASE_URL, RCSB_ALIGNMENT_BASE_URL, BEACONS_BASE_URL, ALPHAFOLD_BASE_URL, MODELARCHIVE_BASE_URL, FOLDSEEK_BASE_URL, UNIPROT_BASE_URL, INTERPRO_BASE_URL. See .env.example for their defaults and 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 protein-mcp-server .
docker run --rm -p 3010:3010 protein-mcp-server
The 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 |
|---|---|
src/index.ts | createApp() entry point: registers tools and resources, inits the provider services. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts) and shared schemas (_schemas.ts). |
src/mcp-server/resources | Resource definitions (*.resource.ts). |
src/services | Upstream clients: rcsb/ (search, data, facets), alphafold/, beacons/ (3D-Beacons), uniprot/ (UniProt, InterPro, GO), alignment/ (RCSB Structural Comparison), foldseek/, and shared/ HTTP, concurrency, identifier, and attribution helpers. |
tests/ | Unit and integration tests mirroring src/. |
Development guide
See CLAUDE.md/AGENTS.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 - Export new definitions from the barrels in
src/mcp-server/*/definitions/index.tsand register them in thecreateApp()arrays insrc/index.ts - Wrap 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 databases, each under its own license. protein_get_structure and protein_get_annotations return an attribution block with the license, citation, and homepage of every source that contributed to that response. CC BY and CC BY-SA sources require attribution on redistribution; CC0 sources ask only for citation.
| Source | Contributes to | License |
|---|---|---|
| RCSB PDB | protein_get_structure — experimental records | CC0 1.0 Universal |
| AlphaFold DB | protein_get_structure — predicted models | CC BY 4.0 |
| ModelArchive | protein_get_structure — MA_* computed models | CC BY 4.0 |
| SWISS-MODEL | protein_get_structure — best_available models | CC BY-SA 4.0 |
| BFVD | protein_get_structure — best_available models | CC BY 4.0 |
| UniProt | protein_get_annotations | CC BY 4.0 |
| InterPro | protein_get_annotations — domain/family data | CC0 1.0 Universal |
| GO | protein_get_annotations — GO terms | CC BY 4.0 |
best_available models arrive through 3D-Beacons, so the block credits the provider that actually supplied the model; a provider with no curated entry gets a See provider terms fallback instead of a guessed license. InterPro and GO are credited separately, each only when it contributes. This table covers upstream data; 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 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.