Skip to main content
Glama

radar-cfm-mcp

Servidor MCP que consulta e monitora resoluções do CFM (Conselho Federal de Medicina) sobre inteligência artificial, telemedicina e prontuário eletrônico. Mantém uma cópia local pesquisável e sempre devolve o link do documento oficial.

⚠️ Não é fonte oficial

  • Não substitui a consulta ao portal do CFM. Este projeto lê o que o portal publica e guarda uma cópia local, que pode estar defasada.

  • Um trecho extraído não é "a posição do CFM". Toda resposta traz a ementa e a URL do PDF oficial justamente para você conferir antes de citar.

  • A extração de PDF pode falhar ou truncar. Quando isso acontece o registro é marcado com metadados_incompletos, mas leia sempre o documento original.

  • Sem validação jurídica. Isto é uma ferramenta de busca, não uma interpretação normativa.

Connector hospedado

Há uma instância pública deste servidor, mantida pelo autor, para quem quer usar sem instalar nada:

https://debian-f.tailf42a96.ts.net/cfm/mcp
  • No Claude (web ou desktop): Configurações, Conectores, adicionar conector personalizado, e colar a URL acima.

  • No Claude Code: claude mcp add --transport http radar-cfm https://debian-f.tailf42a96.ts.net/cfm/mcp

