Managing Mirth Connect with AI Agents: An MCP Server for Healthcare Integration Engines
Mirth Connect (NextGen Connect) is the most widely deployed open-source healthcare integration engine. It moves HL7 messages between EHRs, labs, pharmacies, imaging systems, and billing platforms. A typical hospital runs dozens or hundreds of Mirth channels, each with its own source connector, transformer scripts, filters, and destinations. Managing them means reading XML exports, writing Rhino-compatible JavaScript, debugging cryptic error messages, and reviewing channel configurations before promoting them across environments.
All of this is tedious, detail-oriented work. It is also exactly the kind of work that AI agents handle well -- if you give them the right tools.
The Mirth Connect MCP server exposes 18 tools that let AI assistants parse, analyze, generate, and debug Mirth channels. This article walks through what the tools do and how to use them in practice.
The 18 tools
| Tool | Description |
|---|---|
mirth_parse_channel |
Parse a channel XML export into structured JSON |
mirth_analyze_channel |
Lint a channel for hardcoded IPs, SQL injection, missing error handling, Rhino issues |
mirth_explain_channel |
Generate a plain-English description of what a channel does |
mirth_generate_transformer |
Generate a transformer step in Rhino-compatible JavaScript |
mirth_generate_filter |
Generate a filter step (message type, field value, test patient exclusion) |
mirth_generate_channel |
Generate a complete importable channel XML |
mirth_map_fields |
Generate HL7 field mapping code (PID-5-1 to patient_last_name) |
mirth_generate_code_template |
Generate a code template using the IIFE pattern |
mirth_debug_error |
Explain a Mirth error message and suggest fixes |
mirth_validate_js |
Validate JavaScript for Rhino compatibility across Mirth versions |
mirth_diff_channels |
Compare two channel XMLs and show what changed |
mirth_migration_guide |
Generate a migration guide for upgrading channels between Mirth versions |
mirth_extract_sql |
Extract all SQL queries from a channel and flag injection risks |
mirth_dependency_map |
Map dependencies between channels (Channel Writer/Reader, router.routeMessage) |
mirth_generate_deploy_script |
Generate a bash deploy script for CI/CD pipelines |
mirth_convert_to_code_template |
Convert inline transformer JavaScript into a proper code template |
mirth_estimate_throughput |
Estimate message throughput and identify bottlenecks |
mirth_generate_test_message |
Generate a realistic test message based on source connector type |
Installation
Add to your Claude Desktop config (claude_desktop_config.json):
{
"mcpServers": {
"mirth-connect": {
"command": "npx",
"args": ["-y", "@easysolutions906/mirth-mcp"]
}
}
}
Restart Claude Desktop. All 18 tools become available immediately.
For Cursor, add the same configuration to .cursor/mcp.json in your project. For Claude Code, run:
claude mcp add mirth-connect npx -y @easysolutions906/mirth-mcp
Scenario: Onboarding a new team member
You just joined a healthcare IT team and need to understand 30 Mirth channels you have never seen before. Someone hands you a channel XML export. Normally you would open it in the Mirth Administrator, expand each connector, read the transformer steps, look up field paths in the HL7 specification, and take notes. This takes 15-30 minutes per channel.
Instead, paste the XML into Claude and ask: "Explain this Mirth channel."
Claude calls mirth_explain_channel and returns something like:
## ADT Feed - Epic to Lab
### Source: TCP Listener
Listens on port 6661
**Source Filter** (1 rules):
- Accept ADT A01/A04/A08 only (enabled)
**Source Transformer** (3 steps):
- Extract patient demographics (enabled)
- Format MRN with facility prefix (enabled)
- Map attending physician NPI (enabled)
### Destinations (2)
**1. Lab System** (TCP Sender)
- Target: 10.1.5.20:5000
- Transformer: 2 steps
**2. Patient Index** (Database Writer)
- Transformer: 1 steps
### Properties
- Initial state: STARTED
- Storage mode: PRODUCTION
- Tags: ADT, Epic, Lab
In 10 seconds you know the channel's purpose, data flow, and architecture. You can follow up with "Analyze this channel for issues" and Claude calls mirth_analyze_channel:
{
"channelName": "ADT Feed - Epic to Lab",
"summary": { "total": 4, "errors": 1, "warnings": 2, "info": 1 },
"findings": [
{
"ruleId": "sql-injection",
"severity": "error",
"location": "Destination: Patient Index Transformer",
"detail": "SQL string concatenation detected — use parameterized queries to prevent SQL injection"
},
{
"ruleId": "hardcoded-ip",
"severity": "warning",
"location": "Destination: Lab System",
"detail": "Hardcoded IP \"10.1.5.20\" — use configurationMap or a channel variable instead"
},
{
"ruleId": "missing-error-handling",
"severity": "warning",
"location": "Destination: Patient Index Transformer",
"detail": "I/O operations without try/catch — database operations should be wrapped in error handling"
},
{
"ruleId": "large-inline-script",
"severity": "info",
"location": "Source Transformer",
"detail": "Script is 78 lines — consider extracting to a code template for reusability"
}
]
}
Now you know the channel has a SQL injection vulnerability, hardcoded IPs, and missing error handling. On your first day. Without opening the Mirth Administrator.
Writing Rhino-compatible JavaScript
Mirth runs JavaScript through Mozilla Rhino, not V8 or SpiderMonkey. This means no template literals, no destructuring, no async/await, no optional chaining, no nullish coalescing, and no ES modules. Arrow functions and const work inside IIFEs on Mirth 3.7+ with ES6 mode enabled, but const/let at root level in code templates causes cross-template scope collisions. Every integration engineer has been bitten by at least one of these.
Ask Claude: "Generate a transformer that extracts patient demographics from PID and maps them to channelMap variables."
Claude calls mirth_generate_transformer and returns:
// Transformer: Extract patient demographics from PID
// Generated for Mirth Connect (Rhino ES6)
// Access HL7 message fields via msg object
// Example: var patientName = msg['PID']['PID.5']['PID.5.1'].toString();
try {
var patientLastName = msg['PID']['PID.5']['PID.5.1'].toString();
var patientFirstName = msg['PID']['PID.5']['PID.5.2'].toString();
var mrn = msg['PID']['PID.3']['PID.3.1'].toString();
channelMap.put('patientLastName', patientLastName);
channelMap.put('patientFirstName', patientFirstName);
channelMap.put('mrn', mrn);
} catch (e) {
logger.error('Transformer error: ' + e.message);
throw e;
}
The generated code uses var at root level, string concatenation instead of template literals, and wraps everything in try/catch. It follows Rhino rules automatically.
If you already have JavaScript and want to check it, paste it in and ask Claude to validate it. Claude calls mirth_validate_js and returns a version compatibility matrix:
{
"valid": false,
"mirthVersion": "es5",
"rhinoMode": "ES5 (pre-3.7 or legacy config)",
"errors": 2,
"violations": [
{
"id": "arrow-function",
"message": "Arrow functions require Mirth 3.7+ with rhino.languageversion=es6.",
"fix": "Replace (x) => { } with function(x) { }. Or set rhino.languageversion=es6 in mirth.properties."
},
{
"id": "template-literal",
"message": "Template literals require Mirth 3.7+ with rhino.languageversion=es6.",
"fix": "Use string concatenation: \"hello \" + name. Safest across all versions."
}
],
"versionMatrix": {
"es5": "incompatible",
"3.7": "compatible",
"4.0": "compatible",
"4.5": "compatible"
}
}
This is especially useful when your team supports multiple Mirth versions across different client environments. The version matrix tells you exactly where the code will work and where it will break.
Environment promotion: diffing channels
Before promoting a channel from DEV to PROD, you need to know what changed. Export both versions and ask Claude: "Compare these two channel XMLs."
Claude calls mirth_diff_channels and returns:
{
"channel1": "ADT Feed v2.1 (DEV)",
"channel2": "ADT Feed v2.0 (PROD)",
"totalChanges": 3,
"changes": [
{
"field": "destination.Lab System.transformer",
"from": "2 steps",
"to": "3 steps",
"type": "modified"
},
{
"field": "destination.Audit Log",
"type": "added",
"details": "New Database Writer destination"
},
{
"field": "postprocessingScript",
"type": "modified"
}
],
"summary": "1 added, 0 removed, 2 modified"
}
A clear summary of what will change when you promote. No need to manually compare XML files or click through the Mirth Administrator.
Extracting SQL for DBA review
Healthcare organizations require database changes to go through a DBA review process. If your Mirth channels contain SQL in transformer scripts, Database Reader/Writer connectors, or inline JavaScript, extracting it manually is painful.
Ask Claude: "Extract all SQL from this channel and flag any injection risks."
Claude calls mirth_extract_sql and returns every query with its location and a flag for potential injection vulnerabilities:
{
"channel": "Patient Sync",
"totalQueries": 5,
"injectionRisks": 1,
"queries": [
{
"source": "Source connector query",
"sql": "SELECT patient_id, mrn, last_name, first_name FROM patients WHERE updated_at > ${date}",
"potentialInjection": false
},
{
"source": "Dest[Patient Index] transformer: Update MPI",
"sql": "UPDATE patient_index SET last_name = '" ,
"potentialInjection": true
}
],
"warning": "1 queries may be vulnerable to SQL injection. Use parameterized queries instead of string concatenation."
}
Hand this to your DBA. They get the SQL without needing to open Mirth or understand channel XML structure.
Mapping channel dependencies
In a large Mirth environment with 50+ channels, channels route messages to each other via Channel Writer destinations and router.routeMessage calls. Understanding the dependency graph is critical before you disable, rename, or redeploy a channel.
Pass all your channel XMLs to Claude and ask: "Map the dependencies between these channels."
Claude calls mirth_dependency_map and returns:
{
"totalChannels": 12,
"totalDependencies": 8,
"dependencies": [
{ "from": "ADT Router", "to": "Lab Feed", "type": "Channel Writer", "connector": "Lab Destination" },
{ "from": "ADT Router", "to": "Radiology Feed", "type": "Channel Writer", "connector": "Rad Destination" },
{ "from": "ADT Router", "to": "Audit Logger", "type": "router.routeMessage", "connector": "script" },
{ "from": "Lab Feed", "to": "Results Notifier", "type": "Channel Writer", "connector": "Notify" }
],
"orphans": ["Test Channel", "Old Migration Channel"]
}
You can see which channels feed into which, and which channels are orphaned with no connections -- candidates for cleanup.
Generating complete channels
Need a new channel quickly? Describe it and Claude generates importable XML.
Ask: "Generate a Mirth channel called 'Lab Results Inbound' with a TCP Listener on port 7001 and two destinations: an HTTP Sender called 'EHR API' and a Database Writer called 'Results Archive'."
Claude calls mirth_generate_channel and returns valid XML that you can import directly into Mirth Connect. The generated channel includes proper connector classes, transformer and filter placeholders, and standard channel properties.
Generating deploy scripts for CI/CD
Mirth channels are usually deployed manually through the Administrator GUI. For teams practicing CI/CD, this is a bottleneck. The mirth_generate_deploy_script tool generates a bash script that uses the Mirth REST API to log in, check if the channel exists, stop it, update or create it, deploy, and start it.
Ask Claude: "Generate a deploy script for this channel targeting https://mirth-prod.internal:8443/api."
The output is a ready-to-use bash script for your Jenkins, GitHub Actions, or GitLab CI pipeline.
Debugging errors
Mirth error messages range from helpful to inscrutable. Rhino errors are especially confusing for developers used to V8. Paste an error into Claude and ask what it means.
Ask: "Debug this Mirth error: ReferenceError: \"formatDate\" is not defined"
Claude calls mirth_debug_error and returns:
{
"error": "ReferenceError: \"formatDate\" is not defined",
"cause": "The variable or function \"formatDate\" is not declared in the current scope. In Mirth, code templates execute in a shared global scope — if a code template has not been loaded, its functions will not be available.",
"fixes": [
"Verify the code template library containing \"formatDate\" is enabled and linked to this channel.",
"Check for typos in the function/variable name.",
"If using ES6 syntax (let/const) at root level, switch to var for global visibility.",
"Ensure code template libraries are listed in the correct order (dependencies first)."
]
}
The tool recognizes common error patterns including ReferenceErrors, TypeErrors, SQL exceptions, network connection failures, and OutOfMemoryErrors. Each match returns a specific cause and actionable fixes.
Refactoring: inline scripts to code templates
Mirth best practice is to keep transformer scripts short and put reusable logic into code templates. In practice, integration engineers write everything inline first and refactor later -- or never. The mirth_convert_to_code_template tool automates the refactoring.
Paste an inline transformer script and ask Claude to convert it to a code template. The tool extracts function definitions, wraps them in the IIFE pattern with var declarations at root level for global visibility, and generates usage examples showing how to call the functions from a transformer step.
Estimating throughput
Before going live with a high-volume channel, you want to know where the bottlenecks are. The mirth_estimate_throughput tool analyzes transformer complexity, counts database queries, detects HTTP calls in transformers (a common anti-pattern), identifies heavy regex usage, and factors in destination type overhead.
The output includes an estimated messages-per-second figure and a ranked list of bottlenecks with specific optimization suggestions -- like moving HTTP calls from transformers to HTTP Sender destinations, or replacing repeated new RegExp with pre-compiled patterns in a deploy script.
Upgrading Mirth versions
Upgrading from Mirth 3.x to 4.x, or from 4.x to 4.5, introduces breaking changes in APIs, plugin interfaces, and Rhino behavior. The mirth_migration_guide tool scans all scripts in a channel for deprecated APIs, Rhino compatibility issues, and patterns that changed between versions.
Pass a channel XML and specify the from/to versions. The tool returns a list of issues with locations, descriptions, and fixes -- a checklist you can work through before upgrading.
Generating test messages
When building or debugging a channel, you need test messages that match the source connector type. The mirth_generate_test_message tool analyzes the channel's source connector and generates an appropriate test message: an HL7 ADT^A01 for TCP/LLP sources, a JSON payload for HTTP sources, or delimited text for file reader sources.
Getting started
- Add the MCP server config to Claude Desktop, Cursor, or Claude Code
- Restart and verify the 18 tools appear
- Export a channel from Mirth Connect (Channels > Export Channel)
- Paste the XML into Claude and ask: "Explain this channel" or "Analyze this channel for issues"
- Try generating code: "Generate a transformer that extracts PID-5-1 and PID-3-1 to channelMap"
Mirth Connect is powerful but demands deep knowledge of Rhino quirks, HL7 field positions, and XML channel structure. An MCP server gives AI agents that knowledge, so you can focus on the integration logic instead of fighting the tooling.
Top comments (0)