Projeto IA.med Licença Apache-2.0 Local ou conector Sem LLM

radar-cfm-mcp

Servidor MCP para consultar as resoluções do CFM sobre inteligência artificial, telemedicina e prontuário eletrônico. Use pelo conector hospedado, sem instalar nada, ou rode na sua máquina e ligue ao cliente MCP que preferir.

Antes de usar, leia

  • Não é fonte oficial do CFM e não substitui a leitura da resolução original.
  • Não é aconselhamento jurídico nem ético-profissional, não é apoio à decisão clínica e não é dispositivo médico.
  • Resoluções podem ser revogadas ou substituídas. O projeto sinaliza isso quando consegue identificar no texto, mas não garante a detecção.
  • Todo resultado traz o link da fonte original, que deve ser conferida.

O problema

Por que este projeto existe

Espalhado em PDFs, sem dado aberto

As resoluções do CFM sobre IA, telemedicina e prontuário eletrônico ficam no portal de normas do conselho, sem API nem dado aberto estruturado. Cruzar tema, vigência e número dá trabalho manual.

Saber o que está vigente exige leitura

Uma resolução pode ter sido revogada ou substituída por outra. Descobrir o que ainda vale hoje significa abrir e comparar documentos um a um.

Um modelo de linguagem não alcança isso sozinho

Um modelo de linguagem não consegue consultar o portal e filtrar por tema de forma confiável. Falta a camada que exponha essa busca como ferramenta.

Como funciona

Do portal do conselho ao agente, em quatro camadas

  1. 01

    Crawler

    Varre o portal de normas do CFM com intervalo entre requisições. Um mesmo PDF nunca é baixado duas vezes. Por padrão, só é baixado quando a ementa casa com um tema; com --texto-integral, baixa todos (a instância hospedada roda assim).

  2. 02

    Extração

    Converte PDF e HTML em texto e metadados: número, ano, ementa, data de publicação (lida do cabeçalho do texto) e os sinais de revogação e suspensão.

  3. 03

    Armazenamento

    Guarda tudo localmente em DuckDB, com busca textual (FTS/BM25) e queda para LIKE quando o índice não está disponível.

  4. 04

    Ferramentas MCP

    Expõe a consulta por tema e o monitoramento de novas resoluções como tools, que o modelo chama pelo cliente MCP.

Toda resposta inclui a ementa e o link do PDF oficial. Um trecho extraído é ponto de partida para a leitura, não uma citação normativa.

As ferramentas

Duas tools MCP expostas ao modelo

O modelo chama estas funções durante a conversa. Cada resultado sempre traz a URL de origem para conferência. Acima dos tetos (limite até 100, dias até 3.650) a chamada é recusada. Os retornos abaixo mostram o formato; os campos são os do projeto e os valores, ilustrativos.

consultar_resolucao_cfm

Resoluções relacionadas ao tema, mais relevantes primeiro (BM25), até limite. Revogadas vêm com vigente: false e a que as substituiu. total conta a base inteira e truncado: true avisa que há mais do que veio. Um tema que seja o número da norma (2314/2022) busca aquela resolução direto, inclusive revogada.

consultar_resolucao_cfm(
    tema: str,
    apenas_vigentes: bool = True,
    limite: int = 10,   # 1 a 100
)
{
  "tema": "telemedicina",
  "total": 20,
  "retornados": 1,
  "truncado": true,
  "resultados": [
    {
      "identificador": "2314/2022",
      "numero": "2314",
      "ano": "2022",
      "data_publicacao": "2022-05-05",
      "ementa": "Define e regulamenta a telemedicina, como forma de serviços médicos mediados por tecnologias de comunicação.",
      "trecho_relevante": "...Define e regulamenta a telemedicina, como forma de serviços médicos...",
      "vigente": true,
      "suspensa": false,
      "revogada_por": null,
      "revogada_por_confere": null,
      "revogada_por_provavel": null,
      "url_origem": "https://sistemas.cfm.org.br/normas/visualizar/resolucoes/BR/2022/2314",
      "url_pdf": "https://sistemas.cfm.org.br/normas/arquivos/resolucoes/BR/2022/2314_2022.pdf",
      "texto_completo_disponivel": true,
      "metadados_incompletos": false
    }
  ],
  "aviso": "Cada resultado traz a ementa e a URL de origem: confira o texto oficial antes de tratar qualquer trecho como a posição do CFM. ..."
}
Exemplo do formato de retorno (valores ilustrativos)

