Koskamo

protein-mcp-server

An MCP server that provides federated access to protein structure data, allowing agents to search, fetch, align, and annotate both experimental (PDB) and predicted (AlphaFold) models. It supports tools for searching structures by text or sequence, finding homologs, tracking ligands, and analyzing collections.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

protein-mcp-server logo, by cyanheadsCommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-07Published by cyanheads
MCP endpoint (Streamable HTTP)
https://protein.caseyjhand.com/mcp
Vendor documentation

What its tools do

7 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

7 of 7 have a description · 7 of 7 declare behavior hints · 7 of 7 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Search experimental and predicted protein structures by free text, sequence, or organism.
  • Fetch metadata and coordinate URLs for specific PDB or AlphaFold entries.
  • Find sequence homologs using RCSB mmseqs2 or fold homologs via Foldseek.
  • Resolve ligand names to component IDs and find structures containing them.

Source and maintenance

Community listingRegistry 0.9.0
Maintenance checked

Protocol and capabilities

Server
protein-mcp-server 0.9.0
MCP protocol negotiated in check
2025-11-25
Tools
7 advertised
Resources
1 advertised
Resource templates
3 advertised
Prompts
0 advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "logging": {},
  "prompts": {
    "listChanged": true
  },
  "resources": {
    "subscribe": true,
    "listChanged": true
  },
  "extensions": {
    "io.modelcontextprotocol/skills": {
      "directoryRead": true
    }
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

Find structures with protein_search_structures, then pass the returned IDs to protein_get_structure for metadata and coordinate URLs, or pass UniProt accessions there for AlphaFold predictions and the best available model. A PDB ID also chains into protein_get_annotations, protein_track_ligands, protein_find_similar, and protein_compare_structures for annotations, binding sites, homologs, and structural alignment, while protein_analyze_collection profiles the whole PDB as aggregate counts. A Foldseek search or structural alignment still running when the poll budget elapses returns status "computing" with a ticket (protein_find_similar) or a job UUID (protein_compare_structures); re-call with it to resume that job rather than resubmitting. The protein-guide skill (skill://protein-guide/SKILL.md) carries the identifier forms each tool takes, author versus label chain IDs, residue numbering, and the gates for reading best_available picks, sequence and Foldseek hits, ligand counts, and PDB profiles.

Tools

7 advertised

protein_search_structures — protein-mcp-server: search structures
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Search experimental (PDB) and predicted (computed-model) protein structures by free text, protein sequence (triggers an mmseqs2 similarity search), and/or organism, method, resolution, and bound-ligand filters. Returns ranked hits; the experimental page is enriched with title, method, resolution, and source organisms (for a sequence hit, those of the matched entity), and every sequence hit carries its identity, E-value, bit score, and aligned range against the query. Chain hit IDs into protein_get_structure. Optionally returns a facet breakdown (counts by method / organism / release year / …) alongside the hits in the same response. Facets count the filtered result set, so an active organism or method filter also constrains its own facet: the facet lists only the values found in the matching entries (other organisms in the same complexes, other methods deposited with the same entries), never the alternatives the filter excluded. Numeric histogram buckets (resolution, molecular weight) carry explicit rangeFrom/rangeTo bounds so a boundary label is unambiguous.

protein_search_structures input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "limit": {
      "type": "integer",
      "default": 25,
      "maximum": 100,
      "minimum": 1,
      "description": "Maximum hits to return (1–100)."
    },
    "query": {
      "type": "string",
      "description": "Free-text query (protein name, gene, keyword, PDB title terms)."
    },
    "start": {
      "type": "integer",
      "default": 0,
      "maximum": 9007199254740991,
      "minimum": 0,
      "description": "Zero-based result offset. Combine with limit to retrieve later pages."
    },
    "facets": {
      "type": "array",
      "items": {
        "enum": [
          "method",
          "organism",
          "polymer_type",
          "resolution",
          "release_year",
          "molecular_weight"
        ],
        "type": "string"
      },
      "description": "Optional dimensions to summarize as a facet breakdown alongside the hits. Each dimension at most once; repeating one is rejected."
    },
    "ligand": {
      "type": "string",
      "description": "Filter by bound ligand: an exact chemical component ID (e.g. \"STI\" for imatinib, \"HEM\"), in any letter case. Keeps structures holding the component as a bound (non-polymer) copy, not as a residue inside a polymer chain. Resolve a ligand name to its ID with protein_track_ligands mode \"find_ligand\". Computed models carry no ligands, so under content_type \"predicted\" this filter matches nothing."
    },
    "method": {
      "type": "string",
      "description": "Filter by experimental method: X-RAY DIFFRACTION, ELECTRON MICROSCOPY, SOLUTION NMR, SOLID-STATE NMR, ELECTRON CRYSTALLOGRAPHY, NEUTRON DIFFRACTION, FIBER DIFFRACTION, POWDER DIFFRACTION, SOLUTION SCATTERING, EPR, FLUORESCENCE TRANSFER, INFRARED SPECTROSCOPY, THEORETICAL MODEL (any letter case), or an alias: cryo-EM / cryoEM / EM → ELECTRON MICROSCOPY; X-ray / xray → X-RAY DIFFRACTION; NMR → SOLUTION NMR + SOLID-STATE NMR. Any other value is rejected. Computed models carry no method, so under content_type \"predicted\" this filter matches nothing."
    },
    "organism": {
      "type": "string",
      "description": "Filter by source organism: a scientific name (\"Homo sapiens\"), an NCBI common name (\"human\", \"E. coli\"), or an NCBI taxon ID (\"9606\"), in any letter case. Matches that taxon and every taxon under it (strains, subspecies); a multi-word name also matches scientific names that contain it, such as \"Escherichia coli (strain K12)\". A word fragment (\"coli\") matches nothing."
    },
    "sequence": {
      "type": "string",
      "description": "Protein sequence for RCSB mmseqs2: at least 10 residues in A–I or K–Z (J excluded; B/O/U/X/Z accepted). Whitespace is removed and ASCII lowercase normalized."
    },
    "max_evalue": {
      "type": "number",
      "description": "Maximum E-value for a sequence search. Requires sequence — supplying it without one is rejected, since the threshold filters only a sequence search. Default 1.",
      "exclusiveMinimum": 0
    },
    "content_type": {
      "enum": [
        "experimental",
        "predicted",
        "all"
      ],
      "type": "string",
      "default": "all",
      "description": "Which structure universe to search: experimental (PDB), predicted (computed models), or all."
    },
    "min_identity": {
      "type": "number",
      "maximum": 1,
      "minimum": 0,
      "description": "Minimum sequence identity (0–1) for a sequence search. Requires sequence — supplying it without one is rejected, since the threshold filters only a sequence search. Default 0."
    },
    "max_resolution": {
      "type": "number",
      "description": "Maximum resolution in Å (lower is sharper); applies to experimental structures.",
      "exclusiveMinimum": 0
    }
  },
  "additionalProperties": false
}
protein_search_structures output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "hits",
        "totalCount",
        "start"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "hits": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "source"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Structure identifier (PDB entry ID or computed-model ID)."
          },
          "score": {
            "type": "number",
            "description": "RCSB relevance score, relative to the other hits of this search rather than a similarity measure; a sequence hit's similarity is in identity, evalue, and bitscore."
          },
          "title": {
            "type": "string",
            "description": "Structure title (enriched experimental hits)."
          },
          "evalue": {
            "type": "number",
            "description": "Alignment E-value (sequence hits)."
          },
          "method": {
            "type": "string",
            "description": "Experimental method(s) (enriched experimental hits)."
          },
          "source": {
            "enum": [
              "experimental",
              "predicted"
            ],
            "type": "string",
            "description": "Which universe the hit came from."
          },
          "bitscore": {
            "type": "number",
            "description": "Alignment bit score (sequence hits)."
          },
          "entityId": {
            "type": "string",
            "description": "Matched polymer-entity ID for sequence hits (e.g. 4HHB_1, AF_AFP69905F1_1); id remains the chainable entry ID."
          },
          "identity": {
            "type": "number",
            "description": "Sequence identity 0–1 over the alignment, to 4 decimal places (sequence hits)."
          },
          "queryEnd": {
            "type": "number",
            "description": "Last aligned residue of the query, 1-based, inclusive (sequence hits)."
          },
          "organisms": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Source organisms (enriched experimental hits): for a sequence hit, those of the matched entity (entityId); otherwise every distinct source organism of the entry, in entity-number order. Omitted when unknown, including a sequence hit whose matched entity the entry's metadata lacks."
          },
          "targetEnd": {
            "type": "number",
            "description": "Last aligned residue of the hit, 1-based, inclusive, in the same entity sequence as targetStart (sequence hits)."
          },
          "queryStart": {
            "type": "number",
            "description": "First aligned residue of the query, 1-based, inclusive (sequence hits)."
          },
          "resolution": {
            "type": "number",
            "description": "Resolution in Å (enriched experimental hits)."
          },
          "targetStart": {
            "type": "number",
            "description": "First aligned residue of the hit, 1-based, inclusive, in the matched entity's sequence — not author residue numbering (sequence hits)."
          },
          "targetLength": {
            "type": "number",
            "description": "Length in residues of the entity sequence that targetStart and targetEnd index into (sequence hits)."
          },
          "alignmentLength": {
            "type": "number",
            "description": "Alignment length in columns, gaps included (sequence hits)."
          },
          "uniprotAccession": {
            "type": "string",
            "description": "UniProt accession parsed from a computed-model ID, when available."
          }
        },
        "description": "A ranked structure hit with optional enrichment metadata.",
        "additionalProperties": false
      },
      "description": "Ranked structure hits."
    },
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "invalid_sequence",
                "no_criteria",
                "unknown_method",
                "sequence_modifier_without_sequence",
                "duplicate_dimension"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `invalid_sequence`: The RCSB protein sequence contains invalid residues or has fewer than 10 residues after whitespace removal. `no_criteria`: No query, sequence, organism, method, maximum resolution, or ligand was provided — nothing to search on. `unknown_method`: method is neither one of the 13 RCSB experimental methods nor an accepted alias, so it could only ever match nothing. `sequence_modifier_without_sequence`: min_identity or max_evalue was supplied with no sequence, so the threshold would never reach a sequence search. `duplicate_dimension`: facets lists the same dimension twice, which would return that breakdown twice. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "start": {
      "type": "number",
      "description": "Zero-based offset of the returned page."
    },
    "facets": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "dimension",
          "buckets",
          "missingValueCount"
        ],
        "properties": {
          "buckets": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "label",
                "count"
              ],
              "properties": {
                "count": {
                  "type": "number",
                  "description": "Number of entries in the bucket."
                },
                "label": {
                  "type": "string",
                  "description": "Bucket value — category, numeric bin start, or period."
                },
                "rangeTo": {
                  "type": "number",
                  "description": "Exclusive upper bound of a numeric histogram bin (rangeFrom + bin interval), so the bin covers [rangeFrom, rangeTo). Present only for numeric facets."
                },
                "rangeFrom": {
                  "type": "number",
                  "description": "Inclusive lower bound of a numeric histogram bin (= label). Present only for numeric facets (resolution, molecular_weight); absent for term/period facets."
                }
              },
              "description": "A leaf aggregation bucket: a value and its entry count.",
              "additionalProperties": false
            },
            "description": "Aggregation buckets, count-descending for terms."
          },
          "dimension": {
            "type": "string",
            "description": "Friendly dimension name (e.g. method, organism, release_year)."
          },
          "truncated": {
            "type": "boolean",
            "description": "True when buckets were capped by the per-dimension bucket limit."
          },
          "missingValueCount": {
            "type": "number",
            "description": "Matches in scope that carry no value for this attribute, so they count toward the response total but fall in no bucket (e.g. computed models have no experimental method; solution-NMR entries have no diffraction resolution). Independent of truncation — measured before the bucket cap is applied. 0 means no shortfall was detectable: a multi-valued attribute such as organism can place one match in several buckets, which offsets the shortfall rather than adding to it."
          }
        },
        "description": "A facet dimension and its aggregation buckets.",
        "additionalProperties": false
      },
      "description": "Optional facet breakdown when requested — one flat dimension per requested facet. Cross-tabs (a dimension nested inside another) are protein_analyze_collection territory."
    },
    "notice": {
      "type": "string",
      "description": "Advisory note (empty results, predicted-search caveats, truncation, facet dimensions whose buckets cover materially less than totalCount). Carries every applicable advisory in one string."
    },
    "nextStart": {
      "type": "number",
      "description": "Offset for the next page; absent on the final or past-end page."
    },
    "totalCount": {
      "type": "number",
      "description": "Total matches upstream before pagination."
    },
    "queryLength": {
      "type": "number",
      "description": "Length in residues of the query sequence that every hit's queryStart and queryEnd index into (sequence searches whose hits carry an alignment)."
    },
    "effectiveQuery": {
      "type": "string",
      "description": "Echoed text query for follow-up calls."
    }
  },
  "additionalProperties": false
}
protein_search_structures annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}
protein_get_structure — protein-mcp-server: get structure
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Fetch structures with metadata and coordinate-file URLs. source "experimental" takes PDB entry IDs, and also resolves the computed-model IDs protein_search_structures returns (AF_*/MA_*), which come back marked source "predicted" with their modelling provider; "predicted" takes UniProt accessions, isoform accessions (P04637-2), or AlphaFold DB entry IDs (AF-P04637-2-F1) (AlphaFold, with pLDDT/PAE confidence); "best_available" takes the same identifiers, an entry ID reduced to its accession, and returns the top federated model — the PDB entry with the widest UniProt coverage, ties going to the finest resolution (coverage measures the mapped span, so the pick can be an engineered mutant over the wild-type entry), else the model with the highest confidence on the lDDT scale (pLDDT/100 or QMEANDisCo), unscored models last, which can include an experimental model outside the PDB such as a SASBDB fit; best_available records carry coverage and the UniProt span. Under predicted and best_available, a UniProt accession merged into another entry resolves to its successor's model with a notice naming the merge, and a demerged or deleted accession lands in failed[] with its replacements. Records fetched under source "experimental", computed models included, also carry polymer entities with both chain namespaces (labelAsymIds for protein_compare_structures, authAsymIds for protein_get_annotations), bound ligands, molecular weight, and release date. Resolves up to the configured batch cap per call with per-ID partial success: IDs are trimmed and repeats looked up once, missed IDs are listed in failed[] with their reasons, and IDs beyond the cap are listed in ignored, never looked up. Upstream lookups share one time budget per call; under predicted and best_available, an ID not finished within it, or whose upstream lookup failed, lands in failed[] with a reason to re-call it. Set include_coords to inline coordinate text, held to 24000 characters per response on both surfaces: a lone selected file arrives in 24000-character windows, each giving coordinatesNextOffset to pass back as coords_offset; several selected files inline whole when they total 24000 characters or fewer, and otherwise overflow lists each file's length — re-call with sections naming one structure to page through its file. coordinateUrls always link the complete files.

