openalex-mcp-server

270M+ publicações acadêmicas

Documentação

@cyanheads/openalex-mcp-server

Acesse o catálogo de pesquisa acadêmica do OpenAlex - mais de 270 milhões de publicações via MCP. STDIO e Streamable HTTP.

5 Ferramentas • 2 Prompts

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework

Servidor Público Hospedado: https://openalex.caseyjhand.com/mcp


Visão Geral

Dados de catálogo acadêmico do OpenAlex — mais de 270 milhões de obras, mais de 90 milhões de autores, mais de 100 mil fontes, além de instituições, tópicos, palavras-chave, editoras e financiadores. Pesquise, filtre e agregue em todos os oito tipos de entidade, resolva nomes ambíguos para IDs canônicos e percorra o grafo de citações um salto por vez. Funciona como processo stdio, servidor local Streamable HTTP ou o endpoint público hospedado acima.

Ferramentas

FerramentaDescrição
openalex_search_entitiesPesquise, filtre, ordene ou recupere por ID em todos os 8 tipos de entidade
openalex_analyze_trendsAgregação por grupo para análise de tendências e distribuição
openalex_resolve_nameResolva um nome ou identificador (DOI, ORCID, ROR, PMID, ISSN, ID OpenAlex) para um ID OpenAlex
openalex_get_citation_graphPercorra o grafo de citações um salto a partir de uma obra-semente: cites, cited_by ou related_to
openalex_describe_fieldsListe nomes de campos válidos de filtro, group_by e select para um tipo de entidade

Prompts

PromptDescrição
openalex_literature_reviewOrienta uma busca sistemática de literatura: formule consulta, pesquise, filtre, analise rede de citações, sintetize descobertas
openalex_research_landscapeAnalisa o panorama de pesquisa de um tópico: tendências de volume, principais autores/instituições, taxas de acesso aberto, fontes de financiamento

Referência de capacidades

openalex_search_entities ferramenta

  • Recupere uma única entidade por ID — ID OpenAlex, DOI, ORCID, ROR, PMID, ISSN ou PMCID (forma simples ou URL), ou uma palavra-chave pelo seu slug ou URL de palavra-chave. id tem precedência: parâmetros de busca passados junto são descartados, e a resposta nomeia quais. Um PMCID não resolve nada (o OpenAlex não indexa nenhum) — use o PMID ou DOI da obra
  • Busca por palavras-chave (operadores booleanos, frases entre aspas, curingas, correspondência difusa) além dos modos de busca exact e semantic — o semântico ranqueia um conjunto candidato dependente da consulta a ~1 req/seg (até 50 por página), e seu meta.count reporta a contagem de candidatos em vez de um total de correspondências
  • Sintaxe de filtro rica: AND entre campos, OR dentro de um campo (|), NOT (!), intervalos, comparações; uma vírgula dentro de um valor de filtro é rejeitada (use |, ou um filtro .search para texto livre)
  • select retorna um padrão curado por tipo de entidade, a menos que seja sobrescrito, ou ["*"] para o registro completo; nomes de campo inválidos geram erro com o conjunto válido
  • Paginação por cursor para busca por palavras-chave e exata, até 100 resultados por página (padrão 25); a busca semântica percorre seus candidatos com page (baseado em 1) em vez disso, e misturar qualquer um dos controles com o search_mode errado é rejeitado antes da chamada upstream
  • sample (até 100, apenas uma página — nem cursor nem page se aplicam) além de um seed determinístico para amostragem aleatória reproduzível; apenas modos por palavras-chave e exato, e nunca junto com sort — o OpenAlex não amostra busca semântica e recusa amostra ordenada, então ambas as combinações são rejeitadas antes da chamada upstream
  • Cada resposta mantém 64.000 bytes por superfície (structuredContent, e content[] com seu trailer), a menos que o mínimo que pode retornar seja maior, o que é sinalizado como over_budget: uma página que excederia mantém seus registros iniciais inteiros e nomeia o restante em omitted com a única chamada que os retorna (como um conjunto, na ordem do OpenAlex), sem perturbar next_cursor; um registro grande demais por si só retorna com seus maiores arrays em janelas, preenchidos por sua vez para que cada um mostre o que cabe e rotulados com quanto do array contém, e slice: {field, offset} em uma consulta id pagina qualquer array até o fim
  • Um registro de lista carregando exatamente 100 authorships — o máximo que o OpenAlex retorna em uma resposta de lista — é sinalizado como possivelmente limitado, com a chamada não cobrada id + slice que busca o restante
  • display_name é anulável para registros sem título; toda chamada reporta o custo do orçamento diário do OpenAlex e o saldo restante

