Skip to main content

Agent Features

Each feature that the Agent supports, such as the Agent/$push operation, Agent/$status, Agent/$reload-config, etc. all require minimum versions of both Medplum Server and Medplum Agent in order to work. The matrix of feature, Medplum Server version, and Medplum Agent version looks like this:

FeatureDescriptionMedplum ServerMedplum Agent
Prefer: respond-asyncAllows asynchronous calls to Agent/$push via the Prefer header. The header tells the server to return a 202 Accepted HTTP response and allows the client to poll for the completion of the Agent/$push operation asynchronously without keeping the client waiting for an HTTP response. Useful when a response from a target device can take several seconds or even minutes to come back.> 3.1.5> 3.1.5
Agent/$reload-configAllows for dynamically reloading the config of the Agent from Medplum Server via the Agent/$reload-config FHIR operation. Useful for pushing changes to an Agent via the Agent resource without restarting the Agent service.> 3.1.6> 3.1.6
Agent.statusAllows using Agent.status and Agent.channel.endpoint.status to disable an Agent or a particular channel via the Agent resource. Useful for stopping traffic during Agent maintenance or for debugging of particular channels.> 3.1.6> 3.1.6
Agent keepAlive settingAllows you to tell the Agent to keep TCP connections alive for both outgoing traffic (via Agent/$push) and incoming traffic (via configured Agent channels) by setting the keepAlive setting to true on the Agent resource. Useful when you want to reduce number of connections to the Agent or if a particular device configuration expects the connection not to close.> 3.1.9> 3.1.10
Agent/$upgradeAllows for remotely upgrading the Agent version via the Agent/$upgrade FHIR operation.> 3.1.9> 3.1.10
Channel enhanced mode

Allows agent to acknowledge receipt of a message by enabling enhanced mode. In enhanced mode, the Agent will send a Commit Accept ACK response before the Bot has completed processing. Useful when receiving high volumes of messages.

