Skip to main content
Glama
ICD10 Reference MCP

ICD10 Reference MCP

ICD10 Reference MCP

By JC Rojas. Original project code is licensed under Apache-2.0; see NOTICE, third-party materials and citation metadata. Commercial reuse is permitted under the license; preserve applicable notices. Scholarly citation is appreciated, not an additional license condition.

Local-first ICD-10-CM reference lookup for healthcare teams and researchers. This is a descriptive working name, not trademark clearance or clinical approval.

Primary use: look up an ICD-10-CM code or diagnosis phrase. Returns the official description, assignable-code vs header status, hierarchy, Alphabetic Index references, and applicable inherited Tabular instructions.

Two separate workflows:

  1. Core: code/phrase lookup. Works independently, without OpenMed or model weights.

  2. Optional: local OpenMed note matching and PII preview. Separate Python environment and explicit CLI invocation, synthetic notes only. Missing models never disable core lookup.

See optional OpenMed setup, evaluation and human review, and local execution / later hosting. Technical check results and remaining gates: verification. Step-by-step setup and acceptance: local trial guide. Terminology-only hosting trial: Render demo. Connecting as a user? Follow Python/terminal and Claude Desktop setup. The hosted path needs no local catalogs or models. Public no-login access was deployed and verified on 2026-11-08 at commit 9aed9d9. Subsequent repository hardening has not been deployed; see the security policy. For remote lookup, use the screened local client, not a patient note in a cloud chat.

Research prototype. Not production- or PHI-ready. Results are coder-review candidates, never final assignments. Do not enter patient data. No diagnosis inference, claim submission or application-side LLM calls. Cloud MCP hosts can process conversations before a tool runs. Core lookup runs locally or in the explicitly configured hosting demo; optional OpenMed stays local.

Quick start

Python 3.11+ with SQLite FTS5 and uv are required. Dependencies install from the package registry; lookup/import run offline afterward. The official MCP Python SDK is the mcp package, not a third-party MCP server framework.

For a new checkout:

git clone https://github.com/riccc-rush-lab/icd_10_mcp.git
cd icd_10_mcp
# From the checked-out project directory:
uv sync --frozen --extra dev --python 3.13
uv run icd10-catalog import \
  --downloads /absolute/path/to/april-2026-archives \
  --database data/catalog.sqlite3
uv run icd10-catalog smoke

If the catalog already exists, skip import. The importer deliberately refuses to overwrite it. A completed local catalog is generated during initial implementation.

Look up a code

uv run icd10-catalog lookup E11.9 --date 2026-04-01

Look up a phrase

uv run icd10-catalog lookup "pneumonia" --date 2026-04-01 --limit 5
uv run icd10-catalog lookup "Abdominalgia" --date 2026-04-01
uv run icd10-catalog lookup "Abnormity" --date 2026-04-01
uv run icd10-catalog lookup E11 --date 2026-04-01

Output is JSON. A header such as E11 is not assignable; its response includes descendant examples for refinement. Dotted and undotted codes are accepted. Unknown codes are not autocorrected. Phrase results include matched index paths and references. Ranking is deterministic lexical retrieval, not a probability or clinical confidence. Malformed code-like input such as A00..1 returns needs_clarification with code_validity.status="invalid_format" and no candidates. It is not converted into an unrelated diagnosis search. Numbered phrases such as CMML-1 and B12-deficiency still use phrase lookup.

A service date is required. Two separately imported releases are supported:

Release ID

Effective service dates

Assignable codes / headers

icd10cm-2026-04-01

2026-04-01 through 2026-09-30

74,719 / 23,467

icd10cm-2026-10-01 (FY2027)

2026-10-01 through 2027-09-30

74,879 / 23,524

The default single database remains April 2026 for compatibility. To use both, create data/catalogs.json (paths are relative to this configuration file):

{
  "icd10cm-2026-04-01": "catalog.sqlite3",
  "icd10cm-2026-10-01": "releases/2027/catalog.sqlite3"
}
uv run icd10-catalog lookup E11.9 --date 2026-10-01 --catalog-config data/catalogs.json

With both full catalogs installed, check local trial readiness in one command:

uv run --frozen icd10-catalog trial-check --catalog-config data/catalogs.json