protein_get_structure input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "ids"
  ],
  "properties": {
    "ids": {
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1
      },
      "minItems": 1,
      "description": "PDB entry IDs or computed-model IDs such as AF_AFP69905F1 (source experimental); UniProt accessions, isoform accessions such as P04637-2, or AlphaFold DB entry IDs such as AF-P04637-2-F1 (predicted / best_available). Trimmed, and a repeat (case-insensitive) is looked up once."
    },
    "source": {
      "enum": [
        "experimental",
        "predicted",
        "best_available"
      ],
      "type": "string",
      "default": "experimental",
      "description": "Where to fetch: experimental (PDB), predicted (AlphaFold), or best_available (federated pick)."
    },
    "sections": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Structure IDs to inline coordinates for, in place of include_coords — from an overflow outline, or one ID to page through its file with coords_offset. Each must match the id of a structure this call resolves."
    },
    "coords_offset": {
      "type": "integer",
      "default": 0,
      "maximum": 9007199254740991,
      "minimum": 0,
      "description": "Character offset of the window to return when exactly one structure is selected (sections naming one ID, or include_coords on a one-ID call): the window is characters [coords_offset, coords_offset + 24000). Pass the coordinatesNextOffset a previous window returned."
    },
    "include_coords": {
      "type": "boolean",
      "default": false,
      "description": "Inline coordinate text for every resolved structure — mmCIF, or PDB format when no mmCIF URL is available; coordinateFormat names which. A lone file arrives in 24000-character windows. Off by default — URLs are always returned."
    }
  },
  "additionalProperties": false
}
protein_get_structure output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "structures",
        "failed",
        "attribution",
        "requested",
        "processed",
        "resolved"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "mixed_id_types",
                "all_failed",
                "upstream_unavailable",
                "coords_offset_needs_one_structure"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `mixed_id_types`: The batch mixes PDB IDs and UniProt accessions under a single source that cannot serve both. `all_failed`: No processed ID resolved to a structure, and at least one has none: no record, a malformed ID, or an inactive or unknown accession. data.failed carries each ID with its reason. `upstream_unavailable`: Under predicted or best_available, no processed ID resolved and none is known to lack a structure: each ID's upstream lookup failed (an error status, an HTML page, a network failure, or a request timeout) or ran out of the call's time budget. data.failed carries each ID with its reason. `coords_offset_needs_one_structure`: coords_offset is above 0 while the call selects no structure, or several, for inlined coordinates. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "failed": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "reason"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Requested ID that failed."
          },
          "reason": {
            "type": "string",
            "description": "Why it failed."
          }
        },
        "description": "A requested ID that did not resolve, with the reason.",
        "additionalProperties": false
      },
      "description": "IDs that could not be resolved (partial success)."
    },
    "notice": {
      "type": "string",
      "description": "Every applicable advisory joined into one string: repeated IDs counted once, batch cap, partial failures, a UniProt merge that resolved an accession to its successor, an unavailable PDB check behind a best_available pick, a computed model whose provider coordinate lookup failed (only its BinaryCIF URL listed), the re-call for the next coordinate window, a coords_offset past the end of the file, a sections entry that matched no structure, coordinate-budget overflow, and failed coordinate inlining."
    },
    "ignored": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "IDs past the batch cap, never looked up — trimmed, repeats dropped, in input order. Pass them as ids in a follow-up call with the same source. Absent when the cap dropped nothing."
    },
    "overflow": {
      "type": "object",
      "required": [
        "sections",
        "notice"
      ],
      "properties": {
        "notice": {
          "type": "string",
          "description": "How to page through one structure's coordinates with sections and coords_offset."
        },
        "sections": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "id",
              "bytes"
            ],
            "properties": {
              "id": {
                "type": "string",
                "description": "Structure ID whose coordinates were withheld."
              },
              "bytes": {
                "type": "number",
                "description": "Length of the structure's coordinate file in characters, the unit coords_offset counts."
              }
            },
            "description": "A withheld structure and its coordinate file length.",
            "additionalProperties": false
          },
          "description": "Per-structure coordinate file lengths, for a targeted re-call."
        }
      },
      "description": "Present only when two or more selected coordinate files together exceed 24000 characters, the budget for one response; their coordinates are then withheld from both surfaces.",
      "additionalProperties": false
    },
    "resolved": {
      "type": "number",
      "description": "Number of processed IDs that resolved to a structure."
    },
    "processed": {
      "type": "number",
      "description": "Number of distinct IDs looked up: a repeated ID counts once, and IDs past the batch cap are listed in ignored instead."
    },
    "requested": {
      "type": "number",
      "description": "Number of IDs in the original request, repeats included, before de-duplication and the batch cap."
    },
    "structures": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "source",
          "coordinateUrls"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Structure identifier: the PDB entry ID, or the UniProt accession the model belongs to — isoform suffix kept, the accession an AlphaFold DB entry ID names, or the successor when UniProt merged the requested accession (the notice names the merge)."
          },
          "pdbId": {
            "type": "string",
            "description": "Chosen PDB entry ID when a best_available query resolved to a PDB entry (id stays the queried UniProt accession), so the structure can be cited without parsing the coordinate URL. Absent for any other pick, including an experimental model outside the PDB such as a SASBDB fit."
          },
          "title": {
            "type": "string",
            "description": "Structure / protein title."
          },
          "method": {
            "type": "string",
            "description": "Experimental method(s)."
          },
          "source": {
            "enum": [
              "experimental",
              "predicted"
            ],
            "type": "string",
            "description": "Whether the structure is experimental or predicted."
          },
          "ligands": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "compId"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Chemical name."
                },
                "compId": {
                  "type": "string",
                  "description": "Chemical component ID (e.g. HEM)."
                },
                "formula": {
                  "type": "string",
                  "description": "Molecular formula."
                }
              },
              "description": "A bound ligand (non-polymer chemical component).",
              "additionalProperties": false
            },
            "description": "Bound non-polymer components. Present when the call used source experimental; omitted under source predicted or best_available, when the entry binds none, or when the record carries no ligand data."
          },
          "coverage": {
            "type": "number",
            "description": "Fraction (0–1) of the UniProt sequence the best_available pick's mapped span covers — the span between uniprotStart and uniprotEnd, which can include residues the model leaves unmodeled. Present only under source best_available."
          },
          "provider": {
            "type": "string",
            "description": "Model provider: the modelling provider of a predicted record, or the federated provider of a best_available pick (PDBe for a PDB entry)."
          },
          "meanPlddt": {
            "type": "number",
            "description": "Mean pLDDT confidence (0–100); present only for pLDDT-scored models. For other metrics read confidence + confidenceType."
          },
          "organisms": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Source organisms: under source experimental, every distinct source organism of the entry, in entity-number order; under source predicted, the AlphaFold DB model's organism. Omitted when upstream names none, and on best_available records."
          },
          "paeDocUrl": {
            "type": "string",
            "description": "Predicted Aligned Error documentation URL (predicted)."
          },
          "confidence": {
            "type": "number",
            "description": "Model confidence on its native scale; confidenceType names the metric and range (e.g. pLDDT 0–100, QMEANDisCo 0–1). Present for predicted models that report a score."
          },
          "resolution": {
            "type": "number",
            "description": "Resolution in Å (experimental)."
          },
          "uniprotEnd": {
            "type": "number",
            "description": "Last UniProt residue of the best_available pick's mapped span. Present only under source best_available."
          },
          "coordinates": {
            "type": "string",
            "description": "Inlined coordinate text: characters [coordinatesOffset, coordinatesOffset + its length) of the file coordinateFormat names. A lone selected file arrives in windows of up to 24000 characters; several selected files arrive whole only when they total 24000 characters or fewer."
          },
          "releaseDate": {
            "type": "string",
            "description": "Initial release date (ISO 8601). Present only when the call used source experimental; omitted when the record does not report one."
          },
          "uniprotStart": {
            "type": "number",
            "description": "First UniProt residue of the best_available pick's mapped span. Present only under source best_available."
          },
          "confidenceType": {
            "type": "string",
            "description": "Name of the confidence metric carried in confidence (e.g. \"pLDDT\", \"QMEANDisCo\"). Providers score on different scales; this names the one in use."
          },
          "coordinateUrls": {
            "type": "object",
            "properties": {
              "cif": {
                "type": "string",
                "description": "mmCIF coordinate file URL."
              },
              "pdb": {
                "type": "string",
                "description": "PDB-format coordinate file URL."
              },
              "bcif": {
                "type": "string",
                "description": "Binary CIF coordinate file URL."
              }
            },
            "description": "Coordinate file download URLs. A format with no published file is omitted — e.g. pdb for large entries archived as mmCIF only.",
            "additionalProperties": false
          },
          "molecularWeight": {
            "type": "number",
            "description": "Deposited structure molecular weight in kDa. Present only when the call used source experimental; omitted when the record does not report one."
          },
          "polymerEntities": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "entityId"
              ],
              "properties": {
                "entityId": {
                  "type": "string",
                  "description": "Polymer entity ID (e.g. 4HHB_1)."
                },
                "organisms": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Distinct source organisms of this entity — more than one for a chimera (2RH1_1: Homo sapiens, Tequatrovirus T4). Omitted when upstream names none."
                },
                "authAsymIds": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Author-assigned chain IDs (auth_asym_id, e.g. [\"A\",\"C\"]) — the namespace protein_get_annotations.chain takes. Omitted when upstream does not report them."
                },
                "description": {
                  "type": "string",
                  "description": "Entity description."
                },
                "labelAsymIds": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "mmCIF label_asym_id chain IDs (e.g. [\"I\",\"OB\"]) — the namespace protein_compare_structures.chain takes. Not derivable from authAsymIds: for 6QNR_9 the label chains are I/OB against author chains 82/8E. Omitted when upstream does not report them."
                },
                "sequenceLength": {
                  "type": "number",
                  "description": "Residue count of the sample sequence."
                }
              },
              "description": "A modeled polymer entity (chain group), with both chain namespaces.",
              "additionalProperties": false
            },
            "description": "Modeled polymer entities, each with both chain namespaces — authAsymIds for protein_get_annotations.chain, labelAsymIds for protein_compare_structures.chain. Present when the call used source experimental (computed-model IDs included); omitted under source predicted or best_available and for entries with none."
          },
          "coordinateFormat": {
            "enum": [
              "cif",
              "pdb",
              "bcif"
            ],
            "type": "string",
            "description": "Format of inlined coordinates, when present."
          },
          "confidenceBuckets": {
            "type": "object",
            "required": [
              "veryLow",
              "low",
              "confident",
              "veryHigh"
            ],
            "properties": {
              "low": {
                "type": "number",
                "description": "Fraction with pLDDT 50–70."
              },
              "veryLow": {
                "type": "number",
                "description": "Fraction of residues with pLDDT < 50."
              },
              "veryHigh": {
                "type": "number",
                "description": "Fraction with pLDDT > 90."
              },
              "confident": {
                "type": "number",
                "description": "Fraction with pLDDT 70–90."
              }
            },
            "description": "pLDDT confidence-band fractions (predicted).",
            "additionalProperties": false
          },
          "coordinatesOffset": {
            "type": "number",
            "description": "Character offset in the coordinate file where coordinates begins. Present whenever coordinates is."
          },
          "coordinatesNextOffset": {
            "type": "number",
            "description": "Offset of the next window when the file continues past coordinates — pass it as coords_offset with sections naming this structure. Absent when coordinates reaches the end of the file."
          }
        },
        "description": "A resolved structure with metadata and coordinate-file URLs.",
        "additionalProperties": false
      },
      "description": "Resolved structures (metadata always present)."
    },
    "attribution": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "source",
          "license",
          "citation",
          "homepage"
        ],
        "properties": {
          "source": {
            "type": "string",
            "description": "Contributing data-source display name (e.g. \"RCSB PDB\", \"AlphaFold DB\", \"SWISS-MODEL\", \"UniProt\"). Open-ended — best_available structures are federated through 3D-Beacons providers."
          },
          "license": {
            "type": "string",
            "description": "License the source data is released under (e.g. \"CC BY 4.0\")."
          },
          "citation": {
            "type": "string",
            "description": "Primary-literature citation to credit the source."
          },
          "homepage": {
            "type": "string",
            "description": "Source homepage (absolute URL)."
          }
        },
        "description": "Upstream data-source attribution: license, citation, and homepage.",
        "additionalProperties": false
      },
      "description": "Upstream data-source licenses and citations for every source present in structures[] — RCSB PDB for PDB entries, the providing database (AlphaFold DB, ModelArchive, SWISS-MODEL, SASBDB, …) for any other model. Always present — the attribution obligation travels with the data."
    }
  },
  "additionalProperties": false
}
protein_get_structure annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}
protein_find_similar — protein-mcp-server: find similar
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Find structurally or evolutionarily related proteins. by:"sequence" runs an RCSB mmseqs2 sequence-similarity search (synchronous; experimental PDB entries only — protein_search_structures with a sequence also reaches computed models) over a sequence — supplied directly, taken from one protein entity of a PDB entry (chain picks it; by default the lowest-numbered protein entity of at least 10 residues; queryEntityId names it), or pulled from a UniProt accession (isoforms included) or entry name (HBA_HUMAN); each hit carries its identity, E-value, bit score, and aligned range. by:"structure" runs a Foldseek fold-similarity search (asynchronous) against experimental and predicted databases, uploading the PDB entry's mmCIF file or the accession's AlphaFold DB model, up to 16,000,000 characters; if the job is still computing when the poll budget elapses, or the call's 50 s budget runs out after Foldseek accepted the job, the response reports status "computing" with a ticket — re-call with ticket_id set to that value to resume the same job instead of resubmitting, and a complete response carries the same ticket so a finished job can be re-paged with a different start. Foldseek searches each chain of a multichain structure as its own query: a response covers one query (query, default 0), reports queryCount, and ranks that query's hits by score across all searched databases. Each mode reads only its own controls: sequence, chain, max_evalue and min_identity belong to by:"sequence"; ticket_id, databases and query belong to by:"structure"; pdb_id, uniprot, start and limit are shared. A field the selected mode cannot consume is rejected rather than silently ignored. A UniProt accession merged into another entry answers for its successor with a notice; a demerged or deleted one fails with its replacements. Output names the engine and database each hit came from; a structure hit also carries its Foldseek target name, and an id only where that name maps to a PDB entry or UniProt accession that protein_get_structure resolves.

