fhirHydrant MCP

Servidor MCP FHIR Node.js de código abierto con SMART Backend Services, herramientas de búsqueda/CRUD con reconocimiento de metadatos, respuestas compactas, filtrado FHIRPath, paginación segura, eventos de auditoría y consulta de terminología.

Documentación

fhirHydrant: Servidor MCP de FHIR

Un servidor moderno, totalmente configurable y de código abierto de Node.js para el Protocolo de Contexto de Modelo (MCP) para APIs de FHIR R4+. Conecta clientes de IA compatibles con MCP a datos clínicos mediante SMART on FHIR v2 Backend Services usando credenciales de cliente JWT firmadas.

fhirHydrant convierte recursos FHIR, operaciones nombradas, búsquedas de terminología y paginación en herramientas MCP. Los recursos y operaciones predeterminados son puntos de partida: los recursos, operaciones, controles de búsqueda, instrucciones y mensajes pueden ampliarse, recortarse o reemplazarse mediante archivos de configuración sin cambios en el código fuente.

  • Autenticación SMART Backend Services con alojamiento JWKS, rotación de claves, renovación de tokens y ámbitos dinámicos
  • Herramientas de recursos configurables para búsqueda, lectura directa, vread, historial y CRUD opcional controlado por metadatos
  • Operaciones nombradas impulsadas por configuración para datos clínicos, terminología, IPS, coincidencia de pacientes, validación y flujos de trabajo personalizados
  • Herramientas conscientes de CapabilityStatement, controles de búsqueda, control de operaciones y verificaciones de ámbito en tiempo de ejecución
  • Funciones de economía de tokens: respuestas compactas, filtrado FHIRPath, límites de bytes, _count y reintento de Bundle sobredimensionado
  • Herramientas de terminología opcionales, eventos de auditoría ligeros en PHI (sin contenido de recursos por defecto) y transporte stdio o HTTP Streamable

Nota: Los datos FHIR devueltos a través de llamadas a herramientas MCP pueden contener PHI. Asegúrate de que el almacenamiento de transcripciones y el comportamiento de registro de tu cliente MCP coincidan con tus requisitos de cumplimiento.

Contenido

Inicio Rápido

Requisitos

  • Node.js >= 24
  • Un servidor FHIR compatible
  • Para autenticación SMART (predeterminada): un registro de cliente SMART Backend Services y una clave privada RSA-2048 o EC P-384 cuya clave pública esté disponible a través de JWKS

Para ejecutar contra un servidor de prueba FHIR público y sin autenticación, establece FHIR_AUTH=none y omite el cliente y la clave por completo (consulta Acceso Sin Autenticación).

El transporte stdio generalmente necesita una URL JWKS alojada externamente. El endpoint /jwks integrado está disponible solo cuando fhirHydrant se ejecuta sobre HTTP con autenticación SMART.

Instalación

# install globally
npm install -g fhirhydrant

# or run without installing
npx fhirhydrant

Ejecutar desde el código fuente:

git clone https://github.com/faulkj/fhirhydrant.git
cd fhirhydrant
npm install
npm run build

Configuración del Cliente MCP

Para clientes MCP de escritorio, stdio suele ser el transporte más simple:

{
   "mcpServers": {
      "fhirhydrant": {
         "command": "npx",
         "args": ["-y", "fhirhydrant"],
         "env": {
            "MCP_TRANSPORT": "stdio",
            "FHIR_BASE_URL": "https://fhir.example.org",
            "FHIR_CLIENT_ID": "your-client-id",
            "FHIR_ACTIVE_KEY": "LS0tLS1CRUdJTi...base64-of-your-pem...",
            "FHIR_JWKS_URL": "https://example.org/.well-known/jwks.json"
         }
      }
   }
}

FHIR_ACTIVE_KEY es tu clave privada PKCS#8 (RSA o EC P-384), codificada en base64. El kid se deriva automáticamente al inicio mediante una Huella JWK truncada y se registra en la consola.

Acceso Sin Autenticación

Para apuntar fhirHydrant a un endpoint FHIR público y sin autenticación (útil para probar contra sandboxes abiertos), establece FHIR_AUTH=none. No se requiere ID de cliente ni clave de firma, no se solicita token y las solicitudes se envían sin un encabezado Authorization:

{
   "mcpServers": {
      "fhirhydrant": {
         "command": "npx",
         "args": ["-y", "fhirhydrant"],
         "env": {
            "MCP_TRANSPORT": "stdio",
            "FHIR_AUTH": "none",
            "FHIR_SERVER_URL": "https://hapi.fhir.org/baseR4"
         }
      }
   }
}

Herramientas

fhirHydrant registra herramientas a partir de la configuración y verificaciones de capacidades en tiempo de ejecución. La lista exacta depende de la carpeta config/resources/, los ámbitos SMART otorgados, /metadata, la configuración de escritura, la configuración de operaciones y la configuración de terminología.

