TCP Destination

Send messages over raw TCP or MLLP connections to downstream systems.

Overview

The TCP destination transmits messages over raw TCP sockets or MLLP (Minimal Lower Layer Protocol) connections. MLLP is the standard transport for HL7v2 messaging in healthcare, wrapping each message with start-of-block and end-of-block characters. This destination is commonly used to forward processed HL7v2 messages to downstream clinical systems, lab information systems, or interface engines.

Configuration

Define a TCP destination in your root intu.yaml under the destinations key:

yaml
# intu.yaml
destinations:
  downstream-lis:
    type: tcp
    tcp:
      host: lis.hospital.internal
      port: 6662
      mode: mllp
      timeout_ms: 10000
      keep_alive: true
      tls:
        enabled: true
        ca_cert: /etc/ssl/certs/hospital-ca.pem

Properties

host string required
Hostname or IP address of the target system.
port int required
Port number to connect to on the target host.
mode string optional
Transport mode. One of: raw, mllp. In mllp mode, messages are framed with VT (0x0B) and FS+CR (0x1C 0x0D) characters. Defaults to raw.
timeout_ms int optional
Connection and send timeout in milliseconds. Defaults to 30000.
keep_alive bool optional
Keep the TCP connection open between messages instead of reconnecting for each send. Defaults to false.

TLS

tls.enabled bool optional
Enable TLS encryption for the TCP connection. Defaults to false.
tls.ca_cert string optional
Path to a PEM-encoded CA certificate.
tls.client_cert string optional
Path to a PEM-encoded client certificate for mutual TLS.
tls.client_key string optional
Path to the client private key for mutual TLS.

Full Example

Receive lab orders from a FHIR server, transform them to HL7v2 ORM messages, and forward to a lab information system via MLLP.

Root Configuration

yaml
# intu.yaml
destinations:
  lab-system-mllp:
    type: tcp
    tcp:
      host: lis.hospital.internal
      port: 6662
      mode: mllp
      timeout_ms: 15000
      keep_alive: true
      tls:
        enabled: true
        ca_cert: /etc/ssl/certs/hospital-ca.pem
        client_cert: /etc/ssl/certs/intu-client.pem
        client_key: /etc/ssl/private/intu-client-key.pem

Channel Configuration

yaml
# channels/fhir-to-lab/channel.yaml
name: fhir-to-lab
description: Convert FHIR ServiceRequests to HL7v2 ORM and send to LIS

source:
  type: http
  http:
    port: 8080
    path: /fhir/ServiceRequest

destinations:
  - lab-system-mllp

Destination Transformer

typescript
// channels/fhir-to-lab/transformer.ts
import { Message, Context } from "@intu/sdk";

export default function transform(msg: Message, ctx: Context): Message {
  const serviceRequest = msg.body;

  const now = formatHL7Date(new Date());
  const patientRef = serviceRequest.subject?.reference ?? "";
  const patientId = patientRef.split("/").pop() ?? "UNKNOWN";
  const orderCode = serviceRequest.code?.coding?.[0]?.code ?? "";
  const orderDesc = serviceRequest.code?.coding?.[0]?.display ?? "";

  const segments = [
    `MSH|^~\\&|INTU|HIS|LIS|LAB|${now}||ORM^O01|${msg.id}|P|2.5`,
    `PID|1||${patientId}^^^HIS^MR`,
    `ORC|NW|${serviceRequest.id}|||||||${now}`,
    `OBR|1|${serviceRequest.id}||${orderCode}^${orderDesc}^LN|||${now}`,
  ];

  const hl7Message = segments.join("\r");

  return {
    ...msg,
    body: hl7Message,
  };
}

function formatHL7Date(date: Date): string {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, "0");
  const d = String(date.getDate()).padStart(2, "0");
  const h = String(date.getHours()).padStart(2, "0");
  const min = String(date.getMinutes()).padStart(2, "0");
  const s = String(date.getSeconds()).padStart(2, "0");
  return `${y}${m}${d}${h}${min}${s}`;
}
MLLP Framing When using mode: mllp, intu automatically wraps outbound messages with the required MLLP envelope (VT/FS/CR). Do not include framing characters in your transformer output.
Note Enable keep_alive for high-throughput scenarios to avoid the overhead of establishing a new TCP connection for each message. The connection is automatically re-established if the remote end closes it.