protein_find_similar input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "by"
  ],
  "properties": {
    "by": {
      "enum": [
        "sequence",
        "structure"
      ],
      "type": "string",
      "description": "Similarity axis: sequence (mmseqs2) or structure (Foldseek)."
    },
    "chain": {
      "type": "string",
      "description": "Author chain ID (auth_asym_id, case-sensitive) of pdb_id selecting the protein entity whose sequence by:\"sequence\" searches, e.g. \"B\" for the beta chain of 4HHB. Requires pdb_id. Default: the lowest-numbered protein entity of at least 10 residues; DNA and RNA chains never qualify."
    },
    "limit": {
      "type": "integer",
      "default": 25,
      "maximum": 100,
      "minimum": 1,
      "description": "Maximum hits to return (1–100)."
    },
    "query": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": 0,
      "description": "Zero-based Foldseek query index (by:structure). Default 0. Foldseek splits a multichain structure into one query per chain, in file order; queryCount in the response says how many the job holds. Pass the same value with ticket_id to resume or re-page that query."
    },
    "start": {
      "type": "integer",
      "default": 0,
      "maximum": 9007199254740991,
      "minimum": 0,
      "description": "Zero-based result offset. Pages a by:sequence search, and a completed by:structure job when re-called with its ticket_id."
    },
    "pdb_id": {
      "type": "string",
      "description": "PDB entry ID to derive the query from. by:\"sequence\" searches one of its protein entities (see chain); by:\"structure\" uploads its mmCIF file, up to 16,000,000 characters."
    },
    "uniprot": {
      "type": "string",
      "description": "UniProt identifier to derive the query from: a canonical accession (e.g. P69905), an isoform accession (e.g. P04637-2), or a UniProtKB entry name (e.g. HBA_HUMAN), which resolves to its entry’s accession. by:\"sequence\" searches its UniProt sequence, by:\"structure\" its AlphaFold DB model. A merged accession answers for its successor, with a notice."
    },
    "sequence": {
      "type": "string",
      "description": "Protein sequence for by:sequence: at least 10 residues in A–I or K–Z (J excluded; B/O/U/X/Z accepted). Whitespace is removed and ASCII lowercase normalized."
    },
    "databases": {
      "type": "array",
      "items": {
        "enum": [
          "afdb50",
          "afdb-swissprot",
          "afdb-proteome",
          "bfvd_v3",
          "cath50",
          "mgnify_esm30",
          "pdb100",
          "gmgcl_id",
          "bfmd"
        ],
        "type": "string"
      },
      "description": "Foldseek target databases (by:structure), by exact name. Default pdb100 + afdb50. pdb100: experimental PDB entries; afdb50, afdb-swissprot, afdb-proteome: AlphaFold DB models; cath50: CATH domains of PDB chains and AlphaFold models; bfvd_v3: predicted viral proteins; mgnify_esm30, gmgcl_id: predicted metagenomic proteins; bfmd: predicted complexes."
    },
    "ticket_id": {
      "type": "string",
      "description": "Foldseek ticket ID from a prior by:structure response whose status was \"computing\". When set, polls that existing job instead of submitting a new search (by:structure only) — pdb_id/uniprot/databases are ignored."
    },
    "max_evalue": {
      "type": "number",
      "description": "Maximum E-value (by:sequence). Default 1.",
      "exclusiveMinimum": 0
    },
    "min_identity": {
      "type": "number",
      "maximum": 1,
      "minimum": 0,
      "description": "Minimum sequence identity 0–1 (by:sequence). Default 0."
    }
  },
  "additionalProperties": false
}
protein_find_similar output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "by",
        "engine",
        "status",
        "hits"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "by": {
      "enum": [
        "sequence",
        "structure"
      ],
      "type": "string",
      "description": "Echoed similarity axis."
    },
    "hits": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "source"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Hit identifier that chains directly into protein_get_structure: a bare PDB entry ID (e.g. 1A00), or a UniProt accession for a predicted model. Absent on a structure hit whose target names neither (bfvd_v3, mgnify_esm30, gmgcl_id, bfmd) — read target and database instead."
          },
          "chain": {
            "type": "string",
            "description": "Matched chain of the PDB entry in id (structure hits). pdb100: the author chain ID (auth_asym_id) in the assembly file Foldseek indexed, with a -N suffix marking a symmetry copy (A-2) — drop the suffix before passing it as chain to protein_get_annotations. cath50: the chain of the domain, absent when CATH recorded none."
          },
          "score": {
            "type": "number",
            "description": "Ranking score. by:\"sequence\": the RCSB relevance rank within the result set, bit scores rescaled from 1 (best hit) to 0 (worst) — a rank, not a similarity measure; read identity, evalue, and bitscore for that. by:\"structure\": the Foldseek alignment bit score."
          },
          "taxId": {
            "type": "number",
            "description": "NCBI taxonomy ID of the organism in organisms (structure hits; present exactly when a structure hit carries organisms)."
          },
          "title": {
            "type": "string",
            "description": "Title: the entry title (sequence hits and pdb100 structure hits), or the name of the modeled protein (AlphaFold DB and bfvd_v3 structure hits)."
          },
          "evalue": {
            "type": "number",
            "description": "Alignment E-value."
          },
          "source": {
            "enum": [
              "experimental",
              "predicted"
            ],
            "type": "string",
            "description": "Whether the hit is an experimental or predicted structure. Structure hits are experimental for pdb100 entries and cath50 domains of PDB chains, and predicted for every other database, cath50 domains of AlphaFold models included."
          },
          "target": {
            "type": "string",
            "description": "Foldseek target name (structure hits): the header text before the first space, as Foldseek returns it — e.g. 1crn-assembly1.cif.gz_A (pdb100), AF-P01542-F1-model_v6 (AlphaFold DB), 1cbnA00 (a cath50 domain), MGYP001043648370.pdb.gz (mgnify_esm30). Read it with database; the only handle on a hit with no id."
          },
          "bitscore": {
            "type": "number",
            "description": "Alignment bit score from mmseqs2 (sequence hits); a structure hit carries its bit score as score."
          },
          "database": {
            "type": "string",
            "description": "Source database the hit came from (structure hits)."
          },
          "entityId": {
            "type": "string",
            "description": "Matched polymer-entity ID (e.g. 1A00_1) for sequence hits; the chainable entry ID is in `id`."
          },
          "identity": {
            "type": "number",
            "description": "Sequence identity 0–1 over the alignment, to 4 decimal places."
          },
          "queryEnd": {
            "type": "number",
            "description": "Last aligned residue of the query, 1-based, inclusive."
          },
          "organisms": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Source organisms. Sequence hits: those of the matched polymer entity (entityId), not the whole entry, absent when the entry metadata names none for it. Structure hits: the organism of the target from the Foldseek taxonomy, one element — absent for mgnify_esm30 and gmgcl_id, which carry no taxonomy, and for unclassified targets."
          },
          "targetEnd": {
            "type": "number",
            "description": "Last aligned residue of the hit, 1-based, inclusive, in the same indexed sequence as targetStart."
          },
          "queryStart": {
            "type": "number",
            "description": "First aligned residue of the query, 1-based, inclusive."
          },
          "probability": {
            "type": "number",
            "description": "Estimated probability (0–1), from Foldseek, that the query and hit are homologous (structure hits)."
          },
          "targetStart": {
            "type": "number",
            "description": "First aligned residue of the hit, 1-based, inclusive, in the sequence the search indexed for that hit — not author residue numbering. For a sequence hit that sequence is the matched polymer entity (entityId); for a structure hit, the indexed chain, model, or CATH domain."
          },
          "targetLength": {
            "type": "number",
            "description": "Length in residues of the hit sequence that targetStart and targetEnd index into."
          },
          "alignmentLength": {
            "type": "number",
            "description": "Alignment length in columns, gaps included."
          },
          "uniprotAccession": {
            "type": "string",
            "description": "UniProt accession of the modeled protein (structure hits from AlphaFold DB, bfvd_v3, and cath50 domains of AlphaFold models). A bfvd_v3 hit carries it without an id; pass it to protein_get_annotations."
          }
        },
        "description": "A similar protein, with alignment scores when available.",
        "additionalProperties": false
      },
      "description": "Similar proteins, best first. Structure hits are ranked by score across all searched databases (hits without a score last, ties by database then target)."
    },
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "chain_not_found",
                "chain_without_pdb_id",
                "databases_rejected",
                "inactive_accession",
                "invalid_accession",
                "invalid_sequence",
                "missing_query",
                "mode_mismatched_field",
                "no_sequence",
                "query_out_of_range",
                "search_failed",
                "structure_too_large",
                "ticket_not_found"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `chain_not_found`: chain names no protein polymer entity of the pdb_id entry: no such author chain, a DNA or RNA chain, or a case mismatch. `chain_without_pdb_id`: chain was supplied under by:\"sequence\" without pdb_id. `databases_rejected`: Foldseek refused the structure job submission with HTTP 400: it no longer accepts a requested database name. `inactive_accession`: UniProt lists the uniprot accession as inactive: demerged into several entries, or deleted. `invalid_accession`: uniprot is shaped like none of a canonical accession (P69905), an isoform accession (P04637-2), or a UniProtKB entry name (HBA_HUMAN). `invalid_sequence`: A raw or identifier-resolved RCSB protein sequence contains invalid residues or has fewer than 10 residues after whitespace removal, a pdb_id protein entity picked by chain or by default included. `missing_query`: None of sequence, pdb_id, or uniprot was provided. `mode_mismatched_field`: An input field only the other by mode consumes was supplied: sequence, chain, max_evalue or min_identity under by:\"structure\"; ticket_id, query or a non-empty databases list under by:\"sequence\". `no_sequence`: No query could be derived from the identifier: by:\"sequence\" found no such PDB entry, no protein polymer entity in it, or no UniProt sequence for the accession or entry name; by:\"structure\" found no UniProt entry for the entry name, or no AlphaFold DB model with a PDB-format file for the accession. `query_out_of_range`: The requested query index is not below the number of queries the completed Foldseek job holds. `search_failed`: The Foldseek search service rejected or failed the structure job. `structure_too_large`: The query structure's coordinate file is longer than 16,000,000 characters, the most this tool uploads to Foldseek. `ticket_not_found`: The supplied ticket_id was rejected by Foldseek as an invalid or expired ticket. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "query": {
      "type": "number",
      "description": "Zero-based Foldseek query index the hits belong to (by:structure)."
    },
    "start": {
      "type": "number",
      "description": "Zero-based offset of the returned result page."
    },
    "engine": {
      "type": "string",
      "description": "The engine that answered (e.g. \"RCSB mmseqs2\", \"Foldseek\")."
    },
    "notice": {
      "type": "string",
      "description": "Advisory note: a structure job still computing, or one the call’s time budget cut off after submitting (with how to resume it), no matches, a start past the end of the results, other queries in a multichain structure job, the default protein entity a pdb_id sequence query searched alongside the entry’s other protein entities, or a merged UniProt accession answered for its successor."
    },
    "status": {
      "enum": [
        "complete",
        "computing"
      ],
      "type": "string",
      "description": "complete with hits, or computing (async — re-call with ticket_id to resume)."
    },
    "ticketId": {
      "type": "string",
      "description": "Async job ticket ID (by:structure). Present while status is computing, and also on a complete response — re-call with ticket_id plus a different start/limit to page the same finished job instead of resubmitting."
    },
    "nextStart": {
      "type": "number",
      "description": "Offset for the next result page; absent on the final or past-end page."
    },
    "queryCount": {
      "type": "number",
      "description": "Number of queries the Foldseek job holds, one per chain of the submitted structure (by:structure, complete). Valid query values run from 0 to queryCount - 1."
    },
    "totalCount": {
      "type": "number",
      "description": "Total upstream matches before pagination."
    },
    "queryLength": {
      "type": "number",
      "description": "Length in residues of the query sequence that queryStart and queryEnd index into on every hit (complete responses whose hits carry aligned ranges; for by:structure, the chain of the selected query)."
    },
    "queryEntityId": {
      "type": "string",
      "description": "Polymer entity of pdb_id whose sequence by:\"sequence\" searched (e.g. 4HHB_1). Present only when the query came from pdb_id."
    }
  },
  "additionalProperties": false
}
protein_find_similar annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}
protein_track_ligands — protein-mcp-server: track ligands
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Ligand discovery and binding-site analysis across the PDB. mode "find_ligand" resolves a name or formula to chemical component IDs with metadata (formula, weight, SMILES), ranked by deposition frequency — most-deposited component first, so the top hit is the most common match for the name, not necessarily an exact name-string match. The ranking covers a bounded candidate pool; totalCount and candidatesConsidered report how many components matched and how many were ranked. mode "structures_with_ligand" returns PDB entries holding a bound copy of a ligand (by exact component ID — get the ID from find_ligand first), highest-resolution first, each with its resolution in Å, title, method, and the polymer entities whose chains carry the ligand. This mode and find_ligand's depositionCount count bound copies only: a component present only as a residue inside a polymer chain (e.g. MSE in a selenomethionine protein) or a sugar inside a branched glycan is not counted. mode "binding_site" returns the protein residues lining a ligand's pocket in a given structure, with contact distances, each numbered in both the mmCIF label namespace (asymId, seqId) and the author namespace (authAsymId, authSeqId) used by deposited coordinates and most literature. Binding sites are experimental-only (computed from deposited coordinates; predicted models carry no bound ligands).

