Send, receive, and route DICOM imaging
MessageFoundry treats imaging as a first-class lane: receive stored objects (C-STORE SCP) and send them to a PACS (C-STORE SCU), verify with C-ECHO, and push over modern DICOMweb STOW-RS — with the Structured-Report-to-HL7 v2 mapping written as versioned, testable Python, not a proprietary GUI mapper, and the same reliability and PHI-safe handling as every other connection.
Scope by design — headers and Structured Reports only: no pixel data, no numpy.
A complete DICOM transport lane
Inbound and outbound DIMSE, plus the modern HTTP lane — each riding the same staged pipeline, retries, and audit as the rest of the engine.
C-STORE SCP — receive
A pynetdicom Application Entity accepts stored objects inbound. It returns C-STORE Success only after the object is durably committed (the DIMSE analog of commit-before-ACK) — nothing is accepted-and-dropped.
C-STORE SCU — send
Forward an object to a downstream PACS over a C-STORE association — the same sender scope Mirth covers. The blocking association runs off the event loop, so a slow peer doesn't stall the engine.
C-ECHO — verify
Connectivity verification both ways: the SCP accepts Verification, and an outbound destination's Test Connection issues a C-ECHO before you trust the link.
DICOMweb STOW-RS — send over HTTP
The modern HTTP imaging lane — store/send to {base}/studies as multipart/related. It reuses the hardened REST plumbing (TLS-verifying, no-redirect, egress-gated). Neither Mirth nor Corepoint ships this out of the box.
SR / header → HL7 v2
Map a Structured Report or header to HL7 v2 (ORU/OBX, PID/OBR) in a code-first Handler — versioned and unit-testable, a replacement for the GUI mapper Corepoint sells behind a license.
DICOM-over-TLS
TLS on the wire for both server and client, with opt-in mTLS. A non-loopback cleartext listener is refused at startup unless explicitly overridden.
What it does not do — on purpose
A tight scope is a feature: it keeps the imaging lane small, auditable, and free of a heavy pixel-processing attack surface. The boundary mirrors what a routing engine actually needs (and what Mirth itself draws).
Need full PACS/VNA behavior — query/retrieve, worklists, pixel rendering? That's an archive's job, not an interface engine's. MessageFoundry routes and transforms imaging metadata; it doesn't become your image store.
- No MWL / MPPS — serving a Modality Worklist or performed-procedure-step is out of scope (Mirth doesn't serve them either).
- No Query/Retrieve — C-FIND / C-MOVE / C-GET are not provided.
- No DICOMweb QIDO-RS / WADO-RS — our DICOMweb is store/send only, not query/retrieve.
- No inbound STOW-RS receiver yet — it needs the inbound HTTP listener, which is on the backlog.
- No pixel data, no
numpy— headers and Structured Reports only, which is also a security boundary (no decompression-bomb surface).
Imaging on the same durable, PHI-aware rails
Commit before success
The SCP commits the raw object durably before returning Success; a crash before commit just means the sender re-sends. At-least-once, with idempotent re-store on SOPInstanceUID.
Smart retry classification
Out-of-resources or a transport failure is transient (retried with backoff); a hard refusal — rejected context, unencodable dataset, not-authorized — is permanent and dead-letters, so a bad object doesn't head-block the lane.
PHI-safe by construction
A DICOM object is PHI: stored encrypted, never logged at INFO or above, and egress-allowlisted. Log and error lines carry only routing-safe identifiers (SOP/AE/peer) — never the dataset or pixel data.
Fail-closed egress. A DIMSE destination is gated by the [egress].allowed_tcp allowlist and a DICOMweb destination by [egress].allowed_http — both enforced at load, reload, and startup, so the engine can't send imaging anywhere you didn't approve.
DICOM vs. Mirth & Corepoint
The same DICOM transport scope Mirth covers, a code-first replacement for Corepoint's GUI-mapped transform, and a modern DICOMweb send lane neither incumbent ships.
| Capability | Mirth | Corepoint "DICOM Gear" | MessageFoundry |
|---|---|---|---|
| C-STORE SCP (receive) | Yes | Yes | Yes |
| C-STORE SCU (send) | Yes | Yes | Yes |
| C-ECHO | Yes | Yes | Yes |
| SR / header → HL7 v2 transform | Transport only | Yes — GUI mapper | Yes — code-first Handler |
| DICOMweb STOW-RS send | No | No | Yes |
| MWL / Query-Retrieve / pixel data | No | Partial | No — out of scope |
Honest validation note. The connectors are verified against the DICOM protocol with real pynetdicom loopback tests (and the DICOMweb framing with mocked HTTP) — not yet against a specific vendor PACS. A real-feed validation against your partner's SOP classes, transfer syntaxes, and AE titles is the step before cutover.
Route imaging like any other interface
Wire a DICOM source or destination the same way you wire MLLP or REST — in code you own, tested before it ships.
Frequently asked questions
Does MessageFoundry support DICOM?
Yes. MessageFoundry treats medical imaging as a first-class lane: it receives as a C-STORE SCP and sends as a C-STORE SCU over DIMSE, supports C-ECHO, and speaks DICOMweb STOW-RS over HTTP — alongside HL7 v2 and FHIR in the same engine.
Can MessageFoundry route imaging alongside HL7?
Yes. The same Python config that routes HL7 v2 and FHIR also moves DICOM, so imaging and clinical messaging run on one self-hosted engine with the same reliability and PHI handling.
How does MessageFoundry map imaging data to HL7 v2?
Structured-report (SR) to HL7 v2 mapping is written as versioned Python rather than configured in a GUI mapper, so it is diffable, testable, and reviewed like any other interface code.