Skip to main content
Glama
orphanet-link
by berntpopp

orphanet-link

Python 3.14+ CI Conformance License: MIT

A read-only Model Context Protocol (MCP) server that grounds rare-disease questions in Orphanet's scientific knowledge files (Orphadata, INSERM), served from a locally-built SQLite + FTS5 index of the eight English Orphadata XML products.

IMPORTANT

Research use only. Not clinical decision support. Do not use for diagnosis, treatment, triage, or patient management.

Why

Orphadata ships its rare-disease knowledge as eight separate bulk XML products — nomenclature, cross-references, ~33 per-specialty classification files, gene associations, HPO phenotypes, epidemiology, natural history, functional consequences. They are a download, not a query surface: asking "which genes are linked to Aicardi syndrome, what is its prevalence, and what is it called in OMIM?" means fetching ~150 MB of XML, joining four products on ORPHAcode, and walking a poly-hierarchy by hand.

orphanet-link does that join once — into a normalized, read-only SQLite + FTS5 index with precomputed classification closures — and serves it as MCP tools. A free-text label, a synonym, a bare ORPHA code, or an external CURIE (OMIM, MONDO, ICD-10/11, UMLS, GARD, MeSH, MedDRA) all resolve to the same canonical disorder, and every answer is reproducible against a stated Orphanet release.

Related MCP server: hpo-link

Quick start

The GeneFoundry instance is hosted — no install:

claude mcp add --transport http orphanet-link https://orphanet-link.genefoundry.org/mcp

Locally (Python 3.14+ and uv):

git clone https://github.com/berntpopp/orphanet-link.git
cd orphanet-link
uv sync --group dev
make data-fetch     # pull the prebuilt SQLite index from the GitHub Release
make dev            # unified REST + MCP → http://127.0.0.1:8000/mcp
claude mcp add --transport http orphanet-link http://127.0.0.1:8000/mcp

The server needs a database before it can answer. make data-fetch pulls the prebuilt one published by CI; make data builds it from the Orphadata XML instead (~150 MB). Either way the local server also bootstraps one on first start when none is present — see Data. Production uses the hardened init sidecar to fetch and verify its pinned release before the app starts with a read-only snapshot.

make dev runs --transport unified, the only mode that serves MCP; --transport http is REST/health-only. make docker-up runs the container stack and prints its MCP URL. See Deployment.

Tools

Every tool is read-only, accepts response_mode (minimal / compact / standard / full, default compact), and returns the fleet's success / _meta / payload-or-error envelope. _meta.next_commands carries ready-to-call follow-ups — see Architecture & the MCP surface.

Tool

Purpose

get_server_capabilities

Discovery: tool signatures, response modes, workflows, error taxonomy, limits, Orphanet release

get_diagnostics

Index status: Orphanet release, disorder counts, schema version, build time, runtime metrics

resolve_disease

Free-text label, synonym, ORPHA code (ORPHA:166024 or 166024), or external xref CURIE → canonical {orpha_code, name, match_type}

search_diseases

FTS over disease names and synonyms; relevance-ranked, paginated, optional obsolete inclusion

get_disease

Full disorder record: type/group, synonyms, grouped cross-references, classification parents/children, association counts; sparse fields projection

get_disease_genes

Gene associations: symbol, HGNC id, association type and status, source PMIDs, gene xrefs

get_disease_phenotypes

HPO annotations: HPO id, term name, frequency category; optional frequency filter

get_disease_prevalence

Epidemiology: prevalence type, class band, numeric ValMoy, geography, validation status, source

get_disease_natural_history

Age-of-onset categories and inheritance patterns

get_disease_disability

Functional-consequence annotations: ability categories affected and severity grades

get_disease_classification

Immediate parents and children in Orphanet's poly-hierarchical classification trees

get_disease_ancestors

Transitive classification ancestors (precomputed closure), paginated

get_disease_descendants

Transitive classification descendants (precomputed closure), paginated

map_cross_ontology

A disorder's cross-references grouped by source (OMIM, MONDO, ICD-10/11, UMLS, GARD, MeSH, MedDRA) with mapping relations

resolve_xref

External CURIE → matching Orphanet disorder(s), paginated

find_diseases_by_gene

Reverse lookup: HGNC gene symbol → associated disorders, paginated

find_diseases_by_phenotype

Reverse lookup: HPO term id → associated disorders, paginated

