protocolos-pcdt-mcp
Local MCP server for querying Brazilian Ministry of Health PCDTs and, in local/stdio mode, summarizing recommended conduct for a clinical context with a verified literal citation and official PDF link.
consultar_protocolo: searches active PCDTs by disease/condition name (accent-insensitive, any word order, some acronyms/synonyms); falls back to full-text search with a warning; returns metadata, official PDF/resumido links, available sections, and text-collection status.resumir_conduta: uses a configured local OpenAI-compatible LLM to extract a targeted conduct summary for a clinical context, requiring already-collected full text; returns a summary with source section, literal citation, citation verification fields, and PDF link—or a warning/link if unavailable.In HTTP connector mode,
consultar_protocoloworks the same, butresumir_condutadoes not call the LLM and returnsresumo: nullwith a warning.Runs over stdio by default or streamable HTTP with rate limits and Host validation for remote connector use.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@protocolos-pcdt-mcp Resuma o PCDT de asma para paciente gestante"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
protocolos-pcdt-mcp
Servidor MCP local (stdio) que consulta os PCDTs (Protocolos Clínicos e Diretrizes Terapêuticas) do Ministério da Saúde/Conitec e resume a conduta recomendada para um contexto clínico específico, usando um LLM local. Toda resposta traz o link do PDF oficial.
Por padrão o servidor roda por stdio, na sua máquina, sem porta de rede. Há também um modo connector (HTTP), em que ele só consulta: não chama o LLM e, portanto, não gera resumos.
⚠️ Não substitui o protocolo nem o julgamento clínico
Não é fonte oficial. O projeto lê o que a Conitec publica e guarda uma cópia local, que pode estar defasada em relação ao portal.
O resumo é gerado por LLM e é uma ajuda de leitura. Protocolos têm exceções, populações específicas e notas de rodapé que um resumo de seis linhas não carrega.
A citação literal é conferida, mas a interpretação não. Ver Limitações conhecidas: há um exemplo real de citação correta com conclusão clínica errada.
Sem validação clínica. Não foi avaliado por nenhum órgão e não é dispositivo médico.
Para conduta, leia o protocolo completo. O link vem em toda resposta.
Requisitos
O quê | Versão | Para quê |
Python | 3.12+ | runtime |
recente | dependências e venv | |
Um LLM local com API OpenAI-compatible | - | resumo direcionado |
Espaço em disco | ~1 GB | base DuckDB + PDFs cacheados (protocolos são grandes) |
Related MCP server: Medical MCP Server
Instalação
git clone https://github.com/fabianofilho/protocolos-pcdt-mcp.git
cd protocolos-pcdt-mcp
uv sync
cp .env.example .envConfiguração
Variável | Padrão | Observação |
|
| llama.cpp. Ollama: |
|
| llama.cpp e LM Studio aceitam qualquer nome |
|
| base local |
|
| intervalo entre downloads de PDF |
uv run pcdt-cli llm # confirma o LLM local
uv run pcdt-cli sync --max-pdfs 5 # teste rápido, grava direto na base
uv run pcdt-cli sync --publicar # coleta (20 PDFs por execução) e troca a base no fim
uv run pcdt-cli consultar asma
uv run pcdt-cli resumir "asma" "paciente gestante"A coleta baixa no máximo --max-pdfs protocolos por execução: são ~130 PDFs grandes, e a
ideia é a base completar ao longo de algumas noites em vez de sobrecarregar o portal numa
única. O texto já coletado é preservado entre execuções.
Sync diário com systemd
O servidor MCP não agenda nada sozinho. O caminho oficial para manter a base atualizada é o
timer systemd de usuário versionado em deploy/systemd/: ele roda
pcdt-cli sync --publicar todo dia às 02:40, com até 30 min de atraso aleatório, e recupera
o disparo perdido se a máquina estava desligada.
As units supõem o clone em ~/protocolos-pcdt-mcp e o uv em ~/.local/bin/uv. Se os
seus caminhos forem outros, edite WorkingDirectory e ExecStart antes de copiar.
mkdir -p ~/.config/systemd/user
cp deploy/systemd/protocolos-pcdt-sync.service deploy/systemd/protocolos-pcdt-sync.timer \
~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now protocolos-pcdt-sync.timer
systemctl --user list-timers protocolos-pcdt-sync.timer # próximo disparo
journalctl --user -u protocolos-pcdt-sync.service # saída dos syncsPara o timer rodar sem sessão aberta, habilite loginctl enable-linger $USER.
Ligando ao Claude Code
claude mcp add protocolos-pcdt --scope user \
-e DUCKDB_PATH=/caminho/para/protocolos-pcdt-mcp/data/pcdt.duckdb \
-e QWEN_ENDPOINT=http://127.0.0.1:8080/v1 \
-e QWEN_MODEL=local-model \
-- uv --directory /caminho/para/protocolos-pcdt-mcp run protocolos-pcdt-mcpUso
consultar_protocolo(doenca_ou_condicao: str, limite=10)
limite vai de 1 a 100 e vale para a busca pelo nome; acima disso a chamada é recusada.
Busca primeiro no nome dos PCDTs vigentes:
sem acento e sem caixa, com as palavras em qualquer ordem, sempre no começo de uma palavra ("asma" não casa com "citoplasma");
trocando algumas siglas pelo nome por extenso (
HAS,DPOC,DM1,DM2,TDAH,LES,ELA,IC,DRC, entre outras emnomes.py);aceitando "diabetes"/"diabete" e "mellitus"/"melito", porque a Conitec escreve "Diabete Melito Tipo 1".
Devolve até 10 protocolos pelo nome, com origem: "nome". Se o nome não casar, procura o
termo no texto completo e devolve até 5 com origem: "texto" e um aviso: esses só citam
o termo e muitas vezes não são o PCDT da condição (por exemplo, "depressão" traz Alzheimer
e Parkinson, que mencionam depressão).
O identificador é o nome da condição em minúsculas. Quando o portal pendura uma nota de
revisão no nome, como "Asma (anexo alterado em 04/09/2026)", ela vai para
nota_atualizacao e fica fora do identificador. Saída real, da base local em 24/09/2026:
{
"termo": "acidentes ofídicos",
"total": 1,
"resultados": [
{
"identificador": "acidentes ofídicos",
"condicao": "Acidentes Ofídicos",
"status": "Conitec",
"portaria": "Portaria SECTICS/MS nº 83 - 07/10/2025 (Publicada em 09/10/2025 )",
"data_portaria": "2025-10-07",
"nota_atualizacao": null,
"url_pdf": "https://www.gov.br/conitec/pt-br/midias/protocolos/pcdt_acidentes_ofidicos_final.pdf/@@display-file/file",
"url_resumido": "https://www.gov.br/conitec/pt-br/midias/protocolos/2026/pcdt-resumido/pcdt-resumido-acidentes-ofidicos/@@display-file/file",
"vigente": true,
"secoes_disponiveis": ["introducao", "diagnostico", "classificacao", "monitoramento", "tratamento"],
"texto_completo_disponivel": true,
"extracao_incompleta": false,
"origem": "nome"
}
],
"aviso": null
}status vem do CSV de dados abertos do Ministério da Saúde e é parcial: em 24/09/2026,
só 43 dos 132 PCDTs da listagem tinham status, porque boa parte dos nomes do CSV não
existe na tabela do portal. status: null não quer dizer que o protocolo não está
aprovado; a listagem da Conitec só traz PCDTs vigentes.
resumir_conduta(pcdt_id: str, contexto_clinico: str)
Extrai do protocolo a parte que responde ao contexto, em vez de devolver o documento
inteiro. Aceita o identificador de consultar_protocolo ou o nome da condição sem a nota
de revisão (por exemplo, asma). Precisa do LLM local e do texto completo já coletado;
sem um dos dois, devolve só o link do PDF e um aviso dizendo o que faltou. No modo
connector o LLM nunca é chamado e a resposta vem sempre com resumo: null (ver
abaixo).
{
"condicao": "Acidentes Ofídicos",
"resumo": {
"resumo": "O paciente deve receber soroterapia antiveneno específica para o tipo de envenenamento.",
"secao_origem": "1.3. Acesso a soroterapia antiveneno",
"citacao_literal": "é necessário utilizar a soroterapia antiveneno específica, correspondente ao tipo de envenenamento",
"citacao_confere": true,
"fracao_citacao_verificada": 1.0
},
"url_pdf": "https://www.gov.br/conitec/..."
}A citação é conferida, não só pedida
O prompt exige a citação literal do trecho que sustenta o resumo. Um modelo pequeno às vezes "cita" parafraseando, ou, pior, costura frases reais de partes diferentes do documento num único bloco de aspas. Então o código confere:
Campo | O que significa |
| a citação existe inteira e contígua no protocolo |
| quanto dela existe, frase a frase (0 a 1) |
Fração alta com citacao_confere: false é o caso mais traiçoeiro: parece legítimo na
leitura e não é. Marcadores de omissão ("[...]", "(...)", reticências) nas pontas da
citação são ignorados; no meio, significam que algo foi pulado, e a citação deixa de
contar como contígua. Isso aconteceu no primeiro teste real deste projeto, com o PCDT de
Acidentes Ofídicos, e é por isso que os dois campos existem.
Modo connector (servidor HTTP)
Por padrão o servidor fala stdio: o cliente sobe o processo na máquina de quem usa.
Com TRANSPORTE=streamable-http, ele vira um servidor alcançável pela rede, que é o que
o Claude aceita como custom connector.
TRANSPORTE=streamable-http HTTP_PORTA=8000 uv run protocolos-pcdt-mcpVariável | Padrão | Observação |
|
|
|
|
| |
|
| cada requisição independente; escala melhor |
|
| o teto que protege a máquina |
|
| por origem, contra chamada direta |
| vazio | nomes públicos aceitos no |
Por que dois limites. Quando o Claude chama um connector remoto, as requisições chegam
dos IPs da Anthropic, não do usuário final. Limitar só por IP colocaria todos os
usuários no mesmo balde: ou derruba todo mundo junto, ou não protege nada. O teto global é
o que vale para esse tráfego; o por origem serve contra quem chama o servidor direto.
X-Forwarded-For só é considerado quando a conexão vem do loopback (o proxy local), e
vale a entrada mais à direita, a que o proxy acrescentou.
No modo connector, resumir_conduta não resume
O servidor HTTP não chama o LLM. Resumir sob demanda faria quem hospeda pagar inferência
para qualquer pessoa que chame o connector. Não existe cache de resumos neste projeto
(cada resumo depende do contexto clínico perguntado), então, nesse modo, a tool devolve
o identificador, a condição, o link do PDF, resumo: null e um aviso dizendo que nenhum
resumo foi gerado. Nada é inventado no lugar. consultar_protocolo funciona igual nos
dois modos.
Atrás de um proxy ou túnel, declare o nome público
O SDK do MCP valida o cabeçalho Host e responde 421 Invalid Host ao que não
reconhece. É proteção contra DNS rebinding, um ataque em que um site qualquer faz o
navegador da vítima conversar com um servidor que só deveria ser local. Atrás de um
túnel, o Host que chega é o nome público, então ele precisa ser declarado:
HTTP_HOSTS_PUBLICOS=mcp.exemplo.ts.netO loopback continua valendo junto, porque é assim que se testa o servidor de dentro da máquina.
Rodar como serviço
deploy/systemd/protocolos-pcdt-connector.service
é a unit de usuário do servidor HTTP. Ela escuta só em 127.0.0.1:8104; expor para fora é
uma camada à parte (proxy reverso com TLS ou túnel) que aponta para essa porta. Ajuste
HTTP_HOSTS_PUBLICOS para o seu nome público antes de habilitar.
cp deploy/systemd/protocolos-pcdt-connector.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now protocolos-pcdt-connector.serviceO sync não interrompe quem está lendo
pcdt-cli sync --publicar constrói a base nova ao lado e troca as duas por rename no
fim. O servidor abre a base somente para leitura a cada requisição; quem já abriu continua
no arquivo antigo até fechar, e quem abrir depois pega o novo. É o modo que o timer usa,
e por dois motivos.
O primeiro é a concorrência: o DuckDB não aceita leitor e escritor de processos diferentes ao mesmo tempo. Sem a troca, as consultas durante a coleta (até uma hora, com os downloads de PDF) recebiam o aviso de base travada em vez de resultado, e um sync que começasse no instante de uma consulta falhava.
O segundo é o tamanho. O DuckDB não devolve o espaço das páginas antigas, e a coleta
reescreve o texto completo dos protocolos todo dia: em 11/10/2026, depois de semanas de
syncs diários, o arquivo estava em 1.062 MB para 132 protocolos, contra 49 MB
compactado. A base nova é clonada da servida com COPY FROM DATABASE, e a cópia já sai
compactada.
Sem --publicar, o sync grava direto em DUCKDB_PATH, que é o que se quer num teste
rápido com --max-pdfs. A troca recusa publicar uma base que encolheu mais de 10% em
número de protocolos, para coleta interrompida não substituir a base boa em silêncio;
quando a queda é real, --forcar publica.
Limitações conhecidas
Conferir a citação não pega erro de interpretação. Num teste com "paciente picado por cascavel", o modelo local devolveu uma citação real e contígua do protocolo e mesmo assim classificou o caso como envenenamento botrópico, quando cascavel é crotálico. A citação estava certa; o raciocínio em cima dela, errado. Esta é a limitação mais importante do projeto.
O protocolo é truncado antes de ir para o modelo. Protocolos passam de 200 mil caracteres; o recorte prioriza a vizinhança das palavras do contexto perguntado, mas pode cortar fora a parte relevante.
A segmentação por seções é heurística. A estrutura dos PCDTs varia entre protocolos
antigos e novos. Quando os títulos não são reconhecíveis, secoes_disponiveis vem vazio e
só o texto corrido fica disponível, de propósito, para não inventar estrutura.
A base começa quase vazia. Por causa do teto de PDFs por execução, os primeiros syncs
trazem a listagem completa mas pouco texto. texto_completo_disponivel diz quais já têm.
Na instância do mantenedor, em 24/09/2026, eram 64 de 132 com texto; no ritmo de 20 PDFs
por noite, a base deve completar em cerca de 4 syncs (estimativa). Até lá, PCDTs como
hipertensão arterial sistêmica e os de HIV aparecem na consulta, mas resumir_conduta
responde que o texto ainda não foi coletado. pcdt-cli schema mostra a contagem.
Quando o PCDT muda, o texto antigo é descartado. Se a URL do PDF, a data da portaria ou a nota de revisão mudarem, o sync reextrai o texto, com prioridade na cota da noite. Se não couber na cota, ou se o download falhar, o protocolo fica sem texto até um sync conseguir baixar o PDF novo, em vez de resumir a versão velha com o link da nova. Quando só a nota ou a portaria mudam e a URL continua a mesma, o PDF velho sai do cache em disco na hora, para não ser reextraído depois.
O status é parcial. Ver a seção de consultar_protocolo.
A busca no texto é um último recurso. Ela acha protocolos que citam o termo, não o
PCDT da condição. Siglas fora da lista de nomes.py também caem nela.
Listagem parcial não despromove ninguém. Se a listagem do portal trouxer menos de 80% dos PCDTs vigentes na base, o sync não tira ninguém de vigente e deixa um aviso no journal.
PDFs digitalizados não têm camada de texto. Nesses casos o registro fica com
extracao_incompleta: true e só os metadados.
As URLs das fontes podem mudar. Estão em coleta/listagem.py, confirmadas em
20/09/2026. Observação prática: os links .csv que o portal de dados abertos exibe estão
desatualizados e devolvem 403; os que funcionam terminam em .zip.
Privacidade
Sai da máquina: requisições ao
gov.br/conitece ao bucket de dados abertos do Ministério da Saúde, para a listagem e os PDFs públicos.Não sai: a condição e o contexto clínico que você consulta ficam entre a base local e o seu LLM local.
Sem telemetria, sem analytics.
No modo connector, o que você consulta passa pela máquina que hospeda o servidor (e pelo túnel ou proxy na frente dela). O contexto clínico não vai para LLM nenhum, porque nesse modo o LLM não é chamado.
Atenção: o contexto_clinico que você digita vai para o seu LLM. Se ele estiver
hospedado fora da sua máquina, o texto vai junto, este projeto não impede isso, ao
contrário do revisor-notas-mcp.
Atualizando de uma base anterior
A versão 0.1.0 tira a nota de revisão do identificador e cria a coluna
nota_atualizacao. A migração roda no próximo pcdt-cli sync (ou em qualquer abertura
da base para escrita, como pcdt-cli schema), preserva o texto já extraído e refaz o
índice FTS. Até lá, o servidor continua lendo a
base antiga: os identificadores aparecem com a nota, e resumir_conduta aceita o nome
sem ela.
Segurança
Ver SECURITY.md. Mudanças por versão em CHANGELOG.md.
Contribuindo
Veja CONTRIBUTING.md. Não rode a coleta em loop contra o portal.
Licença e atribuição
Apache License 2.0: escolhida por o projeto tocar em conduta clínica.
Construído no contexto do IA.med.
Available Tools
2 toolsconsultar_protocoloA
Consulta o PCDT vigente do Ministério da Saúde para uma doença ou condição.
Procura primeiro no nome dos PCDTs, sem acento, com as palavras em qualquer ordem e aceitando algumas siglas ("HAS", "DPOC", "DM2") e a grafia "diabetes mellitus". Se o nome não casar, procura o termo no texto dos protocolos e devolve até 5, com origem="texto" e um aviso: esses só citam o termo e muitas vezes não são o PCDT da condição.
Cada resultado traz identificador (use em resumir_conduta), nome da condição, portaria, link do PDF completo e do PCDT resumido, seções extraídas e se o texto completo já foi coletado. O status vem do CSV de dados abertos e só existe para parte dos PCDTs; null não quer dizer que o protocolo não está aprovado. Se houver mais de um protocolo pelo nome, devolve todos (até 10), a escolha é de quem pergunta.
Args: doenca_ou_condicao: nome da doença ou condição, por exemplo "asma".
Inputs: doenca_ou_condicao (required). Returns: aviso, termo, total, resultados
resumir_condutaA
Resume a conduta de um PCDT para um contexto clínico específico.
Em vez de devolver o protocolo inteiro, extrai a parte que responde ao contexto, por exemplo "paciente com contraindicação a metformina". A resposta traz sempre a citação literal do trecho que sustenta o resumo, e diz se essa citação foi de fato encontrada no protocolo.
É ajuda de leitura, não substitui o protocolo: o link do PDF vem junto.
Precisa de um LLM local configurado e do texto completo do protocolo já coletado; sem isso, devolve só o link do PDF e um aviso.
Args: pcdt_id: identificador devolvido por consultar_protocolo. O nome da condição sem a nota de revisão também é aceito, por exemplo "asma". contexto_clinico: a situação concreta sobre a qual se quer a conduta.
Inputs: pcdt_id (required), contexto_clinico (required). Returns: aviso, resumo, url_pdf, condicao, +2 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 2 tools
The two tools have completely distinct purposes: one searches for PCDT documents, the other summarizes a specific clinical conduct from a selected PCDT. There is no overlap or ambiguity in their roles.
Both tool names follow the same verb_noun pattern in Portuguese: 'consultar_protocolo' (consult protocol) and 'resumir_conduta' (summarize conduct). The naming is consistent and predictable.
With only 2 tools, the server is slightly under the typical well-scoped range, but the narrow domain (PCDT consultation and summarization) justifies this minimal set. The tools cover the core workflow without unnecessary extras.
The server covers the essential operations: finding a protocol and summarizing a specific conduct. A minor gap exists in that there is no explicit tool to fetch the full protocol text, but the first tool provides links and sections, and the second tool gracefully degrades if full text is unavailable.
Maintenance
Related MCP Connectors
Medical RAG: semantic search for clinical guidelines, drug interactions, diagnoses & EHR data.
Medical RAG: semantic search for clinical guidelines, drug interactions, diagnoses & EHR data.
Disease Twin — Brazil's rare-disease knowledge graph (10,468) over MCP. Source-grounded, PT-BR.
JusPronto is case-management software for Brazilian law firms. Its remote MCP server (OAuth 2.1 with PKCE, per-permission scopes, audit log) lets Claude and ChatGPT read the firm's own cases, deadlines, agenda, recent court movements and case files with the page cited. Write actions require the lawyer's approval. Requires a JusPronto account.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables querying Anvisa's open data for drug registration status and recent medical devices, with heuristic AI-use classification using a locally hosted LLM.2Apache 2.0
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to query authoritative medical sources such as FDA, WHO, PubMed, RxNorm, and ClinicalTrials.gov for drug information, safety data, health statistics, clinical guidelines, pediatric resources, and evidence-graded literature. Runs locally with no API keys or data leaving the machine.83 npmISC
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to query authoritative medical sources such as FDA, WHO, PubMed, RxNorm, and ClinicalTrials.gov for drug information, safety data, health statistics, medical literature, clinical guidelines, and pediatric resources. Runs fully locally with no API keys or data leaving the machine, and includes resilience features like rate limiting, circuit breakers, caching, and health checks.83 npmISC
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to query authoritative sources like FDA, WHO, PubMed, RxNorm, and Google Scholar for drug information, health statistics, clinical guidelines, trials, and medical literature. It runs locally with no API keys, so data stays private while results come back with evidence grading and resilient fallbacks.83 npmISC