Skip to main content
Glama
fabianofilho

radar-papers-mcp

by fabianofilho

radar-papers-mcp

Servidor MCP que monitora PubMed e medRxiv por tópicos de pesquisa configuráveis e resume os papers com um LLM local. Guarda o resultado numa base local, deduplicado por DOI.

Sobre o que esta ferramenta faz e não faz

  • O resumo sai do abstract, não do texto completo. Ele serve para triagem: decidir se vale abrir o paper. Não substitui a leitura.

  • O resumo é gerado por LLM e pode errar. Confira os números no abstract original, o link vem em toda resposta.

  • A cobertura depende das suas queries. O que não casa com a query configurada simplesmente não aparece; ausência de resultado não significa ausência de literatura.

Requisitos

O quê

Versão

Para quê

Python

3.12+

runtime

uv

recente

dependências e venv

Um LLM local com API OpenAI-compatible

-

resumo dos papers

Chave da NCBI (opcional)

-

eleva o rate limit de 3 para 10 req/s

Related MCP server: kavi-research-assistant-mcp

Instalação

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

Configuração

Variável

Padrão

Observação

QWEN_ENDPOINT

http://127.0.0.1:8080/v1

llama.cpp. Ollama: :11434/v1. LM Studio: :1234/v1

QWEN_MODEL

local-model

llama.cpp e LM Studio aceitam qualquer nome

PUBMED_API_KEY

vazio

chave gratuita da NCBI

DUCKDB_PATH

./data/papers.duckdb

base local

TOPICOS_PATH

./config/topicos.yaml

tópicos monitorados

Os tópicos ficam em config/topicos.yaml. Cada um tem duas configurações, porque as fontes funcionam de forma diferente:

topicos:
  - nome: multicalibração
    pubmed: multicalibration[All Fields]   # sintaxe das E-utilities
    medrxiv:                                # palavras simples, filtradas localmente
      - multicalibration
      - multi-calibration
uv run papers-cli topicos
uv run papers-cli sync --dias 30
uv run papers-cli buscar "multicalibração"
uv run papers-cli resumir "10.1016/j.exemplo.2026.100217"

Sync agendado

O servidor MCP só lê a base; quem a alimenta é papers-cli sync. O agendamento oficial é um timer systemd de usuário, versionado em deploy/: roda todo dia às 04:10, com atraso aleatório de até 30 minutos (para várias máquinas não baterem nas APIs públicas no mesmo minuto) e Persistent=true (se a máquina estava desligada, roda ao ligar).

As units supõem o repositório em ~/radar-papers-mcp e o uv em ~/.local/bin/uv. Se for diferente, ajuste WorkingDirectory e ExecStart antes de instalar.

cp deploy/radar-papers-sync.service deploy/radar-papers-sync.timer \
   deploy/radar-papers-sync-falha.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now radar-papers-sync.timer
systemctl --user list-timers radar-papers-sync.timer   # próxima execução
journalctl --user -u radar-papers-sync.service          # log dos syncs

Falha não passa em silêncio: se o PubMed (em qualquer tópico) ou o medRxiv falhar, papers-cli sync grava o que as outras fontes trouxeram, lista as falhas no stderr e sai com código 1. O systemd marca a unit como failed e o OnFailure roda radar-papers-sync-falha.service, que grava uma linha com prioridade err no journal e, se houver notify-send, mostra uma notificação. Para ser avisado por outro canal, troque o ExecStart dessa unit. Para ver falhas recentes:

systemctl --user status radar-papers-sync.service
journalctl --user -t radar-papers-sync -p err

Sem o timer, rode papers-cli sync à mão ou pelo agendador que preferir; o servidor não agenda nada sozinho.

Atualizando uma base criada antes do schema 2

A versão atual decide o que é "novo" pela data de entrada na fonte (coluna data_entrada). Uma base antiga é migrada sozinha na primeira conexão de escrita (o próximo sync, por exemplo). Na migração, a data de entrada do PubMed é aproximada pelo dia da última coleta; para gravar a data Entrez real dos papers que já estavam na base, rode uma vez:

uv run papers-cli corrigir-datas

Ligando ao Claude Code