It runs both full-corpus smoke checks and a fresh official-client stdio MCP exchange. Exit 0 means ready_for_local_trial, never clinical or patient-data readiness. Exit 2 means not_ready; OpenMed is optional and not checked by this command.

Absent, mismatched or out-of-range releases fail explicitly, never fall back to April. No current-date default or anticipated future release is used. CLI exit codes: 0 for successful workflows (including abstention), 1 for maintenance errors, 2 for invalid requests or unavailable catalog/release.

Related MCP server: OMOPHub MCP Server

MCP host configuration

Use a host that supports local stdio servers. Example server definition:

{
  "mcpServers": {
    "icd10-local": {
      "command": "/absolute/path/to/icd_10_mcp/.venv/bin/icd10-mcp",
      "env": {
        "ICD10_CATALOGS": "/absolute/path/to/icd_10_mcp/data/catalogs.json",
        "ICD10_TRANSPORT": "stdio"
      }
    }
  }
}

This is an example only. No host settings are changed automatically. The server exposes three read-only, structured-output tools in compatibility stdio mode. These legacy synthetic-note helpers are deterministic and do not use OpenMed. The optional OpenMed workflow runs separately through match-note, not through a cloud MCP chat:

Tool

Arguments

Purpose

phrase_search

query, service_date, optional limit (1–25)

Primary code/phrase lookup

suggest_candidates

note, service_date, optional limit

Conservative lexical review candidates, synthetic text only

validate_selected_codes

codes, service_date, optional note

Structural validity, documentation support, selected-set rules

Examples of tool arguments:

{"query": "E11.9", "service_date": "2026-04-01"}
{"note": "No pneumonia. History of cholera.", "service_date": "2026-04-01"}
{"codes": ["T36.0X1A"], "service_date": "2026-04-01"}

Python callers can use ICDService(Catalog(path)).search(...), .suggest(...), and .validate(...) directly, without MCP.

Screened remote reference client

The optional client screens short public code/phrase inputs before any connection, without OpenMed or model weights. Suspected identifiers or note-like inputs return privacy_blocked, without echoing the blocked input. It rejects rather than silently redacting clinical meaning. Codes, ordinary terminology and common eponyms remain supported.

Best effort, not a PII-absence guarantee. Names and identifiers can be missed, and legitimate terminology can be blocked. Never use patient-derived queries. Hosted screening happens after receipt. Arbitrary MCP clients, cloud chats, platform/proxy logs and a caller's debug logging are outside this client's control. The application cannot promise that PII is never transmitted.

Public mode needs no token. Use --anonymous to avoid forwarding an inherited credential. Protected deployments retain private token-file/environment support. See the connection guide for activation status, direct URL setup, local screening, and shared Free quotas. Endpoint: https://icd10-reference-mcp.onrender.com/mcp.

.venv/bin/python -m icd10_mcp.reference_client \
  --url https://icd10-reference-mcp.onrender.com/mcp \
  --anonymous --public-terminology <<'JSON'
{"operation":"lookup","query":"pneumonia","service_date":"2026-10-01","limit":5}
JSON

For selected-code validation, use {"operation":"validate","codes":["E11.9"],"service_date":"2026-10-01"} on stdin. No note field is accepted. Python callers can use ReferenceClient.lookup(...) and .validate(...) from icd10_mcp.reference_client.

The exact service date is checked locally and replaced on the wire by the chosen release's public start date. The result restores the requested date locally. Unsupported dates fail locally, without fallback or a connection. This reduces date disclosure; it does not make a patient-related query safe to upload. The client uses HTTPS (literal loopback HTTP only), ignores proxy environment settings, uses a constant MCP client identity and sanitizes failures.

What is imported