Antes de usar, saiba o que ela é:

  • Os dados são públicos, do CFM. A base é uma cópia do que o portal de normas publica, atualizada uma vez por dia de madrugada. O aviso acima vale inteiro: não é fonte oficial.

  • Sem garantia de disponibilidade. Roda numa máquina pessoal exposta pelo Tailscale Funnel. Pode ficar fora do ar, mudar de endereço ou ser desligada sem aviso. Para uso de que você dependa, rode a sua (instruções abaixo).

  • Sem autenticação, com limites. Qualquer pessoa pode chamar. Por isso há teto de requisições (600 por minuto por origem e 1.200 por minuto 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 essa máquina. Veja Privacidade.

Related MCP server: cfm_estabelecimento

Requisitos

O quê

Versão

Para quê

Python

3.12+

runtime

uv

recente

dependências e venv

Espaço em disco

~200 MB

base DuckDB + PDFs cacheados

Este projeto não usa LLM: a busca é full-text sobre a base local.

Instalação

git clone https://github.com/fabianofilho/radar-cfm-mcp.git
cd radar-cfm-mcp
uv sync
cp .env.example .env

Configuração

Variável

Padrão

Observação

CRAWLER_DELAY_SEGUNDOS

2

intervalo entre requisições ao portal

PALAVRAS_CHAVE

inteligência artificial, telemedicina, prontuário eletrônico, algoritmo

separadas por vírgula; decidem quais PDFs o sync padrão baixa (pela ementa) e o filtro de monitorar_novas_resolucoes (ementa e texto)

DUCKDB_PATH

./data/cfm.duckdb

base local

uv run cfm-cli sync --max-paginas 3    # teste rápido
uv run cfm-cli sync                    # varredura completa (~8 min com delay de 2s)
uv run cfm-cli consultar telemedicina
uv run cfm-cli novas --dias 90
uv run cfm-cli reextrair-datas         # refaz as datas a partir do texto já gravado
uv run cfm-cli schema

Ligando ao Claude Code

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

Uso

consultar_resolucao_cfm(tema: str, apenas_vigentes=True, limite=10)

limite vai de 1 a 100. Um tema que seja o número de uma resolução (2314/2022, 2.314) busca aquela norma diretamente, inclusive revogada.

{
  "tema": "inteligência artificial",
  "total": 1,
  "retornados": 1,
  "truncado": false,
  "resultados": [
    {
      "identificador": "2454/2026",
      "ementa": "Normatiza o uso da inteligência artificial na medicina.",
      "vigente": true,
      "revogada_por": null,
      "trecho_relevante": "...Normatiza o uso da inteligência artificial na medicina. O CONSELHO FEDERAL DE MEDICINA...",
      "url_origem": "https://sistemas.cfm.org.br/normas/visualizar/resolucoes/BR/2026/2454",
      "texto_completo_disponivel": true
    }
  ]
}

Ordena por relevância (BM25 do FTS do DuckDB) e depois por data. Revogadas vêm com vigente: false e o número da que substituiu. total é quantas casam na base inteira; truncado: true quer dizer que há mais do que veio.

monitorar_novas_resolucoes(dias=30, filtrar_tema=True, limite=50)

O que foi publicado nos últimos dias (1 a 3.650), mais recentes primeiro, até limite (1 a 100). Com filtrar_tema, só as que citam alguma das PALAVRAS_CHAVE na ementa ou no texto; o filtro é aplicado antes do limite. A resposta traz total, retornados, truncado e sem_data_publicacao: a janela usa a data extraída do texto, e as resoluções sem data ficam de fora, então total zero com muitas sem data quer dizer "não sei", não "nada foi publicado".

Como a fonte funciona

O portal de busca de normas renderiza os resultados no navegador a partir de uma variável resultadoBuscaJson embutida no HTML. O crawler lê esse JSON em vez de raspar tabela: é mais estável, e já vem com o campo de revogação.

Confirmado em 20/09/2026: 2.457 resoluções, 10 por página, 246 páginas.

Dois detalhes que moldaram o desenho:

  • A busca textual por URL é ignorada pelo portal (o total não muda com busca=), então o filtro por palavra-chave é aplicado localmente sobre a ementa.

  • A página de detalhe é um visualizador PDF.js, não texto. O PDF real segue o padrão sistemas.cfm.org.br/normas/arquivos/resolucoes/BR/{ano}/{numero}_{ano}.pdf.

Respeito ao portal

É o site de um conselho profissional, não uma API feita para volume:

  • intervalo configurável entre requisições (padrão 2s);

  • o mesmo PDF nunca é baixado duas vezes (cache por hash da URL);

  • Por padrão, o PDF só é baixado quando a ementa casa com alguma palavra-chave. A instância hospedada baixou as 2.457 uma vez, e a coleta diária dela só baixa o que é novo (ver "Texto integral" abaixo).

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_HOST=0.0.0.0 HTTP_PORTA=8000 uv run radar-cfm-mcp

Variável

Padrão

Observação

TRANSPORTE

stdio

streamable-http liga o modo connector

HTTP_HOST / HTTP_PORTA / HTTP_PATH

127.0.0.1 / 8000 / /mcp

HTTP_STATELESS

true

cada requisição independente; escala melhor

HTTP_LIMITE_GLOBAL_POR_MINUTO

1200

o teto que protege a máquina

HTTP_LIMITE_POR_MINUTO

600

por origem, contra chamada direta

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.

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.

Quando o servidor fica atrás de um túnel, o Host que chega é o nome público, não 127.0.0.1, e toda requisição legítima leva 421. A saída certa é declarar o nome, não desligar a checagem:

HTTP_HOSTS_PUBLICOS=mcp.exemplo.ts.net

Aceita vários separados por vírgula. O loopback continua valendo junto, porque é assim que se testa o servidor de dentro da máquina.

Texto integral: baixar o PDF de todas

Por padrão o sync baixa o PDF só das resoluções cuja ementa toca em IA ou telemedicina, que é o escopo do projeto. São 5 das 2.457. Para as outras, a busca por tema compara apenas a ementa, e trecho_relevante vem nulo: não porque a norma não trate do assunto, mas porque o texto nunca foi lido. A resposta diz isso, em texto_completo_disponivel e no aviso.

Para servir a base a mais gente, vale baixar tudo uma vez:

uv run cfm-cli sync --texto-integral --max-pdfs 0 --publicar

Com o intervalo padrão de 2s entre requisições, a primeira execução leva perto de uma hora e meia e ocupa cerca de 250 MB em data/pdfs. O cache em disco evita repetir, e resolução que já tem texto na base nem volta ao parser: as execuções seguintes só baixam o que é novo.

A coleta diária de deploy/radar-cfm-sync.service roda com --texto-integral --max-pdfs 25. Sem isso, uma resolução nova fora de IA e telemedicina entraria sem texto e, portanto, sem data de publicação, e nunca apareceria no monitoramento.

A coleta seguinte não apaga o texto. Quem roda o sync diário sem --texto-integral não traz PDF nenhum, e um upsert comum sobrescreveria as extrações com nulo. A coluna só é substituída quando o novo valor tem conteúdo, porque texto ausente na coleta significa "não busquei desta vez", nunca "a norma ficou sem texto".

Rodar como serviço

deploy/ tem as units de usuário do systemd que rodam a instância hospedada. Elas assumem o repositório em ~/radar-cfm-mcp e o uv em ~/.local/bin/uv; ajuste os caminhos se o seu for outro.

Unit

O que faz

radar-cfm-connector.service

o servidor HTTP (modo connector), só leitura

radar-cfm-sync.service

uma coleta com --publicar --texto-integral --max-pdfs 25

radar-cfm-sync.timer

dispara a coleta todo dia às 02:00, com até 30 min de espalhamento

cp deploy/radar-cfm-connector.service deploy/radar-cfm-sync.service \
   deploy/radar-cfm-sync.timer ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now radar-cfm-connector.service radar-cfm-sync.timer

A unit do connector vem com HTTP_HOSTS_PUBLICOS= vazio. Preencha com o nome público do túnel ou proxy antes de habilitar, senão tudo que chega de fora recebe 421. Para atualizar só a coleta numa máquina que já roda o connector, copie apenas radar-cfm-sync.service e radar-cfm-sync.timer e rode systemctl --user daemon-reload; assim o nome público já configurado no connector não se perde.

O timer do systemd é o único agendador: o projeto não tem agendador interno. Para rodar uma coleta fora do horário, systemctl --user start radar-cfm-sync.service, e o resultado sai em journalctl --user -u radar-cfm-sync.

Ela escuta só em 127.0.0.1. Expor para fora é uma camada à parte, um proxy reverso com TLS ou um túnel, que aponta para essa porta. Manter assim deixa a decisão de expor num lugar só, em vez de espalhada em variável de ambiente.

O serviço só lê. Quem escreve é a coleta, que roda separada e troca o arquivo por rename.

Se o processo morrer, o systemd sobe de novo em 5 segundos (Restart=always).

A base não vai junto, e o sync roda fora

O DuckDB recusa abrir para escrita enquanto houver um leitor, e no modo connector o servidor abre a base a cada requisição. Escrever direto no arquivo servido falharia sempre que a coleta caísse em cima de uma consulta.

Por isso o sync usa --publicar: constrói a base ao lado e troca por os.replace, que é atômico no POSIX. Quem já abriu continua no arquivo antigo até fechar (o tempo de uma requisição); quem abrir depois pega o novo.

uv run cfm-cli sync --publicar          # constrói ao lado e troca no fim
uv run cfm-cli sync --publicar --forcar # aceita base menor que a servida

A base ao lado começa como cópia da servida, não vazia. Uma varredura que pare no meio (rede ruim, portal fora) produziria uma base com só uma parte das resoluções, e publicá-la tiraria as outras do ar. Com a cópia, a coleta faz upsert por cima do que já existe: o pior caso é uma base desatualizada, nunca uma base menor. A cópia é feita pelo próprio DuckDB (COPY FROM DATABASE), porque um cp pegaria o arquivo sem o WAL pendente.

A publicação é recusada quando a base nova encolhe mais de 10%. Com a cópia acima, uma varredura interrompida já não produz base pequena: ela só deixa de atualizar. A checagem fica como rede de segurança para o que a cópia não cobre, como um clone que falhou pela metade. A versão trocada fica como .anterior, e store.troca.reverter() volta atrás.

Hospedar reduz a carga no CFM

Hoje, cada pessoa que clona o repositório roda o próprio crawler nas 246 páginas. Com um connector, uma instância varre e todo mundo consulta a mesma base. Para um portal de conselho profissional, o connector é a opção mais respeitosa.

Limitações conhecidas

O corpus relevante é pequeno, e isso é do CFM, não do projeto. Das 2.457 resoluções, apenas 5 ementas mencionam os temas padrão: a 2.454/2026 (IA), a 2.314/2022, as 2.227/2018 e 2.228/2019 (revogadas) e a 1.643/2002. Se você espera dezenas de resultados, o problema é a expectativa.

O filtro age sobre a ementa, não sobre o texto completo. Uma resolução que trate de IA no corpo sem dizer isso na ementa não terá o PDF baixado. Ajuste PALAVRAS_CHAVE se o seu tema for outro.

A vigência vem do portal, não de análise jurídica. O campo reflete o que o CFM marca como revogado. Revogação parcial ou alteração por outra resolução não aparece como tal.

O parser depende do formato da página. Se o portal mudar, o crawler falha com uma mensagem explícita (resultadoBuscaJson não encontrado) em vez de devolver vazio em silêncio, mas vai falhar.

Nem toda resolução tem data de publicação. A data sai do cabeçalho do texto, e o campo de data do portal não serve (é a data de carga no sistema deles). Com o extrator desta versão, medido em 24/09/2026 sobre uma cópia da base, 343 das 2.457 continuam sem data, quase todas antigas cujo PDF traz o cabeçalho sem a data ("Publicada no D.O. Seção I, Parte II de", e mais nada). Essas não entram em monitorar_novas_resolucoes, que informa quantas são em sem_data_publicacao.

O portal erra o ano em revogada_por. A Resolução 1.643/2002 vem como revogada pela "2314/2024", e a 2.314 é de 2022. O valor fica como o CFM publica, mas a resposta marca revogada_por_confere: false e sugere a provável em revogada_por_provavel, que é inferência nossa.

A busca cai para LIKE sem o FTS. A extensão full-text do DuckDB é baixada na primeira execução. Sem rede, a busca continua respondendo, mais lenta e sem ranking.

Privacidade

Rodando localmente (stdio):

  • Sai da máquina: requisições ao portal.cfm.org.br e ao sistemas.cfm.org.br, para a busca e os PDFs públicos, só durante o sync.

  • Não sai: os temas que você consulta. A busca roda contra a base local.

Usando o connector hospedado:

  • Sai da sua máquina: os parâmetros de cada chamada (tema, dias, limite) vão para o servidor do autor, passando pelo Tailscale Funnel.

  • O que o servidor guarda: o código deste projeto não registra os temas consultados. O único registro por requisição é o IP de origem quando uma chamada é recusada por limite de taxa.

Nos dois modos: sem LLM, sem telemetria, sem analytics.

Contribuindo

Veja CONTRIBUTING.md. Não rode o crawler em loop nem reduza o delay.

Licença e atribuição

Apache License 2.0: escolhida por o projeto tocar em regulação de conduta médica.

Construído no contexto do IA.med.

Available Tools

2 tools
consultar_resolucao_cfmA

Consulta resoluções do CFM relacionadas a um tema.

Devolve as resoluções mais relevantes, com número, ano, data, ementa, o trecho em volta do termo buscado e sempre a URL de origem. Resoluções revogadas vêm com vigente=false e o número da que as substituiu.

A resposta traz total (quantas casam na base) e retornados (quantas vieram). Com truncado=true, não conclua "só existem N resoluções sobre isso": aumente limite.

trecho_relevante=null significa que o termo não aparece no texto, e não que a norma não trate do assunto. Nesse caso a resolução casou pela ementa ou pelo índice, então abra a URL antes de afirmar qualquer coisa.

Nunca trate um trecho como "a posição do CFM" sem abrir a fonte: a ementa e o link vêm justamente para isso.

Args: tema: assunto a buscar, por exemplo "telemedicina" ou "inteligência artificial". apenas_vigentes: quando True, omite as resoluções já revogadas. limite: quantas resoluções trazer, no máximo 100. Aumente para ver além das mais relevantes.

ParametersJSON Schema
NameRequiredDescriptionDefault
temaYes
limiteNo
apenas_vigentesNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
temaYes
avisoNo
totalYesQuantas resoluções casam com o tema na base inteira, não quantas vieram nesta resposta. Temas amplos casam com dezenas.
truncadoNoTrue quando total > retornados. As que vieram são as mais relevantes; as demais existem e não estão aqui. Não conclua 'só existem N resoluções sobre isso' a partir da lista.
resultadosYes
retornadosNoQuantas vieram em 'resultados', no máximo 'limite'

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With zero annotations, the description carries the full burden and delivers richly: it discloses that revoked resolutions carry vigente=false plus the replacing number, explains the total vs retornados distinction, and defines the trecho_relevante=null semantics (no textual match, not irrelevance). It also warns against treating an excerpt as the CFM's official position without opening the source — a real hallucination risk the agent could not otherwise anticipate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Every sentence earns its place: purpose, return format, revoked-flag behavior, total/retornados, truncation caveat, null-excerpt caveat, and an anti-overclaiming warning, followed by a structured Args block. Critical interpretation warnings are front-loaded right after the core description, with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 3 params, no annotations, and 0% schema parameter coverage, the description covers invocation semantics, response interpretation, edge cases, and user-error prevention. The only omission is explicit sibling differentiation, which is minor and inferable from the sibling's name.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the Args section fully compensates: tema gets domain examples ('telemedicina', 'inteligência artificial'), apenas_vigentes gets behavioral meaning (omits revoked resolutions), and limite gets usage guidance ('Aumente para ver além das mais relevantes'). This adds genuine value beyond the schema's bare types, defaults, and bounds.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Consulta resoluções do CFM relacionadas a um tema' — search CFM resolutions by theme. The search-by-topic behavior distinguishes it from the sibling monitorar_novas_resolucoes, which by name concerns monitoring new resolutions rather than searching historical ones.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear operational context: search by theme, raise limite when truncado=true, and open the URL when trecho_relevante=null. However, it never explicitly names the sibling tool or the condition that would select monitorar_novas_resolucoes instead; that differentiation is left to inference from the sibling's name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

monitorar_novas_resolucoesA

Resoluções do CFM publicadas nos últimos dias, mais recentes primeiro.

A janela usa a data de publicação extraída do texto da resolução. As que ficaram sem data não entram, e sem_data_publicacao diz quantas são: total zero com esse número alto quer dizer "não sei", não "nada foi publicado".

A resposta traz total (quantas casam no período) e retornados (quantas vieram). Com truncado=true, aumente limite ou encurte dias.

Args: dias: tamanho da janela, em dias, a contar de hoje (máximo 3650). filtrar_tema: quando True, devolve só as que mencionam, na ementa ou no texto, as palavras-chave configuradas no servidor (por padrão inteligência artificial, telemedicina, prontuário eletrônico e algoritmo). limite: quantas resoluções trazer, no máximo 100.

ParametersJSON Schema
NameRequiredDescriptionDefault
diasNo
limiteNo
filtrar_temaNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
diasYes
avisoNo
totalYesQuantas resoluções datadas no período casam com o filtro, na base inteira, não quantas vieram nesta resposta.
truncadoNoTrue quando total > retornados. As que vieram são as mais recentes; as demais existem e não estão aqui. Aumente 'limite' ou encurte 'dias'.
resultadosYes
retornadosNoQuantas vieram em 'resultados', no máximo 'limite'
sem_data_publicacaoNoQuantas resoluções da base não têm data e por isso ficam fora deste filtro, existindo ou não no período. Número alto com total=0 significa 'não sei', não 'nada foi publicado'.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: it discloses that the date window is based on the publication date extracted from the text, that undated resolutions are excluded, and that a high sem_data_publicacao with total zero means 'unknown' rather than 'nothing published'. It also explains the total/retornados response fields and the meaning of truncado=true, going well beyond a simple listing statement.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and then adds only high-value caveats and parameter semantics. The Args block is compact, and each sentence earns its place without filler or repetition of schema defaults.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only monitoring tool with no annotations, the description covers the essential call semantics: window definition, filtering, limits, response fields, and the truncation recovery action. The presence of an output schema is supplemented by the description of total, retornados, sem_data_publicacao, and truncado, so an agent has enough to invoke and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must define the parameters, and it does: dias is the window in days from today (max 3650), filtrar_tema triggers server-side keyword filtering with default topics, and limite caps the number of returned resolutions (max 100). This adds real behavioral meaning that the bare schema cannot convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Resoluções do CFM publicadas nos últimos dias, mais recentes primeiro,' which names the exact resource (CFM resolutions) and the operation (monitor/list recent publications). It also specifies ordering and the time window, making it easy to distinguish from the sibling consultar_resolucao_cfm even without naming it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains how to adjust the call via dias, filtrar_tema, and limite, and how to interpret truncation, but it never explicitly states when to prefer this tool over consultar_resolucao_cfm or when not to use it. Usage is implied by the monitoring purpose rather than contrasted with alternatives.

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. 2 tool updates
    • Changedconsultar_resolucao_cfm12 fields changed
      • addedInput schema / properties / limite
        Added value: +{
        +  "default": 10,
        +  "maximum": 100,
        +  "minimum": 1,
        +  "title": "Limite",
        +  "type": "integer"
        +}
      • addedOutput schema / $defs / ResolucaoCFM / properties / nota_vigencia
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "O texto da marcação, como o CFM escreveu",
        +  "title": "Nota Vigencia"
        +}
      • addedOutput schema / $defs / ResolucaoCFM / properties / revogada_por / description
        Added value: +"Identificador da resolução que revogou esta, como o portal do CFM publica. Confira 'revogada_por_confere' antes de citar: o portal erra o ano em alguns casos."
      • addedOutput schema / $defs / ResolucaoCFM / properties / revogada_por_confere
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "False quando o identificador acima não existe na base, ou seja, o portal publicou um ano que não bate. Nesse caso veja 'revogada_por_provavel'.",
        +  "title": "Revogada Por Confere"
        +}
      • addedOutput schema / $defs / ResolucaoCFM / properties / revogada_por_provavel
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Única resolução com aquele número, quando o identificador publicado não existe. É inferência nossa a partir do número, não o que o CFM publicou: confirme na URL de origem antes de citar.",
        +  "title": "Revogada Por Provavel"
        +}
      • addedOutput schema / $defs / ResolucaoCFM / properties / suspensa
        Added value: +{
        +  "default": false,
        +  "description": "A ementa traz marcação de suspensão. Para quem vai aplicar a norma, suspensa tem o mesmo efeito prático de revogada.",
        +  "title": "Suspensa",
        +  "type": "boolean"
        +}
      • addedOutput schema / $defs / ResolucaoCFM / properties / suspensao_parcial
        Added value: +{
        +  "default": false,
        +  "description": "Só alguns dispositivos foram suspensos; o resto da norma segue valendo",
        +  "title": "Suspensao Parcial",
        +  "type": "boolean"
        +}
      • changedOutput schema / $defs / ResolucaoCFM / properties / trecho_relevante / description
        Previous value: -"Trecho do texto completo em volta do termo buscado"New value: +"Trecho do texto integral em volta do termo buscado. None por dois motivos diferentes, distinguidos por 'texto_completo_disponivel': se for false, o texto integral não foi baixado e a busca viu só a ementa; se for true, o termo não aparece no texto. Em nenhum dos casos conclua que a norma não trata do assunto, abra a URL de origem."
      • addedOutput schema / $defs / ResolucaoCFM / properties / vigente / description
        Added value: +"Só reflete revogação, que é o que o portal marca em campo próprio. Uma norma suspensa vem com vigente=true: veja 'suspensa' antes de concluir que ela está produzindo efeito."
      • addedOutput schema / properties / retornados
        Added value: +{
        +  "default": 0,
        +  "description": "Quantas vieram em 'resultados', no máximo 'limite'",
        +  "title": "Retornados",
        +  "type": "integer"
        +}
      • addedOutput schema / properties / total / description
        Added value: +"Quantas resoluções casam com o tema na base inteira, não quantas vieram nesta resposta. Temas amplos casam com dezenas."
      • addedOutput schema / properties / truncado
        Added value: +{
        +  "default": false,
        +  "description": "True quando total > retornados. As que vieram são as mais relevantes; as demais existem e não estão aqui. Não conclua 'só existem N resoluções sobre isso' a partir da lista.",
        +  "title": "Truncado",
        +  "type": "boolean"
        +}
    • Changedmonitorar_novas_resolucoes15 fields changed
      • addedInput schema / properties / dias / maximum
        Added value: +3650
      • addedInput schema / properties / dias / minimum
        Added value: +1
      • addedInput schema / properties / limite
        Added value: +{
        +  "default": 50,
        +  "maximum": 100,
        +  "minimum": 1,
        +  "title": "Limite",
        +  "type": "integer"
        +}
      • addedOutput schema / $defs / ResolucaoCFM / properties / nota_vigencia
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "O texto da marcação, como o CFM escreveu",
        +  "title": "Nota Vigencia"
        +}
      • addedOutput schema / $defs / ResolucaoCFM / properties / revogada_por / description
        Added value: +"Identificador da resolução que revogou esta, como o portal do CFM publica. Confira 'revogada_por_confere' antes de citar: o portal erra o ano em alguns casos."
      • addedOutput schema / $defs / ResolucaoCFM / properties / revogada_por_confere
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "False quando o identificador acima não existe na base, ou seja, o portal publicou um ano que não bate. Nesse caso veja 'revogada_por_provavel'.",
        +  "title": "Revogada Por Confere"
        +}
      • addedOutput schema / $defs / ResolucaoCFM / properties / revogada_por_provavel
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Única resolução com aquele número, quando o identificador publicado não existe. É inferência nossa a partir do número, não o que o CFM publicou: confirme na URL de origem antes de citar.",
        +  "title": "Revogada Por Provavel"
        +}
      • addedOutput schema / $defs / ResolucaoCFM / properties / suspensa
        Added value: +{
        +  "default": false,
        +  "description": "A ementa traz marcação de suspensão. Para quem vai aplicar a norma, suspensa tem o mesmo efeito prático de revogada.",
        +  "title": "Suspensa",
        +  "type": "boolean"
        +}
      • addedOutput schema / $defs / ResolucaoCFM / properties / suspensao_parcial
        Added value: +{
        +  "default": false,
        +  "description": "Só alguns dispositivos foram suspensos; o resto da norma segue valendo",
        +  "title": "Suspensao Parcial",
        +  "type": "boolean"
        +}
      • changedOutput schema / $defs / ResolucaoCFM / properties / trecho_relevante / description
        Previous value: -"Trecho do texto completo em volta do termo buscado"New value: +"Trecho do texto integral em volta do termo buscado. None por dois motivos diferentes, distinguidos por 'texto_completo_disponivel': se for false, o texto integral não foi baixado e a busca viu só a ementa; se for true, o termo não aparece no texto. Em nenhum dos casos conclua que a norma não trata do assunto, abra a URL de origem."
      • addedOutput schema / $defs / ResolucaoCFM / properties / vigente / description
        Added value: +"Só reflete revogação, que é o que o portal marca em campo próprio. Uma norma suspensa vem com vigente=true: veja 'suspensa' antes de concluir que ela está produzindo efeito."
      • addedOutput schema / properties / retornados
        Added value: +{
        +  "default": 0,
        +  "description": "Quantas vieram em 'resultados', no máximo 'limite'",
        +  "title": "Retornados",
        +  "type": "integer"
        +}
      • addedOutput schema / properties / sem_data_publicacao
        Added value: +{
        +  "default": 0,
        +  "description": "Quantas resoluções da base não têm data e por isso ficam fora deste filtro, existindo ou não no período. Número alto com total=0 significa 'não sei', não 'nada foi publicado'.",
        +  "title": "Sem Data Publicacao",
        +  "type": "integer"
        +}
      • addedOutput schema / properties / total / description
        Added value: +"Quantas resoluções datadas no período casam com o filtro, na base inteira, não quantas vieram nesta resposta."
      • addedOutput schema / properties / truncado
        Added value: +{
        +  "default": false,
        +  "description": "True quando total > retornados. As que vieram são as mais recentes; as demais existem e não estão aqui. Aumente 'limite' ou encurte 'dias'.",
        +  "title": "Truncado",
        +  "type": "boolean"
        +}
  2. 2 tool updatesv0.1.0
    • First observedconsultar_resolucao_cfm
    • First observedmonitorar_novas_resolucoes

TDQS

A4.6/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct purposes: one searches resolutions by topic, the other monitors recently published resolutions. There is no overlap or ambiguity between them.

Naming Consistency5/5

Both tool names follow the same verb_noun pattern in Portuguese: consultar_resolucao_cfm and monitorar_novas_resolucoes. The naming is consistent and predictable.

Tool Count3/5

With only 2 tools, the server feels thin for a domain that could reasonably include fetching a specific resolution by number or listing by year. However, the narrow 'radar' purpose partially justifies the small count, making it borderline rather than extreme.

Completeness4/5

The tool surface covers the two core needs: finding resolutions by topic and tracking new publications. Obvious gaps like fetching a resolution by its number or browsing all resolutions are missing, but agents can work around them via the search tool, so the gaps are minor.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server for querying Brazilian Federal Council of Medicine (CFM) registration data from official sources. It provides a read-only tool to consult medical registrations via natural language.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables querying health establishment data from the Brazilian Federal Council of Medicine (CFM), providing read-only access to official information.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables querying official Brazilian Federal Accounting Council records for accounting professionals and companies, providing read-only consultation through natural language.
    MIT