Skip to main content
Glama

MCPDischarge — Interoperabilidad MCP interdepartamental

EHR × Farmacia × Facturación | RBAC | Límite de PHI | FastMCP

CitiusTech Gen AI & Agentic AI Training — Proyecto 5


El problema que las API tradicionales no pueden resolver

Un paciente está listo para el alta. Los datos deben fluir a través de tres departamentos que nunca han compartido un protocolo común:

Traditional workflow (45 minutes, 15 manual handoffs):
  Ward nurse    → prints discharge note
  Ward nurse    → phones pharmacy to check drug availability
  Pharmacy      → calls back 2 hours later (drug out of stock)
  Nurse         → calls doctor to re-prescribe
  Doctor        → updates chart
  Nurse         → re-contacts pharmacy
  Pharmacy      → dispenses (brand name ≠ generic name — wrong drug dispensed?)
  Nurse         → separately calls billing department
  Billing clerk → manually re-enters ICD-10 codes from printed note
  Billing clerk → can see full medication list including controlled substances (HIPAA risk)
  Patient       → waits, often 4–6 hours post-clinical-readiness

MCP (Model Context Protocol) resuelve esto con una capa de llamada de herramientas estandarizada, tipada y con RBAC aplicado:

MCP workflow (< 1 second, automated):
  DischargeAgent.EHR.get_discharge_medications()           ← structured, not free text
  DischargeAgent.Pharmacy.check_stock()                    ← semantic name matching
  DischargeAgent.Pharmacy.get_alternative()                ← out-of-stock resolution
  DischargeAgent.EHR.get_billing_safe_summary()            ← PHI stripped at source
  DischargeAgent.Billing.generate_invoice()                ← billing never sees clinical notes

Related MCP server: FHIR MCP Server

Arquitectura

┌────────────────────────────────────────────────────────────────┐
│                 Discharge Coordination Agent                    │
│                   (MCP Client — role: discharge_coordinator)   │
└────────┬───────────────────┬───────────────────┬──────────────┘
         │ MCP calls         │ MCP calls          │ MCP calls
         ▼                   ▼                    ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│  EHR MCP Server │ │ Pharmacy Server  │ │ Billing Server   │
│  (port 8001)    │ │ (port 8002)      │ │ (port 8003)      │
│                 │ │                  │ │                  │
│ Tools:          │ │ Tools:           │ │ Tools:           │
│ • discharge_meds│ │ • check_stock    │ │ • get_charges    │
│ • diagnosis_cod │ │ • get_alternative│ │ • get_insurance  │
│ • billing_safe  │ │ • get_price      │ │ • gen_invoice    │
│   _summary      │ │ • dispense_req   │ │                  │
│ [RBAC enforced] │ │ [RBAC enforced]  │ │ [RBAC enforced]  │
└─────────────────┘ └─────────────────┘ └─────────────────┘

PHI Boundary:
  EHR → Billing path uses get_billing_safe_summary()
  PHI fields blocked: name, DOB, MRN, discharge_note, attending_physician
  Billing receives: ICD-10 codes, LOS, ward — non-PHI operational data only

Matriz de políticas RBAC

Rol

Notas clínicas EHR

Medicamentos EHR

Códigos de diagnóstico EHR

Farmacia

Facturación

discharge_coordinator

billing_agent

✗ BLOQUEADO

✗ BLOQUEADO

Solo precio

pharmacy_agent

✗ BLOQUEADO

clinical_agent

Verificación de stock

✗ BLOQUEADO

Cada llamada de herramienta valida el rol del emisor antes de devolver datos. Las llamadas no autorizadas generan un RBACError y se registran en el feed de telemetría.


Inicio rápido

Paso 1: Instalar dependencias

pip install -r requirements.txt

Paso 2: Generar datos

cd data/
python generate_dataset.py

Paso 3: Ejecutar los servidores

Servidores HTTP FastMCP (estilo producción, necesarios para el agente MCP asíncrono):

# Terminal 1:
python src/servers/mcp_servers.py --server ehr

# Terminal 2:
python src/servers/mcp_servers.py --server pharmacy

# Terminal 3:
python src/servers/mcp_servers.py --server billing

O ejecute los tres en un solo proceso (inicia 3 hilos en segundo plano):

python src/servers/mcp_servers.py --all

Python directo (sin HTTP, solo para entrenamiento):

from src.servers.ehr_server import EHRServer

ehr = EHRServer()
meds = ehr.get_discharge_medications("PAT-001", role="discharge_coordinator")

Paso 4: Ejecutar el agente de alta

python src/agents/discharge_agent.py PAT-001
python src/agents/discharge_agent.py PAT-003