monitorar_novas_resolucoes

O que foi publicado nos últimos dias, mais recente primeiro. Com filtrar_tema, só as que citam as palavras-chave do servidor (por padrão inteligência artificial, telemedicina, prontuário eletrônico e algoritmo), filtradas antes do limite. A janela usa a data extraída do texto: sem_data_publicacao conta as que ficam de fora, então total zero com esse número alto quer dizer "não sei", não "nada foi publicado".

monitorar_novas_resolucoes(
    dias: int = 30,          # 1 a 3650
    filtrar_tema: bool = True,
    limite: int = 50,        # 1 a 100
)
{
  "dias": 90,
  "total": 1,
  "retornados": 1,
  "truncado": false,
  "sem_data_publicacao": 343,
  "resultados": [
    {
      "identificador": "2471/2026",
      "data_publicacao": "2026-09-17",
      "vigente": true,
      "url_origem": "https://sistemas.cfm.org.br/normas/visualizar/resolucoes/BR/2026/2471",
      "url_pdf": "https://sistemas.cfm.org.br/normas/arquivos/resolucoes/BR/2026/2471_2026.pdf"
    }
  ],
  "aviso": "..."
}
Exemplo do formato de retorno (campos abreviados)

O que ele não diz

Os números, e onde a resposta pode enganar

Números lidos da base real e de uma execução em 12/10/2026; eles envelhecem. O servidor não usa modelo de linguagem: responde só o que está na base.

2.457
resoluções na base, todas com texto
53 MB
tamanho da base
93
testes automatizados
2
tools expostas

Lido em 12/10/2026.

  • A data de publicação é lida do texto, não de um campo

    O portal não publica a data em metadado. A extração cobre 97% das normas de 2020 em diante, e sem_data_publicacao conta quantas ficaram de fora da janela: total zero com esse número alto quer dizer "não sei", não "nada foi publicado".

  • A revogação marcada no portal está errada na origem

    O campo de ano de revogação do portal foi auditado página por página e não confere. O servidor usa os sinais que consegue ler do próprio texto e não garante a detecção, nem a vigência.

  • Suspensão só conta dentro de parênteses

    É o que separa estado da norma de assunto da norma. Uma resolução que fala sobre suspensão não é uma resolução suspensa.

  • O portal cai, e a coleta cai junto

    A fonte não tem API nem dado estruturado: raspar portal falha de vez em quando, e isso não vai mudar.

A falha de 12/10, e por que ela não apareceu para quem consulta

A coleta das 02:37 morreu no meio, com erro de leitura de rede contra o portal. A base servida não foi tocada: continuou com as 2.457 resoluções, todas com texto, e o conector respondeu 200 durante e depois. O arquivo em construção ficou em 20 MB e será apagado pela próxima coleta. É o que a publicação por troca atômica existe para dar: antes dela, uma coleta interrompida deixava a base servida pela metade.

O portal voltou a responder em seguida, então foi falha passageira, e o agendamento tenta de novo na madrugada seguinte. Isso descreve o que aconteceu, não é promessa de disponibilidade.

Dois jeitos de usar

Pelo conector hospedado, ou na sua máquina

O mesmo servidor fala stdio (local) e streamable-http (conector). Toda resposta traz o link do PDF oficial, nos dois casos.

Conector hospedado

