Early Access · beta. We're building toward 1.0 — and we want people involved now, while it can still be shaped. Where the project stands →

DICOM imaging

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.

What's supported

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.

Deliberately scoped

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).
Reliability & PHI

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.

How it compares

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.

CapabilityMirthCorepoint "DICOM Gear"MessageFoundry
C-STORE SCP (receive)YesYesYes
C-STORE SCU (send)YesYesYes
C-ECHOYesYesYes
SR / header → HL7 v2 transformTransport onlyYes — GUI mapperYes — code-first Handler
DICOMweb STOW-RS sendNoNoYes
MWL / Query-Retrieve / pixel dataNoPartialNo — 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.

FAQ

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.