Herramienta o familiaDisponible cuandoPropósito
Herramientas de recursosEl recurso está configurado y permitido por metadatos/ámbitosBúsqueda, lectura directa, vread, historial y opcionalmente CRUD de recursos FHIR
system_historyEl servidor anuncia interacción de sistema history y los ámbitos lo permitenRecuperar el historial de cambios a nivel de sistema en todos los tipos de recursos
capabilitiesSiempre registradaInspeccionar resumen de CapabilityStatement, herramientas registradas, herramientas omitidas, parámetros de búsqueda, operaciones y notas de metadatos
paginateSiempre registradaObtener la siguiente página de un Bundle FHIR usando una URL next devuelta por el servidor
operateAl menos una operación nombrada pasa el controlInvocar operaciones nombradas FHIR configuradas para datos clínicos, terminología, IPS, coincidencia, validación o flujos de trabajo personalizados
bundleFHIR_BUNDLE_CAPABILITIES está establecidoEnviar un Bundle de lote o transacción FHIR; las escrituras requieren aceptación adicional
terminology_lookupFHIR_TERMINOLOGY_BASE_URL está establecidoBuscar un código LOINC o SNOMED CT
code_searchFHIR_TERMINOLOGY_BASE_URL está establecidoBuscar códigos LOINC o SNOMED CT por texto

Herramientas de Recursos

Las herramientas de recursos se generan desde la carpeta config/resources/ — un archivo JSON por recurso (p. ej. patient.json), escaneado al inicio. La configuración incluida cubre recursos clínicos, administrativos, de medicación, profesionales, organizaciones y documentos comunes. Agrega un archivo para añadir un recurso, o elimina uno para quitarlo — sin cambios en el código fuente.

Cada herramienta de recurso admite parámetros de búsqueda configurados, lecturas directas opcionales con _id, fhirpath y, a menos que esté bloqueado por modo compacto, responseMode. La lectura directa solo ocurre cuando _id es el único argumento no vacío; _id más otros parámetros sigue siendo una búsqueda para que la intención del llamante no se descarte silenciosamente.

Las herramientas de recursos son de búsqueda/lectura por defecto. Establece FHIR_WRITE_CAPABILITIES para habilitar acciones CRUD controladas por metadatos:

FHIR_WRITE_CAPABILITIES=create,update,patch,delete
AcciónParámetros requeridosLlamada FHIR
vread_id, _vidGET /ResourceType/{id}/_history/{vid}
history_id (instancia) o ninguno (tipo)GET /ResourceType/{id}/_history o GET /ResourceType/_history
createbodyPOST /ResourceType
update_id, bodyPUT /ResourceType/{id}
patch_id, bodyPATCH /ResourceType/{id} con JSON Patch
delete_idDELETE /ResourceType/{id}

vread está disponible cuando el recurso tiene supportsDirectRead y el servidor anuncia la interacción vread. history está disponible cuando el servidor anuncia history-instance o history-type. Ambos requieren el permiso SMART r. Los parámetros opcionales _since y _at filtran los resultados del historial. Las respuestas de historial son Bundles y admiten modo compacto, FHIRPath y coalescencia.

Los cuerpos de escritura se validan antes de la llamada FHIR: body.resourceType debe coincidir con el recurso de la herramienta, body.id debe coincidir con _id para actualización cuando esté presente, y el parche requiere un arreglo JSON Patch. Los ámbitos se derivan de las capacidades habilitadas: lectura/búsqueda usa system/Patient.rs, creación/lectura/búsqueda usa system/Patient.crs y el soporte completo de escritura usa system/Patient.cruds. SMART v2 no tiene una letra de parche separada, por lo que el parche se asigna a u.

Herramientas Principales

capabilities devuelve el resumen de CapabilityStatement en caché, herramientas registradas y omitidas, parámetros de búsqueda, operaciones y notas de metadatos.

paginate obtiene una página de Bundle usando una URL next devuelta por el servidor, validada contra el origen FHIR y los prefijos de ruta permitidos. Cuando el modo compacto está activo y la página obtenida tiene más resultados, la paginación automáticamente combina múltiples páginas ascendentes en una respuesta compacta (mismo comportamiento que las herramientas de búsqueda de recursos). Pasa prefetch=false para deshabilitar la coalescencia y obtener una sola página.

Operaciones Nombradas

La herramienta operate invoca operaciones nombradas FHIR desde config/operations.json. El catálogo de operaciones incluido cubre agregación clínica, validación, búsqueda de documentos, operaciones de terminología, generación de IPS y coincidencia de pacientes. Puedes ampliar, recortar, reemplazar o deshabilitar el catálogo de operaciones sin cambios en el código fuente.

