@cyanheads/openalex-mcp-server

v0.6.13 pre-1.0

Search the OpenAlex catalog — 270M+ works, 90M+ authors, 100K+ sources.

@cyanheads/openalex-mcp-server
claude mcp add --transport http openalex-mcp-server https://openalex.caseyjhand.com/mcp
codex mcp add openalex-mcp-server --url https://openalex.caseyjhand.com/mcp
{
  "mcpServers": {
    "openalex-mcp-server": {
      "url": "https://openalex.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http openalex-mcp-server https://openalex.caseyjhand.com/mcp
{
  "mcpServers": {
    "openalex-mcp-server": {
      "command": "bunx",
      "args": [
        "@cyanheads/openalex-mcp-server@latest"
      ],
      "env": {
        "OPENALEX_API_KEY": "your-openalex-api-key"
      }
    }
  }
}
{
  "mcpServers": {
    "openalex-mcp-server": {
      "type": "http",
      "url": "https://openalex.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://openalex.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

4

openalex_resolve_name

open-world

Resolve a name or partial name to an OpenAlex ID. Returns up to 10 matches with disambiguation hints. ALWAYS use this before filtering by entity — names are ambiguous, IDs are not. Also accepts DOIs directly for quick lookup.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openalex_resolve_name",
    "arguments": {
      "query": "<query>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "entity_type": {
      "description": "Entity type to search. Omit for cross-entity search (useful when entity type is unknown).",
      "type": "string",
      "enum": [
        "works",
        "authors",
        "sources",
        "institutions",
        "topics",
        "keywords",
        "publishers",
        "funders"
      ]
    },
    "query": {
      "type": "string",
      "minLength": 1,
      "description": "Name or partial name to resolve. Also accepts DOIs for quick lookup."
    },
    "filters": {
      "description": "Narrow autocomplete results with filters. Example: restrict to a specific country or publication year range.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {
        "type": "string"
      }
    }
  },
  "required": [
    "query"
  ],
  "additionalProperties": false
}
view source ↗

openalex_search_entities

open-world

Search, filter, sort, or retrieve by ID. Covers all OpenAlex entity types (works, authors, sources, institutions, topics, keywords, publishers, funders). Pass `id` to retrieve a single entity. Otherwise, use `query` and/or `filters` for discovery. Supports keyword search with boolean operators, exact phrase matching, and AI semantic search. Use openalex_resolve_name to resolve names to IDs before filtering. Searches return a curated set of fields by default; pass `select` to override with specific fields.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openalex_search_entities",
    "arguments": {
      "entity_type": "<entity_type>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "entity_type": {
      "type": "string",
      "enum": [
        "works",
        "authors",
        "sources",
        "institutions",
        "topics",
        "keywords",
        "publishers",
        "funders"
      ],
      "description": "Type of scholarly entity to search."
    },
    "id": {
      "description": "Retrieve a single entity by ID. Supports: OpenAlex ID (\"W2741809807\"), DOI (\"10.1038/nature12373\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\"), PMCID (\"PMC1234567\"), ISSN (\"1234-5678\"). When provided, other search/filter/sort params are ignored. Use openalex_resolve_name to find the ID if unknown.",
      "type": "string"
    },
    "query": {
      "description": "Text search query. Supports boolean operators (AND, OR, NOT), quoted phrases (\"exact match\"), wildcards (machin*), fuzzy matching (machin~1), and proximity (\"climate change\"~5). Omit for filter-only queries.",
      "type": "string"
    },
    "search_mode": {
      "default": "keyword",
      "description": "Search strategy. \"keyword\": stemmed full-text (default). \"exact\": no stemming, matches individual words (use quoted phrases for multi-word exact match). \"semantic\": AI embedding similarity (max 50 results, 1 req/sec).",
      "type": "string",
      "enum": [
        "keyword",
        "exact",
        "semantic"
      ]
    },
    "filters": {
      "description": "Filter criteria as field:value pairs. AND across fields (multiple keys). OR within field: pipe-separate (\"us|gb\"). NOT: prefix \"!\" (\"!us\"). Range: \"2020-2024\". Comparison: \">100\", \"<50\". AND within same field: \"+\"-separate. Use OpenAlex IDs (not names) for entity filters — resolve names first. Common keys: `openalex` (filter by entity ID, e.g. {\"openalex\": \"W123|W456\"}), `cites` (works citing a given work), `publication_year` (range \"2020-2024\"), `authorships.author.id`, `type`, `is_oa`.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {
        "type": "string"
      }
    },
    "sort": {
      "description": "Sort field. Prefix with \"-\" for descending. Common: \"cited_by_count\", \"-publication_date\", \"-relevance_score\" (default when query present). Note: when combined with a keyword query, an explicit sort overrides relevance ranking entirely — top results may be highly cited but only tangentially on-topic. Use \"-relevance_score\" or omit sort to keep the most relevant results first. \"-relevance_score\" requires an active search via \"query\" or a \"filter:search\" filter — passing it without one will fail.",
      "type": "string"
    },
    "select": {
      "description": "OpenAlex top-level field names to return. Always returned: `id`, `display_name` — additional fields you list are appended. Searches apply a curated default per entity type; pass to override. Single-entity lookups (by `id`) return the full record unless set. Invalid field names produce an error listing the valid ones. Example: [\"doi\", \"authorships\", \"primary_topic\"].",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "per_page": {
      "default": 25,
      "description": "Results per page (1-100). Default 25. Semantic search caps at 50 — when search_mode=\"semantic\", set per_page ≤ 50 (also subject to a 1 req/sec rate limit upstream).",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "cursor": {
      "description": "Pagination cursor from a previous response. Pass to get the next page.",
      "type": "string"
    },
    "sample": {
      "description": "Return a random sample of this many entities matching the filters (1-100). Single page only — pagination via `cursor` is not supported with sampling. Overrides `per_page`. Useful for unbiased exploration: spot-checking filter correctness, stratified review prompts, or generating exploration sets without bias toward most-cited.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "seed": {
      "description": "Deterministic seed for `sample`. Same seed + same filters = same results — pass when reproducibility matters. Has no effect (and is rejected) without `sample`.",
      "type": "string"
    }
  },
  "required": [
    "entity_type",
    "search_mode",
    "per_page"
  ],
  "additionalProperties": false
}
view source ↗

openalex_get_citation_graph

open-world

Walk the citation graph one hop from a seed work. Direction picks the edge: incoming citations (`cites`), the seed's own references (`cited_by`), or OpenAlex's algorithmically-related works (`related_to`). Results use the works schema; combine with filters/sort to narrow further.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "openalex_get_citation_graph",
    "arguments": {
      "seed_id": "<seed_id>",
      "direction": "<direction>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "seed_id": {
      "type": "string",
      "minLength": 1,
      "description": "Seed work identifier. Accepts OpenAlex ID (\"W2741809807\"), DOI (\"10.1038/nature12373\" or full URL), PMID, or PMCID. Use openalex_resolve_name first if you only have a title."
    },
    "direction": {
      "type": "string",
      "enum": [
        "cites",
        "cited_by",
        "related_to"
      ],
      "description": "\"cites\": works that cite seed_id (incoming citations). \"cited_by\": works that seed_id cites (its reference list). \"related_to\": OpenAlex algorithmically-related works (~8-30 typical, may be empty for less-cited seeds)."
    },
    "filters": {
      "description": "Additional filters to narrow the graph, same syntax as openalex_search_entities. Example: publication_year=\">2020\", is_oa=\"true\". Do not include cites/cited_by/related_to — those are set by the `direction` parameter.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {
        "type": "string"
      }
    },
    "sort": {
      "description": "Sort field. Prefix with \"-\" for descending. Common: \"cited_by_count\", \"-publication_date\". Default is OpenAlex relevance.",
      "type": "string"
    },
    "select": {
      "description": "OpenAlex work field names to return. Always returned: id, display_name. Defaults to the curated works select if omitted.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "per_page": {
      "default": 25,
      "description": "Results per page (1-100). Default 25.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "cursor": {
      "description": "Pagination cursor from a previous response. Pass to get the next page.",
      "type": "string"
    }
  },
  "required": [
    "seed_id",
    "direction",
    "per_page"
  ],
  "additionalProperties": false
}
view source ↗

Prompts

2

Guides a systematic literature search: formulate query, search, filter, analyze citation network, synthesize findings.

  • topicrequired — Research topic or question to review (e.g., "CRISPR off-target effects in human cell lines").
  • scope — "narrow": focused on specific question. "broad": survey of the field.

Analyzes the research landscape for a topic: volume trends, top authors/institutions, open access rates, funding sources.

  • topicrequired — Research area to analyze (e.g., "single-cell RNA sequencing").