{
  "markdown": "<!-- mcp-name: io.github.smaniches/uniprot-mcp -->\n\n# UniProt MCP Server\n\n[![CI](https://github.com/smaniches/uniprot-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/smaniches/uniprot-mcp/actions/workflows/ci.yml)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/smaniches/uniprot-mcp/badge)](https://api.securityscorecards.dev/projects/github.com/smaniches/uniprot-mcp)\n[![GitHub Release](https://img.shields.io/github/v/release/smaniches/uniprot-mcp?sort=semver)](https://github.com/smaniches/uniprot-mcp/releases)\n[![PyPI version](https://img.shields.io/pypi/v/uniprot-mcp-server)](https://pypi.org/project/uniprot-mcp-server/)\n[![PyPI downloads/30d](https://img.shields.io/pypi/dm/uniprot-mcp-server?label=downloads%2F30d)](https://pypistats.org/packages/uniprot-mcp-server)\n[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)\n[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)\n[![MCP compatible](https://img.shields.io/badge/MCP-compatible-6e56cf.svg)](https://modelcontextprotocol.io/)\n[![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](pyproject.toml)\n[![Provenance: SHA-256 + verify](https://img.shields.io/badge/provenance-SHA--256_+_verify-blue)](#provenance--verification)\n[![ORCID](https://img.shields.io/badge/ORCID-0009--0005--6480--1987-A6CE39?logo=orcid&logoColor=white)](https://orcid.org/0009-0005-6480-1987)\n[![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.19817710-3C5A99?logo=zenodo&logoColor=white)](https://doi.org/10.5281/zenodo.19817710)\n[![Glama score](https://glama.ai/mcp/servers/smaniches/uniprot-mcp/badges/score.svg)](https://glama.ai/mcp/servers/smaniches/uniprot-mcp)\n[![Awesome MCP Servers](https://img.shields.io/badge/Awesome_MCP-Listed-blue?logo=github)](https://github.com/punkpeye/awesome-mcp-servers#bio)\n\nProduce verifiable, release-aware protein evidence packages from UniProt and linked scientific sources.\n\nUse this MCP server to find proteins, assemble protein, target, and variant evidence, and keep a checkable record of where each result came from. Each successful response records the UniProt release, retrieval time, resolved source URL, and a SHA-256 digest. `uniprot_provenance_verify` can later determine whether the upstream record is unchanged or has drifted.\n\nThe complete tool catalog remains available for specialized research workflows.\n\n> Author: **Santiago Maniches** · ORCID [0009-0005-6480-1987](https://orcid.org/0009-0005-6480-1987) · TOPOLOGICA LLC\n\n**Run it in one line:**\n\n```bash\nuvx uniprot-mcp-server\n```\n\n---\n\n## Verifiable provenance (the receipts)\n\nEvery answer this server returns is traceable to a primary-source URL **and**\na content hash you can re-compute yourself. The walkthrough below is a real\nrun against the live server (UniProt release `2026_01`), independently\nconfirmed against the UniProt REST API.\n\n**Question.** What is the function of human p53 (UniProt `P04637`), what\nheritable cancer syndrome is it associated with, and is the `R175H` mutation\na documented disease variant?\n\n**Answer, with its provenance footer (verbatim from the server):**\n\n- **Function.** *Cellular tumor antigen p53* (gene `TP53`, *Homo sapiens*,\n  393 aa). \"Multifunctional transcription factor that induces cell cycle\n  arrest, DNA repair or apoptosis... Acts as a tumor suppressor in many tumor\n  types.\"\n- **Disease.** *Li-Fraumeni syndrome* (acronym `LFS`, UniProt disease id\n  `DI-01904`, OMIM `151623`) — \"an autosomal dominant familial cancer\n  syndrome... Four types of cancers account for 80% of tumors occurring in\n  TP53 germline mutation carriers.\"\n- **Variant.** `R175H` — \"in LFS; germline mutation and in sporadic cancers;\n  somatic mutation; does not induce SNAI1 degradation; reduces interaction\n  with ZNF385A; dbSNP:`rs28934578`.\"\n\n```\nSource: UniProt release 2026_01 (28-January-2026) • Retrieved 2026-06-09T11:47:51Z\nQuery: https://rest.uniprot.org/uniprotkb/P04637\nSHA-256: 0040d79bb39e2f7386d55f81071e87858ec2e5c2cd9552e93c3633897f78345e\nAccept: application/json\n```\n\n### Reproduce it\n\n**1. Run the server and ask the same question** (any MCP client; tool calls shown):\n\n```bash\nuvx uniprot-mcp-server\n# uniprot_get_entry(accession=\"P04637\")               -> function + gene + diseases\n# uniprot_get_disease_associations(accession=\"P04637\") -> LFS, OMIM 151623\n# uniprot_lookup_variant(accession=\"P04637\", change=\"R175H\") -> the LFS variant record\n```\n\n**2. Confirm the hash re-verifies** (re-fetches the URL and re-checks the\nrelease + canonical hash with the server's own code):\n\n```bash\n# uniprot_provenance_verify(\n#   url=\"https://rest.uniprot.org/uniprotkb/P04637\",\n#   release=\"2026_01\",\n#   response_sha256=\"0040d79bb39e2f7386d55f81071e87858ec2e5c2cd9552e93c3633897f78345e\")\n# -> Status: verified  (release match + SHA-256 match)\n```\n\n**3. Confirm the values against the primary source — no server in the loop:**\n\n```bash\ncurl -s -H \"Accept: application/json\" https://rest.uniprot.org/uniprotkb/P04637 -o p53.json\n\n# UniProt release served (matches the footer):\ncurl -sI -H \"Accept: application/json\" https://rest.uniprot.org/uniprotkb/P04637 | grep -i x-uniprot-release\n# -> X-UniProt-Release: 2026_01\n\npython - <<'PY'\nimport json, hashlib\nd = json.load(open(\"p53.json\", encoding=\"utf-8\"))\nprint(\"gene        :\", d[\"genes\"][0][\"geneName\"][\"value\"])                       # TP53\nprint(\"protein     :\", d[\"proteinDescription\"][\"recommendedName\"][\"fullName\"][\"value\"])  # Cellular tumor antigen p53\nprint(\"organism    :\", d[\"organism\"][\"scientificName\"], \"| length\", d[\"sequence\"][\"length\"])  # Homo sapiens | 393\nfor c in d[\"comments\"]:\n    if c.get(\"commentType\") == \"DISEASE\" and c[\"disease\"].get(\"acronym\") == \"LFS\":\n        x = c[\"disease\"]\n        print(\"disease     :\", x[\"diseaseId\"], \"| OMIM\", x[\"diseaseCrossReference\"][\"id\"])  # Li-Fraumeni syndrome | 151623\nfor f in d[\"features\"]:\n    if f.get(\"type\") == \"Natural variant\" and f[\"location\"][\"start\"][\"value\"] == 175:\n        a = f.get(\"alternativeSequence\", {})\n        if a.get(\"originalSequence\") == \"R\" and a.get(\"alternativeSequences\") == [\"H\"]:\n            print(\"variant     : R175H |\", f[\"description\"])  # in LFS; germline mutation ...\n\n# The footer SHA-256 is reproducible from these exact bytes (no server):\n# the server hashes the JSON re-serialized with sorted keys + compact separators.\ncanonical = json.dumps(d, sort_keys=True, separators=(\",\", \":\"), ensure_ascii=False).encode(\"utf-8\")\nprint(\"sha-256     :\", hashlib.sha256(canonical).hexdigest())\n# -> 0040d79bb39e2f7386d55f81071e87858ec2e5c2cd9552e93c3633897f78345e\nPY\n```\n\n**What this proves:** every returned claim is traceable to a primary-source\nURL and a content hash. The gene, protein name, disease (with OMIM id), and\nvariant the server reports all match the live UniProt entry; the footer\nSHA-256 is reproducible byte-for-byte from the primary source using a\ndocumented, server-independent recipe. A third party can re-run all three\nchecks today, or a year from now, without trusting this server.\n\n> Note on the hash: the footer SHA-256 is of the *canonical* UniProt response\n> body — the JSON re-serialized with sorted keys and compact separators\n> (`json.dumps(obj, sort_keys=True, separators=(\",\", \":\"), ensure_ascii=False)`),\n> so harmless key-order changes within a release do not break verification. A raw\n> `curl | sha256sum` of the bytes will therefore differ; apply the same\n> canonicalization (step 3 above) or use `uniprot_provenance_verify`.\n\n---\n\n## Installation\n\nRun without installing (recommended):\n\n```bash\nuvx uniprot-mcp-server\n```\n\nOr install into an environment:\n\n```bash\npip install uniprot-mcp-server\n```\n\n\n> **Note:** There is an unrelated package named `uniprot-mcp` on PyPI\n> (different author, 5 tools, MIT). This package is `uniprot-mcp-server`.\n> Running `pip install uniprot-mcp` will install the wrong package silently.\n\n## For researchers — where to start\n\nIf you are a biomedical researcher visiting this repo, the highest-signal places to look are:\n\n| Resource | What it gives you |\n|---|---|\n| **[`examples/atlas/`](examples/atlas/)** | Two artifacts with deliberately different scopes: <br>• **Curated atlas (25 entries).** TP53, BRCA1, CFTR, HTT, EGFR, BRAF, KRAS, TEM-1 β-lactamase, more — each linking the canonical UniProt accession to MONDO / OMIM / PharmGKB / ARO IDs and the relevant tool sequence. JSON-LD manifest at `examples/atlas/atlas.json`. <br>• **Comprehensive index (11,590 rows).** UniProt's curated disease + pathogen surface as two TSVs (`comprehensive_index.tsv` 7,250 human disease rows, `comprehensive_index_pathogens.tsv` 4,340 pathogen rows). Each row carries a UniProt disease ID and an OMIM cross-reference where available. MONDO / PharmGKB / ARO mappings exist only in the 25-entry curated atlas, not in the 11,590-row index. SHA-256 reproducibility manifest at `examples/atlas/manifest.json`. <br>Methodology (how compiled, what's verified, what's community-reviewable) at `examples/atlas/METHODOLOGY.md`. |\n| **[`examples/01..04.jsonl`](examples/)** | Full Claude-Desktop transcripts of clinical-variant interpretation (TP53 R175H), drug-target dossier (BRCA1), provenance verification a year later, pathogen drug-discovery (TEM-1). |\n| **[`tests/benchmark/`](tests/benchmark/)** | Pre-registered 30-prompt benchmark with SHA-256 commitments on `main`. The 2026-04-26 v1.1.0 run verified 30/30 against live UniProt — transcript at `tests/benchmark/run-2026-04-26-v1.1.0/`. |\n| **[`scripts/replicate.sh`](scripts/replicate.sh)** | One-command verification that the published PyPI wheel was built from this exact repo (cross-checks SHA-256 across PyPI / GitHub Release / SLSA attestation; runs `--self-test`; re-runs the benchmark live). POSIX + `scripts/replicate.ps1` for Windows. |\n| **[`docs/COMPETITIVE_LANDSCAPE.md`](docs/COMPETITIVE_LANDSCAPE.md)** | Honest 14-server survey of the bio-MCP space (April 2026) and the specific differentiation this server claims. |\n\nIssues / corrections welcome at https://github.com/smaniches/uniprot-mcp/issues. The atlas in particular is community-reviewable — see METHODOLOGY.md for what is machine-verified vs what needs human review.\n\n---\n\n## What makes this different\n\n| | uniprot-mcp | Vanilla LLM + WebFetch | A typical bio-MCP |\n|---|---|---|---|\n| Tool surface | **41 tools, 8 families** | none — caller writes URLs | usually 5–10 |\n| Provenance on every response | release • date • URL • SHA-256 | none | sometimes URL only |\n| Per-query auditability | `uniprot_provenance_verify` re-checks any prior response | not possible | not possible |\n| Release pinning | `--pin-release=YYYY_MM` raises on drift | n/a | n/a |\n| Pre-registered benchmark | 30 prompts, SHA-256 committed on `main` + reproducible verifier | n/a | n/a |\n| Local provenance cache | `uniprot_replay_from_cache` read primitive (automatic cache write-through is not wired into the request path — see [§Provenance & verification](#provenance--verification)) | n/a | n/a |\n| Clinical primitives | sequence chemistry / position-aware features / HGVS variant lookup / disease associations / AlphaFold pLDDT / ClinVar | none | none |\n| Composition tool | `uniprot_target_dossier` — one call, nine sections | n/a | n/a |\n| Input validation | regex + length cap before any HTTP call | none | partial |\n| Error-channel safety | upstream exception text never echoed to LLM | n/a | partial |\n| Cross-origin allowlist | enumerated, threat-modelled, privacy-listed | n/a | usually unaudited |\n| Supply chain | SLSA build provenance + Sigstore + CycloneDX SBOM (post-flip) | n/a | rare |\n| Test layers | unit + property + contract + client + integration + benchmark | n/a | usually unit only |\n| Mutation testing | weekly + on-demand workflow; per-module measurement complete for `cache` 82 %, `proteinchem` 92 %, `client` 70 %; gate currently 0 % (measurement-first), ≥ 95 % is the v1.2.0 target — see `docs/MUTATION_SCORES.md` | n/a | rare |\n\nThe **provenance + verify** chain is, in my 2026-04-26 survey, absent\nfrom every other bio-MCP I could find. A regulated user can take any\nprior `uniprot-mcp` answer and prove — without contacting the author\n— that UniProt still returns the same bytes, or detect exactly how the\nupstream has drifted. If you find a counter-example I missed, please\nfile an issue and I will update the comparison.\n\n---\n\n## Tools (41)\n\nEight endpoint families. All read-only (`readOnlyHint: true`). All\nbut `uniprot_replay_from_cache` interact with at least one upstream\nservice (`openWorldHint: true`). No UniProt API key required.\n\n### Core UniProtKB (10)\n\n| Tool | Purpose |\n|---|---|\n| `uniprot_get_entry` | Full UniProt entry (e.g. `P04637` for p53). Function, gene, organism, disease, cross-refs. |\n| `uniprot_search` | UniProt query language — gene, organism, taxon ID, reviewed flag, free text. |\n| `uniprot_get_sequence` | FASTA. PIR-style provenance comment block above the first record (BLAST+ / biopython compatible). |\n| `uniprot_get_features` | Domains, binding sites, PTMs, signal peptides — optional type filter. |\n| `uniprot_get_variants` | Natural variants and disease mutations. |\n| `uniprot_get_go_terms` | GO annotations grouped by aspect (F / P / C). |\n| `uniprot_get_cross_refs` | Raw cross-references to PDB, Pfam, Ensembl, Reactome, KEGG, STRING … |\n| `uniprot_id_mapping` | Map IDs between databases (Gene_Name → UniProtKB, PDB → UniProtKB, …). |\n| `uniprot_batch_entries` | Up to 100 entries in one call; invalid accessions filtered client-side. |\n| `uniprot_taxonomy_search` | Search UniProt taxonomy by organism name. |\n\n### Controlled vocabularies (4)\n\n| Tool | Purpose |\n|---|---|\n| `uniprot_get_keyword` | Keyword by ID (e.g. `KW-0007` = Acetylation). Definition, synonyms, GO refs, hierarchy. |\n| `uniprot_search_keywords` | Free-text keyword search. |\n| `uniprot_get_subcellular_location` | Subcellular-location term by ID (e.g. `SL-0039` = Cell membrane). |\n| `uniprot_search_subcellular_locations` | Free-text location search. |\n\n### Sequence archives & clusters (4)\n\n| Tool | Purpose |\n|---|---|\n| `uniprot_get_uniref` | UniRef cluster by ID (`UniRef50_P04637`, `UniRef90_P04637`, `UniRef100_P04637`). |\n| `uniprot_search_uniref` | Cluster search with `identity_tier` filter (50 / 90 / 100). |\n| `uniprot_get_uniparc` | Sequence-archive record by UPI (`UPI000002ED67`). |\n| `uniprot_search_uniparc` | UniParc full-text search. |\n\n### Proteomes & literature (4)\n\n| Tool | Purpose |\n|---|---|\n| `uniprot_get_proteome` | Proteome by UP ID (`UP000005640` = human). Counts, BUSCO score, components. |\n| `uniprot_search_proteomes` | Filter by organism / type / completeness. |\n| `uniprot_get_citation` | Citation record by ID (typically a PubMed numeric ID). |\n| `uniprot_search_citations` | Index search across UniProt citations. |\n\n### Structured cross-DB resolvers (4)\n\nGateway-only — no calls leave the UniProt origin. These extract the\nrelevant cross-references from a UniProt entry and return *structured*\nrecords (typed lists / objects, not passthrough strings).\n\n| Tool | Purpose |\n|---|---|\n| `uniprot_resolve_pdb` | PDB structures: id + method + resolution + chain coverage. |\n| `uniprot_resolve_alphafold` | AlphaFold model id + EBI viewer URL (model id only — for pLDDT call the dedicated tool below). |\n| `uniprot_resolve_interpro` | InterPro signatures: id + entry name. |\n| `uniprot_resolve_chembl` | ChEMBL drug-target id + EBI target-card URL. |\n\n### Biomedical features (7)\n\nPure-Python compositions over the entry — no extra origin. The first\nfour answer per-residue and per-variant questions; the last three are\nthe v1.1.0 expansion targeting drug discovery, therapeutic-protein\nengineering, and pathogen-secretion analysis: each is a filter over the\nentry's `features` array, with a structured grouping by feature type\nand an honest empty-set advisory.\n\n| Tool | Purpose |\n|---|---|\n| `uniprot_compute_properties` | Derived sequence chemistry from the FASTA: MW / pI / GRAVY / aromaticity / charge / ε₂₈₀. |\n| `uniprot_features_at_position` | Every feature overlapping a residue position. Critical for variant-effect interpretation. |\n| `uniprot_lookup_variant` | HGVS-shorthand match (`R175H`, `V600E`, `R248*`) against UniProt's natural-variant features. |\n| `uniprot_get_disease_associations` | Structured disease records from DISEASE-type comments: name + acronym + UniProt disease ID + OMIM cross-ref + description. |\n| `uniprot_get_active_sites` | Catalytic and ligand-binding residues: active sites, binding sites, sites, metal binding, DNA binding. The residue-level chemistry of the protein. |\n| `uniprot_get_processing_features` | Maturation features: signal peptide, propeptide, transit peptide, initiator methionine, chain, peptide. Essential for therapeutic-protein engineering and pathogen-secretion analysis. |\n| `uniprot_get_ptms` | Post-translational modifications: modified residues (phospho/acetyl/methyl), glycosylation, lipidation (GPI/prenyl/palmitoyl), disulfide bonds, cross-links. |\n\n### Cross-origin enrichment (3)\n\nThe only tools that consult origins outside `rest.uniprot.org`. Each is documented in [`PRIVACY.md`](PRIVACY.md) and in the [threat model](docs/THREAT_MODEL.md#t3b-cross-origin-allowlist-for-non-uniprot-endpoints).\n\n| Tool | Origin | Purpose |\n|---|---|---|\n| `uniprot_get_alphafold_confidence` | `alphafold.ebi.ac.uk` | pLDDT mean + four-band distribution; lets the agent decide whether to trust the model. |\n| `uniprot_resolve_clinvar` | `eutils.ncbi.nlm.nih.gov` | ClinVar significance + condition + review status by gene + optional HGVS shorthand. |\n| `uniprot_get_publications` | `rest.uniprot.org` | Pure-Python over the entry's references — listed here because it complements the cross-origin enrichment. |\n\n### Composition + provenance (5)\n\n| Tool | Purpose |\n|---|---|\n| `uniprot_resolve_orthology` | Group orthology cross-references by source DB (KEGG / OMA / OrthoDB / eggNOG / 8 more). |\n| `uniprot_get_evidence_summary` | Aggregate ECO codes (Evidence and Conclusion Ontology) across an entry and grade them into a 0-100 evidence-confidence score (high / moderate / low / very-low). Distinguishes wet-lab confirmed from inferred-by-similarity from automatic. |\n| `uniprot_target_dossier` | One-call comprehensive characterisation: nine sections — identity / function / chemistry / structure / drug-target / disease / variants / functional annotations / cross-refs. |\n| `uniprot_provenance_verify` | Re-fetch a previously recorded URL and compare release tag + canonical response SHA-256. Five verdicts (`verified`, `release_drift`, `hash_drift`, `release_and_hash_drift`, `url_unreachable`) each with an advice string. |\n| `uniprot_replay_from_cache` | Read a cached UniProt response without hitting the upstream. Opt-in via `UNIPROT_MCP_CACHE_DIR`. |\n\n---\n\n## Provenance & verification\n\nEvery successful tool response includes a footer like:\n\n```\n---\n_Source: UniProt release 2026_01 (28-January-2026) • Retrieved 2026-04-25T17:09:00Z_\n_Query: https://rest.uniprot.org/uniprotkb/P04637_\n_SHA-256: 0040d79bb39e2f7386d55f81071e87858ec2e5c2cd9552e93c3633897f78345e_\n```\n\nA year later, an auditor can call `uniprot_provenance_verify` with\nthose exact fields:\n\n```\n> uniprot_provenance_verify(\n    url=\"https://rest.uniprot.org/uniprotkb/P04637\",\n    release=\"2026_01\",\n    response_sha256=\"0040d79bb39e2f7386d55f81071e87858ec2e5c2cd9552e93c3633897f78345e\"\n  )\n\n## Provenance Verification\n\n**Status:** verified\n\n**URL:** https://rest.uniprot.org/uniprotkb/P04637\n- ✓ URL resolves (HTTP 200)\n- ✓ Release: recorded '2026_01', current '2026_01'\n- ✓ Response SHA-256: recorded 0040d79bb39e2f73…, current 0040d79bb39e2f73…\n\n**Advice:** Both checks passed. The recorded provenance is reproducible against the live UniProt API.\n```\n\nIf UniProt has moved on, the tool tells you exactly how:\n\n| Verdict | Meaning | Advice |\n|---|---|---|\n| `verified` | Both release and hash match | The provenance is reproducible |\n| `release_drift` | UniProt released a new version | Pin via the FTP snapshot if you need the historical answer |\n| `hash_drift` | Same release, body changed | An in-release edit; investigate or re-fetch |\n| `release_and_hash_drift` | Both moved on | Use a release-specific FTP snapshot |\n| `url_unreachable` | Endpoint dropped or rate-limited | Retry or report to UniProt |\n\nFor strict reproducibility, opt into release pinning:\n\n```bash\nexport UNIPROT_PIN_RELEASE=2026_01\nuniprot-mcp\n# every response is checked against the pinned release;\n# any drift raises `ReleaseMismatchError`, which the server surfaces\n# as an agent-actionable error envelope.\n```\n\nFor offline replay, `uniprot_replay_from_cache(url)` reads a\npreviously-recorded response from a directory pointed at by\n`UNIPROT_MCP_CACHE_DIR`:\n\n```bash\nexport UNIPROT_MCP_CACHE_DIR=~/.uniprot-mcp-cache\nuniprot-mcp\n# uniprot_replay_from_cache(url) returns the entry at\n# $UNIPROT_MCP_CACHE_DIR/<sha256(url)>.json if present.\n```\n\n> **Status note (v1.1.3).** `uniprot_replay_from_cache` is a **read\n> primitive**. The cache must currently be populated by an external\n> process — for example, by the maintainer-provided benchmark capture\n> script, or by you wrapping `httpx` calls and writing to the directory\n> yourself in the documented JSON shape (see `src/uniprot_mcp/cache.py`).\n> Automatic cache write-through is not currently wired into the request\n> path; cache entries must be populated explicitly or by an external\n> capture workflow.\n\nA live end-to-end demonstration is committed at\n[`tests/benchmark/run-2026-04-25-roundtrip/transcript.md`](tests/benchmark/run-2026-04-25-roundtrip/transcript.md)\n— real values, real verdicts, no mocks.\n\n---\n\n## Pre-registered benchmark\n\n`tests/benchmark/` ships a 30-prompt evaluation (Tier A / B / C × 10)\nwith **SHA-256-committed expected answers** on `main`. The plaintext\n`expected.jsonl` is held local-only until a benchmark run is\npublished; the cryptographic commitments mean the author cannot\nrewrite \"correct\" answers post-hoc.\n\n**Third-party reproducibility path (no seal file required).** Re-derive every Tier A / B answer live from UniProt and print it — no `expected.jsonl` required. This confirms the answers are independently reproducible from the primary source today; it does **not** recompute the seal (the committed SHA-256 binds a withheld rationale — see below):\n\n```bash\npython tests/benchmark/verify_against_hashes.py tests/benchmark/expected.hashes.jsonl\n# Re-derives all 30 answers live and prints them (informational; exit 0).\n```\n\n**Maintainer cryptographic verification path (with the local plaintext seal).** The committed digests in `expected.hashes.jsonl` are sealed over `{prompt_id, answer, rationale}`; the rationale is deliberately withheld as part of the sealed pre-registration, so the full cryptographic check requires the local `expected.jsonl`:\n\n```bash\npython tests/benchmark/verify_answers.py tests/benchmark/expected.jsonl\n# OK: all 30 prompts verified against https://rest.uniprot.org\n\npython tests/benchmark/verify.py tests/benchmark/expected.jsonl tests/benchmark/expected.hashes.jsonl\n# OK: 30 commitments verified\n```\n\nSee [`tests/benchmark/AUDIT.md`](tests/benchmark/AUDIT.md) for the\nper-prompt source attribution and the formal independence statement\n(`uniprot-mcp` was *not* used during answer authoring).\n\n---\n\n## Install\n\n```bash\npip install uniprot-mcp-server   # PyPI distribution\n# or, for a pinned, isolated install:\nuvx --from uniprot-mcp-server uniprot-mcp\n```\n\n> **Why three different names?** This is the standard Python packaging pattern, exactly because PyPI's namespace is global and collisions force disambiguation:\n>\n> | Concept | Value | What it is |\n> |---|---|---|\n> | GitHub repository | `smaniches/uniprot-mcp` | source code + issue tracker |\n> | PyPI distribution | `uniprot-mcp-server` | what you `pip install` (the bare `uniprot-mcp` name was already claimed on PyPI when this project published) |\n> | Python module | `uniprot_mcp` | what you `import` (PEP-8 underscore form) |\n> | Console script + MCP server identity | `uniprot-mcp` | what you run from the shell and what Claude Desktop sees |\n>\n> Cross-checks that prove the wheel you installed was built from this repo: each release ships a [Sigstore signature](https://www.sigstore.dev/), [SLSA build provenance](https://slsa.dev/), and a [CycloneDX SBOM](https://cyclonedx.org/), all attached to the [v1.1.0 GitHub Release](https://github.com/smaniches/uniprot-mcp/releases/tag/v1.1.0). Run `bash scripts/replicate.sh` (POSIX) or `pwsh scripts/replicate.ps1` (Windows) to verify the full chain end-to-end. Common precedents for the same one-thing-three-names pattern: `pillow`/`PIL`, `python-dateutil`/`dateutil`, `beautifulsoup4`/`bs4`, `python-Levenshtein`/`Levenshtein`.\n\nFrom source:\n\n```bash\ngit clone https://github.com/smaniches/uniprot-mcp.git\ncd uniprot-mcp\npip install -e .\n```\n\n### Claude Desktop\n\n`claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"uniprot\": {\n      \"command\": \"uvx\",\n      \"args\": [\"uniprot-mcp-server\"]\n    }\n  }\n}\n```\n\nFor pinned, reproducibility-grade access:\n\n```json\n{\n  \"mcpServers\": {\n    \"uniprot\": {\n      \"command\": \"uniprot-mcp\",\n      \"args\": [\"--pin-release=2026_01\"]\n    }\n  }\n}\n```\n\nTo enable `uniprot_replay_from_cache` reads against a cache directory\nyou have populated yourself (automatic write-through is not wired into\nthe request path — see [§Provenance & verification](#provenance--verification)):\n\n```json\n{\n  \"mcpServers\": {\n    \"uniprot\": {\n      \"command\": \"uniprot-mcp\",\n      \"env\": {\n        \"UNIPROT_MCP_CACHE_DIR\": \"/absolute/path/to/cache\"\n      }\n    }\n  }\n}\n```\n\n### Claude Code (CLI)\n\n```bash\nclaude mcp add uniprot -- uniprot-mcp\n```\n\n### Self-test (live UniProt smoke check)\n\n```bash\nuniprot-mcp --self-test\n# [tools] registered: 41/41\n# [live] P04637 -> TP53 OK\n# [PASS]\n```\n\n---\n\n## Example workflows\n\n**1. Clinical-variant interpretation packet for `TP53 R175H`.**\n\n```\n> What's at residue 175 of P04637? Is R175H a known variant? Pull\n> the UniProt and ClinVar evidence and tell me how confident the\n> AlphaFold model is at that residue.\n→ uniprot_features_at_position(\"P04637\", 175)\n→ uniprot_lookup_variant(\"P04637\", \"R175H\")\n→ uniprot_resolve_clinvar(\"P04637\", change=\"R175H\")\n→ uniprot_get_alphafold_confidence(\"P04637\")\n```\n\n**2. Drug-target dossier in one call.**\n\n```\n> Give me a complete drug-target characterisation of human BRCA1.\n→ uniprot_target_dossier(\"P38398\")\n   # nine sections, two upstream calls (entry + FASTA), one tool call.\n```\n\n**3. Sequence chemistry for buffer choice / expression-system selection.**\n\n```\n> What's the molecular weight, pI, and hydrophobicity of human insulin?\n→ uniprot_compute_properties(\"P01308\")\n   # MW 11,981 Da, pI 4.93, ε₂₈₀ 24,980 M⁻¹·cm⁻¹ — pure Python on the FASTA.\n```\n\n**4. Provenance round-trip — proving an answer is reproducible.**\n\n```\n> [later, with the provenance footer from a prior session in hand]\n> Verify the recorded provenance for P04637.\n→ uniprot_provenance_verify(\n    url=\"https://rest.uniprot.org/uniprotkb/P04637\",\n    release=\"2026_01\",\n    response_sha256=\"0040d79bb39e2f7386d55f81071e87858ec2e5c2cd9552e93c3633897f78345e\"\n  )\n```\n\n**5. Replay a previously-cached answer offline (read primitive — see status note below).**\n\n```bash\n# Pre-condition: $UNIPROT_MCP_CACHE_DIR/<sha256(url)>.json already exists,\n# populated by the maintainer benchmark capture script or an external\n# wrapper. Automatic cache write-through is not currently wired into the\n# request path; cache entries must be populated explicitly or by an\n# external capture workflow.\nexport UNIPROT_MCP_CACHE_DIR=~/sealed-cache\n> uniprot_replay_from_cache(\"https://rest.uniprot.org/uniprotkb/P04637\")\n```\n\n---\n\n## Testing\n\n| Layer | Path | What |\n|---|---|---|\n| Unit | `tests/unit/` | Behaviour of every public function. |\n| Property | `tests/property/` | Hypothesis-driven invariants on regexes + query construction. |\n| Contract | `tests/contract/` | Manifest / pyproject / docs / incident-policy / benchmark drift prevention. |\n| Client | `tests/client/` | Retry / back-off / id-mapping polling against `respx`-mocked HTTP. |\n| Integration | `tests/integration/` | Live UniProt + AlphaFold; opt-in via `--integration`. |\n| Benchmark | `tests/benchmark/` | 30 SHA-256-committed prompts + reproducible verifier. |\n\n**956 offline + 44 live integration tests, all green** on `main` (real counts via `pytest --collect-only --ignore=tests/integration` and `pytest --collect-only tests/integration`; the offline count includes the v1.1.x mutation-killer files for `cache`, `proteinchem`, `client`, the contract tests for atlas-manifest / version-consistency / changelog-presence, and the coverage-gap test files that restored full coverage). Line + branch coverage is **100.00 %** across all seven source files, with the `[tool.coverage.report]` gate set to `fail_under = 100` so CI enforces it. Three branches carry a justified `# pragma: no cover` for genuinely-unreachable import-time / defensive fallbacks (documented inline and in `pyproject.toml`). Reproduce locally with `pytest tests/unit tests/property tests/client tests/contract --cov=uniprot_mcp --cov-branch --cov-report=term-missing`. Mypy (strict), ruff (check + format), bandit (0 issues at any severity), pip-audit (`--strict`, no known vulnerabilities) all clean. **Mutation testing infrastructure ships and is measurement-first:** see the per-module table at [`docs/MUTATION_SCORES.md`](docs/MUTATION_SCORES.md) for the latest matrix-workflow results; the ≥ 95 % gate is the v1.2.0 target, not the current state.\n\n```bash\n# Fast, offline (CI on every push):\npytest tests/unit tests/property tests/client tests/contract -v\n\n# Live UniProt (opt-in, nightly in CI):\npytest --integration tests/integration -v\n\n# Lint / type-check / security / SCA:\nruff check . && ruff format --check . && mypy src/uniprot_mcp\nbandit -r src/uniprot_mcp && pip-audit --strict\n```\n\n---\n\n## Architecture & threat model\n\n- [`docs/THREAT_MODEL.md`](docs/THREAT_MODEL.md) — twelve STRIDE-shaped\n  threats, each receipt-anchored to a code path or commit SHA, plus\n  the cross-origin allowlist policy (§T3b).\n- [`docs/INCIDENT_POLICY.md`](docs/INCIDENT_POLICY.md) +\n  [`docs/POSTMORTEM_TEMPLATE.md`](docs/POSTMORTEM_TEMPLATE.md) +\n  [`docs/INCIDENT_LOG.md`](docs/INCIDENT_LOG.md) — every nightly\n  integration breakage triggers a postmortem entry.\n- [`AUDIT.md`](AUDIT.md) — pre-1.0.1 professional audit, P0/P1\n  remediations recorded.\n- [`docs/RELEASE.md`](docs/RELEASE.md) — release runbook covering the\n  tag → PyPI → MCP Registry → Sigstore → GitHub Release → Zenodo chain,\n  including the `release-verify.yml` post-tag verification job and the\n  one-time setup for the Zenodo + PyPI webhooks.\n- [`docs/archive/`](docs/archive/) — pre-flip planning docs retained\n  for audit trail (`PENDING_V1.md`, `MERGE_PLAN.md`,\n  `RELEASE_AUDIT_v1.1.3.md`). Not part of the published docs site;\n  current operational status lives in `README.md`, `CHANGELOG.md`,\n  and `docs/MUTATION_SCORES.md`.\n- [`mkdocs.yml`](mkdocs.yml) — Material-themed docs site, deployable to\n  `gh-pages` via [`.github/workflows/docs.yml`](.github/workflows/docs.yml).\n  Build locally with `pip install -e \".[docs]\" && mkdocs serve`.\n\n---\n\n## Related MCP servers by the same author\n\n- [`alphafold-sovereign-mcp`](https://github.com/smaniches/alphafold-sovereign-mcp) — Model Context Protocol server that integrates AlphaFold DB with eight additional public biomedical data sources, with a local SQLite knowledge graph (`pip install alphafold-sovereign-mcp`).\n- [`semantic-scholar-mcp`](https://github.com/smaniches/semantic-scholar-mcp) — Model Context Protocol server for Semantic Scholar (200M+ academic papers), providing 14 tools for paper search, citation graph traversal, author profiles, and recommendations (`pip install s2-mcp-server`).\n\n---\n\n## Citation\n\nCite via [`CITATION.cff`](CITATION.cff) (GitHub renders a \"Cite this\nrepository\" button). Always also cite the UniProt Consortium:\n\n> The UniProt Consortium. *UniProt: the Universal Protein Knowledgebase\n> in 2025.* Nucleic Acids Research (2025).\n> [doi:10.1093/nar/gkae1010](https://doi.org/10.1093/nar/gkae1010)\n\n---\n\n## License\n\nApache-2.0 — see [LICENSE](LICENSE) and [NOTICE](NOTICE).\n\nThis project is the **gateway** layer of the planned [Topologica\nBio](https://github.com/smaniches) MCP suite. Multi-source orchestration\nand tamper-evident provenance ledgers will live in a companion\n`topologica-bio` repository under BUSL-1.1 (Change Date 2030-04-19,\nauto-reverts to Apache-2.0). That companion repository is currently\nprivate; this README will be updated with a public link when it ships.\n`uniprot-mcp` itself is and will remain permissively Apache-2.0\nregardless of the Topologica Bio side.\n\nCopyright © 2026 Santiago Maniches. TOPOLOGICA LLC.\n",
  "bytes": 32886,
  "sha": "18260b36ab36d263bd29ca109cd8d3e98d1bd9b554778e0e0be230650236ac6d",
  "repo_slug": "smaniches/uniprot-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_smaniches_uniprot_mcp_4460f7ba/readme"
}