openalex_analyze_trends ferramenta

  • Agrupe qualquer campo suportado para análise de tendência, distribuição ou comparativa; combine com filters para delimitar a população antes da agregação
  • Até 200 grupos por página (padrão). order: "count" (padrão) retorna os top-N por contagem sem páginas adicionais; order: "key" enumera todos os valores distintos em ordem crescente de chave com paginação por cursor
  • include_unknown (padrão false) adiciona um grupo para entidades sem valor no campo agrupado, sinalizado como is_unknown: true e rotulado como desconhecido na saída de texto. O OpenAlex o chaveia como -111/-111.0 (campos numéricos), unknown (campos de texto e order: "key"), ou um ID terminando em /unknown; a chave é um sentinela, não um valor de filtro. Campos booleanos não têm tal grupo — um valor ausente conta como false
  • Nem todo campo é agrupável — campos de data bruta, operadores .search, modificadores de intervalo from_*/to_*, pontuações decimais como fwci, display_name, e campos de ID externo como doi são rejeitados; openalex_describe_fields(entity_type, "group_by") lista os campos que agrupam
  • Um group_by de obras em authorships.countries diz em seu aviso que o OpenAlex conta apenas os primeiros 100 autorias de cada obra para esse campo, e nomeia authorships.institutions.country_code como o campo que conta todos eles
  • Reporta o custo do orçamento diário do OpenAlex e o saldo restante — a agregação tem preço muito abaixo de paginar as mesmas entidades

openalex_resolve_name ferramenta

  • Um nome ou nome parcial executa uma busca de autocompletar: até 10 correspondências com dicas de desambiguação (última instituição, organização anfitriã, local, etc.)
  • Um identificador — ID OpenAlex, DOI, ORCID, ROR, PMID, ISSN ou URL de palavra-chave, simples ou em forma de URL — resolve diretamente para o único registro que endereça; sem necessidade de entity_type, pois o identificador determina o seu próprio. Um PMCID é reconhecido mas não resolve nada — o OpenAlex não indexa nenhum
  • filters restringe apenas o autocompletar; em uma consulta por identificador são ignorados e nomeados em um aviso
  • Com entity_type definido, o autocompletar do OpenAlex falha em um nome com mais de 1.000 caracteres; essa falha é reportada uma vez como query_too_long com conselho para encurtar o nome, não repetida como indisponibilidade
  • Reporta o custo do orçamento diário do OpenAlex e o saldo restante

openalex_get_citation_graph ferramenta

  • direction define a aresta: cites (obras que citam a semente), cited_by (a própria lista de referências da semente), related_to (obras relacionadas algorítmicas do OpenAlex, ~8-30 típicas, pode ser vazio)
  • seed_id aceita um ID OpenAlex, DOI ou PMID (PMCID reconhecido mas não resolve nada); validado contra uma consulta ao vivo primeiro, então uma semente inexistente falha como NotFound em vez de retornar um grafo vazio
  • Empilha com filters/sort/select para estreitar o grafo; filters não pode definir cites/cited_by/related_to, nem um alias de um deles como cited_works — essas chaves são reservadas para direction
  • Paginação por cursor, até 100 resultados por página (padrão 25)
  • O mesmo orçamento de resposta de 64.000 bytes e divulgação de limite de 100 autorias que openalex_search_entities; obras cortadas de uma página são nomeadas em omitted com a chamada openalex_search_entities que as retorna, na ordem do OpenAlex
  • Reporta o custo do orçamento diário do OpenAlex, cobrindo tanto a consulta de validação da semente quanto a página do grafo, além do saldo restante

openalex_describe_fields ferramenta

  • Lista todo nome de campo válido para um tipo de entidade + contexto (filter, group_by, select) — o conjunto completo, nunca truncado
  • group_by é o conjunto de filtros menos o que o OpenAlex rejeita como chave de agregação: campos de data bruta, operadores .search/.search.exact, modificadores de intervalo from_*/to_*, e um conjunto por tipo de entidade encontrado agrupando cada campo listado contra a API ao vivo — pontuações decimais como fwci, vários campos de ano de fonte, display_name, e campos de ID externo entre eles
  • query opcional reordena resultados por similaridade de nome sem descartar nenhum campo — o objeto pai de um valor aninhado permanece alcançável mais abaixo na lista
  • Suportado por um catálogo de campos gerado — sem chamadas de API ao vivo