resolve_disease_batch

Batch-resolve up to MAX_BATCH_ITEMS labels/codes/xrefs; partial success per item

get_disease_batch

Batch-fetch up to MAX_BATCH_ITEMS disease records; partial success per item; sparse fields projection

Leaf names are intentionally unprefixed, per the fleet's Tool-Naming Standard v1. Behind genefoundry-router this server mounts under the orphanet namespace, so tools surface as orphanet_<tool> — e.g. orphanet_resolve_disease, the pinned entry point.

Data & provenance

Source — Orphadata, the free-access scientific-knowledge file distribution of Orphanet (INSERM, Paris). Eight English XML products, downloaded directly with no authentication.

Refresh — Orphanet releases bi-annually. CI rebuilds the index weekly and publishes it as a versioned data-<release> GitHub Release (orphanet.sqlite.gz). Local development can fetch that artifact, verify its sha256, and fall back to a local build; production's init sidecar verifies the declared immutable digest and the app only reads the resulting snapshot. make data-status prints the loaded release. Details: Data & the build pipeline.

Runtime data identity — a pinned deployment proves which data release it is serving. The init sidecar records the release tag and digests in data-identity.json beside the database; /health rehashes the database on every call and publishes data_available plus a release_identity {expected, actual} pair, answering 503 if they differ. python -m orphanet_link.data_probe prints a deterministic read-only {data_schema_version, record_count, query_result_sha256} observation of the live store. Details: Runtime data identity.

Licence — Orphadata are CC BY 4.0. Redistributing a derived SQLite database is explicitly permitted provided attribution is given and changes are indicated.

Required citation — also served by the orphanet://citation resource:

"Orphadata Science: Free access data from Orphanet. © INSERM 1999. Available on http://sciences.orphadata.com/. Data version [date/version]." Changes: "Converted Orphadata XML to a normalized SQLite database."

This derived database is not an official Orphanet product and has not been validated by Orphanet or INSERM.

Documentation

  • Data & the build pipeline — the eight Orphadata products, the data CLI, licensing, and the CI artifact pipeline.

  • Deployment — transports (and the --transport http footgun), Docker, the Host/Origin/CORS boundary, router integration, deploy verification.

  • Configuration — the ORPHANET_LINK_* variables; .env.example is the exhaustive annotated reference.

  • Architecture & the MCP surface — response envelope, response modes, orphanet:// resources, error taxonomy, and where the research-use warning lives.

  • AGENTS.md — engineering conventions: the two planes, invariants, the determinism contract, package layout.

  • CHANGELOG.md — release history.

Contributing

See AGENTS.md for the conventions and the definition of done. make ci-local is the gate — format, lint, line budget, README standard, action pins, mypy, and tests — and it must be green before merge.

License

Code: MIT © 2026 Bernt Popp.

Data: Orphadata is CC BY 4.0 © INSERM 1999 — attribution required and changes indicated, as stated under Data & provenance.

Available Tools

19 tools
find_diseases_by_geneFind Diseases by GeneA
Read-onlyIdempotent

Find all Orphanet disorders associated with an HGNC gene symbol. Returns {orpha_code, name} per disorder with pagination. Signature: find_diseases_by_gene(gene_symbol, limit=, offset=, response_mode=).

Inputs: gene_symbol (required), limit, offset, response_mode.

find_diseases_by_phenotypeFind Diseases by PhenotypeA
Read-onlyIdempotent

Find all Orphanet disorders annotated with an HPO term id. Returns {orpha_code, name} per disorder with pagination. Signature: find_diseases_by_phenotype(hpo_id, limit=, offset=, response_mode=).

Inputs: hpo_id (required), limit, offset, response_mode.

get_diagnosticsGet Orphanet DiagnosticsA
Read-onlyIdempotent

Report the local Orphanet index status: whether the data is built, the loaded Orphanet release version, disorder counts, schema version, and when it was built, plus a runtime block (request/error counts, latency percentiles p50/p95/p99, a response_mode distribution that surfaces over-fetch, and a version-hash cache hit/miss ratio). Use this to confirm freshness or diagnose a data_unavailable error. Signature: get_diagnostics().

Inputs: no named parameters.

get_diseaseGet DiseaseA
Read-onlyIdempotent

