Skip to main content
Glama
willianmarcel

medical-mcp-fake

medical-mcp-fake

Servidor MCP (Model Context Protocol) com transporte HTTP streamable e base clínica fictícia, para desenvolver e testar agentes enquanto a integração real com o TASI não existe.

⚠️ Todos os dados são inventados. Nenhum paciente, CPF, profissional ou resultado de exame aqui corresponde a pessoas ou registros reais.

Início rápido

npm install && npm run seed && npm run dev

O servidor sobe em http://localhost:4000/mcp. Confira com:

curl -s localhost:4000/health

Tools

Tool

Entrada

O que devolve

search_patients

query, context?, limit?

Pacientes cujo nome casa com a busca, com os IDs de cada contexto. Ponto de entrada das demais tools.

get_inpatient_full

inpatient_id | patient_id, sections?

Prontuário completo da internação.

get_patient_profile

patient_id

Cadastro + linha do tempo de todos os atendimentos.

get_encounter_details

encounter_id

Blocos clínicos de um atendimento ambulatorial.

get_ps_patient

ps_visit_id | patient_id

Ficha completa de uma passagem pelo pronto-socorro.

Fluxo típico de um agente

search_patients("maria")                    → PAC-0001, internado, INT-0001
  ├─ get_patient_profile("PAC-0001")        → linha do tempo cruzando PS, internação e ambulatório
  ├─ get_inpatient_full("INT-0001")         → prontuário completo da UTI
  └─ get_ps_patient("PS-0001")              → como o caso chegou ao hospital

Detalhes de comportamento

search_patients ignora acentos e maiúsculas (jose acha José Carlos Ferreira) e exige que todos os termos apareçam no nome — maria souza não traz todas as Marias. Ranqueia nome exato > palavra exata > prefixo > substring. context filtra por internacao, ambulatorial, ps ou todos.

get_inpatient_full aceita sections para trazer só os blocos que interessam e economizar contexto do agente:

{ "inpatient_id": "INT-0001", "sections": ["analises_ia", "intercorrencias"] }

Seções disponíveis: sinais_vitais, laboratorio, exames_imagem, intercorrencias, enfermagem, evolucoes_medicas, plano_terapeutico, notas_round, analises_ia. O cabeçalho da internação e os dados do paciente vêm sempre.

get_inpatient_full e get_ps_patient aceitam patient_id no lugar do ID específico e resolvem para o registro ativo (internação em curso / passagem em andamento) ou, na ausência dele, para o mais recente.

Erros — ID inexistente devolve resultado com isError: true e mensagem explícita em português, nunca um objeto vazio. O agente consegue distinguir "não encontrei" de "encontrei e está vazio".

A base fictícia

18 pacientes, 7 internações, 23 atendimentos ambulatoriais e 8 passagens pelo PS. Nomes brasileiros, CID-10, medicações, exames e séries temporais de sinais vitais plausíveis.

A base cobre casos deliberadamente variados: choque séptico em deterioração na UTI, pós-infarto em melhora, ICC compensando, pancreatite pré-cirúrgica, pós-operatório de fratura com delirium, pé diabético infectado, crise asmática em atendimento agora, dor torácica em investigação, e seguimentos ambulatoriais longos (artrite reumatoide, hipotireoidismo, DPOC, demência).

Pacientes aparecem em mais de um contexto. PAC-0001 e PAC-0006 têm a trilha completa PS → internação (ps_visit_id na internação, internacao_gerada na ficha do PS); PAC-0002 tem consultas ambulatoriais anteriores ao infarto que o internou — inclusive um retorno em que faltou, com o teste ergométrico positivo anexado. São os casos que exercitam o cruzamento de histórico pelo agente.

Regenerar ou editar

Os JSON em data/ são gerados a partir dos casos curados em scripts/cases/:

npm run seed

A saída é determinística: os timestamps são ancorados numa data de referência fixa (REF em scripts/seed-utils.ts) e os valores usam PRNG com seed fixa. Rodar duas vezes produz exatamente o mesmo JSON.

Para adicionar um paciente ou caso, edite os arquivos em scripts/cases/ e rode npm run seed. O gerador valida integridade referencial e IDs duplicados antes de escrever — referência quebrada falha o comando.

Configuração

Variável

Padrão

Descrição

PORT

4000

Porta HTTP.

HOST

0.0.0.0

Interface de bind.

API_TOKEN

(vazio)

Se definida, /mcp exige Authorization: Bearer <token>. Vazia = servidor aberto.

DATA_DIR

<cwd>/data

Diretório dos JSON da base.

/health nunca exige token — é o endpoint que o Coolify usa para healthcheck.

Docker

docker compose up --build

Ou direto:

docker build -t medical-mcp-fake . && docker run -p 4000:4000 -e API_TOKEN=seu-token medical-mcp-fake

Deploy no Coolify

  1. Nova aplicação → Dockerfile (ou Docker Compose) apontando para este repositório.

  2. Porta exposta: 4000.

  3. Healthcheck: GET /health.

  4. Variável de ambiente API_TOKEN — recomendado, já que o serviço fica exposto na internet.

O endpoint MCP fica em https://<seu-dominio>/mcp.

Conectando um agente

O servidor roda em modo stateless: cada POST /mcp cria transporte e sessão próprios e os descarta ao final. Não há sessão a manter, porque a base é somente-leitura. GET e DELETE em /mcp respondem 405.

Exemplo de configuração de cliente MCP:

{
  "mcpServers": {
    "tasi-fake": {
      "type": "http",
      "url": "https://<seu-dominio>/mcp",
      "headers": { "Authorization": "Bearer <API_TOKEN>" }
    }
  }
}

Chamada crua, para depurar sem cliente MCP:

curl -s -X POST localhost:4000/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_patients","arguments":{"query":"maria"}}}'

Estrutura

src/
  index.ts          bootstrap HTTP, healthcheck, rotas MCP
  auth.ts           bearer token opcional
  server.ts         McpServer e registro das tools
  db/
    types.ts        modelo de domínio
    load.ts         carga dos JSON e índices em memória
    search.ts       normalização e pontuação de nomes
  tools/            uma tool por arquivo + helpers de resposta
scripts/
  seed-utils.ts     PRNG, séries de vitais, painéis laboratoriais
  cases/            casos clínicos curados
  generate-seed.ts  valida e escreve data/*.json
data/               a base gerada (versionada)

Scripts

Comando

Ação

npm run seed

Regenera data/ a partir de scripts/cases/.

npm run dev

Servidor em modo watch.

npm run build

Compila para dist/.

npm start

Roda o build.

npm run typecheck

Checagem de tipos sem emitir.

Limitações conhecidas

  • Somente leitura. Nenhuma tool grava; não há simulação de prescrição ou evolução criada pelo agente.

  • Sem testes automatizados nesta versão, por decisão de escopo. O gerador valida integridade referencial, e os tipos cobrem o contrato das tools.

  • Datas ancoradas em REF (scripts/seed-utils.ts). Com o passar dos meses os casos "de agora" envelhecem; ajuste REF e rode npm run seed para atualizá-los.

  • Campos aproximados. A modelagem é plausível clinicamente, mas não replica o esquema real do TASI. Quando o contrato real aparecer, o ponto de ajuste é src/db/types.ts mais as tools.