Set by adding the enhanced=true query parameter in the channel endpoint url (e.g. mllp://0.0.0.0:2500?enhanced=true)

> 3.1.9> 4.1.8
Statistics logging

Allows for enabling periodic stats logging on the agent, which includes stats such as: internal message queue depth, number of active HL7 connections, etc.

Set by adding the logStatsFreqSecs setting to the Agent.setting array, with a valid valueInteger value, representing the number of seconds between each statistics log line.

> 3.1.9> 4.3.4
Channel messagesPerMin

Adds a minimum time between processing messages so that at maximum messagesPerMin messages can be processed in a minute. Useful when receiving high volumes of messages, especially when using enhanced mode.

Set by adding the messagesPerMin=<integer> query parameter in the channel endpoint url (e.g. mllp://0.0.0.0:2500?enhanced=true&messagesPerMin=60).

Note: Setting messagesPerMin tries to smooth out load, and is not just a hard cap on messages per minute. For example, messagesPerMin=60 will make it so that time between processing messages is at least 1 second.

> 3.1.9> 4.3.10
Agent/$fetch-logsAllows for remotely fetching the Agent logs via the Agent/$fetch-logs FHIR operation.> 4.3.14> 4.3.14
Channel appLevelAck

Allows configuring application-level acknowledgment behavior for HL7 messages. Controls when application-level ACKs are sent to the remote system based on the ACK code and enhanced mode status.

Valid values: AL (Always - default), ER (Error/Reject only), NE (Never), SU (Success only).

Set by adding the appLevelAck=<value> query parameter in the channel endpoint url (e.g. mllp://0.0.0.0:2500?enhanced=true&appLevelAck=ER).

> 3.1.9> 5.0.4
Channel assignSeqNo

Allows the Agent to automatically assign sequence numbers to incoming HL7 messages in the MSH-13 field. Useful when the sending system does not provide sequence numbers or when you need consistent sequence numbering.

Set by adding the assignSeqNo=true query parameter in the channel endpoint url (e.g. mllp://0.0.0.0:2500?assignSeqNo=true).

> 3.1.9> 5.0.4
Agent maxClientsPerRemote

Allows configuring the maximum number of concurrent HL7 client connections per remote host. Controls connection pooling behavior when sending messages via Agent/$push.

Default is 5, or 1 when keepAlive is enabled (unless explicitly set).

Set by adding the maxClientsPerRemote setting to the Agent.setting array, with a valid valueInteger value.

> 3.1.9> 5.0.4
AA-only enhanced ACK mode (enhanced=aa)

A variant of enhanced mode that sends an Application Accept (AA) immediately instead of Commit Accept (CA). Provides enhanced throughput without requiring the remote system to support or be configured for the two-step enhanced acknowledgement handshake.

Trade-off: Application-level ACKs (AA/AE/AR) are not forwarded after processing, so the remote system cannot receive asynchronous feedback about processing success or failure.

Set by adding the enhanced=aa query parameter in the channel endpoint url (e.g. mllp://0.0.0.0:2500?enhanced=aa). See AA Mode documentation for details.

> 3.1.9> 5.0.11
returnAck parameter

Allows configuring which ACK message the Agent returns when sending HL7 messages via Agent/$push. Valid values:

  • first (default): Returns the first ACK message received (e.g., a Commit ACK CA when the remote uses enhanced mode)
  • application: Waits for and returns the application-level ACK (AA, AE, or AR), skipping any commit-level ACKs

Can be configured at two levels:

  • Per-device default: Set via the defaultReturnAck query parameter on the Device.url (e.g., mllp://192.168.1.100:2575?defaultReturnAck=application)
  • Per-message override: Set via the returnAck parameter on Agent/$push operation or pushToAgent() method

Priority order: per-message returnAck > device defaultReturnAck > first (global default)

> 3.1.9> 5.0.13
Agent/$stats operationAllows for remotely fetching runtime statistics from the Agent via the Agent/$stats FHIR operation. Includes connection counts, queue depths, RTT metrics, and overall agent health. See also Statistics logging for similar functionality without the need for the operation.> 5.1.9> 5.1.9
Byte stream channel autoRespond

Allows a byte stream channel to answer a link-level handshake itself, writing a fixed byte sequence back to the socket as soon as a configured sequence is seen, without waiting on framing or the Bot. Useful for devices that expect an immediate ACK (0x06) after an ENQ (0x05) before they will send a message.

Set by adding an autoRespond=<pattern>:<response> query parameter in the channel endpoint url (e.g. tcp://0.0.0.0:9001?startChar=%02&endChar=%03&autoRespond=%05:%06). Repeat the parameter or comma-separate for more rules; patterns may span several bytes and match across TCP chunk boundaries, per connection.

Byte sequences use the same %XX form as startChar/endChar; since percent-decoding is UTF-8, a byte >= 0x80 needs its UTF-8 form (%C3%A9 for 0xE9).

For the rules an ASTM analyzer expects, see ASTM Channels.

Any> 5.1.28
Byte stream channel body filtering

Allows a byte stream channel to clean up a message body before it is sent to the Bot.

  • stripSequence=<sequence> removes every whole occurrence of a byte sequence; repeat the parameter or comma-separate for more
  • stripControlChars=true removes any remaining C0 control byte (0x00-0x1F), including the startChar/endChar framing
  • keepControlChars=<bytes> exempts bytes from that sweep. Record-oriented protocols need their terminators to survive it — an ASTM body stripped of CR is one run-on line the receiver can no longer split into records, so such a channel wants keepControlChars=%0D%0A.
  • bodyEncoding=hex (default) or utf-8 controls how the body is encoded on the wire to and from the server

Set via query parameters in the channel endpoint url (e.g. tcp://0.0.0.0:9004?startChar=%05&endChar=%04&stripControlChars=true&keepControlChars=%0D%0A&bodyEncoding=utf-8). All are off by default, so existing channels keep sending hex-encoded bodies with their framing intact.

Filtering works on bytes, not on frames, so anything printable in a device's framing still reaches the Bot. An ASTM body arrives carrying each frame's leading sequence number and trailing checksum, which the Bot has to strip itself — see ASTM Channels.

Any> 5.1.28
Byte stream channel ignoreResponse

Makes a byte stream channel one-way: the Bot's response is discarded instead of being written back to the device socket. Messages still reach the Bot as usual, and autoRespond still answers link-level handshakes — only the response leg is dropped.

Use it for devices that never read a reply, such as an analyzer that considers a session complete once its own link-level exchange ends. Without it every message draws a write back to the device, and a Bot that returns nothing draws the server's fallback body — the Bot's own execution logs — which arrives at the device as unframed junk.

Set by adding ignoreResponse=true in the channel endpoint url (e.g. tcp://0.0.0.0:9004?startChar=%05&endChar=%04&ignoreResponse=true). Off by default.

Any> 5.1.28
DICOM channel storage=dicomweb

Sends each instance a DICOM channel receives via C-STORE to the server's DICOMweb STOW-RS endpoint (POST /dicomweb/studies), which files it into DicomStudy, DicomSeries, and DicomInstance resources, instead of uploading it as a FHIR Binary.

Set by adding the storage=dicomweb query parameter in the channel endpoint url (e.g. dicom://0.0.0.0:8104?storage=dicomweb). Defaults to storage=binary, which uploads a Binary and includes a reference to it in the Bot payload, so existing DICOM channels are unaffected. In dicomweb mode the payload has no binary field — the study is addressed through the DICOMweb resources the server created instead.

Requires a server with DICOMweb support; against an older server the STOW-RS request 404s and the C-STORE fails with a processing failure status.

> 5.1.27> 5.1.28
Agent durableQueue

Routes inbound HL7 messages through an on-disk SQLite queue on the Agent before they reach the Bot. The commit ACK (CA, or AA in AA mode) is sent only once the message is committed to disk, so an ACKed message survives an Agent crash, restart, or upgrade; interrupted rows are recovered on startup.

Set by adding the durableQueue setting to the Agent.setting array with valueBoolean: true. Off by default. Related settings: queueDbPath, queueRetentionDays, queueRetentionMaxMb, queueErroredRetentionDays, queueSweepIntervalSecs.

Required for auto-retry and for logical channels. Also enables the duplicateBehavior channel parameter (idempotent / reject) for repeated MSH-10 values. See the High Throughput HL7 guide.

Any> 5.1.22
Channel auto-retry

Retries queue-to-Bot delivery with exponential backoff and jitter when a message fails. Modes: guaranteed (default — retry indefinitely until upstream answers, accepting possible duplicate delivery), normal (transient failures only, capped at 10 attempts), and none.

Set agent-wide via the channelRetryMode, channelAutoRetryBaseDelayMs, channelAutoRetryMaxDelayMs, channelAutoRetryMaxAttempts, and channelAutoRetryBackoffMultiplier settings, or per channel via the retryMode, autoRetryBaseDelayMs, autoRetryMaxDelayMs, autoRetryMaxAttempts, and autoRetryBackoffMultiplier endpoint url parameters, which override the agent-wide settings field by field.

Requires durableQueue; without it the retry settings have no effect and the Agent warns.

Any> 5.1.25
Channel logical channels

Partitions a single HL7 channel's queue into independent FIFO streams keyed on message content, so unrelated messages process concurrently instead of queueing behind each other. Order is strict within a partition and unconstrained across partitions — a feed keyed on patient ID keeps each patient's messages ordered while draining many patients in parallel.

Set the key via the channelLogicalChannelKey agent setting or the logicalChannelKey endpoint url parameter, as comma-separated HL7 field paths in SEGMENT-field[.component[.subcomponent]] notation (e.g. PID-3.1 or MSH-4,MSH-9.2). Set the concurrency via the channelMaxWorkers setting or the maxWorkers parameter (default 1, max 500), e.g. mllp://0.0.0.0:9001?enhanced=true&logicalChannelKey=PID-3.1&maxWorkers=64.

Requires durableQueue; without it both have no effect and the Agent warns. See the High Throughput HL7 guide.

Any> 5.1.29

Major Bug Fixes

Server VersionAgent VersionDescriptionRelated PR
3.2.10N/AFixes HL7 ACK messages from bots not making it back to the sending device.5212
< 3.2.104.1.9Reverted backwards-incompatible change requiring callback field for agent:transmit:response messages.6793
N/A5.0.13Reverted default returnAck behavior back to first for backwards compatibility. Previously changed to application, which broke workflows expecting the first ACK (e.g., Commit ACK CA) to be returned immediately.8279
N/A5.1.15Improves the reliability of the Agent/$upgrade process. A behavior change in the underlying @medplum/hl7 library in v5 introduced a downstream ordering issue during upgrade: the new Agent version would install successfully, but the new service could stall while waiting to acquire its ports because the old service had not yet released them. In practice this required manually stopping the old service to trigger cleanup and complete the upgrade. The shutdown of the old Agent is now signaled before the new Agent waits on its channels, allowing ports to be released in the correct order and making the upgrade process significantly more stable.9382

Compatibility Between Versions

Aside from the features and bug fixes listed above, the majority of the core functionality of the Medplum Agent is broadly compatible across all versions; notably from 3.1.5 onward. This means the Agent/$push FHIR operation functions broadly the same across versions and should be compatible on Medplum Server and Medplum Agent versions > 3.1.5.

However, it is not advised to run older versions of the Medplum Agent or Medplum Server against each other if possible, and we recommend to regularly update both Medplum Server and Medplum Agent in tandem.