Return an Orphanet disease record: definition, synonyms, grouped cross-references, classification parents/children, age of onset, inheritance, and disorder type. The term accepts an ORPHAcode, a label/synonym, or an external xref CURIE (resolved first). xrefs are grouped by source; any nested count is leaf rows, not groups. Pass fields=['xrefs.OMIM', ...] for a sparse projection, or include=['genes','phenotypes','prevalence','disability'] to compose a full entity in ONE call. Signature: get_disease(term, response_mode=, fields=, include=).

Inputs: term (required), fields, include, response_mode.

get_disease_ancestorsGet Disease AncestorsA
Read-onlyIdempotent

Return all transitive ancestors (broader diseases) of an Orphanet disorder via the precomputed closure, with a pagination block {total, returned, limit, offset, truncated, next_offset}. When truncated, next_commands carries a forward-page step. Use get_disease_classification for only the immediate parents. Signature: get_disease_ancestors(term, limit=, offset=, response_mode=).

Inputs: term (required), limit, offset, response_mode.

get_disease_batchGet Diseases (batch)A
Read-onlyIdempotent

Fetch many disease records in one call (partial success per item: each row is the record or its own ok=false/error_code/message). Each term accepts an ORPHAcode, label, or xref CURIE; pass fields=[...] for a sparse projection. Max 50 items; compact per item. Signature: get_disease_batch(terms, response_mode=, fields=).

Inputs: terms (required), fields, response_mode.

get_disease_classificationGet Disease ClassificationA
Read-onlyIdempotent

Return the immediate Orphanet classification parents and children for a disorder. Use get_disease_ancestors / get_disease_descendants for the transitive closure. Signature: get_disease_classification(term, response_mode=).

Inputs: term (required), response_mode.

get_disease_descendantsGet Disease DescendantsA
Read-onlyIdempotent

Return all transitive descendants (more specific diseases) of an Orphanet disorder via the precomputed closure, with a pagination block {total, returned, limit, offset, truncated, next_offset}. When truncated, next_commands carries a forward-page step. Use get_disease_classification for only the immediate children. Signature: get_disease_descendants(term, limit=, offset=, response_mode=).

Inputs: term (required), limit, offset, response_mode.

get_disease_disabilityGet Disease DisabilityA
Read-onlyIdempotent

Return functional consequence (disability) data for an Orphanet disorder: ability categories affected and severity grades. Data coverage is partial: many disorders carry no Orphadata functional-consequence annotation, so a valid result can be empty -- coverage:'none' with count:0 marks this explicitly (it is NOT an error); coverage:'present' means rows exist. Signature: get_disease_disability(term, response_mode=).

Inputs: term (required), response_mode.

get_disease_genesGet Disease GenesA
Read-onlyIdempotent

Return gene-disease associations for an Orphanet disorder: gene symbol, HGNC id, association type, and cross-references (OMIM, Ensembl, etc.). count is the number of leaf gene rows, not grouped associations. Signature: get_disease_genes(term, response_mode=).

Inputs: term (required), response_mode.

get_disease_natural_historyGet Disease Natural HistoryA
Read-onlyIdempotent

Return natural history data for an Orphanet disorder: age of onset categories and inheritance patterns. Signature: get_disease_natural_history(term, response_mode=).

Inputs: term (required), response_mode.

get_disease_phenotypesGet Disease PhenotypesA
Read-onlyIdempotent

Return HPO phenotype annotations for an Orphanet disorder: HPO id, term name, and frequency category. Optionally filter by frequency label. Frequency values: Obligate (100%), Very frequent (99-80%), Frequent (79-30%), Occasional (29-5%) (and others). Signature: get_disease_phenotypes(term, frequency=, response_mode=).

Inputs: term (required), frequency, response_mode.

get_disease_prevalenceGet Disease PrevalenceA
Read-onlyIdempotent

Return prevalence data for an Orphanet disorder: prevalence class, geographic area, and source reference. Signature: get_disease_prevalence(term, response_mode=).

Inputs: term (required), response_mode.

get_server_capabilitiesGet Server CapabilitiesA
Read-onlyIdempotent

Return the orphanet-link discovery surface: identity/build/Orphanet release, the tool list WITH call signatures, response modes, recommended workflows, the cross-reference source ranking, the error taxonomy, and limits. detail='full' adds the full policy notes. Call this first in a cold session, or read orphanet://tools / orphanet://capabilities. Signature: get_server_capabilities(detail=).

Inputs: detail.

map_cross_ontologyMap Cross-OntologyA
Read-onlyIdempotent