Herramientas de Terminología

Establece FHIR_TERMINOLOGY_BASE_URL para habilitar:

HerramientaDescripción
terminology_lookupBusca un código LOINC o SNOMED CT
code_searchBusca códigos por filtro de texto con soporte de paginación

Estas herramientas llaman directamente al servidor de terminología configurado. No usan las credenciales del servidor FHIR clínico. Usa un endpoint de terminología que coincida con tu versión FHIR seleccionada, como https://tx.fhir.org/r4.

Ejecución de Bundles

Establece FHIR_BUNDLE_CAPABILITIES=batch (o batch,transaction) para habilitar bundle. Esta herramienta envía un Bundle de lote o transacción FHIR y devuelve la respuesta del servidor a través del pipeline de respuesta estándar.

Modelo de seguridad:

  • Los Bundles de lote de solo lectura (todas las entradas GET) se permiten solo con FHIR_BUNDLE_CAPABILITIES=batch.
  • Las entradas de escritura (POST, PUT, PATCH, DELETE) requieren adicionalmente FHIR_BUNDLE_WRITES_ENABLED=true y la acción correspondiente en FHIR_WRITE_CAPABILITIES.
  • Los Bundles de transacción requieren FHIR_BUNDLE_CAPABILITIES=transaction explícito.
  • Cada entrada se verifica previamente contra los recursos configurados, los ámbitos SMART y las interacciones de metadatos. Si una sola entrada falla, todo el Bundle se rechaza antes del envío.

Exclusiones V1: Solicitudes condicionales, _history a nivel de sistema, URLs absolutas y URLs $operation dentro de las entradas del Bundle no son compatibles.

Historial en Bundles: vread (Resource/id/_history/vid), historial de instancia (Resource/id/_history) e historial de tipo (Resource/_history) se permiten en Bundles cuando el servidor anuncia la interacción correspondiente y los ámbitos lo permiten. Estas cuentan como entradas de lectura.

Metadatos y Control de Ámbitos

A menos que FHIR_METADATA_MODE=off, fhirHydrant obtiene el CapabilityStatement del servidor FHIR al inicio. En modo strict:

  • Las herramientas de recursos se registran solo cuando el tipo de recurso está presente en /metadata
  • Los controles de búsqueda del lado del servidor como _count, _sort, _summary, _elements, _include y _revinclude se exponen solo cuando se anuncian
  • Los parámetros de búsqueda se bloquean cuando el servidor no los anuncia
  • Las acciones de escritura requieren tanto FHIR_WRITE_CAPABILITIES como interacciones coincidentes en el CapabilityStatement
  • Las operaciones nombradas requieren que exista el tipo de recurso objetivo, que el ámbito SMART otorgado permita el recurso y que la operación en sí se anuncie en la entrada del CapabilityStatement del recurso

En modo warn, los parámetros no anunciados se permiten con una advertencia, pero los tipos de recursos ausentes aún se omiten. Los ámbitos SMART también se verifican en tiempo de ejecución, por lo que una herramienta puede existir en el esquema y aún así estar bloqueada por el ámbito del token otorgado.

Economía de Tokens y Forma de Respuestas

Las respuestas FHIR suelen ser mucho más grandes de lo que un cliente MCP necesita. fhirHydrant da forma a las respuestas para la economía de tokens después de la recuperación, usando controles del lado del servidor cuando el servidor FHIR los anuncia.

CaracterísticaComportamiento
_count predeterminado/límiteNo se inyecta _count por defecto (el servidor decide el tamaño de página). Establece FHIR_DEFAULT_COUNT para inyectar uno; FHIR_MAX_COUNT limita los valores explícitos del llamador (0 = sin límite)
Coalescencia de páginasCuando el modo compacto está activo, el servidor obtiene múltiples páginas ascendentes secuencialmente, compacta cada una inmediatamente y devuelve un Bundle consolidado. Controlado por las variables de entorno maxResults, prefetch y FHIR_PREFETCH_*
Límite de bytesFHIR_MAX_RESPONSE_BYTES limita cada respuesta JSON orientada al modelo; los Bundles sobredimensionados se dividen en fragmentos de forma transparente
Reintento automáticoLos Bundles de búsqueda sobredimensionados intentan primero la fragmentación local, luego reintentan con un _count más pequeño como respaldo
FHIRPathfhirpath filtra el JSON FHIR devuelto localmente y devuelve los nodos coincidentes como un arreglo
Modo compactoresponseMode=compact elimina el ruido común del sobre FHIR y simplifica los tipos de datos
Modo completoresponseMode=full devuelve el JSON FHIR sin procesar
Compacto bloqueadoFHIR_RESPONSE_MODE=compact-locked oculta responseMode del esquema de la herramienta
Artefactos nativosLas respuestas que no son JSON (documentos, imágenes, DICOM, RTF, HTML, XML, CSV, NDJSON, ZIP, octet-stream) y los FHIR Binary JSON se normalizan en un sobre de metadatos más un recurso MCP de texto/blob incrustado. Limitado por FHIR_MAX_ARTIFACT_MB (no el límite JSON), nunca fragmentado y nunca pasado por FHIRPath/compactación/coalescencia. Los argumentos de modelado solo JSON se ignoran con una nota

