@cyanheads/openalex-mcp-server
Accepts DOIs (bare or in URL form) and resolves them to canonical OpenAlex entities — works can be retrieved directly by DOI, DOIs are resolved to OpenAlex IDs via name resolution, and DOI seeds are validated before walking the citation graph.
Accepts ORCID iDs to resolve researcher/author records to their canonical OpenAlex IDs and disambiguate people against the 90M+ author catalog.
Accepts PMIDs and PubMed/PubMed Central URLs, normalizing them for entity retrieval, ID resolution, and citation-graph seeding of biomedical literature (PMCIDs are recognized but resolve to nothing, since OpenAlex indexes none).
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@cyanheads/openalex-mcp-serverSearch for papers about climate change from 2020 to 2023"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://openalex.caseyjhand.com/mcp
Overview
Scholarly catalog data from OpenAlex — 270M+ works, 90M+ authors, 100K+ sources, plus institutions, topics, keywords, publishers, and funders. Search, filter, and aggregate across all eight entity types, resolve ambiguous names to canonical IDs, and walk the citation graph one hop at a time. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
Tools
Tool | Description |
| Search, filter, sort, or retrieve by ID across all 8 entity types |
| Group-by aggregation for trend and distribution analysis |
| Resolve a name or an identifier (DOI, ORCID, ROR, PMID, ISSN, OpenAlex ID) to an OpenAlex ID |
| Walk the citation graph one hop from a seed work: |
| List valid filter, group_by, and select field names for an entity type |
Prompts
Prompt | Description |
| Guides a systematic literature search: formulate query, search, filter, analyze citation network, synthesize findings |
| Analyzes the research landscape for a topic: volume trends, top authors/institutions, open access rates, funding sources |
Related MCP server: mcp-openalex
Capability reference
openalex_search_entities tool
Retrieve a single entity by ID — OpenAlex ID, DOI, ORCID, ROR, PMID, ISSN, or PMCID (bare or URL form).
idtakes precedence: search parameters passed alongside it are dropped, and the response names which ones. A PMCID resolves nothing (OpenAlex indexes none) — use the work's PMID or DOI insteadKeyword search (boolean operators, quoted phrases, wildcards, fuzzy match) plus
exactandsemanticsearch modes — semantic caps at 50 results per page and ~1 req/secRich filter syntax: AND across fields, OR within a field (
|), NOT (!), ranges, comparisons; a comma inside a filter value is rejected (use|, or a.searchfilter for free text)selectreturns a curated per-entity-type default unless overridden, or["*"]for the full record; invalid field names error with the valid setCursor pagination, up to 100 results per page (default 25);
sample(up to 100, single page only, nocursor) plus a deterministicseedfor reproducible random samplingdisplay_nameis nullable for untitled records; every call reports OpenAlex daily-budget cost and remaining balance
openalex_analyze_trends tool
Group any supported field for trend, distribution, or comparative analysis; combine with
filtersto scope the population before aggregationUp to 200 groups per page (default).
order: "count"(default) returns the top-N by count with no further pages;order: "key"enumerates all distinct values key-ascending with cursor paginationinclude_unknown(defaultfalse) adds a group for entities with no value for the grouped fieldNot every field is groupable — raw date fields,
.searchoperators, andfrom_*/to_*range modifiers are rejected; check withopenalex_describe_fields(entity_type, "group_by")Reports OpenAlex daily-budget cost and remaining balance — aggregation is priced far below paging the same entities
openalex_resolve_name tool
A name or partial name runs an autocomplete search: up to 10 matches with disambiguation hints (last institution, host organization, place, etc.)
An identifier — OpenAlex ID, DOI, ORCID, ROR, PMID, or ISSN, bare or in URL form — resolves directly to the one record it addresses; no
entity_typeneeded, since the identifier determines its own. A PMCID is recognized but resolves nothing — OpenAlex indexes nonefiltersnarrows autocomplete only; on an identifier lookup they're ignored and named in a noticeReports OpenAlex daily-budget cost and remaining balance
openalex_get_citation_graph tool
directionsets the edge:cites(works citing the seed),cited_by(the seed's own reference list),related_to(OpenAlex's algorithmic related works, ~8-30 typical, may be empty)seed_idaccepts an OpenAlex ID, DOI, or PMID (PMCID recognized but resolves nothing); validated against a live lookup first, so a non-existent seed fails asNotFoundrather than returning an empty graphStacks with
filters/sort/selectto narrow the graph;filterscannot setcites/cited_by/related_todirectly — those are reserved fordirectionCursor pagination, up to 100 results per page (default 25)
Reports OpenAlex daily-budget cost, covering both the seed-validation lookup and the graph page, plus remaining balance
openalex_describe_fields tool
Lists every valid field name for an entity type + context (
filter,group_by,select) — the complete pool, never truncatedgroup_byis the filter set minus raw date fields,.search/.search.exactoperators, andfrom_*/to_*range modifiers, which OpenAlex rejects as aggregation keysOptional
queryreorders results by name similarity without dropping any field — a nested value's parent object stays reachable further down the listBacked by a generated field catalog — no live API calls
openalex_literature_review prompt
Arguments:
topicrequired;scope(narrow/broad) optional, defaults tonarrowReturns one user message walking a 6-step workflow: resolve entities, search literature, identify key papers, trace citations, analyze the landscape, synthesize findings
scopechanges the search step:narrowfavors exact search with tight topic filters;broadadds semantic search across multiple related topic IDs
openalex_research_landscape prompt
Arguments:
topicrequiredReturns one user message walking a 7-step quantitative workflow: resolve the topic ID, volume trends, top contributors (institutions/countries/journals), open access rate, funding sources, most-cited works, emerging fronts
The funding step groups by
awards.funder_id(resolve names viaopenalex_resolve_name) orawards.funder_display_namefor readable labels in a single hop
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
OpenAlex-specific:
Typed API client with automatic ID normalization (DOI, ORCID, ROR, PMID, PMCID, ISSN, OpenAlex and PubMed/PubMed Central URLs); a PMCID normalizes but resolves nothing since OpenAlex indexes none
Keyless by default — an optional API key raises rate and daily-budget limits, and an optional
mailtoidentifies the caller to OpenAlex's polite poolHTTP status codes mapped to specific MCP error classes (400 → InvalidParams, 422 → ValidationError, 429 → RateLimited) with upstream messages surfaced
Timeout-aware request retries and cancellation support via
AbortSignal
Agent-friendly output:
Provenance — every API-calling tool reports OpenAlex daily-budget cost, remaining balance, and reset time (
budget.costUsd,remainingUsd,resetsInSeconds)Effective-query echo — search, trends, and citation-graph responses echo the criteria that actually ran, so an empty result is diagnosable without re-reading the request
Discriminated output contracts — typed error reasons (
entity_not_found,upstream_budget_exhausted,semantic_per_page_cap,reserved_filter_key, and more) each carrying an explicit recovery hintResponse shaping — abstracts are reconstructed from OpenAlex's inverted-index encoding into plaintext, and
display_namestaysnullfor untitled or paratext records instead of being backfilled
Getting started
Public Hosted Instance
A public instance is available at https://openalex.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"openalex-mcp-server": {
"type": "streamable-http",
"url": "https://openalex.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"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"
}
}
}
}Or with npx (no Bun required):
{
"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"
}
}
}
}Or with 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"
]
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 OPENALEX_API_KEY=... bun run start:http
# Server listens at http://localhost:3010/mcpOPENALEX_API_KEY is optional — set it to a free OpenAlex account key for keyed rate limits and budget under OpenAlex's usage-based pricing, or omit it for anonymous access. Set OPENALEX_MAILTO to an email if you want to identify yourself to OpenAlex (the polite pool).
Prerequisites
Bun v1.4.0 or higher (or Node.js v24+).
Optional: an OpenAlex account API key for keyed rate limits and budget — omit for anonymous access.
Installation
Clone the repository:
git clone https://github.com/cyanheads/openalex-mcp-server.gitNavigate into the directory:
cd openalex-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env and set required varsConfiguration
Variable | Description | Default |
| Transport: |
|
| Port for HTTP server. |
|
| HTTP session mode: |
|
| Auth mode: |
|
| Comma-separated allow-list of browser | loopback only |
| Log level (RFC 5424). |
|
| Directory for log files (Node.js only). |
|
| Storage backend. |
|
| OpenAlex account API key, sent upstream as | — |
| Email sent upstream as | — |
| OpenAlex API base URL. |
|
| Enable OpenTelemetry instrumentation (spans, metrics, completion logs). |
|
See .env.example for the full list of optional overrides.
Running the server
Local development
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:httpRun checks and tests:
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-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/openalex-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| Prompt definitions ( |
| OpenAlex API client, field catalog, and domain types. |
| Unit and integration tests, mirroring the |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor logging,ctx.statefor storageWrap OpenAlex responses: validate the raw payload → normalize to a domain type → return the output schema; never fabricate missing fields
Always resolve names to IDs via
openalex_resolve_namebefore filtering by entity
Contributing
Issues are welcome. Run checks before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
OpenAlex MCP — wraps the OpenAlex API (scholarly works, free, no auth)
Query SEC EDGAR filings, XBRL financials, and company data through MCP. STDIO & Streamable HTTP.
Crossref MCP — wraps the Crossref REST API (academic papers, free, no auth)
CORE Research MCP — wraps CORE API (api.core.ac.uk/v3)
Related MCP Servers
- AlicenseBqualityFmaintenanceProvides access to OpenAlex's catalog of 240M+ scholarly works, enabling search and retrieval of research papers, authors, institutions, journals, concepts, and funders with advanced filtering and classification capabilities.1142 npm5MIT
- AlicenseAqualityDmaintenanceMCP server for the OpenAlex scholarly database, providing AI agents with tools to search and retrieve academic works, authors, and institutions via natural language queries.8MIT
- FlicenseNot gradedqualityDmaintenanceMCP server for academic research using the OpenAlex API, enabling article search, details retrieval, and author profile lookup.-
- AlicenseAqualityAmaintenanceA local MCP server for searching scientific papers, retrieving metadata and abstracts, and legally downloading Open Access PDFs via OpenAlex, CrossRef, and Unpaywall APIs.53MIT