protein_track_ligands input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "mode"
  ],
  "properties": {
    "mode": {
      "enum": [
        "find_ligand",
        "structures_with_ligand",
        "binding_site"
      ],
      "type": "string",
      "description": "Operation: resolve a ligand, find structures containing it, or analyze its binding site."
    },
    "limit": {
      "type": "integer",
      "default": 25,
      "maximum": 100,
      "minimum": 1,
      "description": "Maximum results to return (1–100)."
    },
    "query": {
      "type": "string",
      "description": "Ligand name or formula (mode find_ligand)."
    },
    "start": {
      "type": "integer",
      "default": 0,
      "maximum": 9007199254740991,
      "minimum": 0,
      "description": "Zero-based result offset (modes structures_with_ligand and binding_site; binding_site pages ligand instances)."
    },
    "pdb_id": {
      "type": "string",
      "description": "PDB entry ID (mode binding_site)."
    },
    "comp_id": {
      "type": "string",
      "description": "Exact chemical component ID (modes structures_with_ligand and binding_site)."
    }
  },
  "additionalProperties": false
}
protein_track_ligands output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "mode"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "mode": {
      "enum": [
        "find_ligand",
        "structures_with_ligand",
        "binding_site"
      ],
      "type": "string",
      "description": "Echoed mode."
    },
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "missing_param",
                "not_found"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `missing_param`: The mode-specific required input is absent: query (find_ligand), comp_id (structures_with_ligand), or pdb_id (binding_site). `not_found`: No chemical component matched the name/formula, or the structure has no instance of the ligand. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "start": {
      "type": "number",
      "description": "Zero-based offset of the structures_with_ligand or binding_site result page."
    },
    "notice": {
      "type": "string",
      "description": "Advisory note: a find_ligand candidate pool smaller than the upstream match count, a structures_with_ligand page that is empty because no entry contains the component or because start is past the end, or a binding_site page that leaves instances for a later start or starts past the last instance."
    },
    "ligands": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "compId",
          "depositionCount"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Chemical name."
          },
          "type": {
            "type": "string",
            "description": "Component type (e.g. non-polymer)."
          },
          "compId": {
            "type": "string",
            "description": "Chemical component ID (e.g. STI, HEM)."
          },
          "smiles": {
            "type": "string",
            "description": "Isomeric SMILES."
          },
          "formula": {
            "type": "string",
            "description": "Molecular formula."
          },
          "inchikey": {
            "type": "string",
            "description": "InChIKey."
          },
          "formulaWeight": {
            "type": "number",
            "description": "Formula weight in Da."
          },
          "depositionCount": {
            "type": "number",
            "description": "Number of PDB entries holding a bound (non-polymer) copy of this component — the totalCount structures_with_ligand reports for it. Entries where it occurs only as a residue inside a polymer chain or a sugar inside a branched glycan are not counted. Candidates are ranked by this value, most-deposited first."
          }
        },
        "description": "A resolved chemical component (ligand) and its identifiers.",
        "additionalProperties": false
      },
      "description": "Resolved chemical components (find_ligand)."
    },
    "nextStart": {
      "type": "number",
      "description": "Offset for the next structures_with_ligand or binding_site page; absent on the final or past-end page."
    },
    "structures": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "PDB entry ID holding a bound copy of the ligand."
          },
          "title": {
            "type": "string",
            "description": "Structure title. Omitted when unreported."
          },
          "method": {
            "type": "string",
            "description": "Experimental method(s), comma-joined. Omitted when unreported."
          },
          "resolution": {
            "type": "number",
            "description": "Best reported resolution in Å (absent for methods without one, e.g. NMR)."
          },
          "hostEntities": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "entityId"
              ],
              "properties": {
                "entityId": {
                  "type": "string",
                  "description": "Polymer entity ID (e.g. 3K5V_1)."
                },
                "organisms": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Distinct source organisms of the entity. Omitted when upstream names none."
                },
                "description": {
                  "type": "string",
                  "description": "Entity description (e.g. Tyrosine-protein kinase ABL1)."
                }
              },
              "description": "A polymer entity carrying an instance of the ligand.",
              "additionalProperties": false
            },
            "description": "Polymer entities whose author chains carry an instance of the ligand, in entity-number order. The chain assignment is the depositor's, so a ligand at a subunit interface lists only its assigned chain's entity — use mode binding_site for the residues it contacts. Omitted when no polymer chain carries an instance."
          }
        },
        "description": "A PDB entry holding a bound copy of the ligand: its resolution, title, method, and host entities.",
        "additionalProperties": false
      },
      "description": "PDB entries holding a bound (non-polymer) copy of the ligand, highest-resolution first (structures_with_ligand)."
    },
    "totalCount": {
      "type": "number",
      "description": "Total upstream matches before any local narrowing: PDB entries holding a bound (non-polymer) copy of the component (structures_with_ligand), chemical components matching the query (find_ligand), or ligand instances with pocket contacts (binding_site)."
    },
    "bindingSites": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "ligandCompId",
          "residues"
        ],
        "properties": {
          "residues": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "residueCompId",
                "asymId"
              ],
              "properties": {
                "seqId": {
                  "type": "number",
                  "description": "mmCIF label_seq_id: position in the entity sequence (label namespace). Not the deposited residue number; see authSeqId."
                },
                "asymId": {
                  "type": "string",
                  "description": "mmCIF label_asym_id of the residue's chain (label namespace, paired with seqId). Can differ from authAsymId."
                },
                "distance": {
                  "type": "number",
                  "description": "Contact distance to the ligand in Å."
                },
                "authSeqId": {
                  "type": "number",
                  "description": "Author residue number (auth_seq_id), as deposited and as most literature and viewers number it. Related to seqId by no fixed offset; insertion codes are not reported."
                },
                "authAsymId": {
                  "type": "string",
                  "description": "Author chain ID (auth_asym_id) of the residue's chain, as deposited and as most structure viewers label it."
                },
                "residueCompId": {
                  "type": "string",
                  "description": "Interacting residue type (e.g. ASP)."
                }
              },
              "description": "A pocket residue in contact with the ligand, in both numbering namespaces.",
              "additionalProperties": false
            },
            "description": "Protein residues lining the pocket, nearest first."
          },
          "ligandAsymId": {
            "type": "string",
            "description": "Author chain ID (auth_asym_id) of the ligand instance — the author namespace, unlike residues[].asymId."
          },
          "ligandCompId": {
            "type": "string",
            "description": "Bound ligand chemical component ID."
          },
          "ligandAuthSeqId": {
            "type": "number",
            "description": "Author residue number (auth_seq_id) of the ligand instance."
          }
        },
        "description": "A ligand instance and the protein residues lining its pocket.",
        "additionalProperties": false
      },
      "description": "Ligand instances and their pocket residues (binding_site), in a fixed order — ligands by entity number, then the instances of each ligand by author chain and author residue number — so start/limit pages read every instance exactly once."
    },
    "resolvedCompId": {
      "type": "string",
      "description": "The chemical component ID used to query."
    },
    "candidatesConsidered": {
      "type": "number",
      "description": "Chemical components pulled into the deposition-frequency ranking (find_ligand). Below totalCount when the candidate pool was truncated; the ranking then covers only these candidates."
    }
  },
  "additionalProperties": false
}
protein_track_ligands annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}
protein_compare_structures — protein-mcp-server: compare structures
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Structurally align multiple structures (up to the configured batch cap; structures past it are returned in ignored) via the RCSB Structural Comparison service (TM-align / jFATCAT). reference:"first" aligns every structure to the first; reference:"all_pairs" computes the full pairwise matrix. Each pair is an independent async alignment job with per-pair partial success — a pair still computing when the budget elapses returns status "computing" with its job UUID, and a failed pair degrades its row without sinking the others. Re-call with a matching entry in resume[] to poll a computing pair's UUID instead of resubmitting; a resumed pair reports a and b in the order its job was submitted, and a resume under a different method is rejected. Returns TM-score, RMSD, and aligned-residue count per pair, plus each structure's modeled-residue count and alignment coverage. TM-score is length-normalized and can shift sharply between structures that differ only by a terminal residue or two — the greedy superposition can settle into a worse local optimum — so read tmScore alongside rmsd, alignedResidues, modeledResidues and coverage, the columns that make such cases diagnosable.