claude mcp add radar-papers --scope user \
  -e DUCKDB_PATH=/caminho/para/radar-papers-mcp/data/papers.duckdb \
  -e TOPICOS_PATH=/caminho/para/radar-papers-mcp/config/topicos.yaml \
  -e QWEN_ENDPOINT=http://127.0.0.1:8080/v1 \
  -e QWEN_MODEL=local-model \
  -- uv --directory /caminho/para/radar-papers-mcp run radar-papers-mcp

Uso

buscar_papers_novos(topico="", dias=7, limite=50)

Papers que entraram no PubMed ou no medRxiv nos últimos dias, lidos da base local, com a chave para usar no resumo e o link original.

  • "Novo" é pela data de entrada na fonte (data_entrada: Entrez no PubMed, postagem no medRxiv), não pela data da edição da revista (data_publicacao, só para exibição). A edição pode estar meses antes ou depois da entrada, e muitas revistas informam só o ano ou o mês.

  • topico é o nome de um tópico configurado. Caixa e acento não importam, e basta um trecho com palavras inteiras do nome (fairness, calibracao). A comparação é por palavra inteira: calibração não traz multicalibração. Se o pedido não corresponder a um único tópico, a resposta vem vazia com a lista dos tópicos válidos em aviso.

  • dias vai de 1 a 365 e limite de 1 a 200. Os mais recentes vêm primeiro.

  • total conta todos os papers do período, mesmo os que ficaram além do limite; nesse caso aviso diz quantos foram omitidos.

resumir_paper(paper_id: str)

{
  "chave": "pubmed:42761253",
  "titulo": "Mortality risk ranking after medical emergency team review...",
  "url": "https://pubmed.ncbi.nlm.nih.gov/42761253/",
  "origem": "llm",
  "resumo": {
    "problema": "Validação externa e redesenvolvimento de modelos preditivos de mortalidade após revisão da equipe de emergência.",
    "metodo": "Coorte multicêntrica em quatro hospitais, 1.937 adultos.",
    "achado_principal": "O modelo original discriminou bem (AUC 0,80) mas com estimativas variáveis entre hospitais; o novo modelo chegou a AUC 0,84 com menos variáveis.",
    "relevancia": "Mostra que a discriminação pode ser robusta mesmo quando a calibração absoluta varia entre instituições."
  },
  "aviso": "O resumo é gerado por LLM local a partir do abstract, não do texto completo. Sempre confira no link original antes de citar."
}

O conteúdo do resumo é de um retorno real (a chave acima é ilustrativa). O resumo fica cacheado: o mesmo paper não é resumido duas vezes. Sem abstract, ou com o LLM fora do ar, resumo vem nulo, origem vem indisponivel e aviso explica o motivo.

As duas fontes

Fonte

API

Limite

PubMed

E-utilities (esearch + efetch)

3 req/s sem chave, 10 com chave

medRxiv

api.medrxiv.org/details

sem busca por termo; paginado de 100 em 100

O sync pagina as duas fontes até o fim: o PubMed até o count do esearch (teto de 1000 IDs por tópico) e o medRxiv até o total da janela (teto de 100 páginas, 10 mil preprints). Se um teto for atingido, o log do sync registra um aviso com o total da fonte.

O rate limit da NCBI é aplicado de verdade, a primeira tentativa de teste deste projeto recebeu {"error": "API rate limit exceeded"}. O fetcher espaça as requisições conforme a chave configurada.

O medRxiv não aceita busca por termo: a API é consultada uma vez por janela e o filtro por tópico é local, sobre título e abstract.

Deduplicação por DOI

O mesmo paper casa com mais de um tópico, e um preprint do medRxiv pode sair depois num periódico indexado no PubMed com o mesmo DOI. A chave é o DOI (ou o id da fonte quando não há DOI), e um paper já conhecido ganha o novo tópico na lista em vez de virar uma segunda linha.

Limitações conhecidas

Sem abstract, não há resumo. Um paper sem abstract devolve erro explícito em vez de um resumo gerado a partir do título. Resumir texto vazio produz exatamente o tipo de invenção plausível que torna a ferramenta inútil para pesquisa.

A janela do medRxiv custa caro. Uma semana do medRxiv tem por volta de mil preprints, e o sync baixa todos para filtrar localmente (cerca de 10 requisições). Um backfill largo (sync --dias 90) baixa muito mais; acima de 10 mil preprints na janela, o que passar do teto fica de fora e o log avisa.

