MLLP is how most HL7 v2 interfaces talk to each other. With MessageFoundry you wire an MLLP listener and sender in plain Python — no proprietary channel GUI, no XML — then route and transform each message with ordinary code you can version-control and test.
MLLP — the Minimal Lower Layer Protocol — frames HL7 v2 messages over TCP so a receiver knows where each message starts and ends. MessageFoundry speaks it natively: declare a connection, and the engine runs the listener and hands every message to your code.
MessageFoundry installs from PyPI. Create a virtual environment and install it — no C compiler needed for the default install.
python -m venv .venv # macOS / Linux: . .venv/bin/activate # Windows (PS): .venv\Scripts\Activate.ps1 pip install messagefoundry
Drop a Python module into a config directory. Declare an inbound MLLP listener (name it, give it a port, point it at a router) and an outbound MLLP sender (a downstream host and port).
from messagefoundry import MLLP, Send, inbound, outbound, router, handler # receive HL7 v2 over MLLP on port 2575 inbound("IB_Lab_ORU", MLLP(port=2575), router="oru_router") # send to a downstream system over MLLP outbound("OB_EHR_ORU", MLLP(host="10.0.0.21", port=6661))
A router decides where a message goes by returning handler names. A handler transforms it and sends it on. Fields are addressed by HL7 path (MSH-9.1, OBR-25, …); returning an empty list leaves a message unrouted, and returning None filters it.
@router("oru_router") def route(msg): if msg["MSH-9.1"] != "ORU": return [] # UNROUTED — not a lab result return ["to_ehr"] @handler("to_ehr") def to_ehr(msg): if msg["OBR-25"] == "X": # drop corrected-in-error return None # FILTERED return Send("OB_EHR_ORU", msg)
Point MessageFoundry at your config directory and a store database. It opens the MLLP listener, persists every message before it's acknowledged, and routes it through your code.
python -m messagefoundry serve --config config --db messagefoundry.db
# MLLP listening on 0.0.0.0:2575 — every message is stored, then routed
Validate the config before it ships with the commit gate: python -m messagefoundry check --config config.
Send any HL7 v2 message to port 2575 with your MLLP client of choice (the repository ships a small send_mllp.py helper). An ORU result routes to the downstream connection; anything else is logged unrouted.
python samples/send_mllp.py samples/messages/oru_r01.hl7
# → ORU routed to OB_EHR_ORU; non-ORU logged UNROUTED
MessageFoundry supports MLLP-over-TLS, and TLS is enabled by default for connections whose peer supports it — so HL7 traffic is encrypted in transit without extra work. Many older ancillary systems still can't speak TLS; for those, MessageFoundry also supports plaintext MLLP, which remains HIPAA-compliant when it stays inside your organization's secure network perimeter. You choose per connection. The exact certificate and TLS settings live in the Configuration reference and the Deployment & network-exposure guide.
Why route HL7 in code? Because your interfaces become ordinary Python — diffable, reviewable, unit-testable, and driven by one config repo across Test and Production. See how that compares to channel-based engines →