protein_compare_structures input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "structures"
  ],
  "properties": {
    "method": {
      "enum": [
        "tm-align",
        "fatcat-rigid",
        "fatcat-flexible"
      ],
      "type": "string",
      "default": "tm-align",
      "description": "Alignment algorithm: tm-align, fatcat-rigid, or fatcat-flexible."
    },
    "resume": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "a",
          "b",
          "uuid"
        ],
        "properties": {
          "a": {
            "type": "string",
            "minLength": 1,
            "description": "First structure label (entry or entry.chain) of a pair from a prior response."
          },
          "b": {
            "type": "string",
            "minLength": 1,
            "description": "Second structure label (entry or entry.chain) of a pair from a prior response."
          },
          "uuid": {
            "type": "string",
            "minLength": 1,
            "description": "Alignment job UUID returned for that pair by a prior call."
          }
        },
        "description": "A prior pair to resume by UUID instead of resubmitting."
      },
      "description": "Resume tickets from a prior call: for each pair whose labels match an entry here, poll the existing UUID instead of submitting a new alignment job. Copy a, b, and uuid verbatim from a prior response's pairs[]; keep structures, reference, and method unchanged. The order of structures may change — a resumed pair keeps the orientation its job was submitted in."
    },
    "reference": {
      "enum": [
        "first",
        "all_pairs"
      ],
      "type": "string",
      "default": "first",
      "description": "Align all to the first structure, or compute the full pairwise matrix."
    },
    "timeout_s": {
      "type": "integer",
      "maximum": 120,
      "minimum": 5,
      "description": "Poll budget per pair in seconds before returning \"computing\". Defaults to the server setting."
    },
    "structures": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "pdb_id"
        ],
        "properties": {
          "chain": {
            "type": "string",
            "description": "mmCIF label_asym_id restricting the alignment to a single chain. Read it from polymerEntities[].labelAsymIds on protein_get_structure (source experimental) or the pdb://{entry_id} resource. Author chain IDs are a different namespace — polymerEntities[].authAsymIds, what protein_get_annotations.chain takes — and are not interchangeable with this one. Case-sensitive."
          },
          "pdb_id": {
            "type": "string",
            "minLength": 1,
            "description": "PDB entry ID."
          }
        },
        "description": "A structure to align, by PDB entry ID with optional chain."
      },
      "maxItems": 25,
      "minItems": 2,
      "description": "The structures to compare, up to the configured batch cap; structures past it are returned in ignored and not compared. A structure repeated here is compared once."
    }
  },
  "additionalProperties": false
}
protein_compare_structures output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "method",
        "reference",
        "pairs",
        "pairsTotal",
        "computing"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "resume_pair_unmatched",
                "no_distinct_pair",
                "resume_method_mismatch",
                "resume_job_mismatch"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `resume_pair_unmatched`: A resume entry's a/b labels don't match any pair generated from structures + reference. `no_distinct_pair`: Every entry in structures[] denotes the same structure, leaving no pair to align. `resume_method_mismatch`: A resumed alignment job completed under a different method than this call's method input. `resume_job_mismatch`: A resume entry's uuid belongs to an alignment job for a different structure pair than its a/b labels. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "pairs": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "a",
          "b",
          "status"
        ],
        "properties": {
          "a": {
            "type": "string",
            "description": "First structure of the pair (entry[.chain]), as the alignment job was submitted — for a resumed pair that can differ from this call's structures[] order."
          },
          "b": {
            "type": "string",
            "description": "Second structure of the pair (entry[.chain])."
          },
          "rmsd": {
            "type": "number",
            "description": "RMSD in Å over aligned residues."
          },
          "uuid": {
            "type": "string",
            "description": "Alignment job UUID (present for computing/complete pairs)."
          },
          "error": {
            "type": "string",
            "description": "Failure detail (failed pairs)."
          },
          "status": {
            "enum": [
              "complete",
              "computing",
              "failed"
            ],
            "type": "string",
            "description": "Outcome for this pair."
          },
          "tmScore": {
            "type": "number",
            "description": "TM-score (0–1; higher is more similar). Length-normalized by structure a's modeled length, so the same pair aligned b-first can score very differently (0.17 vs 0.40 for a 141- vs a 46-residue chain). It can also be sensitive to terminal length differences between the two structures — a one-residue overhang can flip the greedy superposition into a worse local optimum, dropping the score sharply. Cross-check rmsd and alignedResidues to spot such cases."
          },
          "coverage": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "maxItems": 2,
            "minItems": 2,
            "description": "Alignment coverage per structure as a 0–100 percentage of that structure's own modeled-residue count — not of the full sequence and not of the shorter structure — ordered [a, b] to match this pair. Read alongside modeledResidues: equal aligned counts give the shorter structure the higher coverage."
          },
          "alignedResidues": {
            "type": "number",
            "description": "Number of aligned residue pairs."
          },
          "modeledResidues": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "maxItems": 2,
            "minItems": 2,
            "description": "Modeled residue count per structure, ordered [a, b] to match this pair. A large gap between the two is the terminal-length asymmetry that can depress tmScore."
          },
          "similarityScore": {
            "type": "number",
            "description": "Raw method-specific alignment score when supplied by RCSB; not normalized across methods."
          },
          "sequenceSimilarity": {
            "type": "number",
            "description": "Sequence similarity as the upstream 0–1 fraction, when supplied."
          }
        },
        "description": "Alignment outcome for one structure pair.",
        "additionalProperties": false
      },
      "description": "One row per aligned pair."
    },
    "method": {
      "type": "string",
      "description": "Alignment method used."
    },
    "notice": {
      "type": "string",
      "description": "Advisory note: pairs still computing or failed (with how to resume them), structures beyond the batch cap that were ignored, and repeated structures compared once."
    },
    "ignored": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "pdb_id"
        ],
        "properties": {
          "chain": {
            "type": "string",
            "description": "Chain, when the structure named one."
          },
          "pdb_id": {
            "type": "string",
            "description": "PDB entry ID."
          }
        },
        "description": "A structure past the batch cap, never compared, in the shape structures[] takes.",
        "additionalProperties": false
      },
      "description": "Structures past the batch cap, never compared — repeats dropped, in input order. Re-call with them alongside the structures to compare them against (e.g. the first structure plus these, reference \"first\"). Absent when the cap dropped nothing."
    },
    "computing": {
      "type": "number",
      "description": "Number of pairs still computing."
    },
    "reference": {
      "enum": [
        "first",
        "all_pairs"
      ],
      "type": "string",
      "description": "Comparison mode used."
    },
    "pairsTotal": {
      "type": "number",
      "description": "Number of pairs compared."
    }
  },
  "additionalProperties": false
}
protein_compare_structures annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}
protein_analyze_collection — protein-mcp-server: analyze collection
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Profile the PDB into distributions and trends over an optional scoping query: counts by method, organism, or polymer composition; resolution and molecular-weight histograms; release-year timelines; and multidimensional cross-tabs (e.g. method × release_year). Aggregation runs at RCSB, so the response carries compact counts per bucket rather than the matching entries. Pass one group_by dimension for a single breakdown, or two distinct dimensions for a cross-tab (the first nests the second). bucket_limit caps each dimension level separately rather than the response, so a cross-tab returns up to that many nested buckets under each of its capped parent buckets; bucketsReturned reports the realized total.

