protocolos-pcdt-mcp
This server lets you query Brazilian clinical protocols (PCDTs) and get AI-generated, citation-checked summaries of recommended conduct for a specific clinical context.
Search for PCDTs by disease/condition name – accepts acronyms (e.g., HAS, DPOC), ignores accents/case, and matches words in any order; returns up to 10 results with metadata (status, portaria, PDF links, available sections, etc.)
Fallback full-text search – if the name doesn't match, searches the full text of protocols and returns up to 5 results with a warning that they may only mention the term
Summarize clinical conduct – given a PCDT identifier and a clinical context (e.g., "gestante com asma"), extracts a short, targeted summary using a local LLM
Verify supporting quotes – the response includes the literal quote from the protocol, whether it was found contiguously, and a fraction of how much of the quote was verified; flags spliced quotes
Always provides the official PDF link – even when text isn't collected or the LLM is unavailable, so you can consult the full protocol directly
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-mcpResuma 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.
O servidor roda só por stdio, na sua máquina, sem porta de rede. Não há transporte HTTP nem connector remoto nesta versão, e expô-lo por túnel não é um uso suportado.
⚠️ 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: Manual RAG — SIH/SUS Query System
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
uv run pcdt-cli sync # coleta (20 PDFs por execução, por padrão)
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 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)
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.
{
"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.
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.
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".
| Name | Required | Description | Default |
|---|---|---|---|
| doenca_ou_condicao | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| aviso | No | |
| termo | Yes | |
| total | Yes | |
| resultados | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations at all, the description carries the full behavioral burden and does so thoroughly. It discloses the two-phase search strategy (name first then text), exact matching nuances (accents, word order, acronyms, 'diabetes mellitus'), the 5-result fallback with origin='texto', the status CSV null caveat, and the return of up to 10 protocols when multiple name matches exist.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Although the description is longer than typical, every sentence earns its place: it covers purpose, search behavior, result fields, an important null-status caveat, and parameter guidance. It is well-structured with the primary sentence firstched and the argument documented at the end.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter lookup tool with an output schema and no annotations, the description is complete. It tells the agent how the search works, what edge cases exist (text matches, multiple protocols, null status), and how to connect to the sibling tool, so there is no ambiguity about how to invoke it successfully.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and there is only one parameter, but the description fully compensates. The 'Args' section defines doenca_ou_condicao with an example, and the main body adds substantial matching semantics that tell the model exactly what kind of input is acceptable and how it will be interpreted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb and resource: 'Consulta o PCDT vigente do Ministério da Saúde para uma doença ou condição.' It clearly identifies the tool as a PCDT lookup for a disease/condition and adds the useful relationship to the sibling tool via the identifier comment.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes the usage context clear: use it to look up a PCDT by disease/condition)Skip; it even notes that the returned identifier is intended for use in resumir_conduta. It does not explicitly state when not to use it or name alternatives, but with only one sibling and such a distinct lookup purpose, that is not a significant gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| pcdt_id | Yes | ||
| contexto_clinico | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| aviso | No | |
| resumo | No | |
| url_pdf | No | |
| condicao | Yes | |
| identificador | Yes | |
| contexto_clinico | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full responsibility for behavioral disclosure. It clearly states that the response always includes a literal citation, states whether the citation was actually found, includes the PDF link, and explains what happens when prerequisites are missing (returns only the link and a warning). This is unusually transparent about failure modes and return contents.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with a clear purpose sentence, then adds differentiation, return behavior, prerequisites, and parameter documentation. It is longer than a two-sentence ideal, but every sentence carries useful information and none is redundant. Minor extra length is justified by the tool's non-trivial behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the tool's purpose, the exact inputs, the return characteristics, the prerequisites, and the fallback behavior. Since an output schema exists, return-value details are not required here. There is no missing information an agent would need to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the schema provides only titles. The description compensates fully by explaining both parameters: pcdt_id is the identifier returned by consultar_protocolo and may also be a condition name without the revision note (e.g., 'asma'), and contexto_clinico is the concrete clinical situation. This adds essential meaning beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with a specific verb and resource: 'Resume a conduta de um PCDT para um contexto clínico específico.' It differentiates itself from the sibling tool by saying it does not return the whole protocol but extracts only the part relevant to the clinical context. This makes the tool easy to distinguish from consultar_protocolo.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states the intended context ('para um contexto clínico específico') and contrasts with returning the full protocol ('Em vez de devolver o protocolo inteiro'), which implies when the sibling would be used. It also gives preconditions (local LLM and collected full protocol text) and the fallback behavior. However, it does not explicitly instruct to use consultar_protocolo when the full protocol is needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
- Changed
consultar_protocolo2 fields changed- added
Output schema / $defs / Protocolo / properties / nota_atualizacaoAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Nota de revisão que o portal põe ao lado do nome, ex. 'Anexo alterado em ...'", + "title": "Nota Atualizacao" +} - added
Output schema / $defs / Protocolo / properties / origemAdded value: +{ + "default": "nome", + "description": "'nome': o termo casou com o nome do PCDT. 'texto': o nome não casou e o protocolo só cita o termo em algum ponto do texto", + "enum": [ + "nome", + "texto" + ], + "title": "Origem", + "type": "string" +}
2 tool updates
v0.1.0- First observed
consultar_protocolo - First observed
resumir_conduta
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.
- docs2mcpOAuthcom.docs2mcp
Query your own PDFs and documents from any MCP client. Every answer cites the page it came from.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to search and query PDF documents through a local RAG system with vector embeddings. Provides semantic document search capabilities while keeping all data stored locally without external dependencies.-
- FlicenseNot gradedqualityDmaintenanceA RAG-based MCP server for natural language querying of Brazilian healthcare manuals (SIH/SUS, SIA/SUS) and official ordinances. It provides 16 tools for semantic search, regulatory critique analysis, and retrieving data from SIGTAP and CNES.1-
- AlicenseNot gradedqualityBmaintenanceEnables querying PDF documents using natural language with grounded answers and source citations via a local RAG pipeline.MIT
- FlicenseAqualityCmaintenanceAssists in writing academic papers by extracting, organizing, and referencing scientific PDFs with ABNT formatting.10-