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,
_county 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
- Herramientas
- Metadatos y Control de Ámbitos
- Economía de Tokens y Forma de Respuestas
- Eventos de Auditoría
- Autenticación SMART Backend y Claves
- Variables de Entorno
- Soporte de Versiones FHIR
- Personalización de Herramientas y Mensajes
- Transportes
- Ejemplos de Despliegue
- Desarrollo
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 familia | Disponible cuando | Propósito |
|---|---|---|
| Herramientas de recursos | El recurso está configurado y permitido por metadatos/ámbitos | Búsqueda, lectura directa, vread, historial y opcionalmente CRUD de recursos FHIR |
system_history | El servidor anuncia interacción de sistema history y los ámbitos lo permiten | Recuperar el historial de cambios a nivel de sistema en todos los tipos de recursos |
capabilities | Siempre registrada | Inspeccionar resumen de CapabilityStatement, herramientas registradas, herramientas omitidas, parámetros de búsqueda, operaciones y notas de metadatos |
paginate | Siempre registrada | Obtener la siguiente página de un Bundle FHIR usando una URL next devuelta por el servidor |
operate | Al menos una operación nombrada pasa el control | Invocar operaciones nombradas FHIR configuradas para datos clínicos, terminología, IPS, coincidencia, validación o flujos de trabajo personalizados |
bundle | FHIR_BUNDLE_CAPABILITIES está establecido | Enviar un Bundle de lote o transacción FHIR; las escrituras requieren aceptación adicional |
terminology_lookup | FHIR_TERMINOLOGY_BASE_URL está establecido | Buscar un código LOINC o SNOMED CT |
code_search | FHIR_TERMINOLOGY_BASE_URL está establecido | Buscar 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ón | Parámetros requeridos | Llamada FHIR |
|---|---|---|
vread | _id, _vid | GET /ResourceType/{id}/_history/{vid} |
history | _id (instancia) o ninguno (tipo) | GET /ResourceType/{id}/_history o GET /ResourceType/_history |
create | body | POST /ResourceType |
update | _id, body | PUT /ResourceType/{id} |
patch | _id, body | PATCH /ResourceType/{id} con JSON Patch |
delete | _id | DELETE /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:
| Herramienta | Descripción |
|---|---|
terminology_lookup | Busca un código LOINC o SNOMED CT |
code_search | Busca 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=truey la acción correspondiente enFHIR_WRITE_CAPABILITIES. - Los Bundles de transacción requieren
FHIR_BUNDLE_CAPABILITIES=transactionexplí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,_includey_revincludese 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_CAPABILITIEScomo 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ística | Comportamiento |
|---|---|
_count predeterminado/límite | No 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áginas | Cuando 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 bytes | FHIR_MAX_RESPONSE_BYTES limita cada respuesta JSON orientada al modelo; los Bundles sobredimensionados se dividen en fragmentos de forma transparente |
| Reintento automático | Los Bundles de búsqueda sobredimensionados intentan primero la fragmentación local, luego reintentan con un _count más pequeño como respaldo |
| FHIRPath | fhirpath filtra el JSON FHIR devuelto localmente y devuelve los nodos coincidentes como un arreglo |
| Modo compacto | responseMode=compact elimina el ruido común del sobre FHIR y simplifica los tipos de datos |
| Modo completo | responseMode=full devuelve el JSON FHIR sin procesar |
| Compacto bloqueado | FHIR_RESPONSE_MODE=compact-locked oculta responseMode del esquema de la herramienta |
| Artefactos nativos | Las 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.
maxResultsestablece 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=falsedesactiva la coalescencia para una llamada_countaú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.urlapunta a dónde se detuvo el servidor; llama apaginateconresponseMode=compactpara continuar (hasMoreindica que quedan más)- Las solicitudes filtradas por FHIRPath permanecen en una sola página (sin coalescencia)
responseMode=fullsiempre 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:
- Genera una nueva clave (RSA-2048 o EC P-384).
- Agrega el nuevo PEM a
FHIR_RETIRED_KEYSy vuelve a implementar para que JWKS incluya ambos. - Registra el nuevo kid (registrado al inicio) con tu servidor de autenticación.
- Mueve el nuevo PEM a
FHIR_ACTIVE_KEYy mueve el PEM antiguo aFHIR_RETIRED_KEYS. Vuelve a implementar. - 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
| Variable | Descripción |
|---|---|
FHIR_BASE_URL | URL 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_ID | ID de cliente SMART Backend Services (no necesario cuando FHIR_AUTH=none) |
FHIR_ACTIVE_KEY | Clave de firma PEM PKCS#8 codificada en base64, RSA o EC P-384 (no necesaria cuando FHIR_AUTH=none) |
Opcionales
| Variable | Predeterminado | Descripción |
|---|---|---|
FHIR_AUTH | smart | smart (SMART Backend Services) o none (sin autenticación, para endpoints de prueba públicos) |
FHIR_RETIRED_KEYS | sin establecer | PEMs codificados en base64 separados por comas para rotación JWKS |
FHIR_VERSION | R4 | Versió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/token | Anulación explícita del endpoint de token |
FHIR_JWKS_URL | sin establecer | URL JWKS externa. Omite en modo HTTP para habilitar /jwks integrado |
MCP_TRANSPORT | http | http o stdio |
PORT | 5000 | Puerto del listener HTTP |
BIND_HOST | 0.0.0.0 (o 127.0.0.1 con la bandera --dev) | Dirección de enlace HTTP |
ALLOWED_HOSTS | sin establecer | Nombres de host separados por comas para protección contra rebinding DNS |
FHIR_METADATA_MODE | strict | strict, warn o off para validación de /metadata |
FHIR_DEFAULT_COUNT | 0 | _count predeterminado inyectado en búsquedas cuando está permitido; 0 = el servidor decide |
FHIR_MAX_COUNT | 0 | Límite en valores explícitos de _count del llamador; 0 = sin límite |
FHIR_MAX_RESPONSE_BYTES | 262144 | Límite de bytes para respuestas JSON orientadas al modelo; los Bundles sobredimensionados se fragmentan |
FHIR_MAX_ARTIFACT_MB | 16 | Techo de bytes separado (MiB) para cuerpos de artefactos nativos/binarios; independiente del límite JSON (transporte base64 ≈ +33%) |
FHIR_REQUEST_TIMEOUT_MS | 30000 | Tiempo de espera por intento para solicitudes FHIR salientes |
MCP_JSON_LIMIT | 4mb | Tamañ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_AUTHZ | none | Proveedor de autorización: none o entra. Controla las herramientas por llamador (solo HTTP + Authorization: Bearer) |
MCP_ROLE_PREFIX | FhirHydrant | Prefijo en valores de rol otorgados (p. ej., FhirHydrant.Patient.Read) |
MCP_ENTRA_TENANT_ID | sin establecer | GUID de tenant de Entra (no un alias de dominio); requerido cuando MCP_AUTHZ=entra |
MCP_ENTRA_AUDIENCE | sin establecer | ID de aplicación (cliente) de API esperado en el aud del token de acceso v2; requerido cuando MCP_AUTHZ=entra |
FHIR_RESPONSE_MODE | sin establecer | compact, 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_CAPABILITIES | sin establecer | Acciones de escritura separadas por comas: create, update, patch, delete |
FHIR_VALIDATE_WRITES | local | off, local (verificaciones estructurales del lado del cliente) o server (verificación previa local + servidor $validate para crear/actualizar) |
FHIR_WRITE_DRY_RUN | false | Establece a true para validar y registrar escrituras sin ejecutarlas contra el servidor FHIR |
FHIR_BUNDLE_CAPABILITIES | sin establecer | Tipos de Bundle separados por comas: batch, transaction; habilita la herramienta bundle |
FHIR_BUNDLE_WRITES_ENABLED | false | Establece a true para permitir entradas de escritura dentro de Bundles (también requiere FHIR_WRITE_CAPABILITIES) |
FHIR_OPERATIONS | sin establecer | Claves 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_URL | sin establecer | Habilita herramientas de terminología, p. ej., https://tx.fhir.org/r4 |
FHIR_PAGINATION_PATHS | sin establecer | Prefijos de ruta adicionales permitidos para enlaces de paginación, p. ej., FHIRProxy |
FHIR_PREFETCH_MAX_PAGES | 5 | Máximo de páginas ascendentes obtenidas por búsqueda compacta coalescida |
FHIR_PREFETCH_MAX_ENTRIES | 5000 | Máximo de entradas ascendentes acumuladas antes de detenerse |
FHIR_PREFETCH_MAX_BYTES | 2097152 | Máximo de bytes sin procesar obtenidos antes de detenerse |
FHIR_PREFETCH_TIMEOUT_MS | 25000 | Presupuesto de tiempo de reloj para el bucle de coalescencia |
FHIR_AUDIT_SINK | sin establecer | Cualquier combinación de console, file, http |
FHIR_AUDIT_FILE | ./audit.jsonl | Archivo JSONL utilizado cuando el sumidero de auditoría file está habilitado |
FHIR_AUDIT_HTTP_URL | sin establecer | URL de destino para el sumidero de auditoría http; requerida cuando http está habilitado |
FHIR_AUDIT_HTTP_FORMAT | raw | raw (JSON de AuditEvent interno) o fhir-auditevent (FHIR R4 AuditEvent) |
FHIR_AUDIT_HTTP_AUTH | sin establecer | Valor del encabezado de autorización enviado textualmente por el sumidero http |
FHIR_AUDIT_USER_HEADER | sin establecer | Encabezado de usuario autenticado por proxy copiado en eventos de auditoría |
LOG_LEVEL | info | Verbosidad 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 archivosconfig/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.
| Archivo | Propósito |
|---|---|
resources/*.json | Herramientas de recursos FHIR (un archivo por recurso): parámetros de búsqueda, comportamiento de lectura directa y reglas de requireOneOf |
operations.json | Catálogo de operaciones nombradas para operate (descripciones y notas por operación) |
search-controls.json | Descripciones para _count, _sort, _summary, _elements, _include, _revinclude, _lastUpdated, fhirpath, responseMode, maxResults y prefetch |
messages/output-schema.json | Descripciones para cada campo outputSchema de herramienta (superposición por clave) |
messages/input-schema.json | Descripciones 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.json | Lista 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/*.md | Fragmentos 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/*.json | Mensajes 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.json | Descripciones 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:
| Campo | Tipo | Descripción |
|---|---|---|
resource | string | Tipo de recurso FHIR |
toolName | string | Nombre de la herramienta MCP; debe ser único |
description | string | Descripción de la herramienta |
supportsDirectRead | boolean | Habilita GET /ResourceType/{id} mediante _id |
searchParams | Record<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):
| Rol | Otorga |
|---|---|
FhirHydrant.<Resource>.Read | búsqueda, lectura, vread, historial para ese recurso |
FhirHydrant.<Resource>.Write | acciones 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.Bundle | la herramienta bundle |
FhirHydrant.SystemHistory.Read | la herramienta system_history a nivel de sistema |
FhirHydrant.Admin | todo 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:
- Cree
ts/mcp/authz/auth0.tsexportando unAuthzProvider— implementevalidate(authorization)para devolver{ subject, roles }(lance para rechazar), y opcionalmentevalidateConfig()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 aConfig. - 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.