fhirHydrant MCP

Servidor FHIR MCP de código aberto em Node.js com SMART Backend Services, ferramentas de busca/CRUD cientes de metadados, respostas compactas, filtragem FHIRPath, paginação segura, eventos de auditoria e consulta de terminologia.

Documentação

fhirHydrant: Servidor MCP FHIR

Um servidor Node.js moderno, totalmente configurável e de código aberto para o Model Context Protocol (MCP) para APIs FHIR R4+. Ele conecta clientes de IA LLM compatíveis com MCP a dados clínicos por meio do SMART on FHIR v2 Backend Services usando credenciais de cliente JWT assinadas.

O fhirHydrant transforma recursos FHIR, operações nomeadas, consultas de terminologia e paginação em ferramentas MCP. Os recursos e operações padrão são pontos de partida: recursos, operações, controles de busca, instruções e mensagens podem ser expandidos, reduzidos ou substituídos por meio de arquivos de configuração sem alterações no código-fonte.

  • Autenticação SMART Backend Services com hospedagem JWKS, rotação de chaves, renovação de token e escopos dinâmicos
  • Ferramentas de recursos configuráveis para busca, leitura direta, vread, histórico e CRUD opcional controlado por metadados
  • Operações nomeadas orientadas por configuração para dados clínicos, terminologia, IPS, correspondência de pacientes, validação e fluxos de trabalho personalizados
  • Ferramentas cientes de CapabilityStatement, controles de busca, controle de operações e verificações de escopo em tempo de execução
  • Recursos de economia de tokens: respostas compactas, filtragem FHIRPath, limites de bytes, modelagem _count e nova tentativa de Bundle superdimensionado
  • Ferramentas de terminologia opcionais, eventos de auditoria leves em PHI (sem conteúdo de recurso por padrão) e transporte stdio ou HTTP Streamable

Observação: Os dados FHIR retornados por meio de chamadas de ferramentas MCP podem conter PHI. Certifique-se de que o armazenamento de transcrições e o comportamento de registro do seu cliente MCP estejam em conformidade com seus requisitos de conformidade.

Conteúdo

Início Rápido

Requisitos

  • Node.js >= 24
  • Um servidor FHIR compatível
  • Para autenticação SMART (padrão): um registro de cliente SMART Backend Services e uma chave privada RSA-2048 ou EC P-384 cuja chave pública esteja disponível por meio de JWKS

Para executar contra um servidor de teste FHIR público e não autenticado, defina FHIR_AUTH=none e ignore o cliente e a chave completamente (consulte Acesso Não Autenticado).

O transporte stdio geralmente precisa de uma URL JWKS hospedada externamente. O endpoint /jwks integrado está disponível apenas quando o fhirHydrant é executado por HTTP com autenticação SMART.

Instalação

# install globally
npm install -g fhirhydrant

# or run without installing
npx fhirhydrant

Execute a partir do código-fonte:

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

Configuração do Cliente MCP

Para clientes MCP de desktop, o stdio geralmente é o transporte mais simples:

{
   "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 é sua chave privada PKCS#8 (RSA ou EC P-384), codificada em base64. O kid é derivado automaticamente na inicialização por meio de um JWK Thumbprint truncado e registrado no console.

Acesso Não Autenticado

Para apontar o fhirHydrant para um endpoint FHIR público e não autenticado (útil para testes em sandboxes abertos), defina FHIR_AUTH=none. Nenhum ID de cliente ou chave de assinatura é necessário, nenhum token é solicitado e as solicitações são enviadas sem um cabeçalho Authorization:

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

Ferramentas

O fhirHydrant registra ferramentas a partir da configuração e verificações de capacidade em tempo de execução. A lista exata depende da pasta config/resources/, dos escopos SMART concedidos, do /metadata, das configurações de gravação, das configurações de operação e das configurações de terminologia.

Ferramenta ou famíliaDisponível quandoFinalidade
Ferramentas de recursosO recurso está configurado e permitido por metadados/escoposBusca, leitura direta, vread, histórico e, opcionalmente, CRUD de recursos FHIR
system_historyO servidor anuncia interação de sistema history e os escopos permitemRecuperar o histórico de alterações em nível de sistema em todos os tipos de recursos
capabilitiesSempre registradaInspecionar o resumo do CapabilityStatement, ferramentas registradas, ferramentas ignoradas, parâmetros de busca, operações e notas de metadados
paginateSempre registradaBuscar a próxima página de um Bundle FHIR usando uma URL next retornada pelo servidor
operatePelo menos uma operação nomeada passa no controleInvocar operações nomeadas FHIR configuradas para dados clínicos, terminologia, IPS, correspondência, validação ou fluxos de trabalho personalizados
bundleFHIR_BUNDLE_CAPABILITIES está definidoEnviar um Bundle de lote ou transação FHIR; gravações exigem aceitação adicional
terminology_lookupFHIR_TERMINOLOGY_BASE_URL está definidoConsultar um código LOINC ou SNOMED CT
code_searchFHIR_TERMINOLOGY_BASE_URL está definidoBuscar códigos LOINC ou SNOMED CT por texto

Ferramentas de Recursos

As ferramentas de recursos são geradas a partir da pasta config/resources/ — um arquivo JSON por recurso (por exemplo, patient.json), verificado na inicialização. A configuração fornecida cobre recursos clínicos, administrativos, de medicação, profissional, organização e documentos comuns. Adicione um arquivo para adicionar um recurso, ou exclua um para removê-lo — sem alterações no código-fonte.

Cada ferramenta de recurso suporta parâmetros de busca configurados, leituras diretas opcionais com _id, fhirpath e, a menos que bloqueado por compactação, responseMode. A leitura direta só acontece quando _id é o único argumento não vazio; _id mais outros parâmetros permanece uma busca para que a intenção do chamador não seja descartada silenciosamente.

As ferramentas de recursos são busca/leitura por padrão. Defina FHIR_WRITE_CAPABILITIES para habilitar ações CRUD controladas por metadados:

FHIR_WRITE_CAPABILITIES=create,update,patch,delete
AçãoParâmetros obrigatóriosChamada FHIR
vread_id, _vidGET /ResourceType/{id}/_history/{vid}
history_id (instância) ou nenhum (tipo)GET /ResourceType/{id}/_history ou GET /ResourceType/_history
createbodyPOST /ResourceType
update_id, bodyPUT /ResourceType/{id}
patch_id, bodyPATCH /ResourceType/{id} com JSON Patch
delete_idDELETE /ResourceType/{id}

vread está disponível quando o recurso tem supportsDirectRead e o servidor anuncia a interação vread. history está disponível quando o servidor anuncia history-instance ou history-type. Ambos exigem a permissão SMART r. Os parâmetros opcionais _since e _at filtram os resultados do histórico. As respostas de histórico são Bundles e suportam modo compacto, FHIRPath e coalescência.

Os corpos de gravação são validados antes da chamada FHIR: body.resourceType deve corresponder ao recurso da ferramenta, body.id deve corresponder a _id para atualização quando presente, e patch requer um array JSON Patch. Os escopos são derivados das capacidades habilitadas: leitura/busca usa system/Patient.rs, criação/leitura/busca usa system/Patient.crs e suporte completo a gravação usa system/Patient.cruds. O SMART v2 não tem uma letra separada para patch, então patch é mapeado para u.

Ferramentas Principais

capabilities retorna o resumo em cache do CapabilityStatement, ferramentas registradas e ignoradas, parâmetros de busca, operações e notas de metadados.

paginate busca uma página de Bundle usando uma URL next retornada pelo servidor, validada contra a origem FHIR e os prefixos de caminho permitidos. Quando o modo compacto está ativo e a página buscada tem mais resultados, a paginação coalesce automaticamente várias páginas upstream em uma resposta compacta (mesmo comportamento das ferramentas de busca de recursos). Passe prefetch=false para desabilitar a coalescência e obter uma única página.

Operações Nomeadas

A ferramenta operate invoca operações nomeadas FHIR de config/operations.json. O catálogo de operações fornecido cobre agregação clínica, validação, consulta de documentos, operações de terminologia, geração de IPS e correspondência de pacientes. Você pode expandir, reduzir, substituir ou desabilitar o catálogo de operações sem alterações no código-fonte.

Ferramentas de Terminologia

Defina FHIR_TERMINOLOGY_BASE_URL para habilitar:

FerramentaDescrição
terminology_lookupConsulta um código LOINC ou SNOMED CT
code_searchBusca códigos por filtro de texto com suporte a paginação

Essas ferramentas chamam o servidor de terminologia configurado diretamente. Elas não usam as credenciais do servidor FHIR clínico. Use um endpoint de terminologia que corresponda à sua versão FHIR selecionada, como https://tx.fhir.org/r4.

Execução de Bundle

Defina FHIR_BUNDLE_CAPABILITIES=batch (ou batch,transaction) para habilitar bundle. Esta ferramenta envia um Bundle de lote ou transação FHIR e retorna a resposta do servidor por meio do pipeline de resposta padrão.

Modelo de segurança:

  • Bundles de lote somente leitura (todas as entradas GET) são permitidos apenas com FHIR_BUNDLE_CAPABILITIES=batch.
  • Entradas de gravação (POST, PUT, PATCH, DELETE) adicionalmente exigem FHIR_BUNDLE_WRITES_ENABLED=true e a ação correspondente em FHIR_WRITE_CAPABILITIES.
  • Bundles de transação exigem FHIR_BUNDLE_CAPABILITIES=transaction explícito.
  • Cada entrada é pré-verificada em relação aos recursos configurados, escopos SMART e interações de metadados. Se qualquer entrada individual falhar, o Bundle inteiro é rejeitado antes do envio.

Exclusões V1: Solicitações condicionais, _history em nível de sistema, URLs absolutas e URLs $operation dentro de entradas de Bundle não são suportadas.

Histórico em Bundles: vread (Resource/id/_history/vid), histórico de instância (Resource/id/_history) e histórico de tipo (Resource/_history) são permitidos em Bundles quando o servidor anuncia a interação correspondente e os escopos permitem. Eles contam como entradas de leitura.

Metadados e Controle de Escopo

A menos que FHIR_METADATA_MODE=off, o fhirHydrant busca o CapabilityStatement do servidor FHIR na inicialização. No modo strict:

  • As ferramentas de recursos são registradas apenas quando o tipo de recurso está presente em /metadata
  • Controles de busca no lado do servidor, como _count, _sort, _summary, _elements, _include e _revinclude, são expostos apenas quando anunciados
  • Os parâmetros de busca são bloqueados quando o servidor não os anuncia
  • As ações de gravação exigem tanto FHIR_WRITE_CAPABILITIES quanto interações correspondentes no CapabilityStatement
  • As operações nomeadas exigem que o tipo de recurso de destino exista, que o escopo SMART concedido permita o recurso e que a própria operação seja anunciada na entrada do CapabilityStatement do recurso

No modo warn, parâmetros não anunciados são permitidos com um aviso, mas tipos de recursos ausentes ainda são ignorados. Os escopos SMART também são verificados em tempo de execução, então uma ferramenta pode existir no esquema e ainda ser bloqueada pelo escopo do token concedido.

Economia de Tokens e Modelagem de Respostas

As respostas FHIR são frequentemente muito maiores do que um cliente MCP precisa. O fhirHydrant modela as respostas para economia de tokens após a recuperação, usando controles no lado do servidor quando o servidor FHIR os anuncia.

RecursoComportamento
_count padrão/limiteNenhum _count injetado por padrão (o servidor decide o tamanho da página). Defina FHIR_DEFAULT_COUNT para injetar um; FHIR_MAX_COUNT limita valores explícitos do chamador (0 = sem limite)
Coalescência de páginasQuando o modo compacto está ativo, o servidor busca várias páginas upstream sequencialmente, compacta cada uma imediatamente e retorna um Bundle consolidado. Controlado pelas variáveis de ambiente maxResults, prefetch e FHIR_PREFETCH_*
Limite de bytesFHIR_MAX_RESPONSE_BYTES limita toda resposta JSON voltada ao modelo; Bundles superdimensionados são divididos em partes de forma transparente
Nova tentativa automáticaBundles de busca superdimensionados tentam primeiro a divisão local, depois repetem com _count menor como fallback
FHIRPathfhirpath filtra o JSON FHIR retornado localmente e retorna os nós correspondentes como uma matriz
Modo compactoresponseMode=compact remove ruídos comuns do envelope FHIR e simplifica tipos de dados
Modo completoresponseMode=full retorna o JSON FHIR bruto
Compacto bloqueadoFHIR_RESPONSE_MODE=compact-locked oculta responseMode do esquema da ferramenta
Artefatos nativosRespostas não JSON (documentos, imagens, DICOM, RTF, HTML, XML, CSV, NDJSON, ZIP, octet-stream) e FHIR Binary JSON são normalizados em um envelope de metadados mais um recurso MCP de texto/blob incorporado. Limitado por FHIR_MAX_ARTIFACT_MB (não pelo limite JSON), nunca dividido e nunca passado por FHIRPath/compactação/coalescência. Argumentos de modelagem somente JSON são ignorados com uma nota

A saída compacta é JSON orientado a IA, não FHIR canônico. Ela remove ou simplifica ruídos FHIR e tipos de dados comuns, como meta, narrativa, extensões, CodeableConcept, Reference, Quantity e tipos de dados mais novos, como CodeableReference. O FHIRPath é executado localmente; o servidor FHIR nunca vê a expressão. Se a avaliação falhar, a resposta bruta é retida e um erro é retornado.

Envelope de Resposta Estruturada

Toda ferramenta de dados FHIR (ferramentas de recurso, paginate, operate, bundle, system_history) retorna um único envelope estruturado, anunciado via outputSchema de cada ferramenta e retornado como structuredContent (o conteúdo de texto é o mesmo envelope serializado). Ele carrega o payload FHIR (data) mais metadados: modo de resposta, um sinal de paginação hasMore/continuation, estatísticas de Bundle e coalescência, e notes legível por humanos. A lista completa de campos é o outputSchema da ferramenta.

Respostas superdimensionadas são divididas quando possível (data preservado, recuperável via continuation); se não for possível dividir, o envelope é marcado como status: "truncated" com data omitido. A truncagem é um resultado bem-sucedido, mas parcial, não um erro. As ferramentas de capacidades e terminologia retornam suas próprias formas estruturadas em vez deste envelope FHIR.

Coalescência de Páginas

Quando o modo compacto está ativo para uma busca (ferramentas de recurso ou paginação), o servidor busca várias páginas FHIR upstream sequencialmente, compacta cada página imediatamente e retorna um Bundle compacto consolidado. Isso reduz as idas e voltas do MCP de muitas chamadas de "próxima página" para apenas uma.

  • maxResults define um alvo — o servidor para de buscar uma vez que esse limite é ultrapassado (pode exceder levemente, pois páginas inteiras são anexadas)
  • prefetch=false desativa a coalescência para uma chamada
  • _count ainda controla o tamanho da página FHIR upstream
  • A coalescência para em limites configuráveis de página, entrada, byte e tempo
  • continuation.url aponta para onde o servidor parou; chame paginate com responseMode=compact para continuar (hasMore indica que há mais)
  • Solicitações filtradas por FHIRPath permanecem em página única (sem coalescência)
  • responseMode=full sempre retorna uma única página upstream

Eventos de Auditoria

Defina FHIR_AUDIT_SINK para qualquer combinação de console, file e http.

O destino http envia cada evento de auditoria via POST para um coletor externo, SIEM ou repositório de auditoria FHIR (não o próprio servidor FHIR). Defina FHIR_AUDIT_HTTP_URL para o destino e FHIR_AUDIT_HTTP_FORMAT para raw (o JSON de auditoria interno com PHI leve, para coletores genéricos como Splunk HEC ou Datadog) ou fhir-auditevent (um recurso FHIR R4 AuditEvent mínimo, adequado para repositórios de auditoria no estilo ATNA e nativos FHIR). O mapeamento fhir-auditevent é intencionalmente leve — não é um perfil de conformidade ATNA/BALP completo. Um valor opcional FHIR_AUDIT_HTTP_AUTH é enviado literalmente como o cabeçalho Authorization. A entrega é do tipo "disparar e esquecer" com timeout de 5s; falhas de transporte são registradas e nunca afetam as respostas das ferramentas.

Os eventos de auditoria incluem timestamp, ferramenta, tipo de recurso quando aplicável, operação, status, duração, tamanho da resposta, resumo de paginação, ID da solicitação e usuário opcional autenticado por proxy. Eles não incluem o conteúdo do recurso FHIR por padrão.

Ao executar atrás de um proxy autenticador, defina FHIR_AUDIT_USER_HEADER para o cabeçalho de identidade confiável injetado por esse proxy:

Cabeçalhos comuns: Azure EasyAuth X-MS-CLIENT-PRINCIPAL-NAME, OAuth2 Proxy X-Auth-Request-Email, Cloudflare Access Cf-Access-Authenticated-User-Email.

Use isso somente quando o proxy remove ou sobrescreve cópias de entrada desse cabeçalho. Caso contrário, clientes podem falsificar usuários de auditoria arbitrários.

Autenticação SMART Backend e Chaves

O fhirHydrant usa SMART Backend Services: credenciais de cliente mais uma asserção JWT assinada. Isso é acesso FHIR de backend, não um lançamento autônomo SMART baseado em navegador; não há fluxo interativo de redirecionamento/login no caminho MCP.

FHIR_ACTIVE_KEY contém a chave de assinatura PKCS#8 bruta (RSA, assinada RS384, ou EC P-384, assinada ES384). No modo HTTP, o endpoint /jwks integrado expõe chaves públicas para a chave ativa mais quaisquer chaves aposentadas quando FHIR_JWKS_URL não está definido. O kid para cada chave é derivado automaticamente via uma impressão digital JWK RFC 7638 truncada (primeiros 12 caracteres base64url do SHA-256 sobre os membros JWK públicos canônicos) e registrado na inicialização.

Fluxo de rotação de chaves:

  1. Gere uma nova chave (RSA-2048 ou EC P-384).
  2. Adicione o novo PEM a FHIR_RETIRED_KEYS e reimplante para que o JWKS inclua ambos.
  3. Registre o novo kid (registrado na inicialização) com seu servidor de autenticação.
  4. Mova o novo PEM para FHIR_ACTIVE_KEY e mova o PEM antigo para FHIR_RETIRED_KEYS. Reimplante.
  5. Após os caches do servidor de autenticação expirarem, remova a chave antiga de FHIR_RETIRED_KEYS.

Se estiver usando JWKS externo, publique a nova chave pública antes de alternar FHIR_ACTIVE_KEY.

Variáveis de Ambiente

Veja .env.example para uma amostra completa.

Obrigatórias

VariávelDescrição
FHIR_BASE_URLURL base usada para derivar a URL do servidor FHIR e a URL do token. Opcional quando FHIR_SERVER_URL está definido (e, para autenticação smart, FHIR_TOKEN_URL)
FHIR_CLIENT_IDID do cliente SMART Backend Services (não necessário quando FHIR_AUTH=none)
FHIR_ACTIVE_KEYChave de assinatura PEM PKCS#8 codificada em base64, RSA ou EC P-384 (não necessária quando FHIR_AUTH=none)

Opcionais

VariávelPadrãoDescrição
FHIR_AUTHsmartsmart (SMART Backend Services) ou none (sem autenticação, para endpoints de teste públicos)
FHIR_RETIRED_KEYSnão definidoPEMs codificados em base64 separados por vírgula para rotação JWKS
FHIR_VERSIONR4Versão FHIR R4+ ativa; controla URL derivada, modelo FHIRPath e metadados do modelo compacto
FHIR_SERVER_URL<base>/api/FHIR/<FHIR_VERSION>Substituição explícita da URL da API FHIR
FHIR_TOKEN_URL<base>/oauth2/tokenSubstituição explícita do endpoint de token
FHIR_JWKS_URLnão definidoURL JWKS externa. Omita no modo HTTP para habilitar o /jwks integrado
MCP_TRANSPORThttphttp ou stdio
PORT5000Porta do listener HTTP
BIND_HOST0.0.0.0 (ou 127.0.0.1 com a flag --dev)Endereço de bind HTTP
ALLOWED_HOSTSnão definidoNomes de host separados por vírgula para proteção contra rebinding de DNS
FHIR_METADATA_MODEstrictstrict, warn ou off para validação de /metadata
FHIR_DEFAULT_COUNT0_count padrão injetado em buscas quando permitido; 0 = o servidor decide
FHIR_MAX_COUNT0Limite em valores explícitos de _count do chamador; 0 = sem limite
FHIR_MAX_RESPONSE_BYTES262144Limite de bytes para respostas JSON voltadas ao modelo; Bundles superdimensionados são divididos
FHIR_MAX_ARTIFACT_MB16Teto de bytes separado (MiB) para corpos de artefatos nativos/binários; independente do limite JSON (transporte base64 ≈ +33%)
FHIR_REQUEST_TIMEOUT_MS30000Timeout por tentativa para solicitações FHIR de saída
MCP_JSON_LIMIT4mbTamanho máximo aceito do corpo da solicitação MCP (string de limite json do Express); aumente se payloads grandes de escrita/bundle forem rejeitados
MCP_AUTHZnoneProvedor de autorização: none ou entra. Controla ferramentas por chamador (somente HTTP + Authorization: Bearer)
MCP_ROLE_PREFIXFhirHydrantPrefixo em valores de função concedidos (ex.: FhirHydrant.Patient.Read)
MCP_ENTRA_TENANT_IDnão definidoGUID do tenant Entra (não um alias de domínio); necessário quando MCP_AUTHZ=entra
MCP_ENTRA_AUDIENCEnão definidoID do aplicativo (cliente) da API esperado no aud do token de acesso v2; necessário quando MCP_AUTHZ=entra
FHIR_RESPONSE_MODEnão definidocompact, full ou compact-locked; não definido significa que buscas usam compacto por padrão e leituras diretas usam completo por padrão
FHIR_WRITE_CAPABILITIESnão definidoAções de escrita separadas por vírgula: create, update, patch, delete
FHIR_VALIDATE_WRITESlocaloff, local (verificações estruturais no lado do cliente) ou server (local + preflight $validate do servidor para criar/atualizar)
FHIR_WRITE_DRY_RUNfalseDefina como true para validar e registrar escritas sem executá-las contra o servidor FHIR
FHIR_BUNDLE_CAPABILITIESnão definidoTipos de Bundle separados por vírgula: batch, transaction; habilita a ferramenta bundle
FHIR_BUNDLE_WRITES_ENABLEDfalseDefina como true para permitir entradas de escrita dentro de Bundles (também requer FHIR_WRITE_CAPABILITIES)
FHIR_OPERATIONSnão definidoChaves de operação separadas por vírgula; none desativa todas as operações de catálogo. Catálogo padrão: everything, lastn, validate, docref, expand, lookup, translate, summary, match
FHIR_TERMINOLOGY_BASE_URLnão definidoHabilita ferramentas de terminologia, ex.: https://tx.fhir.org/r4
FHIR_PAGINATION_PATHSnão definidoPrefixos de caminho adicionais permitidos para links de paginação, ex.: FHIRProxy
FHIR_PREFETCH_MAX_PAGES5Máximo de páginas upstream buscadas por busca compacta coalescida
FHIR_PREFETCH_MAX_ENTRIES5000Máximo de entradas upstream acumuladas antes de parar
FHIR_PREFETCH_MAX_BYTES2097152Máximo de bytes brutos buscados antes de parar
FHIR_PREFETCH_TIMEOUT_MS25000Orçamento de tempo real para o loop de coalescência
FHIR_AUDIT_SINKnão definidoQualquer combinação de console, file, http
FHIR_AUDIT_FILE./audit.jsonlArquivo JSONL usado quando o destino de auditoria file está habilitado
FHIR_AUDIT_HTTP_URLnão definidoURL de destino para o destino de auditoria http; necessário quando http está habilitado
FHIR_AUDIT_HTTP_FORMATrawraw (JSON de AuditEvent interno) ou fhir-auditevent (FHIR R4 AuditEvent)
FHIR_AUDIT_HTTP_AUTHnão definidoValor do cabeçalho de autorização enviado literalmente pelo destino http
FHIR_AUDIT_USER_HEADERnão definidoCabeçalho de usuário autenticado por proxy copiado para eventos de auditoria
LOG_LEVELinfoVerbosidade de log: error, warn, info ou debug
Valores explícitos de FHIR_SERVER_URL e FHIR_TOKEN_URL sempre vencem URLs derivadas.

Suporte a Versões FHIR

Defina FHIR_VERSION para selecionar a versão ativa do FHIR R4+. Isso controla a URL da API FHIR derivada, o contexto do modelo FHIRPath e os metadados do modelo de resposta compacta. Algumas versões podem usar o modelo FHIRPath compatível mais próximo. Para terminologia, use um endpoint que corresponda à versão FHIR selecionada. Os logs de inicialização indicam quando URLs explícitas de FHIR ou terminologia parecem referenciar uma versão diferente.

Personalizando Ferramentas e Mensagens

Tudo em config/ é personalizável sem alterações no código-fonte.

A configuração é resolvida como uma sobreposição parcial: para cada arquivo, um ./config/<file> no diretório de trabalho atual (se presente) substitui o padrão empacotado, e qualquer coisa que você omitir volta ao padrão integrado. Assim, instalações via npm funcionam imediatamente, e para personalizar, você coloca uma pasta ./config ao lado de onde inicia o servidor contendo apenas os arquivos que deseja alterar.

Existem duas granularidades de sobreposição:

  • Arquivo inteiro (resources/*.json, operations.json, search-controls.json, core-tools.json, instructions/*): um arquivo que você fornece substitui completamente o arquivo empacotado. Um novo arquivo de recurso (ex.: ./config/resources/myresource.json) adiciona uma ferramenta. A sobreposição pode substituir e adicionar, mas não pode remover um recurso empacotado — para enviar um catálogo estritamente mínimo, remova os arquivos config/resources/ empacotados (veja o exemplo de compose).
  • Por chave (messages/*.json): um arquivo local substitui apenas as chaves individuais que contém; todas as outras chaves voltam ao padrão empacotado. Assim, você pode ajustar uma única descrição ou mensagem sem copiar o arquivo inteiro. Chaves desconhecidas, valores vazios e JSON malformado falham rapidamente na inicialização para capturar erros de digitação.

Os arquivos messages/*.json são lidos uma vez na inicialização do processo. Alterá-los exige reiniciar o servidor (e, para esquemas de ferramentas ou instruções, reconectar o cliente) para que tenham efeito. O recarregamento automático em desenvolvimento para recursos, controles de busca e operações é descrito abaixo.

ArquivoFinalidade
resources/*.jsonFerramentas de recursos FHIR (um arquivo por recurso): parâmetros de busca, comportamento de leitura direta e regras de requireOneOf
operations.jsonCatálogo de operações nomeadas para operate (descrições e notas por operação)
search-controls.jsonDescrições para _count, _sort, _summary, _elements, _include, _revinclude, _lastUpdated, fhirpath, responseMode, maxResults e prefetch
messages/output-schema.jsonDescrições para cada campo outputSchema de ferramenta (sobreposição por chave)
messages/input-schema.jsonDescrições para parâmetros de entrada de recursos gerados (_id, _vid, _since, _at, action, body) e o título e parâmetros da ferramenta operate (sobreposição por chave)
instructions/manifest.jsonLista ordenada de fragmentos de instrução para compor, cada um com uma porta when opcional (terminology, writes, operations, bundle). Builds personalizados reordenam, adicionam ou removem seções editando este arquivo.
instructions/*.mdFragmentos de instrução referenciados pelo manifesto. Seções condicionadas são incluídas apenas quando seu recurso está habilitado; o token {{OPERATIONS_LIST}} é substituído pelo catálogo de operações ativo.
messages/*.jsonMensagens voltadas ao usuário, erros e notas de resposta (sobreposição por chave, dividida por domínio: núcleo, escrita, operações, terminologia, bundle, artefato)
core-tools.jsonDescrições integradas de ferramentas e dicas de parâmetros

Esquema de Definição de Recurso

Cada arquivo em config/resources/ é um único objeto de definição de recurso. Os arquivos são escaneados em ordem de nome; o nome do arquivo é convencionalmente o nome do recurso em minúsculas (ex.: patient.json). Cada objeto tem estes campos:

CampoTipoDescrição
resourcestringTipo de recurso FHIR
toolNamestringNome da ferramenta MCP; deve ser único
descriptionstringDescrição da ferramenta
supportsDirectReadbooleanHabilita GET /ResourceType/{id} via _id
searchParamsRecord<string,string>Parâmetros de busca FHIR e descrições
requireOneOf(string | string[])[]A busca exige pelo menos uma opção. Uma string é um único parâmetro obrigatório; um array aninhado é um conjunto de parâmetros onde todos são obrigatórios. ["patient"] aceita patient; [["given","family"],["identifier"]] aceita given+family juntos, ou identifier

Os valores de searchParams são descrições, não um modelo completo de capacidade FHIR. O comportamento de busca específico do servidor ainda pode ser aplicado.

Recarregamento Automático

Em desenvolvimento (NODE_ENV não é production), a pasta config/resources/, search-controls.json e operations.json são monitoradas. JSON inválido mantém o último snapshot válido. Um recarregamento materialmente alterado é aplicado transacionalmente: quando os escopos SMART derivados mudam, um token de substituição é adquirido antes que as novas definições e registros de ferramentas sejam confirmados, então uma aquisição falha deixa o catálogo em execução intacto. Adicionar/remover ferramentas, alterações de esquema de operações e nomes de parâmetros são re-registrados ao vivo — sem necessidade de reiniciar. Salvamentos semanticamente inalterados não causam atualização. A produção lê a configuração uma vez na inicialização, mas uma alteração em tempo de execução de /metadata (via capabilities(refresh=true)) ou uma mudança de escopo SMART do backend na atualização de token reavalia as ferramentas disponíveis em todos os modos.

Um limite é inevitável: a lista de ferramentas e esquemas são atualizados a quente, mas os instructions do servidor são enviados uma vez durante o initialize do MCP e não podem ser substituídos em uma conexão existente. Um cliente deve reconectar/reinicializar para receber texto de instrução alterado.

Transportes

Stdio

Defina MCP_TRANSPORT=stdio. O stdout é reservado para o protocolo MCP; os logs são redirecionados para o stderr. Use um FHIR_JWKS_URL externo para implantações stdio.

HTTP Transmissível

O transporte HTTP é sem estado e expõe o MCP em:

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

Configuração do cliente MCP:

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

GET /health retorna um snapshot de prontidão sem PHI:

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

Quando a autorização está habilitada, authz relata o provedor ativo e tools é omitido porque a contagem de ferramentas registradas é específica do chamador.

Use um proxy reverso para TLS e autenticação de usuário ao expor HTTP além de localhost. Defina ALLOWED_HOSTS ao vincular a uma interface pública.

Autorização por chamador (Entra, opcional)

Por padrão (MCP_AUTHZ=none), todo chamador vê o conjunto completo de ferramentas limitado apenas por /metadata e os escopos SMART do backend. Definir MCP_AUTHZ=entra adiciona uma camada opcional por chamador: cada solicitação /mcp deve carregar um Authorization: Bearer <token> emitido pelo Microsoft Entra, e as Funções de Aplicativo do chamador determinam quais ferramentas são construídas para essa solicitação. Isso é apenas autorização na camada MCP — nunca substitui a autorização do próprio servidor FHIR, e só pode subtrair do que o token SMART do backend e a configuração já permitem.

O registro do aplicativo de API deve definir requestedAccessTokenVersion como 2 em seu manifesto. O provedor valida emissores v2 específicos do locatário e espera que MCP_ENTRA_AUDIENCE seja o ID do cliente do aplicativo de API.

Ferramentas para as quais um chamador não tem função não são registradas — elas estão ausentes de tools/list, não apenas bloqueadas. Ferramentas auxiliares (capabilities, paginate, terminology_lookup, code_search) nunca são limitadas.

Valores de Função de Aplicativo (com o prefixo padrão FhirHydrant):

FunçãoConcede
FhirHydrant.<Resource>.Readbusca, leitura, vread, histórico para esse recurso
FhirHydrant.<Resource>.Writeações de leitura mais criar, atualizar, patch, excluir (sujeito a FHIR_WRITE_CAPABILITIES)
FhirHydrant.Operation.<key>a operação nomeada via a ferramenta operate (ex.: FhirHydrant.Operation.everything)
FhirHydrant.Bundlea ferramenta bundle
FhirHydrant.SystemHistory.Reada ferramenta system_history em todo o sistema
FhirHydrant.Admintudo acima, ainda limitado pelos escopos SMART do backend, /metadata e configuração de escrita/bundle/operação

Requer transporte HTTP; MCP_AUTHZ=entra com MCP_TRANSPORT=stdio falha na inicialização. Tokens de portador ausentes ou inválidos recebem 401.

Adicionando um provedor de autorização

Entra é o único provedor incluído, mas a camada de autorização é neutra em relação ao provedor. Esta é uma extensão de código-fonte, não um plugin em tempo de execução: o pacote npm inclui apenas bin/server.js (os provedores são empacotados), então adicionar um significa bifurcar ou clonar o repositório e recompilar.

O pipeline compartilhado é agnóstico ao provedor — um provedor apenas mapeia um cabeçalho Authorization para { subject, roles }. O vocabulário de funções (.Read/.Write/Operation.<key>/Bundle/SystemHistory.Read/Admin) e o tratamento de MCP_ROLE_PREFIX são aplicados por decideAuthz para todos os provedores.

Para adicionar um (ex.: auth0), são necessárias apenas duas edições:

  1. Crie ts/mcp/authz/auth0.ts exportando um AuthzProvider — implemente validate(authorization) para retornar { subject, roles } (lance para rejeitar), e opcionalmente validateConfig() para falhar rapidamente em env ausente do provedor. Mantenha todo o env específico do provedor dentro deste módulo; não adicione campos a Config.
  2. Adicione uma entrada a ts/mcp/authz/registry.ts: auth0: () => import("./auth0.ts").then((m) => m.auth0Provider).

É isso. O tipo AuthzMode, o analisador MCP_AUTHZ e sua mensagem de erro derivam automaticamente das chaves do registro, então MCP_AUTHZ=auth0 funciona com segurança total de tipos — nenhum outro arquivo precisa ser alterado.

Exemplos de Implantação

O diretório examples/ tem exemplos de implantação autônomos para Docker Compose, proxy reverso (Caddy), Azure Container Apps, Azure App Service e Kubernetes. Cada um inclui um Dockerfile que instala a partir do npm e uma sobreposição config/ demonstrando como substituir diferentes arquivos de configuração.

Desenvolvimento

# dev server
npm run dev

# type-check
npm run check

# build and run
npm run build
npm start

A saída do build vai para bin/server.js.