HL7 v2.5.1 → FHIR R4 Mapping MCP Server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@HL7 v2.5.1 → FHIR R4 Mapping MCP ServerConvert this ORM^O01 message into a FHIR R4 transaction Bundle"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
HL7 v2.5.1 → FHIR R4 Mapping MCP Server
A Model Context Protocol server for the HL7 v2.5.1 → FHIR R4 crossing. It answers what does this v2 field become in FHIR? at message, segment, field, data type and code level, and converts whole messages into a FHIR R4 transaction Bundle with a warning for every value it could not map faithfully.
Transports | stdio (default) and Streamable HTTP |
Source | HL7 v2.5.1 |
Target | FHIR R4 (4.0.1) |
Runtime | Node.js 20+ |
License | MIT (data sources are listed in NOTICE) |
Companion server: hl7-v2-mcp-server answers what does this segment mean in v2.5.1. Both servers share its
hl7v2-corepackage, so they parse messages the same way and agree on every v2.5.1 field, data type and code.
Two sources, labelled separately
Every mapping tool answers from two places and never mixes them:
server: this server's curated rules. They are what
convert_messagedoes.ig: the rows of the official HL7 Version 2 to FHIR IG (1.0.0 STU1), imported from HL7/v2-to-fhir at a pinned commit.
The IG is written against later v2 versions, so each IG row is checked against v2.5.1. A row that
names a field or component v2.5.1 doesn't define is flagged inV251: false with the reason (461
of 2,524 segment rows, for example PID-40). Each IG code row carries its v2.5.1 status (valid,
not-in-2.5.1 or unverified).
Where the server's code translations deliberately differ from the IG, compare_with_ig says so
code by code:
Table | Server → FHIR | IG → FHIR |
0001 | N → | N → |
0004 | R, C → | B, C, N, R, U keep the v2-0004 code |
0007 | A, E → | keeps the v2-0007 code |
0085 | I → | no target |
0119 | CA → | CA, HD → |
0123 | A → | R → |
The server's reason for each choice is in its per-code note, which compare_with_ig returns as
serverNote.
Table 0002 (Marital Status) now matches the IG exactly.
Related MCP server: HL7-Bridge MCP
What's covered
v1 | v2 | |
Message conversions | ADT A01/A04/A08/A31/A40, ORM^O01, ORU^R01 | + SIU (S12–S24, S26), MDM (T01–T11), OML^O21, OMI^O23 |
Curated segment maps | 15 segments, 132 fields | 23 segments, 170 fields |
Curated data type maps | 16 | 17 (adds CWE) |
Curated ConceptMaps | 13 tables, 130 codes | 13 tables, 137 codes (0002 rebuilt with all 16 v2.5.1 codes) |
IG reference data | — | 13 message maps, 75 segment maps, 105 data type maps, 99 ConceptMaps |
Tools / resources | 9 / 0 | 10 / 5 |
FHIR validator (R4, no tx server) | ORU fails (2 errors) | 13 sample bundles, 0 errors (run in the test suite) |
Quick start
Claude Code
claude mcp add hl7-fhir -- npx -y hl7-v2-fhir-mcp-serverOr add it to the project's .mcp.json:
{
"mcpServers": {
"hl7-fhir": { "command": "npx", "args": ["-y", "hl7-v2-fhir-mcp-server"] }
}
}Claude Desktop, Cursor and other stdio clients
{
"mcpServers": {
"hl7-fhir": { "command": "npx", "args": ["-y", "hl7-v2-fhir-mcp-server"] }
}
}The Claude Desktop config is at ~/Library/Application Support/Claude/claude_desktop_config.json
(Mac) or %APPDATA%\Claude\claude_desktop_config.json (Windows).
Over HTTP
npx hl7-v2-fhir-mcp-server --http # http://localhost:3001/mcp
# or from a clone: npm install && npm start
claude mcp add --transport http hl7-fhir http://localhost:3001/mcpVariable | Default | Description |
|
| HTTP port ( |
|
| Bind address ( |
| (unset) | Clients send |
| (loopback) | Extra |
| (none) | Browser origins allowed through CORS. No CORS headers are sent by default. |
|
| Idle sessions are closed after this many milliseconds (30 minutes). |
|
| Cap on concurrent sessions. |
|
| Request body limit. |
|
| Larger tool results return an error that explains how to narrow the request. |
/health returns the server name and version. node server.js still starts the HTTP server on
port 3001, as it did in v1.
Tools
All tools are read-only, return structuredContent matching a published output schema, and accept
lenient input ("25" or 25; table 2 or 0002; siu_s12, SIU^S12).
Tool | What it does |
| Message types the server converts (and the triggers each covers), plus the IG's message maps. |
| Segment-to-resource plan and pitfalls for one message type; the IG message map alongside. |
| Field-by-field targets for a segment: the server's rules and the IG rows (paginated, flagged against v2.5.1). |
| One field: its v2.5.1 definition, the server's rule and the IG rows. |
| Component mapping for a data type. |
| Translate a table value: server target, IG target, whether they differ, and the code's v2.5.1 status. |
| New. Every place the server's ConceptMaps differ from the IG, as a summary or code by code. |
| Reverse lookup from a FHIR resource type. Matches whole names ( |
| HL7 TS → FHIR date/dateTime, keeping the source precision and flagging a missing offset. |
| A whole message → FHIR R4 transaction Bundle, with warnings and notes. |
Resources: fhirmap://segment/{code}, fhirmap://datatype/{code}, fhirmap://conceptmap/{table},
fhirmap://message/{type}, fhirmap://about.
What each message becomes
Message | Resources emitted | The part that goes wrong |
| Patient, Encounter, Location chain, Practitioner, Condition, AllergyIntolerance |
|
| Patient, Encounter, Condition, AllergyIntolerance | A08 is a snapshot, but most pipelines treat it as a patch, so a field the sender cleared never clears downstream. |
| Patient only | Person-level, so no Encounter, even when the sender includes a PV1. |
| Patient (survivor) + Patient (retired, | PID survives, MRG-1 is retired with |
| ServiceRequest, Patient, Encounter, Practitioner, Observation, Specimen (SPM), ImagingStudy (ZDS or IPC) | One message can carry several orders: N ServiceRequests. OBX in an order is supporting information ( |
| DiagnosticReport, Observation, Patient, Encounter, Specimen, Practitioner, ImagingStudy | Repeating narrative TX rows are one report. Vital-sign LOINCs get |
| Appointment, Patient, Encounter, Practitioner, Location |
|
| DocumentReference, Patient, Encounter, Practitioner, ServiceRequest | TXA-12 is the document's identity across updates. TXA-19 (table 0273) sets |
Where the status fields go
Source | Table | FHIR element |
OBR-25 | 0123 |
|
OBX-11 | 0085 |
|
ORC-5 | 0038 |
|
ORC-1 | 0119 | (create / update / cancel — a verb, not a state) |
SCH-25 | 0278 |
|
TXA-19 | 0273 |
|
Rules the converter holds to
Rule | Why |
No invented systems | An assigning authority with no universal ID becomes |
No invented codes | A value outside its table is warned about and left out. Where R4 requires an element v2.5.1 can't supply (Appointment.participant.status, DocumentReference.status), the server emits a |
Precision is preserved |
|
Timezones are never assumed | A TS with a time and no offset is converted without one and flagged; it is never used for an |
Idempotent output |
|
Escapes are reversed | HL7 escapes are decoded by the shared |
OBX-2 decides value[x] | NM → |
Example prompts
"Where does OBR-25 go in FHIR, and does the IG agree?" → get_field_mapping, lookup_concept_map
"DiagnosticReport.effectiveDateTime is empty. Which field?" → which_v2_fields_feed
"Where does this server differ from the HL7 v2-to-FHIR IG?" → compare_with_ig
"Convert this SIU^S12 to an Appointment." → convert_message
"Will this MDM^T02 convert cleanly?" → convert_message(include="summary")
"How does CWE map to a CodeableConcept in the IG?" → get_datatype_mapping(datatype="CWE", igMap="CodeableConcept")Development
# hl7v2-core lives in the companion repo; clone both side by side until it is published
git clone https://github.com/coffeemilktea/hl7-v2-mcp-server
git clone https://github.com/coffeemilktea/hl7-v2-fhir-mcp-server
cd hl7-v2-fhir-mcp-server && npm install
npm test # unit, MCP, HTTP security, stdio
FHIR_VALIDATOR_JAR=/path/to/validator_cli.jar npm test # also runs the HL7 FHIR validator (needs Java 17+)
npm run import-ig # rebuild data/ig from HL7/v2-to-fhir at the pinned commitThe layout:
src/maps.js: the curated mapping rules.src/ig.js,data/ig/: the IG reference data and the v2.5.1 checks on it.src/convert/: the converters (messages,orders,scheduling,documents,segments,datatypes,bundle).src/tools/,src/resources.js,src/server.js: the MCP surface.src/transport/,bin/cli.js: stdio and HTTP.
Remote deployment (synthetic or de-identified data only)
Don't expose the server without authentication. If you bind a non-loopback HOST without an
API_KEY, the server refuses to start.
HOST=0.0.0.0 API_KEY="$(openssl rand -hex 32)" ALLOWED_HOSTS=fhir.example.org npx hl7-v2-fhir-mcp-server --httpThe server accepts whatever message you POST. Treat remote instances as lab or synthetic-data playgrounds, never as a place to send real PHI.
Related
hl7-v2-mcp-server: the companion HL7 v2.5.1 reference server
coffeemilktea.github.io: browser-based healthcare IT tools
hl7-dicom-tools: DICOM and HL7 v2 browser tools
HL7® and FHIR® are registered trademarks of Health Level Seven International. This project isn't affiliated with or endorsed by HL7 International. MIT licensed; see LICENSE and NOTICE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Diagnoses, drugs & lab codes: ICD-11, LOINC, RxNorm, MeSH, ATC, CID-10. 33 tools, MIT.
Privacy-preserving synthetic health data generation. FHIR R4/R5 compliant.
Look up ISO 20022 messages, bank transaction codes, legacy MT replacements, schemes and code sets.
- mcpOAuthcom.medplum
Securely access and manage FHIR healthcare data stored in Medplum.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to securely interact with FHIR R4 servers for clinical decision support workflows, including PlanDefinition execution, FHIR resource management, terminology services, and Questionnaire/StructureMap transformation via Matchbox.1-
- AlicenseAqualityBmaintenanceTranslates HL7 v2.x messages to FHIR R4, validates against profiles like US Core, and explains errors in natural language for AI agents.40Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables natural-language querying of a mock legacy healthcare database and returns validated FHIR resources (Patient, Observation, Condition).MIT
- FlicenseNot gradedqualityAmaintenanceConnects MCP clients to FHIR R4+ clinical APIs over SMART on FHIR v2 Backend Services, exposing resources, named operations, terminology lookup, and pagination as configurable tools. It adds metadata- and scope-aware search/CRUD, compact responses with FHIRPath filtering, safe pagination, audit events, and bundle execution.15 npm18-