La salida compacta es JSON orientado a IA, no FHIR canónico. Elimina o simplifica el ruido FHIR y los tipos de datos comunes como meta, narrativa, extensiones, CodeableConcept, Reference, Quantity y tipos de datos más nuevos como CodeableReference. FHIRPath se ejecuta localmente; el servidor FHIR nunca ve la expresión. Si la evaluación falla, la respuesta sin procesar se retiene y se devuelve un error.

Sobre de respuesta estructurado

Cada herramienta de datos FHIR (herramientas de recursos, paginate, operate, bundle, system_history) devuelve un único sobre estructurado, anunciado a través de cada outputSchema de la herramienta y devuelto como structuredContent (el contenido de texto es el mismo sobre serializado). Lleva la carga útil FHIR (data) más metadatos: modo de respuesta, una señal de paginación hasMore/continuation, estadísticas de Bundle y coalescencia, y notes legible por humanos. La lista completa de campos es el outputSchema de la herramienta.

Las respuestas sobredimensionadas se fragmentan cuando es posible (data conservado, recuperable a través de continuation); si no se pueden fragmentar, el sobre se marca como status: "truncated" con data omitido. La truncación es un resultado exitoso pero parcial, no un error. Las herramientas de capacidades y terminología devuelven sus propias formas estructuradas en lugar de este sobre FHIR.

Coalescencia de páginas

Cuando el modo compacto está activo para una búsqueda (herramientas de recursos o paginación), el servidor obtiene múltiples páginas FHIR ascendentes secuencialmente, compacta cada página inmediatamente y devuelve un Bundle compacto consolidado. Esto reduce los viajes de ida y vuelta de MCP de muchas llamadas de "siguiente página" a una sola.

  • maxResults establece un objetivo: el servidor deja de obtener una vez que se cruza este umbral (puede excederse ligeramente ya que se agregan páginas completas)
  • prefetch=false desactiva la coalescencia para una llamada
  • _count aún controla el tamaño de página FHIR ascendente
  • La coalescencia se detiene en límites configurables de página, entrada, byte y tiempo
  • continuation.url apunta a dónde se detuvo el servidor; llama a paginate con responseMode=compact para continuar (hasMore indica que quedan más)
  • Las solicitudes filtradas por FHIRPath permanecen en una sola página (sin coalescencia)
  • responseMode=full siempre devuelve una única página ascendente

Eventos de auditoría

Establece FHIR_AUDIT_SINK a cualquier combinación de console, file y http.

El sumidero http publica cada evento de auditoría a un recolector externo, SIEM o repositorio de auditoría FHIR (no el propio servidor FHIR). Establece FHIR_AUDIT_HTTP_URL al destino y FHIR_AUDIT_HTTP_FORMAT a raw (el JSON de auditoría interno ligero en PHI, para recolectores genéricos como Splunk HEC o Datadog) o fhir-auditevent (un recurso FHIR R4 AuditEvent mínimo, adecuado para repositorios de auditoría estilo ATNA y nativos de FHIR). El mapeo fhir-auditevent es intencionalmente ligero: no es un perfil de cumplimiento ATNA/BALP completo. Un valor opcional FHIR_AUDIT_HTTP_AUTH se envía textualmente como el encabezado Authorization. La entrega es de tipo "dispara y olvida" con un tiempo de espera de 5 s; los fallos de transporte se registran y nunca afectan las respuestas de las herramientas.

Los eventos de auditoría incluyen marca de tiempo, herramienta, tipo de recurso cuando corresponde, operación, estado, duración, tamaño de respuesta, resumen de paginación, ID de solicitud y usuario opcional autenticado por proxy. No incluyen contenido de recursos FHIR por defecto.

Cuando se ejecuta detrás de un proxy autenticador, establece FHIR_AUDIT_USER_HEADER al encabezado de identidad de confianza inyectado por ese proxy:

Encabezados comunes: Azure EasyAuth X-MS-CLIENT-PRINCIPAL-NAME, OAuth2 Proxy X-Auth-Request-Email, Cloudflare Access Cf-Access-Authenticated-User-Email.

Usa esto solo cuando el proxy elimina o sobrescribe las copias entrantes de ese encabezado. De lo contrario, los clientes pueden falsificar usuarios de auditoría arbitrarios.

Autenticación SMART Backend y claves