Há uma instância pública, mantida pelo autor, para usar sem instalar nada. No Claude (web ou desktop): Configurações, Conectores, adicionar conector personalizado, e colar a URL abaixo.

https://mcp.iamed.cc/cfm/mcp
URL do conector
claude mcp add --transport http radar-cfm https://mcp.iamed.cc/cfm/mcp
No Claude Code

Antes de usar o conector

  • Dados públicos do CFM A base é uma cópia do que o portal de normas publica, atualizada uma vez por dia de madrugada. Não é fonte oficial.
  • Sem garantia de disponibilidade Roda numa máquina pessoal exposta por um túnel (mcp.iamed.cc). Pode ficar fora do ar, mudar de endereço ou ser desligado sem aviso. Se você depende dele, rode o seu.
  • Sem autenticação, com limites Qualquer pessoa pode chamar. Há teto de 600 requisições por minuto por origem e 1.200 no total, e teto nos parâmetros (limite até 100, dias até 3.650). Acima disso a chamada é recusada.
  • O que você consulta passa por lá Os parâmetros de cada chamada (tema, dias, limite) chegam ao servidor do autor. O código não registra os temas; só o IP de origem quando uma chamada é recusada por limite.

stdio (local)

O cliente sobe o processo na sua máquina, contra a sua cópia da base (passo a passo abaixo). Nada fica exposto na rede, e os temas consultados não saem do seu computador.

streamable-http (o seu conector)

Para hospedar a sua instância. O tráfego do Claude chega dos IPs da Anthropic, então há um teto global e um por origem. Uma instância varre o portal e todos consultam a mesma base: para um portal de conselho, é a opção mais respeitosa.

# expor a sua própria instância como conector HTTP
TRANSPORTE=streamable-http HTTP_HOST=127.0.0.1 HTTP_PORTA=8000 uv run radar-cfm-mcp

# atrás de túnel ou proxy, declare o nome público (senão responde 421)
HTTP_HOSTS_PUBLICOS=mcp.exemplo.ts.net

Como rodar

Na sua máquina

Além do conector hospedado, você pode rodar a sua instância: clona o repositório, sincroniza a base a partir do portal do CFM e o servidor MCP roda ali, no seu computador. O projeto não usa LLM: a busca é full-text sobre a base local.

# 1. clonar o repositório
git clone https://github.com/fabianofilho/radar-cfm-mcp.git
cd radar-cfm-mcp

# 2. instalar as dependências (Python 3.12+ e uv)
uv sync

# 3. configurar o ambiente
cp .env.example .env

# 4. rodar a coleta inicial
uv run cfm-cli sync --max-paginas 3   # teste rápido
uv run cfm-cli sync                    # varredura completa (~8 min)

# 5. subir o servidor MCP (stdio) e conectar ao seu cliente
uv run radar-cfm-mcp
Confira os comandos e opções no README do projeto.
claude mcp add radar-cfm --scope user \
  -e DUCKDB_PATH=/caminho/para/radar-cfm-mcp/data/cfm.duckdb \
  -- uv --directory /caminho/para/radar-cfm-mcp run radar-cfm-mcp
Ligando a instância local ao Claude Code
# baixa o PDF de todas as resoluções, não só das que tocam no tema
uv run cfm-cli sync --texto-integral --max-pdfs 0

# constrói a base ao lado e troca no fim (quando há um servidor HTTP lendo)
uv run cfm-cli sync --publicar --texto-integral --max-pdfs 25

# refaz as datas de publicação a partir do texto já gravado, sem tocar no portal
uv run cfm-cli reextrair-datas [--publicar]
Outras opções do cfm-cli

O crawler respeita o portal: intervalo entre requisições, cache por PDF e, por padrão, download só quando a ementa casa com um tema. No modo local, os temas consultados não saem da sua máquina; só o sync fala com o portal do CFM. No conector hospedado, os parâmetros de cada chamada passam pelo servidor do autor.