Skip to content

TCP / MLLP Source

The TCP source opens a socket listener that accepts raw TCP connections or HL7v2 MLLP (Minimal Lower Layer Protocol) framed connections. MLLP is the standard transport for HL7v2 messages in healthcare and is supported by virtually every hospital information system.

MLLP wraps each HL7v2 message in a simple byte envelope:

ByteHexPurpose
Start Block0x0BSignals the beginning of a message.
messageThe HL7v2 payload.
End Block0x1CSignals the end of the message body.
Carriage Return0x0DTerminates the frame.

In raw mode these framing bytes are not expected; the source reads until the connection closes or a timeout is reached.

source:
type: tcp
port: 2575
mode: mllp
max_connections: 50
timeout_ms: 30000
tls:
cert_file: ./certs/server.crt
key_file: ./certs/server.key
ack:
auto: true
success_code: AA
error_code: AE
reject_code: AR
PropertyTypeRequiredDefaultDescription
portintYesTCP port to listen on. 2575 is the standard MLLP port.
modestringNorawraw for plain TCP, mllp for HL7v2 MLLP framing.
max_connectionsintNo100Maximum concurrent client connections.
timeout_msintNo30000Idle timeout in milliseconds before a connection is closed.
tlsobjectNoTLS certificate and key for encrypted connections.
ackobjectNoAcknowledgment settings (primarily used with MLLP).

When mode is mllp, acknowledgments are sent back to the sender after each message.

PropertyTypeRequiredDefaultDescription
autoboolNotrue (mllp)Automatically generate and return an ACK.
success_codestringNoAAMSA acknowledgment code for successful processing.
error_codestringNoAEMSA code when processing encounters an error.
reject_codestringNoARMSA code when the message is rejected outright.
channel.yaml
channel:
name: adt-mllp-listener
description: Receive ADT messages from HIS over MLLP
source:
type: tcp
port: 2575
mode: mllp
max_connections: 50
timeout_ms: 30000
ack:
auto: true
success_code: AA
error_code: AE
transformer:
type: typescript
file: ./transforms/parse-adt.ts
destination:
type: kafka
topic: hospital.adt.events

Parse the PID segment from an incoming HL7v2 ADT message:

transforms/parse-adt.ts
export default function transform(msg: IntuMessage): IntuMessage {
const segments = msg.payload.split("\r");
const pid = segments.find((s: string) => s.startsWith("PID"));
if (!pid) {
throw new Error("PID segment not found in message");
}
const fields = pid.split("|");
const patient = {
id: fields[3],
last_name: fields[5]?.split("^")[0],
first_name: fields[5]?.split("^")[1],
dob: fields[7],
sex: fields[8],
};
msg.payload = JSON.stringify(patient);
return msg;
}