fhirHydrant usa SMART Backend Services: credenciales de cliente más una aserción JWT firmada. Esto es acceso FHIR de backend, no un lanzamiento independiente SMART basado en navegador; no hay flujo de redirección/inicio de sesión interactivo en la ruta MCP.

FHIR_ACTIVE_KEY contiene la clave de firma PKCS#8 sin procesar (RSA, firmada RS384, o EC P-384, firmada ES384). En modo HTTP, el endpoint integrado /jwks expone claves públicas para la clave activa más cualquier clave retirada cuando FHIR_JWKS_URL no está establecido. El kid para cada clave se deriva automáticamente mediante una huella digital JWK RFC 7638 truncada (primeros 12 caracteres base64url de SHA-256 sobre los miembros públicos JWK canónicos) y se registra al inicio.

Flujo de rotación de claves:

  1. Genera una nueva clave (RSA-2048 o EC P-384).
  2. Agrega el nuevo PEM a FHIR_RETIRED_KEYS y vuelve a implementar para que JWKS incluya ambos.
  3. Registra el nuevo kid (registrado al inicio) con tu servidor de autenticación.
  4. Mueve el nuevo PEM a FHIR_ACTIVE_KEY y mueve el PEM antiguo a FHIR_RETIRED_KEYS. Vuelve a implementar.
  5. Después de que expiren los cachés del servidor de autenticación, elimina la clave antigua de FHIR_RETIRED_KEYS.

Si usas JWKS externo, publica la nueva clave pública antes de cambiar FHIR_ACTIVE_KEY.

Variables de entorno

Consulta .env.example para una muestra completa.

Requeridas

VariableDescripción
FHIR_BASE_URLURL base utilizada para derivar la URL del servidor FHIR y la URL del token. Opcional cuando FHIR_SERVER_URL está establecido (y, para autenticación smart, FHIR_TOKEN_URL)
FHIR_CLIENT_IDID de cliente SMART Backend Services (no necesario cuando FHIR_AUTH=none)
FHIR_ACTIVE_KEYClave de firma PEM PKCS#8 codificada en base64, RSA o EC P-384 (no necesaria cuando FHIR_AUTH=none)

Opcionales