List an Orphanet disorder's cross-references to other ontologies, grouped by source (OMIM/MONDO/ICD-10/ICD-11/UMLS/GARD/MeSH/MedDRA), each with its mapping relation. Returns them under mappings (get_disease returns the same data under xrefs). Use prefixes=['OMIM'] to restrict to a subset of sources. count is the number of leaf mapping rows (individual targets), not the number of source groups. Signature: map_cross_ontology(term, prefixes=, response_mode=).

Inputs: term (required), prefixes, response_mode.

resolve_diseaseResolve DiseaseA
Read-onlyIdempotent

Resolve a disease label, synonym, or ORPHAcode (ORPHA:166024 or 166024) to the canonical Orphanet term {orpha_code, name, match_type}. An ambiguous label returns ambiguous_query with candidates. Signature: resolve_disease(query, response_mode=).

Inputs: query (required), response_mode.

resolve_disease_batchResolve Diseases (batch)A
Read-onlyIdempotent

Resolve many labels/ORPHAcodes/xrefs in one call (partial success: each item returns its resolution {orpha_code, name, match_type} or its own ok=false/error_code/message; the call never fails wholesale). Max 50 items; compact per item. Signature: resolve_disease_batch(queries, response_mode=).

Inputs: queries (required), response_mode.

resolve_xrefResolve Cross-ReferenceA
Read-onlyIdempotent

Resolve an external cross-reference CURIE (OMIM/MONDO/ICD-10/ICD-11/UMLS/GARD/MeSH/MedDRA) back to the Orphanet disorder(s) that map to it. Returns matches[] plus a pagination block {total, returned, limit, offset, truncated, next_offset}; when truncated, next_commands carries a forward-page step. Miss semantics (list-shaped, unlike resolve_disease): a malformed CURIE is rejected with invalid_input, while a well-formed but unmapped CURIE returns an empty page (total: 0), not not_found. Signature: resolve_xref(xref_id, limit=, offset=, response_mode=).

Inputs: xref_id (required), limit, offset, response_mode.

search_diseasesSearch DiseasesA
Read-onlyIdempotent

Full-text search over Orphanet disease names, synonyms, and definitions (FTS, relevance-ranked). Returns {orpha_code, name, score} plus a pagination block {total, returned, limit, offset, truncated, next_offset}. When truncated, next_commands carries a forward-page step. Obsolete terms are excluded unless include_obsolete=true. Signature: search_diseases(query, limit=, offset=, include_obsolete=, response_mode=).

Inputs: query (required), limit, offset, response_mode, +1 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.1/5.0

    Scored across 19 tools

    Disambiguation4/5

    Most tools map to clearly distinct data facets, but get_disease can return xrefs, natural history, and other fields that have dedicated tools, and map_cross_ontology overlaps with get_disease's xrefs. The overlap is documented in descriptions, so an agent can still disambiguate, but it is not always obvious which tool is primary.

    Naming Consistency5/5

    Tool names follow a consistent snake_case verb_noun pattern: get_disease_*, resolve_*, find_diseases_by_*, search_diseases, and batch variants extend the same pattern predictably. This makes the toolset easy to navigate and guess.

    Tool Count3/5

    19 tools is on the heavy side for an MCP server, and some redundancy exists: get_disease can compose several facets that also have dedicated tools, and resolve_disease_batch/get_disease_batch add convenience but also surface area. The count is defensible for the breadth of Orphanet data, but feels slightly over-scoped.

    Completeness5/5

    The toolset covers the core Orphanet domain thoroughly: disease resolution and search, full disease records with genes/phenotypes/prevalence/natual-history/disability, reverse lookups by gene and phenotype, classification closure, external cross-reference mapping in both directions, and batch operations. There are no obvious dead ends or missing critical operations for a read-only data server.

    Maintenance

    ActivityActive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      B
      maintenance
      MCP server that provides tools for querying the Human Phenotype Ontology (HPO) including term lookup, hierarchy exploration, cross-ontology mappings, and gene-phenotype-disease associations, all grounded in a local SQLite database for fast offline lookups.
      17
      1
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      An MCP server for searching and accessing RNA sequencing datasets from the European Nucleotide Archive (ENA), supporting bulk, single-cell, and spatial transcriptomics with advanced filtering and download capabilities.
      11
      1,843 PyPI
      1
      Apache 2.0