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.
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
| Ferramenta | Descrição |
|---|---|
openalex_search_entities | Pesquise, filtre, ordene ou recupere por ID em todos os 8 tipos de entidade |
openalex_analyze_trends | Agregação por grupo para análise de tendências e distribuição |
openalex_resolve_name | Resolva um nome ou identificador (DOI, ORCID, ROR, PMID, ISSN, ID OpenAlex) para um ID OpenAlex |
openalex_get_citation_graph | Percorra o grafo de citações um salto a partir de uma obra-semente: cites, cited_by ou related_to |
openalex_describe_fields | Liste nomes de campos válidos de filtro, group_by e select para um tipo de entidade |
Prompts
| Prompt | Descrição |
|---|---|
openalex_literature_review | Orienta uma busca sistemática de literatura: formule consulta, pesquise, filtre, analise rede de citações, sintetize descobertas |
openalex_research_landscape | Analisa 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.
idtem 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
exactesemantic— o semântico ranqueia um conjunto candidato dependente da consulta a ~1 req/seg (até 50 por página), e seumeta.countreporta 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.searchpara texto livre) selectretorna 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 osearch_modeerrado é rejeitado antes da chamada upstream sample(até 100, apenas uma página — nemcursornempagese aplicam) além de umseeddeterminístico para amostragem aleatória reproduzível; apenas modos por palavras-chave e exato, e nunca junto comsort— 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, econtent[]com seu trailer), a menos que o mínimo que pode retornar seja maior, o que é sinalizado comoover_budget: uma página que excederia mantém seus registros iniciais inteiros e nomeia o restante emomittedcom a única chamada que os retorna (como um conjunto, na ordem do OpenAlex), sem perturbarnext_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, eslice: {field, offset}em uma consultaidpagina 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 cobradaid+sliceque 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
filterspara 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ãofalse) adiciona um grupo para entidades sem valor no campo agrupado, sinalizado comois_unknown: truee rotulado como desconhecido na saída de texto. O OpenAlex o chaveia como-111/-111.0(campos numéricos),unknown(campos de texto eorder: "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 comofalse- Nem todo campo é agrupável — campos de data bruta, operadores
.search, modificadores de intervalofrom_*/to_*, pontuações decimais comofwci,display_name, e campos de ID externo comodoisão rejeitados;openalex_describe_fields(entity_type, "group_by")lista os campos que agrupam - Um group_by de obras em
authorships.countriesdiz em seu aviso que o OpenAlex conta apenas os primeiros 100 autorias de cada obra para esse campo, e nomeiaauthorships.institutions.country_codecomo 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 filtersrestringe apenas o autocompletar; em uma consulta por identificador são ignorados e nomeados em um aviso- Com
entity_typedefinido, o autocompletar do OpenAlex falha em um nome com mais de 1.000 caracteres; essa falha é reportada uma vez comoquery_too_longcom 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
directiondefine 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_idaceita 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 comoNotFoundem vez de retornar um grafo vazio- Empilha com
filters/sort/selectpara estreitar o grafo;filtersnão pode definircites/cited_by/related_to, nem um alias de um deles comocited_works— essas chaves são reservadas paradirection - 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 emomittedcom a chamadaopenalex_search_entitiesque 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 intervalofrom_*/to_*, e um conjunto por tipo de entidade encontrado agrupando cada campo listado contra a API ao vivo — pontuações decimais comofwci, vários campos de ano de fonte,display_name, e campos de ID externo entre elesqueryopcional 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:
topicobrigatório;scope(narrow/broad) opcional, padrãonarrow - 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
scopemuda a etapa de busca:narrowfavorece busca exata com filtros de tópico restritos;broadadiciona busca semântica em múltiplos IDs de tópico relacionados
openalex_research_landscape prompt
- Argumentos:
topicobrigató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 viaopenalex_resolve_name) ouawards.funder_display_namepara 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
mailtoopcional 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_keye 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_namepermanecenullpara 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\nliteral) vira um espaço; texto literal comoA < Be 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
- Bun v1.4.0 ou superior (ou Node.js v24+).
- Opcional: uma chave de API de conta OpenAlex para limites de taxa com chave e orçamento — omita para acesso anônimo.
Instalação
- Clone o repositório:
git clone https://github.com/cyanheads/openalex-mcp-server.git
- Navegue até o diretório:
cd openalex-mcp-server
- Instale as dependências:
bun install
- Configure o ambiente:
cp .env.example .env
# edit .env and set required vars
Configuração
| Variável | Descrição | Padrão |
|---|---|---|
MCP_TRANSPORT_TYPE | Transporte: stdio ou http. | stdio |
MCP_HTTP_PORT | Porta para o servidor HTTP. | 3010 |
MCP_SESSION_MODE | Modo 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_MODE | Modo de autenticação: none, jwt ou oauth. | none |
MCP_ALLOWED_ORIGINS | Lista 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_LEVEL | Nível de log (RFC 5424). | debug |
LOGS_DIR | Diretório para arquivos de log (somente Node.js). | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Backend de armazenamento. | in-memory |
OPENALEX_API_KEY | Chave 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_MAILTO | E-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_URL | URL base da API OpenAlex. | https://api.openalex.org |
OTEL_ENABLED | Ativar 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ório | Finalidade |
|---|---|
src/index.ts | Ponto 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/catchna lógica de ferramentas - Use
ctx.logpara registro de logs,ctx.statepara 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_nameantes 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.