O filtro do medRxiv privilegia a cobertura, não a precisão. Um preprint casa com o tópico quando qualquer termo da lista aparece como trecho do título ou do abstract. Isso é intencional, para não perder preprint relevante, mas traz ruído: no tópico de calibração aparecem preprints que falam de calibrar um instrumento ou um modelo econômico, sem relação com modelo clínico. A triagem fica com você (ou com o resumir_paper, cujo campo relevancia diz quando o paper só tangencia o tópico). Para reduzir o ruído, use termos mais específicos no YAML.

A query do PubMed é sua responsabilidade. Uma query mal formada devolve zero sem erro. Teste no PubMed antes de colocar no YAML, na prática, buscas muito específicas devolvem pouquíssimo (multicalibration retorna ~14 resultados em toda a base).

O resumo não é verificado contra o abstract. Diferente do projeto de protocolos, aqui não há conferência de citação literal: o campo achado_principal pode conter um número que o modelo interpretou errado.

Só PubMed e medRxiv. Sem arXiv, bioRxiv, Scopus ou Web of Science.

Privacidade

  • Sai da máquina: requisições ao PubMed (NCBI) e ao medRxiv. Se você configurar uma chave da NCBI, ela vai junto nas requisições, é o funcionamento normal da API.

  • Não sai: seus tópicos de pesquisa ficam no arquivo local; as queries vão às APIs como qualquer busca.

  • O abstract vai para o seu LLM no resumo.

  • Sem telemetria, sem analytics.

Contribuindo

Veja CONTRIBUTING.md. PubMed e medRxiv são serviços públicos: não rode sincronização em loop nem contorne o limitador de taxa.

Licença e atribuição

MIT: este projeto é agregação de literatura e metadados abertos, sem contato com regulação, conduta clínica ou dado de paciente.

Construído no contexto do IA.med.

Available Tools

2 tools
buscar_papers_novosA

Papers que entraram no PubMed ou no medRxiv nos últimos dias, por tópico monitorado.

Consulta a base local, alimentada pelo sync (papers-cli sync, em geral agendado por um timer diário). "Novo" é pela data de entrada na fonte (Entrez no PubMed, postagem no medRxiv), não pela data da edição da revista. Cada resultado traz a chave para usar em resumir_paper e o link original. 'total' conta todos os papers do período; se passar de 'limite', o aviso diz.

Args: topico: nome de um tópico configurado; vazio devolve todos. Caixa e acento não importam, e basta um trecho com palavras inteiras do nome ("fairness"). Se não corresponder a um único tópico, a resposta traz a lista dos tópicos válidos no aviso. dias: tamanho da janela, de 1 a 365, a contar de hoje. limite: máximo de resultados devolvidos, de 1 a 200. Os mais recentes vêm primeiro.

ParametersJSON Schema
NameRequiredDescriptionDefault
diasNo
limiteNo
topicoNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
diasYes
avisoNo
totalYesQuantos papers o período tem, mesmo além do limite
topicoYes
resultadosYes

TDQS

A4.8/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 behavioral burden and does so thoroughly: it defines 'new' by source entry date, explains the local database sync, specifies that results include the key and link, describes the total/warning behavior when exceeding the limit, and details topic-matching nuances such as case/accent insensitivity and ambiguous-topic handling.

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 well structured: a one-sentence summary, followed by behavioral context, then a clear Args list. It is front-loaded with the essential purpose and contains no filler.

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/search tool with an output schema, the description covers everything needed to invoke it correctly: source, freshness definition, parameter semantics, output content, warnings, and the link to the sibling tool. Very little is left to guesswork.

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 compensate. The Args block fully documents all three parameters: topico's matching and failure behavior, dias' 1-365 window counted from today, and limite's 1-200 cap with newest-first ordering. This is substantial value beyond the bare schema.

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 clearly identifies the tool as a search/lookup operation for papers newly entered in PubMed or medRxiv, scoped by monitored topic. It also differentiates from the only sibling, resumir_paper, by stating each result carries the key to use in that summarization tool.

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?

It gives clear context for use: consult a local database fed by a scheduled sync, filter by topic, time window, and result limit, and then use the resulting key with resumir_paper. It does not explicitly list when-not-to-use or alternative conditions, but the workflow context is unambiguous enough.

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

resumir_paperA

Resumo estruturado de um paper: problema, método, achado e relevância.

