GitHub repo:
fzlzjerry/uniprot-mcp· PyPI package & command:uniprotkb-mcp(the Python import package isuniprot_mcp).
A production-quality MCP server that exposes the UniProt REST API
to LLM clients (Claude Code, Claude Desktop, …) over stdio. Built with
FastMCP and managed with uv.
Tools return compact, token-efficient summaries by default and full payloads only on request, with robust error handling and an embedded UniProt query cheat-sheet so the model writes valid queries.
Published on PyPI — no clone, no install needed:
uvx uniprotkb-mcpThen point your MCP client at it (full config below):
{
"mcpServers": {
"uniprot": {
"command": "uvx",
"args": ["uniprotkb-mcp"],
"env": { "UNIPROT_MCP_CONTACT": "you@example.org" }
}
}
}| Tool | What it does |
|---|---|
search_uniprotkb |
Search UniProtKB with native query syntax. reviewed / organism_id filters are added for you. Summary, FASTA, or TSV output. |
get_entry |
One entry as a curated digest (function, names, organism, length, subcellular location, family/domains, key features, PTMs, keywords, PDB/AlphaFold/Ensembl/RefSeq/InterPro/GO cross-refs) or json/fasta/txt/gff. |
get_fasta |
Raw FASTA for one accession or a batch. |
map_ids |
Convert ids across databases via UniProt's async ID-mapping (e.g. RefSeq_Protein→UniProtKB, UniProtKB_AC-ID→PDB). Returns mapped pairs and unmapped ids; validates the db pair against the live config. |
get_taxonomy |
Resolve an organism name or taxon id → taxon id, names, rank, lineage. Turn "human" into organism_id:9606. |
search_uniref |
Search UniRef100/90/50 sequence-similarity clusters. |
search_proteomes |
Search proteomes (whole-organism protein sets); reference-proteome filter. |
Plus an MCP resource resource://uniprot/query-cheatsheet documenting the
UniProtKB query syntax (gene:, organism_id:, reviewed:true,
length:[X TO Y], keyword:, ec:, boolean AND/OR/NOT, …).
- Python ≥ 3.10 (the repo pins 3.13 via
.python-version) uv
git clone https://github.com/fzlzjerry/uniprot-mcp
cd uniprot-mcp
uv sync # creates .venv and installs fastmcp + httpx# stdio server (what MCP clients launch):
uv run uniprotkb-mcpUniProt asks API clients to identify themselves with a contact address. Set one
via the UNIPROT_MCP_CONTACT environment variable (it goes into the
User-Agent); otherwise a placeholder is used.
UNIPROT_MCP_CONTACT="you@example.org" uv run uniprotkb-mcpuvx (a.k.a. uv tool run) fetches, builds, and runs the console script in a
throwaway environment — nothing to install first. Pick whichever source you have:
# From PyPI (published):
uvx uniprotkb-mcp
# From a Git repo (note: repo is uniprot-mcp, command is uniprotkb-mcp):
uvx --from git+https://github.com/fzlzjerry/uniprot-mcp uniprotkb-mcp
# From a local checkout (this directory):
uvx --from /ABSOLUTE/PATH/TO/uniprot-mcp uniprotkb-mcp
# From a built wheel:
uvx --from ./dist/uniprotkb_mcp-0.1.0-py3-none-any.whl uniprotkb-mcpPin a version with uvx uniprotkb-mcp@0.1.0, or force a refresh of the cached
build with uvx --refresh --from <source> uniprotkb-mcp.
Edit claude_desktop_config.json
(macOS: ~/Library/Application Support/Claude/claude_desktop_config.json,
Windows: %APPDATA%\Claude\claude_desktop_config.json) and add:
{
"mcpServers": {
"uniprot": {
"command": "uvx",
"args": ["uniprotkb-mcp"],
"env": { "UNIPROT_MCP_CONTACT": "you@example.org" }
}
}
}This runs the published package straight from PyPI. To run unreleased code
instead, add a source: "args": ["--from", "git+https://github.com/fzlzjerry/uniprot-mcp", "uniprotkb-mcp"]
(git) or "args": ["--from", "/ABSOLUTE/PATH/TO/uniprot-mcp", "uniprotkb-mcp"]
(local checkout). Make sure uvx is on the PATH Claude Desktop sees (it ships
with uv; give the absolute path to uvx if needed, e.g. ~/.local/bin/uvx).
Restart Claude Desktop and the uniprot tools appear.
Prefer a cloned checkout instead of
uvx? Use"command": "uv", "args": ["run", "--directory", "/ABSOLUTE/PATH/TO/uniprot-mcp", "uniprotkb-mcp"].
Project-scoped via a .mcp.json in your project root (same shape):
{
"mcpServers": {
"uniprot": {
"command": "uvx",
"args": ["uniprotkb-mcp"],
"env": { "UNIPROT_MCP_CONTACT": "you@example.org" }
}
}
}Or from the CLI:
# via uvx (published / git / local source):
claude mcp add uniprot -e UNIPROT_MCP_CONTACT=you@example.org -- uvx uniprotkb-mcp
# via a local checkout with uv:
claude mcp add uniprot -e UNIPROT_MCP_CONTACT=you@example.org \
-- uv run --directory /ABSOLUTE/PATH/TO/uniprot-mcp uniprotkb-mcpExercises every tool against the live API and prints the output:
UNIPROT_MCP_CONTACT="you@example.org" uv run python -m tests.smokeDeveloping, testing, CI, and the release process (CI-driven PyPI Trusted
Publishing — no token) are documented in CONTRIBUTING.md.
TL;DR: uv sync, then uv run python -m tests.check_structure (offline) and
uv run python -m tests.smoke (live API).
- Single shared
httpx.AsyncClientwith a descriptiveUser-Agentincluding your contact. - Retry/backoff on
429(honoringRetry-After) and5xx;400surfaces UniProt's own error message; no raw tracebacks reach the client (errors are raised asToolError). - Pagination via the
Linkheader /x-total-results; result sizes are capped (≤ 500) and the total is always reported so you can narrow or page. - ID mapping follows the real async flow:
POST /idmapping/run→ poll/idmapping/status/{job}(a303+Locationsignals completion) → fetch results, automatically choosing the enriched UniProtKB results endpoint vs. the simple-pair endpoint based on the target database.
src/uniprot_mcp/
server.py # FastMCP instance, the 7 tools, cheat-sheet resource, main()
client.py # shared AsyncClient, retry/backoff, error mapping, header parsing
idmapping.py # async run/poll/results flow with target-aware routing
config.py # cached idmapping db config + from/to validation
formatting.py # JSON -> compact summary digests
cheatsheet.py # UniProt query cheat-sheet
tests/smoke.py # live-API smoke test