VariablePredeterminadoDescripción
FHIR_AUTHsmartsmart (SMART Backend Services) o none (sin autenticación, para endpoints de prueba públicos)
FHIR_RETIRED_KEYSsin establecerPEMs codificados en base64 separados por comas para rotación JWKS
FHIR_VERSIONR4Versión FHIR R4+ activa; controla la URL derivada, el modelo FHIRPath y los metadatos del modelo compacto
FHIR_SERVER_URL<base>/api/FHIR/<FHIR_VERSION>Anulación explícita de la URL de la API FHIR
FHIR_TOKEN_URL<base>/oauth2/tokenAnulación explícita del endpoint de token
FHIR_JWKS_URLsin establecerURL JWKS externa. Omite en modo HTTP para habilitar /jwks integrado
MCP_TRANSPORThttphttp o stdio
PORT5000Puerto del listener HTTP
BIND_HOST0.0.0.0 (o 127.0.0.1 con la bandera --dev)Dirección de enlace HTTP
ALLOWED_HOSTSsin establecerNombres de host separados por comas para protección contra rebinding DNS
FHIR_METADATA_MODEstrictstrict, warn o off para validación de /metadata
FHIR_DEFAULT_COUNT0_count predeterminado inyectado en búsquedas cuando está permitido; 0 = el servidor decide
FHIR_MAX_COUNT0Límite en valores explícitos de _count del llamador; 0 = sin límite
FHIR_MAX_RESPONSE_BYTES262144Límite de bytes para respuestas JSON orientadas al modelo; los Bundles sobredimensionados se fragmentan
FHIR_MAX_ARTIFACT_MB16Techo de bytes separado (MiB) para cuerpos de artefactos nativos/binarios; independiente del límite JSON (transporte base64 ≈ +33%)
FHIR_REQUEST_TIMEOUT_MS30000Tiempo de espera por intento para solicitudes FHIR salientes
MCP_JSON_LIMIT4mbTamaño máximo aceptado del cuerpo de solicitud MCP (cadena de límite json de Express); aumenta si se rechazan cargas útiles grandes de escritura/bundle
MCP_AUTHZnoneProveedor de autorización: none o entra. Controla las herramientas por llamador (solo HTTP + Authorization: Bearer)
MCP_ROLE_PREFIXFhirHydrantPrefijo en valores de rol otorgados (p. ej., FhirHydrant.Patient.Read)
MCP_ENTRA_TENANT_IDsin establecerGUID de tenant de Entra (no un alias de dominio); requerido cuando MCP_AUTHZ=entra
MCP_ENTRA_AUDIENCEsin establecerID de aplicación (cliente) de API esperado en el aud del token de acceso v2; requerido cuando MCP_AUTHZ=entra
FHIR_RESPONSE_MODEsin establecercompact, full o compact-locked; sin establecer significa que las búsquedas usan compacto por defecto y las lecturas directas usan completo por defecto
FHIR_WRITE_CAPABILITIESsin establecerAcciones de escritura separadas por comas: create, update, patch, delete
FHIR_VALIDATE_WRITESlocaloff, local (verificaciones estructurales del lado del cliente) o server (verificación previa local + servidor $validate para crear/actualizar)
FHIR_WRITE_DRY_RUNfalseEstablece a true para validar y registrar escrituras sin ejecutarlas contra el servidor FHIR
FHIR_BUNDLE_CAPABILITIESsin establecerTipos de Bundle separados por comas: batch, transaction; habilita la herramienta bundle
FHIR_BUNDLE_WRITES_ENABLEDfalseEstablece a true para permitir entradas de escritura dentro de Bundles (también requiere FHIR_WRITE_CAPABILITIES)
FHIR_OPERATIONSsin establecerClaves de operación separadas por comas; none desactiva todas las operaciones de catálogo. Catálogo predeterminado: everything, lastn, validate, docref, expand, lookup, translate, summary, match
FHIR_TERMINOLOGY_BASE_URLsin establecerHabilita herramientas de terminología, p. ej., https://tx.fhir.org/r4
FHIR_PAGINATION_PATHSsin establecerPrefijos de ruta adicionales permitidos para enlaces de paginación, p. ej., FHIRProxy
FHIR_PREFETCH_MAX_PAGES5Máximo de páginas ascendentes obtenidas por búsqueda compacta coalescida
FHIR_PREFETCH_MAX_ENTRIES5000Máximo de entradas ascendentes acumuladas antes de detenerse
FHIR_PREFETCH_MAX_BYTES2097152Máximo de bytes sin procesar obtenidos antes de detenerse
FHIR_PREFETCH_TIMEOUT_MS25000Presupuesto de tiempo de reloj para el bucle de coalescencia
FHIR_AUDIT_SINKsin establecerCualquier combinación de console, file, http
FHIR_AUDIT_FILE./audit.jsonlArchivo JSONL utilizado cuando el sumidero de auditoría file está habilitado
FHIR_AUDIT_HTTP_URLsin establecerURL de destino para el sumidero de auditoría http; requerida cuando http está habilitado
FHIR_AUDIT_HTTP_FORMATrawraw (JSON de AuditEvent interno) o fhir-auditevent (FHIR R4 AuditEvent)
FHIR_AUDIT_HTTP_AUTHsin establecerValor del encabezado de autorización enviado textualmente por el sumidero http
FHIR_AUDIT_USER_HEADERsin establecerEncabezado de usuario autenticado por proxy copiado en eventos de auditoría
LOG_LEVELinfoVerbosidad de registro: error, warn, info o debug
Los valores explícitos de FHIR_SERVER_URL y FHIR_TOKEN_URL siempre tienen prioridad sobre las URLs derivadas.

Soporte de Versiones FHIR

Establezca FHIR_VERSION para seleccionar la versión activa de FHIR R4+. Esto controla la URL derivada de la API FHIR, el contexto del modelo FHIRPath y los metadatos del modelo de respuesta compacto. Algunas versiones pueden usar el modelo FHIRPath compatible más cercano. Para terminología, use un endpoint que coincida con la versión FHIR seleccionada. Los registros de inicio sugieren cuándo las URLs explícitas de FHIR o terminología parecen referenciar una versión diferente.

Personalización de Herramientas y Mensajes

Todo bajo config/ es personalizable sin cambios en el código fuente.

La configuración se resuelve como una superposición parcial: para cada archivo, un ./config/<file> en el directorio de trabajo actual (si está presente) anula el valor predeterminado empaquetado, y cualquier cosa que omita vuelve al valor predeterminado integrado. Así, las instalaciones de npm funcionan de inmediato, y para personalizar, coloque una carpeta ./config junto a donde inicia el servidor que contenga solo los archivos que desea cambiar.