openalex_literature_review prompt

  • Argumentos: topic obrigatório; scope (narrow / broad) opcional, padrão narrow
  • Retorna uma mensagem de usuário percorrendo um fluxo de trabalho de 6 etapas: resolva entidades, pesquise literatura, identifique artigos-chave, rastreie citações, analise o panorama, sintetize descobertas
  • scope muda a etapa de busca: narrow favorece busca exata com filtros de tópico restritos; broad adiciona busca semântica em múltiplos IDs de tópico relacionados

openalex_research_landscape prompt

  • Argumentos: topic obrigatório
  • Retorna uma mensagem de usuário percorrendo um fluxo de trabalho quantitativo de 7 etapas: resolva o ID do tópico, tendências de volume, principais contribuidores (instituições/países/periódicos), taxa de acesso aberto, fontes de financiamento, obras mais citadas, frentes emergentes
  • A etapa de financiamento agrupa por awards.funder_id (resolva nomes via openalex_resolve_name) ou awards.funder_display_name para rótulos legíveis em um único salto

Recursos

Construído sobre @cyanheads/mcp-ts-core: transportes stdio e Streamable HTTP, autenticação plugável (none / jwt / oauth), armazenamento intercambiável (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), registro estruturado com rastreamento OpenTelemetry opcional.

Específico do OpenAlex:

  • Cliente de API tipado com normalização automática de ID (DOI, ORCID, ROR, PMID, PMCID, ISSN, URLs do OpenAlex e PubMed/PubMed Central); um PMCID normaliza mas não resolve nada, pois o OpenAlex não indexa nenhum
  • Sem chave por padrão — uma chave de API opcional aumenta os limites de taxa e orçamento diário, e um mailto opcional identifica o chamador ao pool educado do OpenAlex
  • Códigos de status HTTP mapeados para classes de erro MCP específicas (400 → InvalidParams, 422 → ValidationError, 429 → RateLimited) com mensagens upstream exibidas
  • Repetições de requisição cientes de tempo limite e suporte a cancelamento via AbortSignal

Saída amigável ao agente:

  • Proveniência — toda ferramenta que chama a API relata o custo do orçamento diário do OpenAlex, o saldo restante e o horário de redefinição (budget.costUsd, remainingUsd, resetsInSeconds)
  • Eco da consulta efetiva — respostas de busca, tendências e gráfico de citações ecoam os critérios que realmente foram executados, para que um resultado vazio seja diagnosticável sem reler a solicitação
  • Contratos de saída discriminados — razões de erro tipadas (entity_not_found, upstream_budget_exhausted, semantic_per_page_cap, reserved_filter_key e outras), cada uma com uma dica explícita de recuperação
  • Modelagem de resposta — resumos são reconstruídos da codificação de índice invertido do OpenAlex para texto simples, e display_name permanece null para registros sem título ou com paratexto, em vez de ser preenchido retroativamente
  • Texto limpo do provedor — o OpenAlex passa títulos, resumos e nomes sem sanitização; entidades HTML são decodificadas conforme a tabela completa do WHATWG, comentários e tags de formatação HTML/JATS/MathML são removidos, wrappers CDATA e marcadores matemáticos <?CDATA …?> da IOP são desembrulhados com seu TeX preservado, e uma quebra de linha com escape duplo (um \n literal) vira um espaço; texto literal como A < B e TeX como \nu é mantido. Campos de identificador e URL (id, doi, ids, orcid, ror, issn, *_url, linhagens) são retornados exatamente como o OpenAlex os armazena, para que cada um resolva quando passado de volta. A saída de texto escapa esse texto para Markdown, para que um *, <tag> ou [x](y) perdido seja renderizado como escrito; IDs e URLs que renderizam como links permanecem byte-idênticos

Primeiros passos

Instância pública hospedada

Uma instância pública está disponível em https://openalex.caseyjhand.com/mcp — sem necessidade de instalação. Aponte qualquer cliente MCP para ela via Streamable HTTP:

{
  "mcpServers": {
    "openalex-mcp-server": {
      "type": "streamable-http",
      "url": "https://openalex.caseyjhand.com/mcp"
    }
  }
}

Auto-hospedado / Local

Adicione o seguinte ao arquivo de configuração do seu cliente MCP.

{
  "mcpServers": {
    "openalex-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/openalex-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "OPENALEX_API_KEY": "your-api-key"
      }
    }
  }
}

Ou com npx (sem necessidade de Bun):

{
  "mcpServers": {
    "openalex-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@cyanheads/openalex-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "OPENALEX_API_KEY": "your-api-key"
      }
    }
  }
}

