This workflow follows the HTTP Request → OpenAI recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "Health Automation - HL7/FHIR LLM with Guardrail & MCP",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "health-llm-guardrail",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook",
"name": "Webhook - Receive HL7/FHIR",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
250,
300
]
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "const hl7 = require('hl7'); // optional if available; manual parsing fallback\n\n// Input data\nconst inputData = $input.first().json.body;\nlet parsed = { type: null, data: null, raw: inputData };\n\n// Detect HL7 (pipe-separated, typical MSH segment)\nif (typeof inputData === 'string' && (inputData.startsWith('MSH') || inputData.includes('\\nMSH'))) {\n // Simple HL7 to JSON\n const segments = inputData.split(/\\r?\\n/);\n const hl7Json = { segments: [] };\n for (const seg of segments) {\n const fields = seg.split('|');\n hl7Json.segments.push({ name: fields[0], fields: fields.slice(1) });\n }\n parsed.type = 'HL7';\n parsed.data = hl7Json;\n parsed.patientId = hl7Json.segments.find(s => s.name === 'PID')?.fields[2] || 'unknown';\n} else if (typeof inputData === 'object' && (inputData.resourceType || inputData.entry)) {\n // FHIR resource or bundle\n parsed.type = 'FHIR';\n parsed.data = inputData;\n parsed.patientId = inputData.id || (inputData.subject?.reference) || 'unknown';\n} else {\n throw new Error('Unsupported format. Please send HL7 string or FHIR JSON.');\n}\n\n// Extract condition/problem for LLM context\nlet clinicalContext = '';\nif (parsed.type === 'HL7') {\n const obxSegments = parsed.data.segments.filter(s => s.name === 'OBX');\n clinicalContext = obxSegments.map(s => s.fields[4] || '').join(', ');\n} else if (parsed.type === 'FHIR') {\n if (parsed.data.resourceType === 'Condition') {\n clinicalContext = parsed.data.code?.text || parsed.data.code?.coding?.[0]?.display || '';\n } else if (parsed.data.entry) {\n const conditionEntry = parsed.data.entry.find(e => e.resource?.resourceType === 'Condition');\n clinicalContext = conditionEntry?.resource?.code?.text || '';\n }\n}\n\nreturn {\n parsed,\n clinicalContext: clinicalContext || 'No specific condition found.',\n patientId: parsed.patientId\n};"
},
"id": "detect-parse",
"name": "Detect & Parse HL7/FHIR",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
450,
300
]
},
{
"parameters": {
"url": "https://your-mcp-server.example.com/context",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "patientId",
"value": "={{ $json.patientId }}"
},
{
"name": "clinicalContext",
"value": "={{ $json.clinicalContext }}"
}
]
},
"options": {}
},
"id": "mcp",
"name": "MCP - Model Context Protocol",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
650,
300
],
"notesInFlow": true,
"notes": "Replace with your actual MCP server endpoint. The server should return relevant clinical guidelines or safety context based on patientId and condition."
},
{
"parameters": {
"model": "gpt-4",
"messages": {
"values": [
{
"role": "system",
"content": "You are a clinical decision support assistant with strict guardrails.\n\nGUARDRAILS (MUST FOLLOW):\n1. NEVER provide definitive diagnoses or treatment plans.\n2. ALWAYS recommend consultation with a licensed physician.\n3. DO NOT predict outcomes or guarantee results.\n4. REFUSE to answer if the input is outside evidence-based guidelines.\n5. If uncertain, respond: 'I cannot provide an answer without verified clinical review.'\n\nYour role is to summarize, flag potential risks, and suggest general educational information only."
},
{
"role": "user",
"content": "=== PATIENT CLINICAL DATA ===\nHL7/FHIR Extract: {{ $json.clinicalContext }}\nPatient ID: {{ $json.patientId }}\n\n=== MCP CONTEXT (Clinical Guidelines & Safety) ===\n{{ $json.mcpResponse }}\n\nBased on the above, answer the following question (if any was provided in the original request) OR generate a brief risk assessment and educational summary. Ensure your response complies with the guardrails."
}
]
},
"options": {
"temperature": 0.3,
"maxTokens": 1000
}
},
"id": "llm",
"name": "LLM with Guardrail Prompt",
"type": "n8n-nodes-base.openAi",
"typeVersion": 1,
"position": [
850,
300
],
"credentials": {
"openAiApi": "<your credential>"
}
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "const llmOutput = $input.first().json.message.content;\n\n// Guardrail violation patterns\nconst forbiddenPatterns = [\n /guarantee/i,\n /100% cure/i,\n /will definitely/i,\n /always safe/i,\n /no side effects/i,\n /diagnose you with/i,\n /prescribe/i,\n /take this medication/i\n];\n\nlet isSafe = true;\nlet violations = [];\nfor (const pattern of forbiddenPatterns) {\n if (pattern.test(llmOutput)) {\n isSafe = false;\n violations.push(pattern.source);\n }\n}\n\nlet finalOutput = llmOutput;\nif (!isSafe) {\n finalOutput = \"[GUARDRAIL ACTIVATED] The generated response contained potentially unsafe content. Please consult a licensed healthcare provider directly.\\n\\nOriginal violations: \" + violations.join(\", \");\n}\n\nreturn {\n originalLlmResponse: llmOutput,\n guardrailPassed: isSafe,\n finalResponse: finalOutput,\n violationsDetected: violations\n};"
},
"id": "guardrail-output",
"name": "Output Guardrail Check",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1050,
300
]
},
{
"parameters": {
"options": {}
},
"id": "response",
"name": "Send Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
1250,
300
]
}
],
"connections": {
"Webhook - Receive HL7/FHIR": {
"main": [
[
{
"node": "Detect & Parse HL7/FHIR",
"type": "main",
"index": 0
}
]
]
},
"Detect & Parse HL7/FHIR": {
"main": [
[
{
"node": "MCP - Model Context Protocol",
"type": "main",
"index": 0
}
]
]
},
"MCP - Model Context Protocol": {
"main": [
[
{
"node": "LLM with Guardrail Prompt",
"type": "main",
"index": 0
}
]
]
},
"LLM with Guardrail Prompt": {
"main": [
[
{
"node": "Output Guardrail Check",
"type": "main",
"index": 0
}
]
]
},
"Output Guardrail Check": {
"main": [
[
{
"node": "Send Response",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
"healthcare",
"llm",
"guardrail",
"hl7",
"fhir",
"mcp"
],
"triggerCount": 0,
"updatedAt": "2025-01-23T12:00:00.000Z",
"versionId": "1.0.0"
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
openAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Health Automation - HL7/FHIR LLM with Guardrail & MCP. Uses httpRequest, openAi. Webhook trigger; 6 nodes.
Source: https://github.com/mrzasad/n8n-hl7-fhir-llm-guardrail/blob/main/n8n-hl7-fhir-llm-guardrail.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This powerful n8n automation workflow is designed to execute advanced B2B lead enrichment and hyper-personalization for cold email outreach. By orchestrating a complex chain of data scraping, AI analy
Eu Clara – Funil Kiwify Completo. Uses postgres, openAi, httpRequest, gmail. Webhook trigger; 70 nodes.
This workflow bridges the gap between raw product data and revenue sales tools. It automates the entire Product Qualified Lead (PQL) lifecycle—from real-time intent routing to churn prevention—reducin
Lua Nova - Sistema Completo. Uses postgres, httpRequest, openAi. Webhook trigger; 55 nodes.
User Signup & Verification: The workflow starts when a user signs up. It generates a verification code and sends it via SMS using Twilio. Code Validation: The user replies with the code. The workflow