For April 2026, these exact archives and members from ~/Downloads:

  • icd10cm-table-and-index-April-1-2026.zip

    • complete icd10cm-codes-April-1-2026.txt

    • complete icd10cm-order-April-1-2026.txt

  • icd10cm-April-1-2026-XML.zip

    • icd10c-tabular-April-1-2026.xml (CDC's actual filename)

    • icd10cm-index-April-1-2026-XML.xml

    • icd10cm-eindex-April-1-2026-XML.xml

    • icd10cm-drug-April-1-2026-XML.xml

    • icd10cm-neoplasm-April-1-2026-XML.xml

The code-description ZIP containing PDFs is not a complete code corpus and is not needed. PDF renderings and XSDs are not ingested. The 2027-icd-10-cm-addendum.zip and all other addenda are ignored, even if present in the same directory.

The importer checks 74,719 assignable codes and 23,467 headers, agreement between the complete code and order descriptions, XML root/version, and Tabular ancestry for every order entry. It stores chapter/section/diagnosis hierarchy, all four index trees, nonessential modifiers, cross-references, manifestation/category references, and table column labels. Codes expanded by seventh character in order text link to their nearest Tabular XML ancestor.

Instructions include Includes, inclusion terms, Excludes1/2, Code First, Code Also, Use Additional Code, seventh-character definitions/notes, general notes, and visual impairment tables. Original instruction XML and grouping paths are retained. Introduction conventions, effective period, archive/member SHA-256 hashes, source member names, order/code line numbers, and XML paths are preserved in SQLite.

Import uses safe XML parsing, a temporary database, consistency/integrity checks, and atomic no-overwrite publication. It never extracts archives over arbitrary paths. Hashes provide reproducible provenance, not independent proof of CDC authenticity. Full-corpus publication also requires the seven exact verified member hashes pinned in the release profile. A well-formed empty index or removed Tabular diagnosis cannot be relabeled a complete release merely because code counts and XML versions match. Changed publisher bytes require a separately verified profile update, not a manifest edit. No source archives or generated catalog are committed; .gitignore excludes both. The database contains public terminology only, never tool requests or notes.

FY2027 complete import

The original April catalog is retained. Complete official archives, not addenda, belong in a separate source directory:

  • icd10cm-code-descriptions-2027.zip, containing nested icd10cm-code-descriptions-2027/icd10cm-{codes,order}-2027.txt.

  • icd10cm-table-and-index-2027.zip, containing nested icd10cm-table-and-index-2027/icd10cm-tabular_-2027.xml (actual underscore), plus icd10cm-{index,eindex,drug,neoplasm}-2027.xml in that directory.

# Skip import when this separately verified catalog already exists.
uv run icd10-catalog import --release icd10cm-2026-10-01 \
  --downloads data/releases/2027/sources --database data/releases/2027/catalog.sqlite3
uv run icd10-catalog smoke --release icd10cm-2026-10-01 \
  --database data/releases/2027/catalog.sqlite3

Official source directory: https://ftp.cdc.gov/pub/Health_Statistics/NCHS/Publications/ICD10CM/2027/. Archive/member hashes and local acquisition provenance are recorded beside sources. Counts are observed and reconciled import counts, not a claim of publisher certification.

Interpreting results

  • Code validity means exact assignable membership in the selected release. Headers, invalid formats, unknown codes, and missing/invalid seventh characters or placeholders are distinct. No encounter character or placeholder is guessed.

  • Documentation support is assessed separately, only when synthetic text is supplied. lexical_support means an affirmative description/inclusion match, not clinical proof. Index defaults alone are partial; noncurrent mentions and explicit laterality conflicts are flagged. Evidence spans use zero-based Python Unicode character offsets, end-exclusive, into the submitted text.

  • Completeness is never certified. Missing specificity and unresolved instructions prompt review. No whole-note, encounter, principal-diagnosis, or claim-completeness claim.

  • Index see/seeAlso traversal is bounded and cycle-safe. Unresolved references and code stems remain visible for clarification, not silently converted to specific descendants. Supplied heading alternatives are resolved within the same index hierarchy, with exact headings preferred. Ambiguous aliases, cycles, and depth limits are reported explicitly instead of selecting an arbitrary target. Top-level reference_issues retains traversal warnings even when limit=1 truncates the detailed index matches.

  • Excludes1 pair matches are potential conflicts for review, allowing for clinical exceptions. Excludes2 does not prohibit coexistence. Code First/Use Additional Code checks use proposed list order; Code Also does not set order. Conditional instructions and prose without parseable code references always require human interpretation.

  • abstain, needs_clarification, release_unavailable, and catalog_unavailable are explicit statuses. Lookup does not assess documentation that was not supplied. Catalog admission checks required schema columns, read-only FTS readiness, manifest/scope structure, and supplied member/archive provenance fields. Missing or malformed catalog metadata returns catalog_unavailable.

Limitations and safety

This is a terminology lookup aid, not a clinical coding system. It is ICD-10-CM (US diagnosis terminology), not ICD-10-PCS, WHO ICD-10, or a billing service.

Core matching is lexical, with no embeddings, medical synonym expansion beyond CDC index entries, abbreviation inference, or clinical reasoning. Bounded retrieval can miss relevant candidates. Note handling is intentionally conservative and incomplete: simple clause-scoped negation, uncertainty, history, resolution, and family-history patterns do not handle every chart format, experiencer, double negation, or copied-forward statement. Do not use it to infer an active diagnosis or absence of disease. Drug/neoplasm table cells are exposed in lookup, not automatically turned into note suggestions without intent/behavior selection.

Rules surface Tabular instructions; they do not implement all Official Guidelines, setting-specific uncertain-diagnosis rules, causal relationships, guideline exceptions, combination-code logic, payer edits, sequencing across an entire encounter, or all special tabular tables. Preserved XML remains available for human review.

The application opens the catalog read-only, does not persist requests, does not configure telemetry, and defaults to stdio. Optional HTTP is loopback-only and excludes note inputs. An MCP host or its model may store or transmit tool arguments and outputs. Local server operation is not a privacy guarantee. The default local launcher has no authentication. The separate prepared demo uses a shared bearer secret, not institutional OAuth or validated PHI safeguards. There is no security certification, institutional audit control or production acceptance. Use only synthetic text. Do not connect this to patient records.

Development checks

uv run pytest -q
uv run ruff check src tests scripts
uv run ruff format --check src tests scripts
uv run icd10-catalog smoke --database data/catalog.sqlite3

Enable the fresh-import integration checks against the supplied complete archives:

uv run pytest -q tests --cdc-downloads /absolute/path/to/april-2026-archives \
  --fy2027-downloads data/releases/2027/sources

Without --cdc-downloads, corpus import tests are explicitly skipped. An explicitly requested directory missing required archives fails the check. These tests build a new catalog in a temporary directory, verify public lookup and an independently recorded member checksum, and reject a wrong XML release without publishing a catalog. They do not replace the working catalog or commit/copy source data into the project.

Unit tests build small synthetic catalogs in temporary directories. They do not need CDC files, do not use patient data, and include a real stdio MCP handshake/tool-call test. The smoke command requires the full local CDC catalog and checks counts, all-code ancestry, provenance, four indexes, instructions, lookup/cross-references, seventh characters/placeholders, noncurrent-note abstention, and release boundaries.

Updating safely

  1. Obtain complete code/order, Tabular XML, and all index XML files for a new release from CDC/NCHS. Independently verify source authenticity, dates, counts, and changes. An addendum alone is insufficient.

  2. Build a release-specific import profile and separately verified catalog. Do not relabel this release, extend its date interval, change filenames to trick this importer, or append FY2027 addenda to April 2026 data.

  3. Define nonoverlapping effective intervals and explicit date selection before adding new release support. The current profiles accept April 2026 and FY2027 separately; the tool cannot anticipate an intervening future midyear update.

  4. Add release-specific regression fixtures, count checks, source hashes, import smoke checks, and boundary tests. Review changed instructions and seventh-character behavior.

  5. To rebuild April 2026, import to a new path, run tests and smoke there, then point ICD10_CATALOG at it. Keep the previous catalog until verification is complete.

Do not commit CDC source archives, generated databases, notes, or patient fixtures.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    MCP server for automated ICD-10 medical coding. Code clinical text to ICD-10-CM diagnoses, search 74,000+ codes, and de-identify PHI via the AutoICD API.
    6
    19 npm
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Provides AI agents with instant access to 10M+ OMOP medical vocabulary concepts for searching, mapping, and navigating clinical codes across SNOMED, ICD-10, RxNorm, LOINC, and more.
    11
    97 npm
    6
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Decodes, searches, validates, and crosswalks US medical codes (ICD-10-CM, ICD-10-PCS, HCPCS Level II) using an offline bundled index via MCP.
    390 npm
    4
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides AI assistants instant access to WHO ICD-10 and ICD-11 classification systems for code lookup, search, autocoding, validation, and hierarchy browsing via 12 tool actions.
    2
    MIT