O resumo vem do abstract, não do texto completo, e é gerado pelo LLM local. Fica cacheado: o mesmo paper não é resumido duas vezes. Sem abstract, ou com o LLM fora do ar, resumo vem nulo, origem vem "indisponivel" e o aviso diz o motivo, em vez de um resumo inventado.

Args: paper_id: a chave devolvida por buscar_papers_novos (o DOI, em geral).

ParametersJSON Schema
NameRequiredDescriptionDefault
paper_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
urlYes
avisoNo
chaveYes
origemYesllm, cache ou indisponivel
resumoNo
tituloYes

TDQS

A4.4/5.0
Behavior5/5

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

No annotations are provided, so the description carries the full burden — and it delivers. It discloses that the summary comes from the abstract (not full text), that it is generated by the local LLM, that results are cached (same paper never summarized twice), and precisely how failures behave: null summary, origin 'indisponivel', and a warning explaining the reason instead of fabricating content. This is exemplary edge-case disclosure.

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?

Compact and well-structured: purpose sentence first, then behavioral constraints, then the single argument. Every sentence earns its place — the caching, fallback, and source details are all high-value. No filler or repetition of the schema.

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

Completeness4/5

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

Complete for a single-parameter tool. An output schema exists, so return values need not be spelled out in the description. The description covers purpose, input provenance, caching, and failure modes. The only minor gap is that it doesn't explicitly enumerate the output schema fields, but that is the output schema's job.

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

Parameters4/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 compensate — and it does. It explains paper_id as the key returned by buscar_papers_novos (usually the DOI), giving both the provenance and format of the value. For a single-parameter tool this is sufficient; a slight gap is not spelling out the expected DOI format explicitly, but the source reference covers it.

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+resource: a structured summary (problema, método, achado, relevância) of a paper. It clearly distinguishes from the sibling buscar_papers_novos (search vs. summarize), and even references that tool as the source of the input key, so an agent cannot confuse the two.

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?

Usage context is implied rather than stated. The Args section references 'a chave devolvida por buscar_papers_novos', which implies the correct workflow (call search first, then summarize). However, it never explicitly says 'use this after buscar_papers_novos' or gives a when-not-to-use condition beyond the abstract/LLM fallback, so the guidance is implicit.

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. 1 tool update
    • Changedbuscar_papers_novos4 fields changed
      • addedInput schema / properties / limite
        Added value: +{
        +  "default": 50,
        +  "title": "Limite",
        +  "type": "integer"
        +}
      • addedOutput schema / $defs / PaperEncontrado / properties / data_entrada
        Added value: +{
        +  "anyOf": [
        +    {
        +      "format": "date",
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Data em que o paper entrou na fonte; é a que define 'novo'",
        +  "title": "Data Entrada"
        +}
      • addedOutput schema / $defs / PaperEncontrado / properties / data_publicacao / description
        Added value: +"Data da edição da revista (ou da postagem do preprint)"
      • addedOutput schema / properties / total / description
        Added value: +"Quantos papers o período tem, mesmo além do limite"
  2. 2 tool updatesv0.1.0
    • First observedbuscar_papers_novos
    • First observedresumir_paper

TDQS

A4.5/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct purposes: one retrieves recent paper lists, the other generates a structured summary of a single paper. No overlap or ambiguity in their roles.

Naming Consistency5/5

Both tool names follow a consistent verb_noun pattern in Portuguese: buscar_papers_novos and resumir_paper. Naming style is uniform, lowercase with underscores.

Tool Count4/5

With only two tools, the set is minimal but fits a narrow, focused purpose (monitor new papers and summarize them). It stays on the thin side but does not feel inadequate for that bounded scope.

Completeness4/5

The core workflow of finding new papers and getting summaries is fully supported. Minor gaps exist (e.g., no tool to fetch a single paper's raw metadata by ID), but agents can complete the primary loop without dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    MCP server pulling academic publications (arXiv, PubMed, HF Daily Papers), trending code (GitHub, HF Hub), and medical-device regulatory data (FDA 510(k), recalls) into newspaper-style briefings. Per-category round-robin, weighted configuration, sandbox-safe Python launcher.
    16
    6
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables local research workflows (paper discovery, relevance scoring, digests) and homelab monitoring (Prometheus, logs) through an MCP server, using local LLM inference via Ollama with no cloud dependencies.
    -