Interface health for AI agents
Review recorded HL7 failures across interfaces in one result.
The clinical audit log records HL7 failures with their interface, outcome and error. This page builds a service that groups those events by interface and exposes the result as an MCP tool, so you can ask your AI which interfaces had failures overnight.
Start with Expose services as MCP - it creates the clinical MCP gateway and the API key that this page builds on. The service below reads the same clinical audit log that every MLLP channel already writes to.
Write the service
The service searches the failures through self.audit and groups them by the channel they arrived on. How its docstring and declared fields become the tool's definition is covered under Expose services as MCP:
# -*- coding: utf-8 -*-
# Zato
from zato.common.audit_log.api import AuditOutcome, AuditSource
from zato.server.service import Service
# #####################################################################
# #####################################################################
class InterfaceHealth(Service):
""" Returns, per interface, the HL7 messages that failed since a given
time, with the control ID and error of each failure.
"""
name = 'interface.health'
input = 'since'
output = 'since', 'has_failures', 'interfaces'
def handle(self) -> 'None':
# Read the start of the requested period ..
since = self.request.input.since
# .. look up every failure recorded since then ..
failures = self.audit.search(
source=AuditSource.MLLP_Channel,
outcome=AuditOutcome.Error,
time_from=since,
)
# .. group the failures by the channel they arrived on ..
by_interface = {}
for failure in failures:
# .. find or start the group of this failure's channel ..
interface = failure['object_name']
if interface not in by_interface:
by_interface[interface] = []
# .. copy only the fields needed by the caller ..
by_interface[interface].append({
'control_id': failure['msg_id'],
'error': failure['status'],
'received_at': failure['event_time_iso'],
})
# .. turn each group into one interface result ..
interfaces = []
for interface, interface_failures in by_interface.items():
# .. with the failures of that interface and their count ..
interfaces.append({
'interface': interface,
'failure_count': len(interface_failures),
'failures': interface_failures,
})
# .. determine whether the period contains failures ..
has_failures = len(interfaces) > 0
# .. and return the declared tool response.
self.response.payload = {
'since': since,
'has_failures': has_failures,
'interfaces': interfaces,
}
Add the tool to the gateway
Assign the new service to the clinical gateway created under Expose services as MCP:
- Go to AI > MCP gateways and open the
clinicalgateway - In the Services picker, drag
interface.healthto the Assigned zone - Click OK
Verify the lookup
You can now ask your AI:
Behind this exchange, the model selected interface.health and called it with:
With two failures recorded overnight on the lab feed, the tool returned:
{
"since": "2026-03-15T22:00:00",
"has_failures": true,
"interfaces": [{
"interface": "Results from Lab",
"failure_count": 2,
"failures": [
{
"control_id": "MSG00214",
"error": "Unknown test code in OBX-3",
"received_at": "2026-03-16T02:41:07"
},
{
"control_id": "MSG00219",
"error": "Unknown test code in OBX-3",
"received_at": "2026-03-16T03:15:44"
}
]
}]
}
And this is the same question on a night with no failures:
This time, the tool returned an empty result, which is how AI knew there were no failures:
Schedule a meaningful demo
Book a demo with an expert who will help you build meaningful systems that match your ambitions
"We evaluated 12 integration platforms and Zato was the only one to score 100%."
Philip Zuñiga, Assistant Professor, University of the Philippines