protein_analyze_collection input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "group_by"
  ],
  "properties": {
    "query": {
      "type": "string",
      "description": "Optional free-text scope (e.g. \"kinase\"); omit to profile the whole PDB."
    },
    "method": {
      "type": "string",
      "description": "Optional experimental-method scope: X-RAY DIFFRACTION, ELECTRON MICROSCOPY, SOLUTION NMR, SOLID-STATE NMR, ELECTRON CRYSTALLOGRAPHY, NEUTRON DIFFRACTION, FIBER DIFFRACTION, POWDER DIFFRACTION, SOLUTION SCATTERING, EPR, FLUORESCENCE TRANSFER, INFRARED SPECTROSCOPY, THEORETICAL MODEL (any letter case), or an alias: cryo-EM / cryoEM / EM → ELECTRON MICROSCOPY; X-ray / xray → X-RAY DIFFRACTION; NMR → SOLUTION NMR + SOLID-STATE NMR. Any other value is rejected."
    },
    "group_by": {
      "type": "array",
      "items": {
        "enum": [
          "method",
          "organism",
          "polymer_type",
          "resolution",
          "release_year",
          "molecular_weight"
        ],
        "type": "string"
      },
      "maxItems": 2,
      "minItems": 1,
      "description": "1 dimension for a breakdown, or 2 distinct dimensions for a cross-tab (the first nests the second). Repeating a dimension is rejected."
    },
    "interval": {
      "anyOf": [
        {
          "type": "number",
          "description": "Numeric bin width for a value histogram (e.g. resolution Å).",
          "exclusiveMinimum": 0
        },
        {
          "enum": [
            "year"
          ],
          "type": "string",
          "description": "Period granularity for a date histogram. Only \"year\"."
        }
      ],
      "description": "Bin width for a histogram dimension (a number, for resolution or molecular_weight) or period for a date histogram (\"year\", for release_year). Applies to whichever requested group_by dimension can consume that value type — primary or nested child — so a cross-tab like [\"method\",\"resolution\"] bins its nested resolution child. When both requested dimensions can consume it the primary takes it and the child keeps its default. When neither can, the call is rejected rather than silently ignoring the override."
    },
    "organism": {
      "type": "string",
      "description": "Optional source-organism scope: a scientific name (\"Homo sapiens\"), an NCBI common name (\"human\"), or an NCBI taxon ID (\"9606\"), in any letter case. Matches that taxon and every taxon under it; a multi-word name also matches scientific names that contain it. A word fragment (\"coli\") matches nothing."
    },
    "bucket_limit": {
      "type": "integer",
      "maximum": 500,
      "minimum": 1,
      "description": "Max buckets per dimension level, not per response. A cross-tab applies the cap separately to the parent dimension and to the nested child inside each parent bucket, so up to bucket_limit × (1 + bucket_limit) buckets can come back — 2550 at the default 50. The realized count comes back as bucketsReturned. Defaults to the configured server cap."
    },
    "content_type": {
      "enum": [
        "experimental",
        "predicted",
        "all"
      ],
      "type": "string",
      "default": "experimental",
      "description": "Which structure universe to profile. Default experimental. Computed models carry no experimental metadata, so method and resolution return nothing under \"predicted\"."
    },
    "max_resolution": {
      "type": "number",
      "description": "Optional maximum-resolution scope (Å).",
      "exclusiveMinimum": 0
    }
  },
  "additionalProperties": false
}
protein_analyze_collection output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "total",
        "facets",
        "bucketsReturned"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "interval_not_applicable",
                "duplicate_dimension",
                "unknown_method"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `interval_not_applicable`: interval was supplied but neither requested group_by dimension aggregates by a histogram that accepts a value of that type. `duplicate_dimension`: group_by lists the same dimension twice, which would cross a dimension with itself. `unknown_method`: method is neither one of the 13 RCSB experimental methods nor an accepted alias, so it could only ever match nothing. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "scope": {
      "type": "string",
      "description": "Echoed scope description for follow-up calls."
    },
    "total": {
      "type": "number",
      "description": "Total entries in the scoped collection."
    },
    "facets": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "dimension",
          "buckets",
          "missingValueCount"
        ],
        "properties": {
          "buckets": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "label",
                "count"
              ],
              "properties": {
                "child": {
                  "type": "object",
                  "required": [
                    "dimension",
                    "buckets",
                    "missingValueCount"
                  ],
                  "properties": {
                    "buckets": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "label",
                          "count"
                        ],
                        "properties": {
                          "count": {
                            "type": "number",
                            "description": "Number of entries in the bucket."
                          },
                          "label": {
                            "type": "string",
                            "description": "Bucket value — category, numeric bin start, or period."
                          },
                          "rangeTo": {
                            "type": "number",
                            "description": "Exclusive upper bound of a numeric histogram bin (rangeFrom + bin interval), so the bin covers [rangeFrom, rangeTo). Present only for numeric facets."
                          },
                          "rangeFrom": {
                            "type": "number",
                            "description": "Inclusive lower bound of a numeric histogram bin (= label). Present only for numeric facets (resolution, molecular_weight); absent for term/period facets."
                          }
                        },
                        "description": "A leaf aggregation bucket: a value and its entry count.",
                        "additionalProperties": false
                      },
                      "description": "Nested buckets within the parent bucket."
                    },
                    "dimension": {
                      "type": "string",
                      "description": "Nested dimension name."
                    },
                    "truncated": {
                      "type": "boolean",
                      "description": "True when this nested bucket list was capped by the per-dimension bucket limit."
                    },
                    "missingValueCount": {
                      "type": "number",
                      "description": "Matches inside the parent bucket that carry no value for this nested attribute, so they fall in no nested bucket. 0 when the nested buckets account for the whole parent bucket."
                    }
                  },
                  "description": "Nested dimension breakdown for a cross-tab. Present whenever a second dimension was requested — with an empty bucket list when nothing in this bucket carries a value for it — so its absence means no cross-tab was asked for. At most one: a bucket is never cross-tabbed by more than one dimension.",
                  "additionalProperties": false
                },
                "count": {
                  "type": "number",
                  "description": "Number of entries in the bucket."
                },
                "label": {
                  "type": "string",
                  "description": "Bucket value — category, numeric bin start, or period."
                },
                "rangeTo": {
                  "type": "number",
                  "description": "Exclusive upper bound of a numeric histogram bin (rangeFrom + bin interval), so the bin covers [rangeFrom, rangeTo). Present only for numeric facets."
                },
                "rangeFrom": {
                  "type": "number",
                  "description": "Inclusive lower bound of a numeric histogram bin (= label). Present only for numeric facets (resolution, molecular_weight); absent for term/period facets."
                }
              },
              "description": "A top-level aggregation bucket, optionally cross-tabbed by a nested dimension.",
              "additionalProperties": false
            },
            "description": "Aggregation buckets, count-descending for terms."
          },
          "dimension": {
            "type": "string",
            "description": "Friendly dimension name (e.g. method, organism, release_year)."
          },
          "truncated": {
            "type": "boolean",
            "description": "True when buckets were capped by the per-dimension bucket limit."
          },
          "missingValueCount": {
            "type": "number",
            "description": "Matches in scope that carry no value for this attribute, so they count toward the response total but fall in no bucket (e.g. computed models have no experimental method; solution-NMR entries have no diffraction resolution). Independent of truncation — measured before the bucket cap is applied. 0 means no shortfall was detectable: a multi-valued attribute such as organism can place one match in several buckets, which offsets the shortfall rather than adding to it."
          }
        },
        "description": "A facet dimension and its aggregation buckets, each optionally cross-tabbed.",
        "additionalProperties": false
      },
      "description": "The requested breakdown(s)."
    },
    "notice": {
      "type": "string",
      "description": "Advisory note (per-position bucket truncation, a scope that matched nothing, dimensions with no data under the requested content_type, dimensions whose buckets cover materially less than the total). Carries every applicable advisory in one string."
    },
    "truncated": {
      "type": "boolean",
      "description": "True when at least one dimension position — the top-level dimension or a nested cross-tab child — had more buckets than the applied cap. Which positions, and by how much, is named in notice."
    },
    "bucketsReturned": {
      "type": "number",
      "description": "Buckets in this response, summed over every dimension level: the top-level buckets plus, for a cross-tab, the nested child buckets under each of them. Since bucket_limit caps each level separately, this is the size those caps actually produced — always present, cross-tab or not."
    }
  },
  "additionalProperties": false
}
protein_analyze_collection annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}
protein_get_annotations — protein-mcp-server: get annotations
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Sequence and functional annotation for a protein: UniProt positional features (domains, binding and active sites, PTMs including cross-links and lipidation, topology, DNA binding, processing products such as chains and signal peptides, mutagenesis), natural variants, and InterPro domain/family memberships (Pfam, PROSITE, …) with GO terms. Provide a canonical UniProt accession directly, or a PDB ID — it is resolved to its UniProt accession via the structure's sequence cross-reference. A multi-chain PDB entry can map to several accessions; the default pick is deterministic (lowest author chain ID) and the alternatives are listed in "ambiguity" — pass "chain" to select a specific one. An accession UniProt merged into another entry answers for that successor with a notice; a demerged or deleted one fails with its replacement accessions. Use "include" to scope which annotation classes are fetched. Every response carries an "attribution" block with the upstream data licenses and citations.