Paso 5: Demo completa

python demo/demo.py               # Runs 4 scenarios
python demo/demo.py --scenario 3  # RBAC violation only

Interfaz de chat (React)

Este repositorio incluye un frontend de chat simple en React que llama a una puerta de enlace FastAPI ligera, la cual a su vez llama a los servidores MCP.

1) Iniciar servidores MCP (SSE)

python src/servers/mcp_servers.py --all

2) Iniciar API de puerta de enlace de chat (puerto 8000)

copy .env.example .env   # then fill in Azure OpenAI settings (optional)
python -m uvicorn src.gateway.chat_gateway:app --reload --port 8000

3) Iniciar servidor de desarrollo React (puerto 5173)

cd frontend
npm install
npm run dev

Paso 6: Evaluación

cd evaluation/
python eval_dashboard.py

Nota: la evaluación requiere que los servidores MCP estén en ejecución (Paso 3), ya que llama al agente MCP asíncrono a través de SSE.


Estructura del proyecto

mcpdischarge/
├── data/
│   ├── generate_dataset.py          ← Run this first
│   ├── ehr_patients.json            ← 6 patient records with discharge medications
│   ├── pharmacy_inventory.json      ← 17 drugs (4 out of stock, aliases table)
│   ├── billing_rate_cards.json      ← 15 charge codes
│   ├── insurance_contracts.json     ← 2 insurer contracts
│   ├── patient_insurance_map.json   ← Patient → insurer mappings
│   ├── icd10_billing_codes.json     ← ICD-10 → DRG billing mappings
│   └── rbac_policies.json           ← RBAC matrix (role → server → tools)
│
├── src/
│   ├── servers/
│   │   └── mcp_servers.py           ← EHRServer, PharmacyServer, BillingServer + FastMCP wrappers
│   └── agents/
│       └── discharge_agent.py       ← DischargeCoordinationAgent + WorkflowMetrics
│
├── evaluation/
│   ├── eval_dashboard.py
│   ├── 01_manual_vs_mcp.png
│   ├── 02_rbac_telemetry.png
│   └── 03_data_integrity.png
│
├── demo/
│   └── demo.py                      ← 4 scenarios + 2 limitations
│
├── configs/
│   ├── fastmcp_deployment.md        ← FastMCP HTTP server setup
│   ├── azure_foundry_mcp.md         ← Azure AI Foundry MCP integration
│   └── rbac_design.md               ← RBAC policy design guide
│
└── README.md

Patrones de desafío inyectados

Patrón

Paciente

Medicamento

Problema inyectado

[NAME_MISMATCH]

PAT-001

Dapagliflozin/Farxiga

EHR usa marca; Farmacia almacena genérico

[OUT_OF_STOCK]

PAT-001

Furosemide 40mg

Stock=0; MCP muestra Torsemide como alternativa

[OUT_OF_STOCK]

PAT-003

Humira/Adalimumab

Marca sin stock; se encontró biosimilar Exemptia

[OUT_OF_STOCK]

PAT-004

Tafamidis/Vyndamax

Medicamento para enfermedad rara — sin alternativa; escalar

[OUT_OF_STOCK]

PAT-005

Osimertinib/Tagrisso

Medicamento especializado — pedido a farmacia central

[DATA_DRIFT]

PAT-002

Semaglutide 0.5mg

Dosis de mantenimiento EHR vs dosis inicial de formulario 0.25mg

[SCOPE_VIOLATION]

PAT-006

Modafinil Schedule H

Facturación NO debe ver detalles de sustancias controladas

[PHI_BOUNDARY]

Todos

5 campos PHI bloqueados antes de la factura de facturación


Los tres servidores MCP (Detallado)

Servidor EHR

Herramientas sensibles a PHI (solo roles clínicos):

get_patient_discharge_summary(patient_id, caller_role)  # full clinical note
get_discharge_medications(patient_id, caller_role)       # medication list

Herramientas seguras para PHI (todos los roles, incluida facturación):

get_diagnosis_codes(patient_id, caller_role)             # ICD-10 only
get_admission_info(patient_id, caller_role)              # LOS, ward, dates
get_billing_safe_summary(patient_id, caller_role)        # strips PHI fields

Eliminación de PHI (lo que se bloquea para facturación):

PHI_FIELDS = {"name", "dob", "mrn", "discharge_note", "attending_physician"}
# Billing receives: patient_id, ward, admission_date, discharge_date, los_days, diagnosis_icd10

Servidor de Farmacia

Resolución de nombres semánticos:

# EHR says "Dapagliflozin" → Pharmacy stores as "Farxiga"
# MCP alias table: {"farxiga": "PH-001", "dapa": "PH-001", "sglt2 inhibitor": "PH-001"}
drug = _find_drug_by_name("Dapagliflozin")  # → PH-001 (Dapagliflozin)
drug = _find_drug_by_name("Humira")          # → PH-008 (Adalimumab, branded)

Detección de conflictos de dosis:

# EHR prescribes Semaglutide 0.5mg, formulary standard is 0.25mg starter
if queried_dose not in formulary_dose:
    dose_conflict = True  # triggers clinical review alert

Puntuación de coincidencia semántica:

# score = word overlap / max(len(ehr_words), len(pharm_words))
# score < 0.85 → NAME_MISMATCH alert even if drug found
semantic_drug_match_score("Humira", "Adalimumab")  # → 0.0 (no word overlap)
semantic_drug_match_score("Furosemide", "Furosemide")  # → 1.0 (exact)

Servidor de Facturación

Generación de facturas (protección PHI):

def generate_invoice(patient_id, billing_safe_ehr, drug_costs, ...):
    # Verify PHI is stripped
    for phi_field in PHI_FIELDS:
        if phi_field in billing_safe_ehr:
            raise PermissionError(f"PHI field '{phi_field}' in billing payload")
    # Process invoice using only: ICD-10 + LOS + ward + drug prices

Comparación MCP vs API tradicional

Capacidad

API REST tradicionales

Protocolo MCP

Descubrimiento de esquema

Documentos Swagger estáticos

Manifiestos de herramientas dinámicos

Llamadas interdepartamentales

Punto a punto frágil

Llamadas de herramientas estandarizadas

Aplicación de RBAC

Capa de aplicación (inconsistente)

Capa de protocolo (garantizado)

Límite de PHI

Política manual

Aplicado por herramienta

Resolución de nombres de medicamentos

Mapeo codificado

Tabla de alias semánticos

Manejo de falta de stock

Devolución de llamada manual a farmacia

Búsqueda automática de alternativas

Telemetría

Registro personalizado

Seguimiento de llamadas de herramientas integrado

Incorporación de nuevo departamento

Nueva integración de API

Registrar nuevo servidor MCP


Resultados de la evaluación (6 altas de pacientes)

Paciente

Llamadas MCP

Éxito

Alertas

PHI bloqueado

PAT-001 HFrEF

16

100%

1

5 campos

PAT-002 AKI

11

100%

1

5 campos

PAT-003 RA

13

100%

2

5 campos

PAT-004 ATTR

14

100%

2

5 campos

PAT-005 NSCLC

9

100%

1

5 campos

PAT-006 MS

9

100%

1

5 campos

Total: 72 llamadas de herramientas MCP | 100% éxito | 15 transferencias manuales reemplazadas por alta | ~45 minutos ahorrados por caso


Despliegue de FastMCP HTTP

Ver configs/fastmcp_deployment.md. Patrón clave:

from fastmcp import FastMCP

ehr_mcp = FastMCP("EHR-Server")

@ehr_mcp.tool()
def get_discharge_medications(patient_id: str, caller_role: str) -> dict:
    """Get discharge medication list from EHR."""
    return EHRServer().get_discharge_medications(patient_id, caller_role)

# Run as HTTP SSE server
ehr_mcp.run(transport="sse", host="0.0.0.0", port=8001)

El agente se conecta como cliente MCP:

from mcp import ClientSession, StdioServerParameters
from mcp.client.sse import sse_client

async with sse_client("http://localhost:8001/sse") as (read, write):
    async with ClientSession(read, write) as session:
        result = await session.call_tool(
            "get_discharge_medications",
            {"patient_id": "PAT-001", "caller_role": "discharge_coordinator"}
        )

Integración con Azure AI Foundry

Ver configs/azure_foundry_mcp.md. Los servidores MCP se registran como herramientas de Foundry:

from azure.ai.projects.models import McpToolDefinition

mcp_tools = [
    McpToolDefinition(server_url="http://ehr-server:8001/sse", name="ehr-server"),
    McpToolDefinition(server_url="http://pharmacy-server:8002/sse", name="pharmacy-server"),
    McpToolDefinition(server_url="http://billing-server:8003/sse", name="billing-server"),
]

agent = client.agents.create_agent(
    model="gpt-4o",
    name="DischargeCoordinationAgent",
    instructions=DISCHARGE_AGENT_SYSTEM_PROMPT,
    tools=[t.as_tool_definition() for t in mcp_tools],
)

Programa de formación en IA generativa y agentes de CitiusTech — Proyecto 5 de 5

Related MCP Connectors

Related MCP Servers