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
_counte 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
- Ferramentas
- Metadados e Controle de Escopo
- Economia de Tokens e Modelagem de Respostas
- Eventos de Auditoria
- Autenticação e Chaves SMART Backend
- Variáveis de Ambiente
- Suporte a Versões FHIR
- Personalizando Ferramentas e Mensagens
- Transportes
- Exemplos de Implantação
- Desenvolvimento
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ília | Disponível quando | Finalidade |
|---|---|---|
| Ferramentas de recursos | O recurso está configurado e permitido por metadados/escopos | Busca, leitura direta, vread, histórico e, opcionalmente, CRUD de recursos FHIR |
system_history | O servidor anuncia interação de sistema history e os escopos permitem | Recuperar o histórico de alterações em nível de sistema em todos os tipos de recursos |
capabilities | Sempre registrada | Inspecionar o resumo do CapabilityStatement, ferramentas registradas, ferramentas ignoradas, parâmetros de busca, operações e notas de metadados |
paginate | Sempre registrada | Buscar a próxima página de um Bundle FHIR usando uma URL next retornada pelo servidor |
operate | Pelo menos uma operação nomeada passa no controle | Invocar operações nomeadas FHIR configuradas para dados clínicos, terminologia, IPS, correspondência, validação ou fluxos de trabalho personalizados |
bundle | FHIR_BUNDLE_CAPABILITIES está definido | Enviar um Bundle de lote ou transação FHIR; gravações exigem aceitação adicional |
terminology_lookup | FHIR_TERMINOLOGY_BASE_URL está definido | Consultar um código LOINC ou SNOMED CT |
code_search | FHIR_TERMINOLOGY_BASE_URL está definido | Buscar 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ção | Parâmetros obrigatórios | Chamada FHIR |
|---|---|---|
vread | _id, _vid | GET /ResourceType/{id}/_history/{vid} |
history | _id (instância) ou nenhum (tipo) | GET /ResourceType/{id}/_history ou GET /ResourceType/_history |
create | body | POST /ResourceType |
update | _id, body | PUT /ResourceType/{id} |
patch | _id, body | PATCH /ResourceType/{id} com JSON Patch |
delete | _id | DELETE /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:
| Ferramenta | Descrição |
|---|---|
terminology_lookup | Consulta um código LOINC ou SNOMED CT |
code_search | Busca 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=truee a ação correspondente emFHIR_WRITE_CAPABILITIES. - Bundles de transação exigem
FHIR_BUNDLE_CAPABILITIES=transactionexplí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,_includee_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_CAPABILITIESquanto 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.
| Recurso | Comportamento |
|---|---|
_count padrão/limite | Nenhum _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áginas | Quando 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 bytes | FHIR_MAX_RESPONSE_BYTES limita toda resposta JSON voltada ao modelo; Bundles superdimensionados são divididos em partes de forma transparente |
| Nova tentativa automática | Bundles de busca superdimensionados tentam primeiro a divisão local, depois repetem com _count menor como fallback |
| FHIRPath | fhirpath filtra o JSON FHIR retornado localmente e retorna os nós correspondentes como uma matriz |
| Modo compacto | responseMode=compact remove ruídos comuns do envelope FHIR e simplifica tipos de dados |
| Modo completo | responseMode=full retorna o JSON FHIR bruto |
| Compacto bloqueado | FHIR_RESPONSE_MODE=compact-locked oculta responseMode do esquema da ferramenta |
| Artefatos nativos | Respostas 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.
maxResultsdefine um alvo — o servidor para de buscar uma vez que esse limite é ultrapassado (pode exceder levemente, pois páginas inteiras são anexadas)prefetch=falsedesativa a coalescência para uma chamada_countainda controla o tamanho da página FHIR upstream- A coalescência para em limites configuráveis de página, entrada, byte e tempo
continuation.urlaponta para onde o servidor parou; chamepaginatecomresponseMode=compactpara continuar (hasMoreindica que há mais)- Solicitações filtradas por FHIRPath permanecem em página única (sem coalescência)
responseMode=fullsempre 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:
- Gere uma nova chave (RSA-2048 ou EC P-384).
- Adicione o novo PEM a
FHIR_RETIRED_KEYSe reimplante para que o JWKS inclua ambos. - Registre o novo kid (registrado na inicialização) com seu servidor de autenticação.
- Mova o novo PEM para
FHIR_ACTIVE_KEYe mova o PEM antigo paraFHIR_RETIRED_KEYS. Reimplante. - 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ável | Descrição |
|---|---|
FHIR_BASE_URL | URL 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_ID | ID do cliente SMART Backend Services (não necessário quando FHIR_AUTH=none) |
FHIR_ACTIVE_KEY | Chave de assinatura PEM PKCS#8 codificada em base64, RSA ou EC P-384 (não necessária quando FHIR_AUTH=none) |
Opcionais
| Variável | Padrão | Descrição |
|---|---|---|
FHIR_AUTH | smart | smart (SMART Backend Services) ou none (sem autenticação, para endpoints de teste públicos) |
FHIR_RETIRED_KEYS | não definido | PEMs codificados em base64 separados por vírgula para rotação JWKS |
FHIR_VERSION | R4 | Versã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/token | Substituição explícita do endpoint de token |
FHIR_JWKS_URL | não definido | URL JWKS externa. Omita no modo HTTP para habilitar o /jwks integrado |
MCP_TRANSPORT | http | http ou stdio |
PORT | 5000 | Porta do listener HTTP |
BIND_HOST | 0.0.0.0 (ou 127.0.0.1 com a flag --dev) | Endereço de bind HTTP |
ALLOWED_HOSTS | não definido | Nomes de host separados por vírgula para proteção contra rebinding de DNS |
FHIR_METADATA_MODE | strict | strict, warn ou off para validação de /metadata |
FHIR_DEFAULT_COUNT | 0 | _count padrão injetado em buscas quando permitido; 0 = o servidor decide |
FHIR_MAX_COUNT | 0 | Limite em valores explícitos de _count do chamador; 0 = sem limite |
FHIR_MAX_RESPONSE_BYTES | 262144 | Limite de bytes para respostas JSON voltadas ao modelo; Bundles superdimensionados são divididos |
FHIR_MAX_ARTIFACT_MB | 16 | Teto de bytes separado (MiB) para corpos de artefatos nativos/binários; independente do limite JSON (transporte base64 ≈ +33%) |
FHIR_REQUEST_TIMEOUT_MS | 30000 | Timeout por tentativa para solicitações FHIR de saída |
MCP_JSON_LIMIT | 4mb | Tamanho 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_AUTHZ | none | Provedor de autorização: none ou entra. Controla ferramentas por chamador (somente HTTP + Authorization: Bearer) |
MCP_ROLE_PREFIX | FhirHydrant | Prefixo em valores de função concedidos (ex.: FhirHydrant.Patient.Read) |
MCP_ENTRA_TENANT_ID | não definido | GUID do tenant Entra (não um alias de domínio); necessário quando MCP_AUTHZ=entra |
MCP_ENTRA_AUDIENCE | não definido | ID do aplicativo (cliente) da API esperado no aud do token de acesso v2; necessário quando MCP_AUTHZ=entra |
FHIR_RESPONSE_MODE | não definido | compact, 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_CAPABILITIES | não definido | Ações de escrita separadas por vírgula: create, update, patch, delete |
FHIR_VALIDATE_WRITES | local | off, local (verificações estruturais no lado do cliente) ou server (local + preflight $validate do servidor para criar/atualizar) |
FHIR_WRITE_DRY_RUN | false | Defina como true para validar e registrar escritas sem executá-las contra o servidor FHIR |
FHIR_BUNDLE_CAPABILITIES | não definido | Tipos de Bundle separados por vírgula: batch, transaction; habilita a ferramenta bundle |
FHIR_BUNDLE_WRITES_ENABLED | false | Defina como true para permitir entradas de escrita dentro de Bundles (também requer FHIR_WRITE_CAPABILITIES) |
FHIR_OPERATIONS | não definido | Chaves 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_URL | não definido | Habilita ferramentas de terminologia, ex.: https://tx.fhir.org/r4 |
FHIR_PAGINATION_PATHS | não definido | Prefixos de caminho adicionais permitidos para links de paginação, ex.: FHIRProxy |
FHIR_PREFETCH_MAX_PAGES | 5 | Máximo de páginas upstream buscadas por busca compacta coalescida |
FHIR_PREFETCH_MAX_ENTRIES | 5000 | Máximo de entradas upstream acumuladas antes de parar |
FHIR_PREFETCH_MAX_BYTES | 2097152 | Máximo de bytes brutos buscados antes de parar |
FHIR_PREFETCH_TIMEOUT_MS | 25000 | Orçamento de tempo real para o loop de coalescência |
FHIR_AUDIT_SINK | não definido | Qualquer combinação de console, file, http |
FHIR_AUDIT_FILE | ./audit.jsonl | Arquivo JSONL usado quando o destino de auditoria file está habilitado |
FHIR_AUDIT_HTTP_URL | não definido | URL de destino para o destino de auditoria http; necessário quando http está habilitado |
FHIR_AUDIT_HTTP_FORMAT | raw | raw (JSON de AuditEvent interno) ou fhir-auditevent (FHIR R4 AuditEvent) |
FHIR_AUDIT_HTTP_AUTH | não definido | Valor do cabeçalho de autorização enviado literalmente pelo destino http |
FHIR_AUDIT_USER_HEADER | não definido | Cabeçalho de usuário autenticado por proxy copiado para eventos de auditoria |
LOG_LEVEL | info | Verbosidade 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 arquivosconfig/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.
| Arquivo | Finalidade |
|---|---|
resources/*.json | Ferramentas de recursos FHIR (um arquivo por recurso): parâmetros de busca, comportamento de leitura direta e regras de requireOneOf |
operations.json | Catálogo de operações nomeadas para operate (descrições e notas por operação) |
search-controls.json | Descrições para _count, _sort, _summary, _elements, _include, _revinclude, _lastUpdated, fhirpath, responseMode, maxResults e prefetch |
messages/output-schema.json | Descrições para cada campo outputSchema de ferramenta (sobreposição por chave) |
messages/input-schema.json | Descriçõ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.json | Lista 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/*.md | Fragmentos 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/*.json | Mensagens 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.json | Descriçõ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:
| Campo | Tipo | Descrição |
|---|---|---|
resource | string | Tipo de recurso FHIR |
toolName | string | Nome da ferramenta MCP; deve ser único |
description | string | Descrição da ferramenta |
supportsDirectRead | boolean | Habilita GET /ResourceType/{id} via _id |
searchParams | Record<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ção | Concede |
|---|---|
FhirHydrant.<Resource>.Read | busca, leitura, vread, histórico para esse recurso |
FhirHydrant.<Resource>.Write | açõ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.Bundle | a ferramenta bundle |
FhirHydrant.SystemHistory.Read | a ferramenta system_history em todo o sistema |
FhirHydrant.Admin | tudo 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:
- Crie
ts/mcp/authz/auth0.tsexportando umAuthzProvider— implementevalidate(authorization)para retornar{ subject, roles }(lance para rejeitar), e opcionalmentevalidateConfig()para falhar rapidamente em env ausente do provedor. Mantenha todo o env específico do provedor dentro deste módulo; não adicione campos aConfig. - 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.