protein_get_annotations input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "chain": {
      "type": "string",
      "description": "Author chain ID (auth_asym_id, e.g. \"A\") that disambiguates a multi-chain PDB entry to a specific UniProt accession. Case-sensitive — must match the author chain ID exactly (large structures can carry distinct \"A\" and \"a\" chains). Only applies with pdb_id; ignored when uniprot is supplied directly. See polymerEntities[].authAsymIds in the pdb://{entry_id} resource for an entry's author chain IDs."
    },
    "limit": {
      "type": "integer",
      "default": 50,
      "maximum": 200,
      "minimum": 1,
      "description": "Per-class page size (1–200, default 50). Continue each class independently with features_offset, variants_offset, or domains_offset; the notice gives the next offset."
    },
    "pdb_id": {
      "type": "string",
      "description": "PDB entry ID; resolved to a UniProt accession via cross-reference."
    },
    "include": {
      "enum": [
        "features",
        "domains",
        "variants",
        "all"
      ],
      "type": "string",
      "default": "all",
      "description": "Which annotation classes to fetch: features, domains (InterPro), variants, or all."
    },
    "uniprot": {
      "type": "string",
      "description": "Canonical UniProt accession (e.g. P69905). Isoform accessions (e.g. P04637-2) are rejected; UniProt annotates the canonical entry. Takes precedence over pdb_id."
    },
    "domains_offset": {
      "type": "integer",
      "default": 0,
      "maximum": 9007199254740991,
      "minimum": 0,
      "description": "Zero-based offset into InterPro memberships; independent of features and variants."
    },
    "features_offset": {
      "type": "integer",
      "default": 0,
      "maximum": 9007199254740991,
      "minimum": 0,
      "description": "Zero-based offset into functional features; independent of variants and domains."
    },
    "variants_offset": {
      "type": "integer",
      "default": 0,
      "maximum": 9007199254740991,
      "minimum": 0,
      "description": "Zero-based offset into natural variants; independent of features and domains."
    }
  },
  "additionalProperties": false
}
protein_get_annotations output schema
{
  "type": "object",
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "accession",
        "geneNames",
        "attribution"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "error": {
      "type": "object",
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": -9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "examples": [
                "missing_identifier",
                "invalid_accession",
                "accession_not_found",
                "inactive_accession",
                "no_uniprot_mapping",
                "chain_not_found"
              ],
              "description": "Machine-readable failure mode. Declared by this tool: `missing_identifier`: Neither uniprot nor pdb_id was supplied, so there is no protein to look up. `invalid_accession`: The supplied uniprot value is not a canonical UniProt accession: malformed, or an isoform accession (e.g. P04637-2), which UniProt does not annotate apart from its canonical entry. `accession_not_found`: UniProtKB has no entry for a well-formed accession: it was never assigned. `inactive_accession`: UniProt lists the accession as inactive: demerged into several entries, or deleted. `no_uniprot_mapping`: A supplied PDB ID resolved to no usable UniProt cross-reference (e.g. a nucleic-acid-only entry). `chain_not_found`: A supplied chain matches no UniProt-mapped polymer entity in the resolved PDB entry. Other values are possible when a failure originates below the handler."
            },
            "recovery": {
              "type": "object",
              "required": [
                "hint"
              ],
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "description": "Actionable next step for the caller.",
              "additionalProperties": {}
            },
            "retryable": {
              "type": "boolean",
              "description": "Whether retrying may succeed."
            }
          },
          "additionalProperties": {}
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        }
      },
      "description": "Present when the call failed. Absent on success.",
      "additionalProperties": {}
    },
    "notice": {
      "type": "string",
      "description": "The merge when UniProt merged the requested accession into another entry, first; then per class: the next offset, advice to lower an exhausted offset, an empty class, or an InterPro walk that stopped short of its count."
    },
    "domains": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "accession",
          "name",
          "type",
          "memberDatabases",
          "goTerms"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Domain/family name."
          },
          "type": {
            "type": "string",
            "description": "Entry type (e.g. domain, family, homologous_superfamily)."
          },
          "goTerms": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "description": "GO term ID (e.g. GO:0005515)."
                },
                "name": {
                  "type": "string",
                  "description": "GO term name."
                },
                "category": {
                  "type": "string",
                  "description": "GO aspect (molecular_function, biological_process, …)."
                }
              },
              "description": "An associated Gene Ontology term.",
              "additionalProperties": false
            },
            "description": "Associated GO terms."
          },
          "accession": {
            "type": "string",
            "description": "InterPro accession (e.g. IPR000001)."
          },
          "locations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "fragments": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "end": {
                        "type": "number",
                        "description": "Fragment end residue (1-based, UniProt numbering)."
                      },
                      "start": {
                        "type": "number",
                        "description": "Fragment start residue (1-based, UniProt numbering)."
                      },
                      "dcStatus": {
                        "type": "string",
                        "description": "InterPro discontinuity qualifier, as supplied."
                      }
                    },
                    "description": "One domain fragment; gaps between fragments are not part of the domain.",
                    "additionalProperties": false
                  },
                  "description": "Ordered fragments within this location, when supplied."
                }
              },
              "description": "One InterPro location on the requested protein.",
              "additionalProperties": false
            },
            "description": "Separate locations for this membership on the requested UniProt protein."
          },
          "memberDatabases": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Contributing member databases (e.g. pfam, profile)."
          }
        },
        "description": "An InterPro domain/family membership with GO terms.",
        "additionalProperties": false
      },
      "description": "InterPro domain/family memberships."
    },
    "features": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "end": {
            "type": "number",
            "description": "End residue (1-based)."
          },
          "type": {
            "type": "string",
            "description": "Feature type as UniProt names it (e.g. Domain, Binding site, Modified residue, Cross-link, Lipidation, Topological domain, Chain, Mutagenesis, Non-standard residue)."
          },
          "start": {
            "type": "number",
            "description": "Start residue (1-based)."
          },
          "featureId": {
            "type": "string",
            "description": "Stable UniProt feature identifier when supplied."
          },
          "description": {
            "type": "string",
            "description": "Feature description."
          },
          "originalSequence": {
            "type": "string",
            "description": "Source-provided original amino-acid sequence; empty and absent values remain distinct."
          },
          "alternativeSequences": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Source-provided alternatives, preserving order and empty values; absence does not assert a deletion."
          }
        },
        "description": "A sequence feature or natural variant over a residue range.",
        "additionalProperties": false
      },
      "description": "Positional features other than natural variants, in UniProt order (grouped by type). Secondary structure, isoform sequences, and sequence-record notes are not included."
    },
    "function": {
      "type": "string",
      "description": "UniProt function summary."
    },
    "organism": {
      "type": "string",
      "description": "Source organism scientific name."
    },
    "variants": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "end": {
            "type": "number",
            "description": "End residue (1-based)."
          },
          "type": {
            "type": "string",
            "description": "Feature type as UniProt names it (e.g. Domain, Binding site, Modified residue, Cross-link, Lipidation, Topological domain, Chain, Mutagenesis, Non-standard residue)."
          },
          "start": {
            "type": "number",
            "description": "Start residue (1-based)."
          },
          "featureId": {
            "type": "string",
            "description": "Stable UniProt feature identifier when supplied."
          },
          "description": {
            "type": "string",
            "description": "Feature description."
          },
          "originalSequence": {
            "type": "string",
            "description": "Source-provided original amino-acid sequence; empty and absent values remain distinct."
          },
          "alternativeSequences": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Source-provided alternatives, preserving order and empty values; absence does not assert a deletion."
          }
        },
        "description": "A sequence feature or natural variant over a residue range.",
        "additionalProperties": false
      },
      "description": "Natural sequence variants."
    },
    "accession": {
      "type": "string",
      "description": "UniProt accession the annotations describe — the successor when UniProt merged the requested accession, which the notice names."
    },
    "ambiguity": {
      "type": "object",
      "required": [
        "accessions",
        "notice"
      ],
      "properties": {
        "notice": {
          "type": "string",
          "description": "Why multiple mappings exist and how to select one via the chain input."
        },
        "accessions": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "chain",
              "accession"
            ],
            "properties": {
              "chain": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Author chain IDs (auth_asym_id) this entity covers (e.g. [\"A\", \"C\"])."
              },
              "accession": {
                "type": "string",
                "description": "UniProt accession the chains map to."
              },
              "proteinName": {
                "type": "string",
                "description": "Polymer entity description."
              }
            },
            "description": "One chain-group → UniProt accession mapping within the entry.",
            "additionalProperties": false
          },
          "description": "Every distinct UniProt mapping for the entry, lowest-chain first."
        }
      },
      "description": "Alternative UniProt mappings when a PDB ID resolved ambiguously (no chain given).",
      "additionalProperties": false
    },
    "geneNames": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Gene names."
    },
    "truncated": {
      "type": "boolean",
      "description": "True when at least one requested class has records past its returned page (the notice gives the next offset), or InterPro paging stopped before retrieving every membership."
    },
    "attribution": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "source",
          "license",
          "citation",
          "homepage"
        ],
        "properties": {
          "source": {
            "type": "string",
            "description": "Contributing data-source display name (e.g. \"RCSB PDB\", \"AlphaFold DB\", \"SWISS-MODEL\", \"UniProt\"). Open-ended — best_available structures are federated through 3D-Beacons providers."
          },
          "license": {
            "type": "string",
            "description": "License the source data is released under (e.g. \"CC BY 4.0\")."
          },
          "citation": {
            "type": "string",
            "description": "Primary-literature citation to credit the source."
          },
          "homepage": {
            "type": "string",
            "description": "Source homepage (absolute URL)."
          }
        },
        "description": "Upstream data-source attribution: license, citation, and homepage.",
        "additionalProperties": false
      },
      "description": "Upstream data-source licenses and citations for every source that contributed to this response. Always present — the attribution obligation travels with the data."
    },
    "proteinName": {
      "type": "string",
      "description": "Recommended protein name."
    },
    "domainsTotal": {
      "type": "number",
      "description": "InterPro's membership count for the protein; present only when requested. When InterPro paging stopped short of it, the notice names how many memberships domains_offset can reach."
    },
    "resolvedFrom": {
      "type": "string",
      "description": "PDB ID the accession was resolved from, when applicable."
    },
    "featuresTotal": {
      "type": "number",
      "description": "Total positional features in the entry; present only when requested."
    },
    "variantsTotal": {
      "type": "number",
      "description": "Total natural variants in the entry; present only when requested."
    },
    "sequenceLength": {
      "type": "number",
      "description": "Sequence length in residues."
    }
  },
  "additionalProperties": false
}
protein_get_annotations annotations
{
  "readOnlyHint": true,
  "openWorldHint": true
}