Ou com Docker:

{
  "mcpServers": {
    "openalex-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT_TYPE=stdio",
        "-e", "OPENALEX_API_KEY=your-api-key",
        "ghcr.io/cyanheads/openalex-mcp-server:latest"
      ]
    }
  }
}

Para Streamable HTTP, defina o transporte e inicie o servidor:

MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 OPENALEX_API_KEY=... bun run start:http
# Server listens at http://localhost:3010/mcp

OPENALEX_API_KEY é opcional — defina-o como uma chave de conta OpenAlex gratuita para limites de taxa com chave e orçamento sob o preço baseado em uso do OpenAlex, ou omita-o para acesso anônimo. Defina OPENALEX_MAILTO como um e-mail se quiser se identificar para o OpenAlex (o pool educado).

Pré-requisitos

Instalação

  1. Clone o repositório:
git clone https://github.com/cyanheads/openalex-mcp-server.git
  1. Navegue até o diretório:
cd openalex-mcp-server
  1. Instale as dependências:
bun install
  1. Configure o ambiente:
cp .env.example .env
# edit .env and set required vars

Configuração

VariávelDescriçãoPadrão
MCP_TRANSPORT_TYPETransporte: stdio ou http.stdio
MCP_HTTP_PORTPorta para o servidor HTTP.3010
MCP_SESSION_MODEModo de sessão HTTP: stateless, stateful ou auto (resolve para stateful). O servidor declara stateless no código; um valor explícito o substitui.stateless
MCP_AUTH_MODEModo de autenticação: none, jwt ou oauth.none
MCP_ALLOWED_ORIGINSLista de permissões separada por vírgulas de cabeçalhos Origin do navegador para transporte HTTP. Não definido = somente loopback; defina como * para desativar.somente loopback
MCP_LOG_LEVELNível de log (RFC 5424).debug
LOGS_DIRDiretório para arquivos de log (somente Node.js).<project-root>/logs
STORAGE_PROVIDER_TYPEBackend de armazenamento.in-memory
OPENALEX_API_KEYChave de API de conta OpenAlex, enviada upstream como api_key= (gratuita em openalex.org/settings/api). Sem ela, aplicam-se limites de taxa anônimos.—
OPENALEX_MAILTOE-mail enviado upstream como mailto= para se identificar para o OpenAlex (o "pool educado"); um identificador de cortesia, separado da chave de API.—
OPENALEX_BASE_URLURL base da API OpenAlex.https://api.openalex.org
OTEL_ENABLEDAtivar instrumentação OpenTelemetry (spans, métricas, logs de conclusão).false

Consulte .env.example para a lista completa de substituições opcionais.

Executando o servidor

Desenvolvimento local

  • Compilar e executar:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
    
  • Executar verificações e testes:

    bun run devcheck   # Lints, formats, type-checks
    bun run test       # Runs the test suite
    

Docker

docker build -t openalex-mcp-server .
docker run --rm -e OPENALEX_API_KEY=your-key -p 3010:3010 openalex-mcp-server

O Dockerfile usa como padrão transporte HTTP, modo de sessão sem estado e registra logs em /var/log/openalex-mcp-server. Dependências de pares do OpenTelemetry são instaladas por padrão — compile com --build-arg OTEL_ENABLED=false para omiti-las.

Estrutura do projeto

DiretórioFinalidade
src/index.tsPonto de entrada createApp() — registra ferramentas e prompts.
src/config/Análise e validação de variáveis de ambiente específicas do servidor com Zod.
src/mcp-server/tools/definitions/Definições de ferramentas (*.tool.ts).
src/mcp-server/prompts/definitions/Definições de prompts (*.prompt.ts).
src/services/openalex/Cliente da API OpenAlex, catálogo de campos e tipos de domínio.
tests/Testes unitários e de integração, espelhando a estrutura de src/.

Guia de desenvolvimento

Consulte CLAUDE.md para diretrizes de desenvolvimento e regras arquiteturais. A versão resumida:

  • Handlers lançam, o framework captura — sem try/catch na lógica de ferramentas
  • Use ctx.log para registro de logs, ctx.state para armazenamento
  • Envolva respostas do OpenAlex: valide o payload bruto → normalize para um tipo de domínio → retorne o esquema de saída; nunca invente campos ausentes
  • Sempre resolva nomes para IDs via openalex_resolve_name antes de filtrar por entidade

Contribuindo

Issues são bem-vindas. Execute as verificações antes de enviar:

bun run devcheck
bun run test

Licença

Apache-2.0 — consulte LICENSE para detalhes.