Hay dos granularidades de superposición:

  • Archivo completo (resources/*.json, operations.json, search-controls.json, core-tools.json, instructions/*): un archivo que proporcione reemplaza completamente el archivo empaquetado. Un nuevo archivo de recurso (por ejemplo, ./config/resources/myresource.json) agrega una herramienta. La superposición puede anular y agregar, pero no puede eliminar un recurso empaquetado — para enviar un catálogo estrictamente mínimo, elimine los archivos config/resources/ empaquetados (vea el ejemplo de compose).
  • Por clave (messages/*.json): un archivo local anula solo las claves individuales que contiene; cada otra clave vuelve al valor predeterminado empaquetado. Así puede ajustar una sola descripción o mensaje sin copiar todo el archivo. Claves desconocidas, valores vacíos y JSON malformado fallan rápidamente al inicio para detectar errores tipográficos.

Los archivos messages/*.json se leen una vez al inicio del proceso. Cambiarlos requiere un reinicio del servidor (y, para esquemas de herramientas o instrucciones, una reconexión del cliente) para que surtan efecto. La recarga en caliente de desarrollo para recursos, controles de búsqueda y operaciones se describe a continuación.

ArchivoPropósito
resources/*.jsonHerramientas de recursos FHIR (un archivo por recurso): parámetros de búsqueda, comportamiento de lectura directa y reglas de requireOneOf
operations.jsonCatálogo de operaciones nombradas para operate (descripciones y notas por operación)
search-controls.jsonDescripciones para _count, _sort, _summary, _elements, _include, _revinclude, _lastUpdated, fhirpath, responseMode, maxResults y prefetch
messages/output-schema.jsonDescripciones para cada campo outputSchema de herramienta (superposición por clave)
messages/input-schema.jsonDescripciones para parámetros de entrada de recursos generados (_id, _vid, _since, _at, action, body) y el título y parámetros de la herramienta operate (superposición por clave)
instructions/manifest.jsonLista ordenada de fragmentos de instrucciones para componer, cada uno con una puerta when opcional (terminology, writes, operations, bundle). Las compilaciones personalizadas reordenan, agregan o eliminan secciones editando este archivo.
instructions/*.mdFragmentos de instrucciones referenciados por el manifiesto. Las secciones con puerta se incluyen solo cuando su característica está habilitada; el token {{OPERATIONS_LIST}} se reemplaza con el catálogo de operaciones en vivo.
messages/*.jsonMensajes orientados al usuario, errores y notas de respuesta (superposición por clave, divididos por dominio: núcleo, escritura, operaciones, terminología, lote, artefacto)
core-tools.jsonDescripciones de herramientas integradas y sugerencias de parámetros

Esquema de Definición de Recursos

Cada archivo en config/resources/ es un objeto de definición de recurso único. Los archivos se escanean en orden de nombre de archivo; el nombre de archivo es convencionalmente el nombre del recurso en minúsculas (por ejemplo, patient.json). Cada objeto tiene estos campos:

CampoTipoDescripción
resourcestringTipo de recurso FHIR
toolNamestringNombre de la herramienta MCP; debe ser único
descriptionstringDescripción de la herramienta
supportsDirectReadbooleanHabilita GET /ResourceType/{id} mediante _id
searchParamsRecord<string,string>Parámetros de búsqueda FHIR y descripciones
requireOneOf(string | string[])[]La búsqueda requiere al menos una opción. Una cadena es un parámetro requerido único; una matriz anidada es un conjunto de parámetros donde cada parámetro es requerido. ["patient"] acepta patient; [["given","family"],["identifier"]] acepta given+family juntos, o identifier

Los valores de searchParams son descripciones, no un modelo completo de capacidades FHIR. El comportamiento de búsqueda específico del servidor aún puede aplicarse.

Recarga en Caliente

En desarrollo (NODE_ENV no es production), la carpeta config/resources/, search-controls.json y operations.json se observan. El JSON inválido mantiene la última instantánea válida. Una recarga materialmente cambiada se aplica transaccionalmente: cuando los alcances SMART derivados cambian, se adquiere un token de reemplazo antes de que se confirmen las nuevas definiciones y registros de herramientas, por lo que una adquisición fallida deja el catálogo en ejecución intacto. Agregar/eliminar herramientas, cambios de esquema de operaciones y nombres de parámetros se vuelven a registrar en vivo — sin necesidad de reinicio. Los guardados semánticamente sin cambios no causan actualización. La producción lee la configuración una vez al inicio, pero un cambio de /metadata en tiempo de ejecución (mediante capabilities(refresh=true)) o un cambio de alcance SMART del backend en la actualización de token re-evalúa las herramientas disponibles en cada modo.

Un límite es inevitable: la lista de herramientas y los esquemas se actualizan en caliente, pero los instructions del servidor se envían una vez durante initialize de MCP y no se pueden reemplazar en una conexión existente. Un cliente debe reconectarse/reinicializarse para recibir texto de instrucciones cambiado.

Transportes

Stdio

Establezca MCP_TRANSPORT=stdio. stdout está reservado para el protocolo MCP; los registros se redirigen a stderr. Use un FHIR_JWKS_URL externo para implementaciones stdio.

HTTP Transmisible

El transporte HTTP no tiene estado y expone MCP en:

POST http://localhost:5000/mcp
Accept: application/json, text/event-stream
Content-Type: application/json

Configuración del cliente MCP:

{
   "mcpServers": {
      "fhirhydrant": {
         "url": "http://localhost:5000/mcp"
      }
   }
}

GET /health devuelve una instantánea de preparación sin PHI:

{
   "status": "ok",
   "mcp": true,
   "metadata": true,
   "tools": 23,
   "auth": true,
   "tokenExpiresIn": 287
}

Cuando la autorización está habilitada, authz informa el proveedor activo y tools se omite porque el recuento de herramientas registradas es específico del llamante.

Use un proxy inverso para TLS y autenticación de usuarios al exponer HTTP más allá de localhost. Establezca ALLOWED_HOSTS al enlazar a una interfaz pública.

Autorización por llamante (Entra, opcional)

De forma predeterminada (MCP_AUTHZ=none), cada llamante ve el conjunto completo de herramientas limitado solo por /metadata y los alcances SMART del backend. Establecer MCP_AUTHZ=entra agrega una capa opcional por llamante: cada solicitud /mcp debe llevar un Authorization: Bearer <token> emitido por Microsoft Entra, y los Roles de Aplicación del llamante determinan qué herramientas se construyen para esa solicitud. Esto es solo autorización a nivel de MCP — nunca reemplaza la autorización propia del servidor FHIR, y solo puede restar de lo que el token SMART del backend y la configuración ya permiten.

El registro de la aplicación API debe establecer requestedAccessTokenVersion a 2 en su manifiesto. El proveedor valida emisores v2 específicos del inquilino y espera que MCP_ENTRA_AUDIENCE sea el ID de cliente de la aplicación API.

Las herramientas para las que un llamante no tiene un rol no se registran en absoluto — están ausentes de tools/list, no solo bloqueadas. Las herramientas auxiliares (capabilities, paginate, terminology_lookup, code_search) nunca están limitadas por roles.

Valores de Roles de Aplicación (con el prefijo predeterminado FhirHydrant):

RolOtorga
FhirHydrant.<Resource>.Readbúsqueda, lectura, vread, historial para ese recurso
FhirHydrant.<Resource>.Writeacciones de lectura más crear, actualizar, parchear, eliminar (sujeto a FHIR_WRITE_CAPABILITIES)
FhirHydrant.Operation.<key>la operación nombrada mediante la herramienta operate (por ejemplo, FhirHydrant.Operation.everything)
FhirHydrant.Bundlela herramienta bundle
FhirHydrant.SystemHistory.Readla herramienta system_history a nivel de sistema
FhirHydrant.Admintodo lo anterior, aún limitado por alcances SMART del backend, /metadata y configuración de escritura/lote/operaciones

Requiere transporte HTTP; MCP_AUTHZ=entra con MCP_TRANSPORT=stdio falla al inicio. Los tokens de portador faltantes o inválidos reciben 401.

Agregar un proveedor de autorización

Entra es el único proveedor incluido, pero la capa de autorización es neutral respecto al proveedor. Esta es una extensión de código fuente, no un complemento en tiempo de ejecución: el paquete npm incluye solo bin/server.js (los proveedores están integrados), por lo que agregar uno significa bifurcar o clonar el repositorio y recompilar.

La canalización compartida es agnóstica al proveedor — un proveedor solo mapea un encabezado Authorization a { subject, roles }. El vocabulario de roles (.Read/.Write/Operation.<key>/Bundle/SystemHistory.Read/Admin) y el manejo de MCP_ROLE_PREFIX son aplicados por decideAuthz para cada proveedor.

Para agregar uno (por ejemplo, auth0) solo se necesitan dos ediciones:

  1. Cree ts/mcp/authz/auth0.ts exportando un AuthzProvider — implemente validate(authorization) para devolver { subject, roles } (lance para rechazar), y opcionalmente validateConfig() para fallar rápidamente si falta el entorno del proveedor. Mantenga todo el entorno específico del proveedor dentro de este módulo; no agregue campos a Config.
  2. Agregue una entrada a ts/mcp/authz/registry.ts: auth0: () => import("./auth0.ts").then((m) => m.auth0Provider).

Eso es todo. El tipo AuthzMode, el analizador MCP_AUTHZ y su mensaje de error se derivan automáticamente de las claves del registro, por lo que MCP_AUTHZ=auth0 simplemente funciona con seguridad de tipos completa — ningún otro archivo necesita cambiar.

Ejemplos de Implementación

El directorio examples/ tiene ejemplos de implementación independientes para Docker Compose, proxy inverso (Caddy), Azure Container Apps, Azure App Service y Kubernetes. Cada uno incluye un Dockerfile que instala desde npm y una superposición config/ que demuestra cómo anular diferentes archivos de configuración.

Desarrollo

# dev server
npm run dev

# type-check
npm run check

# build and run
npm run build
npm start

La salida de compilación va a bin/server.js.