Prompts

0 advertised

No prompt definitions available.

Resources

1 advertised

protein-guide

Advertised by the server during the last successful anonymous check.

Identifier chains and gates for the protein_* tools - which ID each tool takes (PDB entry, polymer entity, RCSB computed model, AlphaFold entry, UniProt accession or isoform, ligand component), author versus label chains, residue numbering, and reading homolog, ligand, best-available, and PDB-profile results. Use before passing one protein_* result into another call, or reporting scores, counts, chains, or residue numbers from them.

protein-guide URI
skill://protein-guide/SKILL.md

MIME type: text/markdown

pdb-structure-summary — PDB structure summary

Advertised by the server during the last successful anonymous check.

Experimental structure summary for a PDB entry: title, method, resolution, source organisms, bound ligands, and per-entity chain IDs in both the author (auth_asym_id) and mmCIF label (label_asym_id) namespaces.

pdb-structure-summary URI template
pdb://{entry_id}

MIME type: application/json

alphafold-structure-summary — AlphaFold structure summary

Advertised by the server during the last successful anonymous check.

Predicted-structure summary from AlphaFold DB for a UniProt accession, isoform accession, or AlphaFold DB entry ID: mean pLDDT, confidence-band fractions, model URLs, and version. A UniProt accession merged into another entry answers with the successor’s model and a notice; a demerged or deleted one fails with its replacements.

alphafold-structure-summary URI template
af://{uniprot}

MIME type: application/json

io.modelcontextprotocol/skills

Advertised by the server during the last successful anonymous check.

io.modelcontextprotocol/skills URI template
skill://{+path}

90-day uptime

A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.

Too few checks for a percentage yet (2 of 2 answered).

  1. 2026-11-07: 1 of 1 checks answered
  2. 2026-11-09: 1 of 1 checks answered

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
750 ms
95th percentile latency
750 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 750 ms · metadata changed · 7 tool(s), 1 resource(s), 3 resource template(s), 0 prompt(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http protein-mcp-server-caseyjhand https://protein.caseyjhand.com/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add protein-mcp-server-caseyjhand --url https://protein.caseyjhand.com/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable protein-mcp-server-caseyjhand in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "protein-mcp-server-caseyjhand": {
      "url": "https://protein.caseyjhand.com/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "protein-mcp-server-caseyjhand": {
      "type": "streamableHttp",
      "url": "https://protein.caseyjhand.com/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start protein-mcp-server-caseyjhand and inspect its tools.
VS Code configuration
{
  "servers": {
    "protein-mcp-server-caseyjhand": {
      "type": "http",
      "url": "https://protein.caseyjhand.com/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http protein-mcp-server-caseyjhand https://protein.caseyjhand.com/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://protein.caseyjhand.com/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "protein-mcp-server-caseyjhand": {
      "serverUrl": "https://protein.caseyjhand.com/mcp"
    }
  }
}

Let your agent find its tools

Find servers like protein-mcp-server from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.