openalex-mcp-server
Server Details
Access the OpenAlex academic research catalog — 270M+ publications.
- Status
- Healthy
- Uptime
- 99.9% over 82 days
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- Repository
- cyanheads/openalex-mcp-server
- GitHub Stars
- 17
- Server Listing
- @cyanheads/openalex-mcp-server
- ChatGPT
- –
- Claude
- –
TDQS
Scored across 5 tools
Each tool has a recognizable core job: aggregation (analyze_trends), schema introspection (describe_fields), citation walking (get_citation_graph), name/ID resolution (resolve_name), and general search/retrieval (search_entities). There is some residual overlap: resolve_name's autocomplete and search_entities' `query` both search by name, and get_citation_graph is essentially a works search scoped by cites/cited_by/related_to filters. The descriptions do give clear routing guidance ("ALWAYS use resolve_name before filtering"), so misselection is unlikely but not impossible.
All five tools share the openalex_ prefix followed by a clean snake_case verb_noun pattern (analyze_trends, describe_fields, get_citation_graph, resolve_name, search_entities). No camelCase, no mixed verb styles, and the names read predictably as a set.
Five tools is on the lean side for an API spanning nine entity types, but each tool is a deliberate, high-leverage primitive rather than a thin wrapper, and none is redundant. The meta-tool design keeps the surface small without obvious filler.
For a read-only scholarly index, the surface covers the main workflows: discovery and ID lookup, field-name validation, aggregation, citation traversal, and name-to-ID resolution, with no create/update/delete needed. Minor gaps remain—no explicit entity-type enumeration, no dedicated autocomplete/suggest endpoint, and no export or topic-hierarchy traversal—but agents can work around these through search_entities.
Available Tools
5 toolsopenalex_analyze_trendsOpenalex Analyze TrendsARead-onlyIdempotentInspect
Aggregate OpenAlex entities into groups and count them. Use for trend analysis (group works by publication_year), distribution analysis (group by oa_status, type, country), and comparative analysis (group by institution or topic). Combine with filters to scope the analysis. Returns up to 200 groups per page — use order "key" and cursor pagination for fields with many distinct values. OpenAlex can wrap a key-ordered walk to earlier groups. Stop when a page's first key repeats an earlier key, or when a page is short or empty.
| Name | Required | Description | Default |
|---|---|---|---|
| order | No | Sort order for groups. Without a cursor, omit or pass "count" (default) to return the top-N groups by count descending — no further pages. Pass "key" to enumerate distinct values in key-ascending order with cursor pagination. Boolean fields keep count order even with "key" and do not support cursor pagination. A supplied cursor selects key order even if order is omitted or "count". OpenAlex can wrap a key-ordered walk to earlier groups. Stop when a page's first key repeats an earlier key, or when a page is short or empty. | |
| cursor | No | Pagination cursor from a previous response. A supplied cursor selects key order even if order is omitted or "count". Pass the next_cursor from the previous response to advance, subject to the stop conditions below. Omit it on the first call — an empty string is rejected, since a supplied-but-blank cursor is a caller mistake rather than a request for the first page. OpenAlex can wrap a key-ordered walk to earlier groups. Stop when a page's first key repeats an earlier key, or when a page is short or empty. | |
| filters | No | Filter record object, using the same value syntax as openalex_search_entities; native string input is unavailable here. Narrows the population before aggregation. Country fields take ISO 3166-1 alpha-2 codes ("DE") and `language` takes ISO 639-1 codes ("en"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so "South Korea|Japan" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, awards.funder_display_name, geo.city, raw_affiliation_strings) matches as one phrase ("National Science Foundation"; a comma, as in "University of California, Berkeley", is part of it, and it cannot contain a double quote of its own), "!" and "|" included, but cannot be ANDed with "+" in the same field. A value sent unquoted must have paired double quotes; balanced search phrases remain valid. A value mixing "|" with an AND operator — a "+", or a space on a field where words mean AND — is rejected, since OpenAlex drops every "|" alternative that ANDs more than one value; put the AND in a second key instead. For full-text within filters, use abstract.search, title.search, or default.search — there is no bare 'search' filter key. Example: group works by year filtered to a specific topic. | |
| group_by | Yes | Field to group by. Works examples: "publication_year", "type", "oa_status", "primary_topic.field.id", "authorships.institutions.country_code", "is_retracted". The native ":include_unknown" suffix also enables include_unknown, even when the boolean is false; passing both adds the suffix once. OpenAlex builds authorships.countries groups from only the first 100 authorships of each work; authorships.institutions.country_code counts every authorship. Authors: "last_known_institutions.country_code", "has_orcid". Sources: "type", "is_oa", "country_code". Awards: "start_year", "funder.id", "funding_type" — groups count awards and do not sum amount_usd. Not all fields support group_by — call openalex_describe_fields(entity_type, "group_by") for the groupable set. | |
| per_page | No | Maximum groups per page. Default 200 (the upstream cap); positive integers above 200 clamp to 200 with a notice unless OPENALEX_CLAMP_PER_PAGE=false restores rejection. A real top-N knob in count order without a cursor (the default) — reduce to return only the highest-count groups. | |
| entity_type | Yes | Entity type to aggregate. | |
| include_unknown | No | Add a group for entities with no value for the grouped field. Hidden by default unless group_by has the native ":include_unknown" suffix, which enables this setting even when the boolean is false; passing both adds the suffix once. That group carries `is_unknown: true`; OpenAlex keys it -111 or -111.0 on numeric fields, "unknown" on text fields and under order "key", and an ID ending in /unknown on ID fields — a sentinel, not a measured value. The key is not a filter value: passing -111 as a filter matches a numeric range, not the entities with no value. Boolean fields have no separate group — a missing value counts as false. |
Output Schema
| Name | Required | Description |
|---|---|---|
| echo | No | Compact echo of the criteria (entity_type, group_by, filters) and effective include_unknown and order settings — surfaces what was actually requested when no groups are returned. |
| meta | No | Aggregation metadata. |
| error | No | Present when the call failed. Absent on success. |
| budget | No | What this call cost against the OpenAlex daily budget and what is left of it — weigh `remainingUsd` against `costUsd` before enumerating every group with `order: "key"`. Absent when OpenAlex omitted the accounting headers. |
| groups | No | Aggregation groups with counts. |
| notice | No | Guidance notice. Set when per_page was clamped (requested and applied sizes), on every effective key-order call (upstream wrap warning and stopping conditions), when a first call returns no groups (recovery suggestions), when a cursor continuation returns none because the traversal is already finished, when a count-order page is full and more groups likely exist (truncation signal with narrowing advice), or when works are grouped by authorships.countries, which OpenAlex counts from only the first 100 authorships of each work. Absent otherwise. |
| totalCount | No | Total entities matching the filters before grouping (across all pages). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, and open-world behavior. The description adds valuable non-obvious operational details: the 200-group cap, key-order pagination, possible wrapping to earlier groups, and stop conditions when keys repeat or pages are short/empty. This goes well beyond what annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and usage, then moves to pagination behavior and stop conditions. Every sentence adds useful information, and there is no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the rich input schema, existing output schema, and annotations, the description covers the essential operational quirks an agent needs to paginate safely. It does not explicitly route the agent away from sibling search tools, but the schema and examples provide enough context for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents each parameter thoroughly. The description restates some of that guidance (order 'key', cursor pagination, 200-group cap) but adds little new meaning beyond the structured parameter descriptions. Baseline 3 is appropriate when the schema carries the semantic load.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Aggregate OpenAlex entities into groups and count them.' It further clarifies purpose with trend, distribution, and comparative examples. However, it does not explicitly differentiate itself from sibling tools like openalex_search_entities, leaving that distinction implicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage contexts, listing trend, distribution, and comparative analyses, and advises combining with filters to scope results. It also explains when to use key order and cursor pagination. It lacks explicit when-not-to-use guidance or named alternatives, which keeps it from a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openalex_describe_fieldsOpenalex Describe FieldsARead-onlyIdempotentInspect
List valid field names for an OpenAlex entity type and context (filter, group_by, or select). Use proactively before constructing a filter or group_by to avoid invalid-field 400 errors. Pass query to rank the list by name similarity — useful when you have a partial or guessed field name. Ranking never drops a field: the full list comes back either way.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Optional partial or guessed field name to sort results by similarity. Pass the field you tried (e.g. "funder") to get the closest matches first. The complete field list is returned either way — a query reorders it, it does not filter it, so a nested value's parent object (e.g. `summary_stats` for "h_index") is still reachable further down. | |
| context | Yes | Field usage context. "filter": fields accepted in the filter param; created_date, updated_date, and their from_/to_ forms, where listed, are ones OpenAlex serves only on a paid plan, and a filter on one fails without it. "group_by": fields accepted in group_by — a subset of the filter set that leaves out what OpenAlex refuses to aggregate (raw dates, *.search operators, decimal scores, display_name, external-ID fields, and fields OpenAlex looks up from a related entity, such as primary_location.source.country_code, among them). "select": fields accepted in select. | |
| entity_type | Yes | OpenAlex entity type to list fields for. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| total | No | Total number of valid fields for this entity_type + context. |
| fields | No | Every valid field name for this entity_type + context — the complete pool, ranked by similarity when `query` is provided. Never truncated, so this always holds `total` entries. |
| context | No | Context queried (filter, group_by, or select). |
| entity_type | No | Entity type queried. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish this as a safe, idempotent read. The description adds meaningful behavior the annotations don't cover: that `query` only reorders and 'never drops a field', so agents know a parent object stays reachable further down the list. It stops short of noting list size or latency, which would matter for a large enumeration.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with what the tool returns, then when to call it, then the one non-obvious parameter behavior. No filler and no redundancy with the name or title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a full schema, enums, output schema, and read-only annotations, the description covers what an agent needs to select and invoke the tool. The only gap is practical scale — nothing indicates how large the returned field list typically is.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with detailed per-parameter text including the enum semantics for context and the reorder-not-filter behavior of `query`. The description's sentence about ranking is essentially a restatement of what the schema already says, so it adds little beyond the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'List valid field names for an OpenAlex entity type and context'. It also names the three contexts (filter, group_by, select), making clear this is a schema-introspection tool, distinct from the search/analyze/graph/resolve siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance: 'Use proactively before constructing a filter or group_by to avoid invalid-field 400 errors', including the failure mode it prevents. It doesn't state when not to bother calling it, but no sibling overlaps enough to require named alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openalex_get_citation_graphOpenalex Get Citation GraphARead-onlyIdempotentInspect
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). Note: direction follows OpenAlex's filter convention, which inverts the common English reading — cites returns works that cite the seed; cited_by returns works the seed cites. Results use the works schema; combine with filters/sort to narrow further. A page holds per_page works and next_cursor continues it.
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | Sort field. Prefix with "-" for descending. Comma-separate for a multi-key sort, applied left to right, with the "-" prefix set per key ("-publication_year,cited_by_count" sorts by year descending, then citations ascending). Common: "cited_by_count", "-publication_date". Default is OpenAlex relevance. | |
| cursor | No | Pagination cursor from a previous response. Pass to get the next page. Omit it on the first call — an empty string is rejected, since a supplied-but-blank cursor is a caller mistake rather than a request for the first page. | |
| select | No | OpenAlex work field names to return. Always returned: id, display_name. Defaults to the curated works select if omitted. `author_list` returns each author in authorship order as `{id, display_name, orcid}` (`orcid` null when absent), a compact alternative to `authorships`, which also carries institutions and affiliations; neither the default nor `["*"]` includes it. A wide projection on a large page makes a large response, so name the fields you need. | |
| filters | No | Additional filter record object to narrow the graph, using the same value syntax as openalex_search_entities; native string input is unavailable here. Example: publication_year=">2020", is_oa="true". Country fields take ISO 3166-1 alpha-2 codes ("DE") and `language` takes ISO 639-1 codes ("en"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so "South Korea|Japan" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, awards.funder_display_name, authorships.institutions.geo.city, raw_affiliation_strings) matches as one phrase ("National Science Foundation"; a comma, as in "University of California, Berkeley", is part of it, and it cannot contain a double quote of its own), "!" and "|" included, but cannot be ANDed with "+" in the same field. A value sent unquoted must have paired double quotes; balanced search phrases remain valid. Filters are checked before the seed lookup. A value mixing "|" with an AND operator — a "+", or a space on a field where words mean AND — is rejected, since OpenAlex drops every "|" alternative that ANDs more than one value; put the AND in a second key instead. Do not include cites/cited_by/related_to, nor an alias of one such as cited_works — those keys are set by the `direction` parameter. | |
| seed_id | Yes | Seed work identifier. Accepts OpenAlex work ID ("W2741809807", or its OpenAlex record-page or API URL such as "https://openalex.org/works/W2741809807"), DOI ("10.1038/nature12373" or full URL), or PMID ("12345678" or "https://pubmed.ncbi.nlm.nih.gov/12345678"). A PMCID is recognized too, bare or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. Use openalex_resolve_name first if you only have a title. | |
| per_page | No | Results per page. Default 25; a larger value returns at most 100 and says so (rejected instead on a server set to OPENALEX_CLAMP_PER_PAGE=false). | |
| direction | Yes | "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). |
Output Schema
| Name | Required | Description |
|---|---|---|
| echo | No | Compact echo of seed_id, direction, filters, sort — surfaces what was actually queried when no edges are returned. |
| meta | No | Result metadata including pagination. |
| error | No | Present when the call failed. Absent on success. |
| budget | No | What this call cost against the OpenAlex daily budget and what is left of it. Price a full walk before committing to it: `totalCount` ÷ `per_page` × `costUsd` against `remainingUsd`. Absent when OpenAlex omitted the accounting headers. |
| notice | No | Guidance notice. Set when per_page was clamped (requested and applied sizes), when no edges are returned — a first call suggests verifying the seed_id, broadening filters, or trying a different direction; a cursor continuation says the walk is already past its last edge — and when a work carries exactly 100 authorships or author_list entries (possibly capped). Absent otherwise. |
| results | No | Works on the citation graph in this direction. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them; an abstract arrives reconstructed as `abstract`, and a selected `author_list` as one `{id, display_name, orcid}` entry per author. Possibly capped author arrays are in `windows`. |
| windows | No | Author arrays possibly capped at 100 on a list record or 5,000 stored on a singleton, and the window of every `slice` call — present even when the slice holds the whole array. A slice window's `next` repeats its `slice.limit` from the following offset; `next` is null at the stored-array end, including a possibly capped singleton. |
| totalCount | No | Total edges from seed_id in this direction across all pages. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and openWorldHint, so the safety profile is covered. The description adds valuable behavioral context beyond that: the one-hop traversal model, the counterintuitive direction convention, and pagination via per_page/next_cursor.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core operation, then covers direction semantics, the inversion caveat, and pagination in a few tight sentences. Every sentence contributes necessary information without repetition or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the rich schema, annotations, and output schema, the description supplies everything an agent needs to call the tool correctly: seed work, direction semantics, filter/sort narrowing, and pagination behavior. No critical gap remains for this traversal tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all seven parameters. The description still adds useful meaning, especially the note that 'direction' follows OpenAlex's inverted filter convention and that filters/sort can narrow the graph, which go beyond the schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Walk the citation graph one hop from a seed work.' It then distinguishes the three edge types precisely, so an agent can tell exactly what operation this tool performs versus sibling tools like search_entities or analyze_trends.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly explains how to choose a direction and notes that results can be narrowed with filters/sort. However, it does not explicitly contrast this tool with sibling tools or state when not to use it, leaving some routing inference to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openalex_resolve_nameOpenalex Resolve NameARead-onlyIdempotentInspect
Resolve a name or an identifier to an OpenAlex ID. ALWAYS use this before filtering by entity — names are ambiguous, IDs are not. A name returns up to 10 autocomplete matches with disambiguation hints. An identifier — OpenAlex ID, DOI, ORCID, ROR, PMID, or ISSN, bare or in URL form — resolves directly to the record it addresses instead of running a name search. Short names share the bare OpenAlex ID shape (keyword p53 reads as publisher ID P53), so a bare OpenAlex ID that resolves nothing is searched as a name next. Two identifiers can address more than one entity type: a ROR names an organization's institution, funder, and publisher records alike, so it returns each one that exists (institution first) unless entity_type picks one of those three; and a Crossref Funder Registry DOI (10.13039/…) resolves to the funder unless entity_type is works. A PMCID is recognized as well, bare or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. An award ID (G…, bare or as an OpenAlex URL) is not looked up, since OpenAlex has no award autocomplete: it returns no matches and a notice naming the openalex_search_entities call that opens the award. Under entity_type, a bare G… is searched as a name of that type instead.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID ("W2741809807", "F4320332161", or an OpenAlex record-page or API URL such as "https://openalex.org/works/W2741809807"), DOI ("10.1038/nature12373", or a funder's Funder Registry DOI such as "10.13039/100000001"), ORCID ("0000-0002-1825-0097"), ROR ("https://ror.org/00hx57361"), PMID ("12345678" or "https://pubmed.ncbi.nlm.nih.gov/12345678"), ISSN ("1234-5678") — which resolves straight to the record it addresses, or for a ROR up to three (see entity_type), instead of running a name search. A bare OpenAlex ID that resolves nothing is then searched as a name — under entity_type when given, and not at all when filters come without entity_type — since short names share its shape ("P53" is a keyword); under entity_type keywords it is searched as a name from the start. A keyword URL ("https://openalex.org/keywords/groundwater") resolves the same way; a bare keyword slug reads as a name and runs a name search, which finds it too. A PMCID ("PMC1234567" or a PubMed Central URL) is recognized but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. An award ID ("G417894356", or "https://openalex.org/awards/G417894356") sends no request and names the openalex_search_entities call for it; with entity_type, a bare one is searched as a name of that type. | |
| filters | No | Narrow autocomplete results with a filter record object, using the openalex_search_entities value syntax; native string input is unavailable here. Example: restrict to a specific country or publication year range. Country fields take ISO 3166-1 alpha-2 codes ({"country_code": "DE"} on institutions) and `language` takes ISO 639-1 codes ("en"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so "South Korea|Japan" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, geo.city, geo.region, awards.funder_display_name) matches as one phrase ({"geo.city": "New York"} on institutions; a comma, as in "University of California, Berkeley", is part of it, and it cannot contain a double quote of its own), "!" and "|" included, but cannot be ANDed with "+" in the same field. A value sent unquoted must have paired double quotes; balanced search phrases remain valid. A value mixing "|" with an AND operator — a "+", or a space on a field where words mean AND — is rejected, since OpenAlex drops every "|" alternative that ANDs more than one value; put the AND in a second key instead. Requires entity_type — filter fields belong to one entity type, so a name search across every type takes none, and a name query passing filters without entity_type is rejected. Applies to name queries only — an identifier lookup returns the records it addresses regardless. | |
| entity_type | No | Entity type to search. Awards are not among them: OpenAlex has no award autocomplete, so search awards with openalex_search_entities. Omit for cross-entity search (useful when entity type is unknown). With an identifier `query` it narrows only an identifier that can address more than one type: a ROR to institutions, funders, or publishers (omit it to get every one of the three that exists), and a Funder Registry DOI (10.13039/…) to works instead of the funder. Every other identifier resolves as the type it belongs to, whatever this names — except under keywords, where a bare OpenAlex ID shape ("P53") is searched as a keyword name, since keyword IDs are slugs. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| budget | No | What this call cost against the OpenAlex daily budget and what is left of it. Read `remainingUsd` here to size the search or traversal this resolution feeds. Absent when OpenAlex omitted the accounting headers. |
| notice | No | Guidance notice. Set when nothing matched (echoes the query, and the filters when a name search applied them, and suggests corrections), when a bare OpenAlex ID resolved nothing and the query was searched as a name instead (names both outcomes, or why the name search did not run or finish), when an identifier query was passed name-search parameters that do not apply to it, when one of the lookups for a ROR failed upstream (names the entity type whose record may be missing), or when the query is an award ID (names the openalex_search_entities call that opens it). Caller text in it is JSON-encoded and Markdown-escaped, the same string on both surfaces. Absent otherwise. |
| results | No | Matches: up to 10 autocomplete matches for a name; for an identifier, the record it addresses — for a ROR, up to three, institution then funder then publisher — or none. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover only safety/idempotency, and the description goes well past them: it discloses that a PMCID resolves nothing because OpenAlex indexes no PMCIDs, that award IDs issue no request and return a notice pointing at openalex_search_entities, and that a ROR fans out to up to three entity records with institution first. These are non-obvious failure modes and multi-result behaviors an agent could not infer from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The key instruction and the identifier-vs-name split are front-loaded, which is good. But the body runs roughly 300 words and much of it duplicates the query and entity_type schema descriptions nearly verbatim, so a substantial share of sentences do not earn extra value over the structured fields.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations, a full-coverage schema, an output schema, and a nested filters object, this is a complex tool — and the description covers every edge case an agent needs (ambiguous multi-type identifiers, unsupported identifier families, filter/entity_type dependency) without needing to explain return values.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the three parameters are fully documented in the schema, so the baseline is 3. The description's parameter content largely restates the schema's own wording (identifier forms, entity_type narrowing rules) rather than adding syntax or semantics the schema lacks.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: 'Resolve a name or an identifier to an OpenAlex ID.' It immediately distinguishes the tool's role from the search sibling by stating that awards are handled by openalex_search_entities, so an agent can place it in the toolset without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit directive: 'ALWAYS use this before filtering by entity — names are ambiguous, IDs are not,' gives both the when and the reason. It also names the alternative for awards (openalex_search_entities) and the condition that selects it, plus the fallback path when a bare OpenAlex ID resolves nothing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openalex_search_entitiesOpenalex Search EntitiesARead-onlyIdempotentInspect
Search, filter, sort, or retrieve by ID. Covers all OpenAlex entity types (works, authors, sources, institutions, topics, keywords, publishers, funders, awards). Pass id to retrieve a single entity. Otherwise, use query and/or filters for discovery. Filters take a record object; an unambiguous native string such as "issn:0920-8542" is also accepted when enabled and disclosed in notice. Native clauses split on commas outside paired double quotes and the first colon; duplicate keys and bare fragments are rejected. Any filter value sent unquoted must have paired double quotes; balanced search phrases remain valid. Supports keyword search with boolean operators, exact phrase matching, AI semantic search, and seeded random samples. Use openalex_resolve_name to resolve names to IDs before filtering. Searches and ID lookups return a curated set of fields by default; pass select to override with specific fields, or ["*"] for the full record. A page holds per_page records and next_cursor continues it — semantic search and a seeded sample continue with page instead; an id lookup returns every selected array whole, and slice pages one array by count.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Retrieve a single entity by ID. Supports: OpenAlex ID ("W2741809807", or its OpenAlex record-page or API URL such as "https://openalex.org/works/W2741809807" or "https://api.openalex.org/works/W2741809807"), whose letter must name `entity_type` — W works, A authors, S sources, I institutions, T topics, P publishers, F funders, G awards; DOI ("10.1038/nature12373"; under entity_type "funders", a funder's Crossref Funder Registry DOI such as "10.13039/100000001"), ORCID ("0000-0002-1825-0097"), ROR ("https://ror.org/00hx57361" — one ROR can name an institution, a funder, and a publisher, and `entity_type` picks which), PMID ("12345678" or "https://pubmed.ncbi.nlm.nih.gov/12345678"), ISSN ("1234-5678"). Keywords are identified by slug rather than a native ID — pass either the slug ("groundwater") or the URL a search returns ("https://openalex.org/keywords/groundwater"). A PMCID is recognized too, bare ("PMC1234567") or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `["*"]` for the complete record). Every selected array returns whole; `slice` pages a long one by count. To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown. | |
| page | No | Page number (1-based) for semantic search and for a seeded `sample`, the two searches that paginate with `page` instead of `cursor`. Semantic search ranks a query-dependent candidate set whose size `meta.count` reports, so the last reachable page is ceil(meta.count / per_page) — e.g. page 14 for a count of 70 with per_page=5. A sample draws min(sample, meta.count) records, so its last page is ceil(min(sample, meta.count) / per_page); paging a sample requires `seed`, and OpenAlex serves only its first 10,000 records, so a page × per_page above 10,000 is rejected. Passing it with any other search is rejected. | |
| seed | No | Deterministic seed for `sample`. Same seed + same filters = the same draw, page for page — required to walk a sample larger than one page with `page`, and worth passing whenever reproducibility matters. Has no effect without `sample`, and a search that passes it alone is rejected. | |
| sort | No | Sort field. Prefix with "-" for descending. Comma-separate for a multi-key sort, applied left to right, with the "-" prefix set per key ("-publication_year,cited_by_count" sorts by year descending, then citations ascending). 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. Not combinable with `sample` — a search passing both is rejected. | |
| query | No | 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 — an empty string is rejected, since a blank search is a mistake rather than a request for the whole catalog. | |
| slice | No | Page one array of the record at `id`: returns `id`, `display_name`, and `limit` elements of `field` from `offset` — fewer only at the array end — with the window in `windows`, whose `next` call repeats `limit` from the following offset. Requires `id`; replaces `select`. An offset at or past the end returns an empty window. A 100-author list cap can be continued on the singleton; at 5,000 stored authors the byline remains possibly capped, but `next` is null once stored entries are exhausted. | |
| cursor | No | Pagination cursor from a previous response. Pass to get the next page. Omit it on the first call — an empty string is rejected, since a supplied-but-blank cursor is a caller mistake rather than a request for page 1. Keyword and exact modes only — semantic search walks its candidates with `page`, and a `cursor` sent with it is rejected. | |
| sample | No | Return a random sample of this many entities matching the filters, up to 10,000; a larger value draws 10,000 and says so (rejected instead on a server set to OPENALEX_CLAMP_PER_PAGE=false). The sample comes back `per_page` records at a time — by default the whole sample up to 100 — and a larger one is walked with `page` and a `seed`, which fixes the draw; without `seed` only its first page is returned. `meta.count` stays the population matching the filters. Keyword and exact modes only: OpenAlex does not sample a semantic search, so `sample` with search_mode "semantic" is rejected. Cannot be combined with `cursor` or `sort` — a sample has no order, and a search passing either is rejected. Useful for unbiased exploration: spot-checking filter correctness, stratified review prompts, or generating exploration sets without bias toward most-cited. | |
| select | No | OpenAlex top-level field names to return. Always returned: `id`, `display_name` — additional fields you list are appended. A curated default per entity type applies to both searches and single-entity (`id`) lookups; pass field names to override it, or `["*"]` to retrieve the complete record (every field). Only top-level fields project, so a nested value is requested by its parent object: bibliometrics (`h_index`, `i10_index`, `2yr_mean_citedness`) live under `summary_stats` on authors, sources, institutions, publishers, and funders, and naming a leaf returns that object. On sources, `publisher` returns `host_organization_name`: the publisher of a journal, the hosting institution of a repository, and null on most sources. On works, `author_list` returns each author in authorship order as `{id, display_name, orcid}` (`orcid` null when absent), a compact alternative to `authorships`, which also carries institutions and affiliations; neither the default nor `["*"]` includes it. Invalid field names produce an error identifying the rejected field. A wide projection on a large page makes a large response, so name the fields you need. Not applied with `slice`. Example: ["doi", "author_list", "primary_topic"]. | |
| filters | No | 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 ("us+gb"); inside a `.search` value, a DOI, a date (a timestamp's "+00:00" offset), a URL field such as landing_page_url, an exactly matched name (display_name, awards.funder_display_name — "C++", "Erasmus+"), a biblio field (issue "1+2"), or awards.funder_award_id, "+" is a literal character. A value cannot mix "|" with an AND operator — a "+", or a space between values on an ID, code, or `language` key (a space inside a language name is part of the name, and a country field never reads a space as AND) — OpenAlex splits it on "|" first and drops every alternative that ANDs more than one value, so such a value is rejected; put the AND in a second key instead ("institutions.country_code": "US" beside "authorships.institutions.country_code": "DE|FR" on works). On a field matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, biblio fields), a space is part of the value: "New York", "!New York", and "New York|Boston" match as written, but quotes around one "|" alternative make that alternative match nothing. A comma is part of such a value too ("University of California, Berkeley" on raw_affiliation_strings): a value holding one is sent as one quoted phrase, its "+" a literal character. A value sent as a quoted phrase cannot contain a double quote of its own. A multi-word value there cannot be ANDed with another ("New York+Boston" matches nothing); to require two funders or institutions, AND their IDs (awards.funder_id, authorships.institutions.id). Country fields (keys ending in country_code, country_codes, or countries) take ISO 3166-1 alpha-2 codes ("DE"): an alpha-3 code ("DEU"), numeric code ("276"), or English name ("Germany", "South Korea") is converted, "UK" becomes "GB", and a value that cannot be a country code is rejected. A space there is part of a name, never a separator: "South Korea|Japan" ORs two countries, and "DE US" is rejected. `language` takes ISO 639-1 codes ("en"): an ISO 639-2 code ("eng") or English name ("English") is converted. Two keys that resolve to the same upstream field (an alias and its canonical name, e.g. `year` and `publication_year`) are both applied and AND'd, so they narrow rather than override each other. 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`. | |
| per_page | No | Results per page. Default 25, or under `sample` the sample size up to 100, so a sample of 100 or fewer returns whole in one call. A larger value returns at most 100 and says so — at most 50 under search_mode "semantic", which OpenAlex also limits to about 1 request per second. A server set to OPENALEX_CLAMP_PER_PAGE=false rejects a value over either cap instead. An `id` lookup ignores page size. | |
| entity_type | Yes | Type of scholarly entity to search. | |
| search_mode | No | 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 over a query-dependent candidate set whose size `meta.count` reports, at ~1 req/sec, up to 50 per page, and paginated with `page` rather than `cursor`. | keyword |
Output Schema
| Name | Required | Description |
|---|---|---|
| echo | No | Compact echo of the criteria that actually ran (entity_type, query, filters, sort, search_mode) — surfaces what was searched when results are empty. An `id` lookup echoes entity_type and id alone, because the search criteria are not applied on that path. |
| meta | No | Result metadata including pagination. |
| error | No | Present when the call failed. Absent on success. |
| budget | No | What this call cost against the OpenAlex daily budget and what is left of it. Price a full traversal before committing to it: `totalCount` ÷ `per_page` × `costUsd` against `remainingUsd`. Absent when OpenAlex omitted the accounting headers. |
| notice | No | Guidance notice. Set when per_page, sample, or slice.limit was clamped (requested and applied sizes), a native filter string was converted, a first call has no matches, a continuation is exhausted, an id lookup ignores search criteria, semantic search reports a candidate total and whether a later `page` holds more, a sample draws more than one page (the next `page`, its last page, or that `seed` makes it pageable), an author array is possibly capped (100 list entries or 5,000 stored singleton entries), a slice offset is past the end, or slice replaces select. Absent otherwise. |
| results | No | OpenAlex entity objects. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them; an abstract arrives reconstructed as `abstract`, and a selected `author_list` as one `{id, display_name, orcid}` entry per author. Additional fields depend on entity_type and select. Possibly capped author arrays and `slice` windows are in `windows`. |
| windows | No | Author arrays possibly capped at 100 on a list record or 5,000 stored on a singleton, and the window of every `slice` call — present even when the slice holds the whole array. A slice window's `next` repeats its `slice.limit` from the following offset; `next` is null at the stored-array end, including a possibly capped singleton. |
| totalCount | No | Total results matching the query/filters across all pages. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, openWorld), and the description adds substantial beyond-schema behavior: id overrides query/search_mode/filters/sort/sample/seed and the response `notice` reports them, semantic search is rate-limited to ~1 req/sec and caps at 50 per page, sample caps at 10,000 and needs `seed` to page, and cursor vs page vs slice are three distinct pagination regimes. That is real operational context, not restatement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core routing (ID vs discovery, resolve names first) is correctly front-loaded, but the body is a dense 180-word run that repeats pagination and projection rules already documented in the parameter schemas. Sentences are individually informative, yet the aggregate duplicates structured data and is harder to scan than it needs to be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 13-parameter tool with nested objects, two enums, and an output schema, the description covers everything the agent must know to choose a mode and avoid rejection: ID-lookup precedence, the three pagination schemes, sample constraints, and the sort/relevance caveat. Return values are left to the output schema, as appropriate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the per-parameter baseline is 3; the description earns above baseline by disclosing cross-parameter interactions the schema does not state as a whole — which parameters are ignored when `id` is set, that `select` still applies to ID lookups, and that `slice` replaces `select`. It stops short of 5 because much of the filter-quoting and select-projection detail merely paraphrases what the schema properties already spell out.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific set of verbs (search, filter, sort, retrieve by ID) and an explicit resource scope: all OpenAlex entity types, enumerated. It also routes the reader away from the wrong path by naming openalex_resolve_name, so the tool is distinguishable from its siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the branch condition directly: pass `id` for a single entity, otherwise use `query` and/or `filters` for discovery, and 'To filter, drop `id` and search.' It also names the prerequisite step ('Use openalex_resolve_name to resolve names to IDs before filtering'), which is exactly the alternative-selection guidance an agent needs.
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.
5 tool updates
- Changed
openalex_analyze_trends3 fields changed- changed
Input schema / properties / entity_type / enumPrevious value: -[ - "works", - "authors", - "sources", - "institutions", - "topics", - "keywords", - "publishers", - "funders" -]New value: +[ + "works", + "authors", + "sources", + "institutions", + "topics", + "keywords", + "publishers", + "funders", + "awards" +] - changed
Input schema / properties / group_by / descriptionPrevious value: -"Field to group by. Works examples: \"publication_year\", \"type\", \"oa_status\", \"primary_topic.field.id\", \"authorships.institutions.country_code\", \"is_retracted\". The native \":include_unknown\" suffix also enables include_unknown, even when the boolean is false; passing both adds the suffix once. OpenAlex builds authorships.countries groups from only the first 100 authorships of each work; authorships.institutions.country_code counts every authorship. Authors: \"last_known_institutions.country_code\", \"has_orcid\". Sources: \"type\", \"is_oa\", \"country_code\". Not all fields support group_by — call openalex_describe_fields(entity_type, \"group_by\") for the groupable set."New value: +"Field to group by. Works examples: \"publication_year\", \"type\", \"oa_status\", \"primary_topic.field.id\", \"authorships.institutions.country_code\", \"is_retracted\". The native \":include_unknown\" suffix also enables include_unknown, even when the boolean is false; passing both adds the suffix once. OpenAlex builds authorships.countries groups from only the first 100 authorships of each work; authorships.institutions.country_code counts every authorship. Authors: \"last_known_institutions.country_code\", \"has_orcid\". Sources: \"type\", \"is_oa\", \"country_code\". Awards: \"start_year\", \"funder.id\", \"funding_type\" — groups count awards and do not sum amount_usd. Not all fields support group_by — call openalex_describe_fields(entity_type, \"group_by\") for the groupable set." - removed
Input schema / properties / per_page / maximumRemoved value: -9007199254740991
- Changed
openalex_describe_fields1 field changed- changed
Input schema / properties / entity_type / enumPrevious value: -[ - "works", - "authors", - "sources", - "institutions", - "topics", - "keywords", - "publishers", - "funders" -]New value: +[ + "works", + "authors", + "sources", + "institutions", + "topics", + "keywords", + "publishers", + "funders", + "awards" +]
- Changed
openalex_get_citation_graph13 fields changed- changed
Input schema / properties / per_page / descriptionPrevious value: -"Results per page. Default 25; positive integers above 100 clamp to 100 with a notice unless OPENALEX_CLAMP_PER_PAGE=false restores rejection. A budget-cut page returns fewer (`omitted`)."New value: +"Results per page. Default 25; a larger value returns at most 100 and says so (rejected instead on a server set to OPENALEX_CLAMP_PER_PAGE=false)." - removed
Input schema / properties / per_page / maximumRemoved value: -9007199254740991 - changed
Input schema / properties / select / descriptionPrevious value: -"OpenAlex work field names to return. Always returned: id, display_name. Defaults to the curated works select if omitted. `author_list` returns each author in authorship order as `{id, display_name, orcid}` (`orcid` null when absent), a compact alternative to `authorships`, which also carries institutions and affiliations; neither the default nor `[\"*\"]` includes it. Large projections may be cut to fit the response budget (`omitted`, `windows`)."New value: +"OpenAlex work field names to return. Always returned: id, display_name. Defaults to the curated works select if omitted. `author_list` returns each author in authorship order as `{id, display_name, orcid}` (`orcid` null when absent), a compact alternative to `authorships`, which also carries institutions and affiliations; neither the default nor `[\"*\"]` includes it. A wide projection on a large page makes a large response, so name the fields you need." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `unmatched_quote_in_filter_value`: A filter value sent unquoted has an unmatched double quote. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, authorships.institutions.geo.city, authorships.institutions.geo.region, raw_affiliation_strings, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used but the citation-graph query has no active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `reserved_filter_key`: filters contains cites/cited_by/related_to, or an alias of one such as cited_works — the direction parameter reserves those keys. `id_type_mismatch`: seed_id is a native OpenAlex ID of another entity type — an author, source, institution, topic, publisher, funder, or concept ID rather than a work ID. `id_dot_segment`: seed_id holds a `.` or `..` path segment, written plainly or percent-encoded. `entity_not_found`: OpenAlex has no work matching the seed_id. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `unmatched_quote_in_filter_value`: A filter value sent unquoted has an unmatched double quote. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, authorships.institutions.geo.city, authorships.institutions.geo.region, raw_affiliation_strings, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used but the citation-graph query has no active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `reserved_filter_key`: filters contains cites/cited_by/related_to, or an alias of one such as cited_works — the direction parameter reserves those keys. `id_type_mismatch`: seed_id is a native OpenAlex ID of another entity type — an author, source, institution, topic, publisher, funder, award, or concept ID rather than a work ID. `id_dot_segment`: seed_id holds a `.` or `..` path segment, written plainly or percent-encoded. `entity_not_found`: OpenAlex has no work matching the seed_id. `response_too_large`: The response's structuredContent or content[] text would exceed 8,000,000 bytes — a wide `select` on a large page. A page is never shortened to fit. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "unmatched_quote_in_filter_value", - "rate_limited", - "upstream_budget_exhausted", - "upstream_plan_required", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "invalid_country_code", - "mixed_and_or_in_filter_value", - "quote_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_sort_requires_search", - "upstream_invalid_params_other", - "reserved_filter_key", - "id_type_mismatch", - "id_dot_segment", - "entity_not_found" -]New value: +[ + "unmatched_quote_in_filter_value", + "rate_limited", + "upstream_budget_exhausted", + "upstream_plan_required", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "invalid_country_code", + "mixed_and_or_in_filter_value", + "quote_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "upstream_invalid_params_other", + "reserved_filter_key", + "id_type_mismatch", + "id_dot_segment", + "entity_not_found", + "response_too_large" +] - changed
Output schema / properties / meta / properties / next_cursor / descriptionPrevious value: -"Cursor for next page. null if no more results. Continues after the full upstream page, `omitted` works included."New value: +"Cursor for the next page; pass it back unchanged as `cursor`. null when no further page exists, except on a final page that exactly fills `per_page`: OpenAlex still returns a cursor there, and it leads to an empty page." - changed
Output schema / properties / meta / properties / per_page / descriptionPrevious value: -"Page size OpenAlex echoed for this request — the applied per_page after clamping, not the number of records returned. A short or exhausted page carries fewer records than this, as does a page the response budget cut (`omitted`)."New value: +"Page size OpenAlex echoed for this request — the applied per_page after clamping, not the number of records returned. A short or exhausted page carries fewer records than this." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when per_page was clamped (requested and applied sizes), when no edges are returned — a first call suggests verifying the seed_id, broadening filters, or trying a different direction; a cursor continuation says the walk is already past its last edge — when the response budget cut works, windowed an array, or ran over, and when a work carries exactly 100 authorships or author_list entries (possibly capped). Absent otherwise."New value: +"Guidance notice. Set when per_page was clamped (requested and applied sizes), when no edges are returned — a first call suggests verifying the seed_id, broadening filters, or trying a different direction; a cursor continuation says the walk is already past its last edge — and when a work carries exactly 100 authorships or author_list entries (possibly capped). Absent otherwise." - removed
Output schema / properties / omittedRemoved value: -{ - "additionalProperties": false, - "description": "Present when the response budget cut whole records from the page end; pagination continues after the full upstream page.", - "properties": { - "ids": { - "description": "Bare IDs of the records left out, in page order (a keyword keeps its URL).", - "items": { - "type": "string" - }, - "type": "array" - }, - "next": { - "additionalProperties": false, - "description": "One call returning those records as a set, in OpenAlex's order, not page order. Budgeted too, so it may carry its own `omitted`.", - "properties": { - "arguments": { - "additionalProperties": {}, - "description": "Arguments to pass as-is.", - "properties": {}, - "type": "object" - }, - "tool": { - "const": "openalex_search_entities", - "description": "Tool to call.", - "type": "string" - } - }, - "required": [ - "tool", - "arguments" - ], - "type": "object" - } - }, - "required": [ - "ids", - "next" - ], - "type": "object" -} - removed
Output schema / properties / over_budgetRemoved value: -{ - "description": "True when even the least this call can return — the first record's non-array fields (its arrays windowed to empty), or one `slice` element — exceeds the budget.", - "type": "boolean" -} - changed
Output schema / properties / results / descriptionPrevious value: -"Works on the citation graph in this direction. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them; an abstract arrives reconstructed as `abstract`, and a selected `author_list` as one `{id, display_name, orcid}` entry per author. Works cut by the response budget are in `omitted`; partial or possibly capped arrays are in `windows`."New value: +"Works on the citation graph in this direction. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them; an abstract arrives reconstructed as `abstract`, and a selected `author_list` as one `{id, display_name, orcid}` entry per author. Possibly capped author arrays are in `windows`." - changed
Output schema / properties / windows / descriptionPrevious value: -"Arrays windowed to fit the budget, paged by `slice`, or possibly capped at 100 list authors or 5,000 stored singleton authors. A `slice` call always carries its window, even for a whole array. `next` is null at the stored-array end, including a possibly capped singleton."New value: +"Author arrays possibly capped at 100 on a list record or 5,000 stored on a singleton, and the window of every `slice` call — present even when the slice holds the whole array. A slice window's `next` repeats its `slice.limit` from the following offset; `next` is null at the stored-array end, including a possibly capped singleton." - changed
Output schema / properties / windows / items / descriptionPrevious value: -"An array returned in part."New value: +"An array returned in part, or possibly in part."
- Changed
openalex_resolve_name3 fields changed- changed
Input schema / properties / entity_type / descriptionPrevious value: -"Entity type to search. Omit for cross-entity search (useful when entity type is unknown). With an identifier `query` it narrows only an identifier that can address more than one type: a ROR to institutions, funders, or publishers (omit it to get every one of the three that exists), and a Funder Registry DOI (10.13039/…) to works instead of the funder. Every other identifier resolves as the type it belongs to, whatever this names — except under keywords, where a bare OpenAlex ID shape (\"P53\") is searched as a keyword name, since keyword IDs are slugs."New value: +"Entity type to search. Awards are not among them: OpenAlex has no award autocomplete, so search awards with openalex_search_entities. Omit for cross-entity search (useful when entity type is unknown). With an identifier `query` it narrows only an identifier that can address more than one type: a ROR to institutions, funders, or publishers (omit it to get every one of the three that exists), and a Funder Registry DOI (10.13039/…) to works instead of the funder. Every other identifier resolves as the type it belongs to, whatever this names — except under keywords, where a bare OpenAlex ID shape (\"P53\") is searched as a keyword name, since keyword IDs are slugs." - changed
Input schema / properties / query / descriptionPrevious value: -"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\", or an OpenAlex record-page or API URL such as \"https://openalex.org/works/W2741809807\"), DOI (\"10.1038/nature12373\", or a funder's Funder Registry DOI such as \"10.13039/100000001\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\") — which resolves straight to the record it addresses, or for a ROR up to three (see entity_type), instead of running a name search. A bare OpenAlex ID that resolves nothing is then searched as a name — under entity_type when given, and not at all when filters come without entity_type — since short names share its shape (\"P53\" is a keyword); under entity_type keywords it is searched as a name from the start. A keyword URL (\"https://openalex.org/keywords/groundwater\") resolves the same way; a bare keyword slug reads as a name and runs a name search, which finds it too. A PMCID (\"PMC1234567\" or a PubMed Central URL) is recognized but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead."New value: +"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\", or an OpenAlex record-page or API URL such as \"https://openalex.org/works/W2741809807\"), DOI (\"10.1038/nature12373\", or a funder's Funder Registry DOI such as \"10.13039/100000001\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\") — which resolves straight to the record it addresses, or for a ROR up to three (see entity_type), instead of running a name search. A bare OpenAlex ID that resolves nothing is then searched as a name — under entity_type when given, and not at all when filters come without entity_type — since short names share its shape (\"P53\" is a keyword); under entity_type keywords it is searched as a name from the start. A keyword URL (\"https://openalex.org/keywords/groundwater\") resolves the same way; a bare keyword slug reads as a name and runs a name search, which finds it too. A PMCID (\"PMC1234567\" or a PubMed Central URL) is recognized but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. An award ID (\"G417894356\", or \"https://openalex.org/awards/G417894356\") sends no request and names the openalex_search_entities call for it; with entity_type, a bare one is searched as a name of that type." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when nothing matched (echoes the query, and the filters when a name search applied them, and suggests corrections), when a bare OpenAlex ID resolved nothing and the query was searched as a name instead (names both outcomes, or why the name search did not run or finish), when an identifier query was passed name-search parameters that do not apply to it, or when one of the lookups for a ROR failed upstream (names the entity type whose record may be missing). Absent otherwise."New value: +"Guidance notice. Set when nothing matched (echoes the query, and the filters when a name search applied them, and suggests corrections), when a bare OpenAlex ID resolved nothing and the query was searched as a name instead (names both outcomes, or why the name search did not run or finish), when an identifier query was passed name-search parameters that do not apply to it, when one of the lookups for a ROR failed upstream (names the entity type whose record may be missing), or when the query is an award ID (names the openalex_search_entities call that opens it). Caller text in it is JSON-encoded and Markdown-escaped, the same string on both surfaces. Absent otherwise."
- Changed
openalex_search_entities24 fields changed- changed
Input schema / properties / entity_type / enumPrevious value: -[ - "works", - "authors", - "sources", - "institutions", - "topics", - "keywords", - "publishers", - "funders" -]New value: +[ + "works", + "authors", + "sources", + "institutions", + "topics", + "keywords", + "publishers", + "funders", + "awards" +] - changed
Input schema / properties / id / descriptionPrevious value: -"Retrieve a single entity by ID. Supports: OpenAlex ID (\"W2741809807\", or its OpenAlex record-page or API URL such as \"https://openalex.org/works/W2741809807\" or \"https://api.openalex.org/works/W2741809807\"), whose letter must name `entity_type` — W works, A authors, S sources, I institutions, T topics, P publishers, F funders; DOI (\"10.1038/nature12373\"; under entity_type \"funders\", a funder's Crossref Funder Registry DOI such as \"10.13039/100000001\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\" — one ROR can name an institution, a funder, and a publisher, and `entity_type` picks which), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\"). Keywords are identified by slug rather than a native ID — pass either the slug (\"groundwater\") or the URL a search returns (\"https://openalex.org/keywords/groundwater\"). A PMCID is recognized too, bare (\"PMC1234567\") or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). An array too long for the response budget comes back as a window (`windows`); page the rest with `slice`. To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown."New value: +"Retrieve a single entity by ID. Supports: OpenAlex ID (\"W2741809807\", or its OpenAlex record-page or API URL such as \"https://openalex.org/works/W2741809807\" or \"https://api.openalex.org/works/W2741809807\"), whose letter must name `entity_type` — W works, A authors, S sources, I institutions, T topics, P publishers, F funders, G awards; DOI (\"10.1038/nature12373\"; under entity_type \"funders\", a funder's Crossref Funder Registry DOI such as \"10.13039/100000001\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\" — one ROR can name an institution, a funder, and a publisher, and `entity_type` picks which), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\"). Keywords are identified by slug rather than a native ID — pass either the slug (\"groundwater\") or the URL a search returns (\"https://openalex.org/keywords/groundwater\"). A PMCID is recognized too, bare (\"PMC1234567\") or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). Every selected array returns whole; `slice` pages a long one by count. To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown." - changed
Input schema / properties / page / descriptionPrevious value: -"Page number (1-based) for semantic search, the one mode that paginates with `page` instead of `cursor`. Semantic search ranks a query-dependent candidate set whose size `meta.count` reports, so the last reachable page is ceil(meta.count / per_page) — e.g. page 14 for a count of 70 with per_page=5. Passing it under any other search_mode is rejected."New value: +"Page number (1-based) for semantic search and for a seeded `sample`, the two searches that paginate with `page` instead of `cursor`. Semantic search ranks a query-dependent candidate set whose size `meta.count` reports, so the last reachable page is ceil(meta.count / per_page) — e.g. page 14 for a count of 70 with per_page=5. A sample draws min(sample, meta.count) records, so its last page is ceil(min(sample, meta.count) / per_page); paging a sample requires `seed`, and OpenAlex serves only its first 10,000 records, so a page × per_page above 10,000 is rejected. Passing it with any other search is rejected." - removed
Input schema / properties / per_page / defaultRemoved value: -25 - changed
Input schema / properties / per_page / descriptionPrevious value: -"Results per page. Default 25; positive integers above 100 clamp to 100 with a notice unless OPENALEX_CLAMP_PER_PAGE=false restores rejection. Semantic search caps at 50 — when search_mode=\"semantic\", set per_page ≤ 50 (also subject to a 1 req/sec rate limit upstream). The semantic cap checks the requested size. An `id` lookup ignores page size, and `sample` overrides it. A budget-cut page returns fewer (`omitted`)."New value: +"Results per page. Default 25, or under `sample` the sample size up to 100, so a sample of 100 or fewer returns whole in one call. A larger value returns at most 100 and says so — at most 50 under search_mode \"semantic\", which OpenAlex also limits to about 1 request per second. A server set to OPENALEX_CLAMP_PER_PAGE=false rejects a value over either cap instead. An `id` lookup ignores page size." - removed
Input schema / properties / per_page / maximumRemoved value: -9007199254740991 - changed
Input schema / properties / sample / descriptionPrevious value: -"Return a random sample of this many entities matching the filters (1-100). Single page only — neither `cursor` nor `page` pagination applies to sampling, and a search that passes either alongside it is rejected. Keyword and exact modes only: OpenAlex does not sample a semantic search, so `sample` with search_mode \"semantic\" is rejected. Cannot be combined with `sort` — a sample has no order, and a search passing both is rejected. Overrides `per_page`. Useful for unbiased exploration: spot-checking filter correctness, stratified review prompts, or generating exploration sets without bias toward most-cited."New value: +"Return a random sample of this many entities matching the filters, up to 10,000; a larger value draws 10,000 and says so (rejected instead on a server set to OPENALEX_CLAMP_PER_PAGE=false). The sample comes back `per_page` records at a time — by default the whole sample up to 100 — and a larger one is walked with `page` and a `seed`, which fixes the draw; without `seed` only its first page is returned. `meta.count` stays the population matching the filters. Keyword and exact modes only: OpenAlex does not sample a semantic search, so `sample` with search_mode \"semantic\" is rejected. Cannot be combined with `cursor` or `sort` — a sample has no order, and a search passing either is rejected. Useful for unbiased exploration: spot-checking filter correctness, stratified review prompts, or generating exploration sets without bias toward most-cited." - removed
Input schema / properties / sample / maximumRemoved value: -100 - changed
Input schema / properties / seed / descriptionPrevious value: -"Deterministic seed for `sample`. Same seed + same filters = same results — pass when reproducibility matters. Has no effect without `sample`, and a search that passes it alone is rejected."New value: +"Deterministic seed for `sample`. Same seed + same filters = the same draw, page for page — required to walk a sample larger than one page with `page`, and worth passing whenever reproducibility matters. Has no effect without `sample`, and a search that passes it alone is rejected." - changed
Input schema / properties / select / descriptionPrevious value: -"OpenAlex top-level field names to return. Always returned: `id`, `display_name` — additional fields you list are appended. A curated default per entity type applies to both searches and single-entity (`id`) lookups; pass field names to override it, or `[\"*\"]` to retrieve the complete record (every field). Only top-level fields project, so a nested value is requested by its parent object: bibliometrics (`h_index`, `i10_index`, `2yr_mean_citedness`) live under `summary_stats` on authors, sources, institutions, publishers, and funders, and naming a leaf returns that object. On sources, `publisher` returns `host_organization_name`: the publisher of a journal, the hosting institution of a repository, and null on most sources. On works, `author_list` returns each author in authorship order as `{id, display_name, orcid}` (`orcid` null when absent), a compact alternative to `authorships`, which also carries institutions and affiliations; neither the default nor `[\"*\"]` includes it. Invalid field names produce an error identifying the rejected field. Large projections may be cut to fit the response budget (`omitted`, `windows`). Not applied with `slice`. Example: [\"doi\", \"author_list\", \"primary_topic\"]."New value: +"OpenAlex top-level field names to return. Always returned: `id`, `display_name` — additional fields you list are appended. A curated default per entity type applies to both searches and single-entity (`id`) lookups; pass field names to override it, or `[\"*\"]` to retrieve the complete record (every field). Only top-level fields project, so a nested value is requested by its parent object: bibliometrics (`h_index`, `i10_index`, `2yr_mean_citedness`) live under `summary_stats` on authors, sources, institutions, publishers, and funders, and naming a leaf returns that object. On sources, `publisher` returns `host_organization_name`: the publisher of a journal, the hosting institution of a repository, and null on most sources. On works, `author_list` returns each author in authorship order as `{id, display_name, orcid}` (`orcid` null when absent), a compact alternative to `authorships`, which also carries institutions and affiliations; neither the default nor `[\"*\"]` includes it. Invalid field names produce an error identifying the rejected field. A wide projection on a large page makes a large response, so name the fields you need. Not applied with `slice`. Example: [\"doi\", \"author_list\", \"primary_topic\"]." - changed
Input schema / properties / slice / descriptionPrevious value: -"Page one array of the record at `id`: returns `id`, `display_name`, and `field` from `offset` onward, as many elements as fit the response budget (at least one), with the window and its `next` call in `windows`. Requires `id`; replaces `select`. An offset at or past the end returns an empty window. A 100-author list cap can be continued on the singleton; at 5,000 stored authors the byline remains possibly capped, but `next` is null once stored entries are exhausted."New value: +"Page one array of the record at `id`: returns `id`, `display_name`, and `limit` elements of `field` from `offset` — fewer only at the array end — with the window in `windows`, whose `next` call repeats `limit` from the following offset. Requires `id`; replaces `select`. An offset at or past the end returns an empty window. A 100-author list cap can be continued on the singleton; at 5,000 stored authors the byline remains possibly capped, but `next` is null once stored entries are exhausted." - added
Input schema / properties / slice / properties / limitAdded value: +{ + "default": 50, + "description": "Elements to return. Default 50; a larger value returns at most 5,000 and says so (rejected instead on a server set to OPENALEX_CLAMP_PER_PAGE=false).", + "minimum": 1, + "type": "integer" +} - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `invalid_filter_string`: A native filter string has an incomplete clause or unmatched double quotes. `duplicate_filter_string_key`: A native filter string repeats an exact key. `unmatched_quote_in_filter_value`: A filter value sent unquoted has an unmatched double quote. `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` under a search_mode other than \"semantic\". `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_with_page`: A search (no `id`) provided both `sample` and `page`. `sample_with_semantic`: A search (no `id`) provided `sample` with search_mode \"semantic\", which OpenAlex does not sample — it returns the same ranked candidates under every seed. `sample_with_sort`: A search (no `id`) provided both `sample` and `sort`, which OpenAlex refuses together. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `slice_without_id`: A search passed `slice` without `id` — slice pages one array of one record. `slice_field_not_array`: The `slice` field is `*`, or is not an array on the record at `id` — absent, null, a scalar, or an object. `id_type_mismatch`: `id` is a native OpenAlex ID whose letter names another entity type than `entity_type`, or a concept ID (C…), a type this server does not serve. `id_dot_segment`: `id` holds a `.` or `..` path segment, written plainly or percent-encoded. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, a body that was empty, HTML, or unparseable JSON, or a semantic search whose query embedding failed upstream (HTTP 400 `Failed to embed query:`, or semantic search not configured). `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `invalid_filter_string`: A native filter string has an incomplete clause or unmatched double quotes. `duplicate_filter_string_key`: A native filter string repeats an exact key. `unmatched_quote_in_filter_value`: A filter value sent unquoted has an unmatched double quote. `semantic_per_page_cap`: A semantic search (no `id`) set per_page above its cap of 50 on a server with OPENALEX_CLAMP_PER_PAGE=false; with clamping on (the default), it returns 50 and says so. `response_too_large`: The response's structuredContent or content[] text would exceed 8,000,000 bytes — a wide `select` on a large page, or a record with very long arrays. A page is never shortened to fit. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` with neither search_mode \"semantic\" nor `sample`. `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_page_without_seed`: A search (no `id`) provided `page` with `sample` but no `seed`, which OpenAlex refuses: an unseeded sample redraws on every call, so its pages would overlap. `sample_page_too_deep`: A sample page reaches past record 10,000 (`page` × `per_page` above 10,000), the most of a sample OpenAlex serves by page number. `sample_with_semantic`: A search (no `id`) provided `sample` with search_mode \"semantic\", which OpenAlex does not sample — it returns the same ranked candidates under every seed. `sample_with_sort`: A search (no `id`) provided both `sample` and `sort`, which OpenAlex refuses together. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `slice_without_id`: A search passed `slice` without `id` — slice pages one array of one record. `slice_field_not_array`: The `slice` field is `*`, or is not an array on the record at `id` — absent, null, a scalar, or an object. `id_type_mismatch`: `id` is a native OpenAlex ID whose letter names another entity type than `entity_type`, or a concept ID (C…), a type this server does not serve. `id_dot_segment`: `id` holds a `.` or `..` path segment, written plainly or percent-encoded. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, a body that was empty, HTML, or unparseable JSON, or a semantic search whose query embedding failed upstream (HTTP 400 `Failed to embed query:`, or semantic search not configured). `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "invalid_filter_string", - "duplicate_filter_string_key", - "unmatched_quote_in_filter_value", - "semantic_per_page_cap", - "semantic_without_query", - "semantic_with_cursor", - "page_without_semantic", - "sample_with_cursor", - "sample_with_page", - "sample_with_semantic", - "sample_with_sort", - "seed_without_sample", - "slice_without_id", - "slice_field_not_array", - "id_type_mismatch", - "id_dot_segment", - "entity_not_found", - "rate_limited", - "upstream_budget_exhausted", - "upstream_plan_required", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "invalid_country_code", - "mixed_and_or_in_filter_value", - "quote_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_sort_requires_search", - "query_too_long", - "upstream_invalid_params_other", - "upstream_validation_failed" -]New value: +[ + "invalid_filter_string", + "duplicate_filter_string_key", + "unmatched_quote_in_filter_value", + "semantic_per_page_cap", + "response_too_large", + "semantic_without_query", + "semantic_with_cursor", + "page_without_semantic", + "sample_with_cursor", + "sample_page_without_seed", + "sample_page_too_deep", + "sample_with_semantic", + "sample_with_sort", + "seed_without_sample", + "slice_without_id", + "slice_field_not_array", + "id_type_mismatch", + "id_dot_segment", + "entity_not_found", + "rate_limited", + "upstream_budget_exhausted", + "upstream_plan_required", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "invalid_country_code", + "mixed_and_or_in_filter_value", + "quote_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "query_too_long", + "upstream_invalid_params_other", + "upstream_validation_failed" +] - changed
Output schema / properties / meta / properties / count / descriptionPrevious value: -"Total results matching the query/filters. Under search_mode \"semantic\" it is instead the size of the ranked candidate set — the most results `page` can reach — not an exhaustive match total."New value: +"Total results matching the query/filters — under `sample` too, whose draw holds min(sample, count) records. Under search_mode \"semantic\" it is instead the size of the ranked candidate set — the most results `page` can reach — not an exhaustive match total." - changed
Output schema / properties / meta / properties / next_cursor / descriptionPrevious value: -"Cursor for next page. null if no more results. Continues after the full upstream page, `omitted` records included."New value: +"Cursor for the next page; pass it back unchanged as `cursor`. null when no further page exists — always under semantic search and `sample`, which continue with `page` — except on a final page that exactly fills `per_page`: OpenAlex still returns a cursor there, and it leads to an empty page." - changed
Output schema / properties / meta / properties / per_page / descriptionPrevious value: -"Page size OpenAlex echoed for this request — the applied per_page after clamping or sample override, not the number of records returned. A singleton reports 1. A short or exhausted page carries fewer records than this, as does a page the response budget cut (`omitted`)."New value: +"Page size OpenAlex echoed for this request — the applied per_page after clamping or its default, not the number of records returned. A singleton reports 1. A short or exhausted page carries fewer records than this." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when per_page was clamped (requested and applied sizes), a native filter string was converted, a first call has no matches, a continuation is exhausted, an id lookup ignores search criteria, semantic search reports a candidate total, the response budget cut records, windowed an array, or ran over, an author array is possibly capped (100 list entries or 5,000 stored singleton entries), a slice offset is past the end, or slice replaces select. Absent otherwise."New value: +"Guidance notice. Set when per_page, sample, or slice.limit was clamped (requested and applied sizes), a native filter string was converted, a first call has no matches, a continuation is exhausted, an id lookup ignores search criteria, semantic search reports a candidate total and whether a later `page` holds more, a sample draws more than one page (the next `page`, its last page, or that `seed` makes it pageable), an author array is possibly capped (100 list entries or 5,000 stored singleton entries), a slice offset is past the end, or slice replaces select. Absent otherwise." - removed
Output schema / properties / omittedRemoved value: -{ - "additionalProperties": false, - "description": "Present when the response budget cut whole records from the page end; pagination continues after the full upstream page.", - "properties": { - "ids": { - "description": "Bare IDs of the records left out, in page order (a keyword keeps its URL).", - "items": { - "type": "string" - }, - "type": "array" - }, - "next": { - "additionalProperties": false, - "description": "One call returning those records as a set, in OpenAlex's order, not page order. Budgeted too, so it may carry its own `omitted`.", - "properties": { - "arguments": { - "additionalProperties": {}, - "description": "Arguments to pass as-is.", - "properties": {}, - "type": "object" - }, - "tool": { - "const": "openalex_search_entities", - "description": "Tool to call.", - "type": "string" - } - }, - "required": [ - "tool", - "arguments" - ], - "type": "object" - } - }, - "required": [ - "ids", - "next" - ], - "type": "object" -} - removed
Output schema / properties / over_budgetRemoved value: -{ - "description": "True when even the least this call can return — the first record's non-array fields (its arrays windowed to empty), or one `slice` element — exceeds the budget.", - "type": "boolean" -} - changed
Output schema / properties / results / descriptionPrevious value: -"OpenAlex entity objects. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them; an abstract arrives reconstructed as `abstract`, and a selected `author_list` as one `{id, display_name, orcid}` entry per author. Additional fields depend on entity_type and select. Records cut by the response budget are in `omitted`; partial or possibly capped arrays are in `windows`."New value: +"OpenAlex entity objects. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them; an abstract arrives reconstructed as `abstract`, and a selected `author_list` as one `{id, display_name, orcid}` entry per author. Additional fields depend on entity_type and select. Possibly capped author arrays and `slice` windows are in `windows`." - changed
Output schema / properties / results / items / properties / id / descriptionPrevious value: -"OpenAlex ID URL (e.g., \"https://openalex.org/W2741809807\"). `windows` and `omitted` name records by the bare ID (\"W2741809807\"); a keyword keeps its URL."New value: +"OpenAlex ID URL (e.g., \"https://openalex.org/W2741809807\"). `windows` names records by the bare ID (\"W2741809807\"); a keyword keeps its URL." - changed
Output schema / properties / windows / descriptionPrevious value: -"Arrays windowed to fit the budget, paged by `slice`, or possibly capped at 100 list authors or 5,000 stored singleton authors. A `slice` call always carries its window, even for a whole array. `next` is null at the stored-array end, including a possibly capped singleton."New value: +"Author arrays possibly capped at 100 on a list record or 5,000 stored on a singleton, and the window of every `slice` call — present even when the slice holds the whole array. A slice window's `next` repeats its `slice.limit` from the following offset; `next` is null at the stored-array end, including a possibly capped singleton." - changed
Output schema / properties / windows / items / descriptionPrevious value: -"An array returned in part."New value: +"An array returned in part, or possibly in part."
4 tool updates
- Changed
openalex_analyze_trends14 fields changed- changed
Input schema / properties / cursor / descriptionPrevious value: -"Pagination cursor from a previous response. Only relevant when order is \"key\" — count-descending results have no next page. Pass the next_cursor from the previous response to advance. Omit it on the first call — an empty string is rejected, since a supplied-but-blank cursor is a caller mistake rather than a request for the first page."New value: +"Pagination cursor from a previous response. A supplied cursor selects key order even if order is omitted or \"count\". Pass the next_cursor from the previous response to advance, subject to the stop conditions below. Omit it on the first call — an empty string is rejected, since a supplied-but-blank cursor is a caller mistake rather than a request for the first page. OpenAlex can wrap a key-ordered walk to earlier groups. Stop when a page's first key repeats an earlier key, or when a page is short or empty." - changed
Input schema / properties / filters / descriptionPrevious value: -"Filter criteria (same syntax as openalex_search_entities filters). Narrows the population before aggregation. Country fields take ISO 3166-1 alpha-2 codes (\"DE\") and `language` takes ISO 639-1 codes (\"en\"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so \"South Korea|Japan\" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, awards.funder_display_name, geo.city, raw_affiliation_strings) matches as one phrase (\"National Science Foundation\"; a comma, as in \"University of California, Berkeley\", is part of it, and it cannot contain a double quote of its own), \"!\" and \"|\" included, but cannot be ANDed with \"+\" in the same field. A value mixing \"|\" with an AND operator — a \"+\", or a space on a field where words mean AND — is rejected, since OpenAlex drops every \"|\" alternative that ANDs more than one value; put the AND in a second key instead. For full-text within filters, use abstract.search, title.search, or default.search — there is no bare 'search' filter key. Example: group works by year filtered to a specific topic."New value: +"Filter record object, using the same value syntax as openalex_search_entities; native string input is unavailable here. Narrows the population before aggregation. Country fields take ISO 3166-1 alpha-2 codes (\"DE\") and `language` takes ISO 639-1 codes (\"en\"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so \"South Korea|Japan\" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, awards.funder_display_name, geo.city, raw_affiliation_strings) matches as one phrase (\"National Science Foundation\"; a comma, as in \"University of California, Berkeley\", is part of it, and it cannot contain a double quote of its own), \"!\" and \"|\" included, but cannot be ANDed with \"+\" in the same field. A value sent unquoted must have paired double quotes; balanced search phrases remain valid. A value mixing \"|\" with an AND operator — a \"+\", or a space on a field where words mean AND — is rejected, since OpenAlex drops every \"|\" alternative that ANDs more than one value; put the AND in a second key instead. For full-text within filters, use abstract.search, title.search, or default.search — there is no bare 'search' filter key. Example: group works by year filtered to a specific topic." - changed
Input schema / properties / group_by / descriptionPrevious value: -"Field to group by. Works examples: \"publication_year\", \"type\", \"oa_status\", \"primary_topic.field.id\", \"authorships.institutions.country_code\", \"is_retracted\". OpenAlex builds authorships.countries groups from only the first 100 authorships of each work; authorships.institutions.country_code counts every authorship. Authors: \"last_known_institutions.country_code\", \"has_orcid\". Sources: \"type\", \"is_oa\", \"country_code\". Not all fields support group_by — call openalex_describe_fields(entity_type, \"group_by\") for the groupable set."New value: +"Field to group by. Works examples: \"publication_year\", \"type\", \"oa_status\", \"primary_topic.field.id\", \"authorships.institutions.country_code\", \"is_retracted\". The native \":include_unknown\" suffix also enables include_unknown, even when the boolean is false; passing both adds the suffix once. OpenAlex builds authorships.countries groups from only the first 100 authorships of each work; authorships.institutions.country_code counts every authorship. Authors: \"last_known_institutions.country_code\", \"has_orcid\". Sources: \"type\", \"is_oa\", \"country_code\". Not all fields support group_by — call openalex_describe_fields(entity_type, \"group_by\") for the groupable set." - changed
Input schema / properties / include_unknown / descriptionPrevious value: -"Add a group for entities with no value for the grouped field. Hidden by default. That group carries `is_unknown: true`; OpenAlex keys it -111 or -111.0 on numeric fields, \"unknown\" on text fields and under order \"key\", and an ID ending in /unknown on ID fields — a sentinel, not a measured value. The key is not a filter value: passing -111 as a filter matches a numeric range, not the entities with no value. Boolean fields have no separate group — a missing value counts as false."New value: +"Add a group for entities with no value for the grouped field. Hidden by default unless group_by has the native \":include_unknown\" suffix, which enables this setting even when the boolean is false; passing both adds the suffix once. That group carries `is_unknown: true`; OpenAlex keys it -111 or -111.0 on numeric fields, \"unknown\" on text fields and under order \"key\", and an ID ending in /unknown on ID fields — a sentinel, not a measured value. The key is not a filter value: passing -111 as a filter matches a numeric range, not the entities with no value. Boolean fields have no separate group — a missing value counts as false." - changed
Input schema / properties / order / descriptionPrevious value: -"Sort order for groups. Omit or pass \"count\" (default) to return the top-N groups by count descending — no further pages. Pass \"key\" to enumerate all distinct values in key-ascending order with cursor pagination. Use \"key\" only when you need a full traversal; most analysis calls want \"count\"."New value: +"Sort order for groups. Without a cursor, omit or pass \"count\" (default) to return the top-N groups by count descending — no further pages. Pass \"key\" to enumerate distinct values in key-ascending order with cursor pagination. Boolean fields keep count order even with \"key\" and do not support cursor pagination. A supplied cursor selects key order even if order is omitted or \"count\". OpenAlex can wrap a key-ordered walk to earlier groups. Stop when a page's first key repeats an earlier key, or when a page is short or empty." - changed
Input schema / properties / per_page / descriptionPrevious value: -"Maximum groups per page (1-200). Default 200 (the upstream cap). A real top-N knob when order is count (the default) — reduce to return only the highest-count groups."New value: +"Maximum groups per page. Default 200 (the upstream cap); positive integers above 200 clamp to 200 with a notice unless OPENALEX_CLAMP_PER_PAGE=false restores rejection. A real top-N knob in count order without a cursor (the default) — reduce to return only the highest-count groups." - changed
Input schema / properties / per_page / maximumPrevious value: -200New value: +9007199254740991 - changed
Output schema / properties / echo / descriptionPrevious value: -"Compact echo of the input criteria (entity_type, group_by, filters) — surfaces what was actually requested when no groups are returned."New value: +"Compact echo of the criteria (entity_type, group_by, filters) and effective include_unknown and order settings — surfaces what was actually requested when no groups are returned." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid group_by or filter field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_ungroupable_group_by`: group_by targets a field OpenAlex cannot aggregate — a raw date, a decimal score, a *.search operator, a field such as display_name, doi, or referenced_works, or a concept key on authors, which OpenAlex reports as an invalid OpenAlex ID (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). `upstream_missing_group_by`: OpenAlex answered with its plain list shape, carrying no aggregation for the requested group_by. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `unmatched_quote_in_filter_value`: A filter value sent unquoted has an unmatched double quote. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid group_by or filter field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_ungroupable_group_by`: group_by targets a field OpenAlex cannot aggregate — a raw date, a decimal score, a *.search operator, a field such as display_name, doi, or referenced_works, or a concept key on authors, which OpenAlex reports as an invalid OpenAlex ID (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). `upstream_missing_group_by`: OpenAlex answered with its plain list shape, carrying no aggregation for the requested group_by. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "rate_limited", - "upstream_budget_exhausted", - "upstream_plan_required", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "invalid_country_code", - "mixed_and_or_in_filter_value", - "quote_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_ungroupable_group_by", - "upstream_invalid_params_other", - "upstream_validation_failed", - "upstream_missing_group_by" -]New value: +[ + "unmatched_quote_in_filter_value", + "rate_limited", + "upstream_budget_exhausted", + "upstream_plan_required", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "invalid_country_code", + "mixed_and_or_in_filter_value", + "quote_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_ungroupable_group_by", + "upstream_invalid_params_other", + "upstream_validation_failed", + "upstream_missing_group_by" +] - changed
Output schema / properties / groups / items / properties / key_display_name / descriptionPrevious value: -"Human-readable group label as plain text, with HTML entities decoded and markup removed."New value: +"Human-readable group label as plain text, with HTML entities decoded and markup removed; null when OpenAlex supplies no label. Text output uses the group key when the label is null." - changed
Output schema / properties / groups / items / properties / key_display_name / typePrevious value: -"string"New value: +[ + "string", + "null" +] - changed
Output schema / properties / meta / properties / next_cursor / descriptionPrevious value: -"Cursor for next page of groups. null if no more groups."New value: +"Upstream continuation cursor; null when OpenAlex supplies none. A non-null cursor does not guarantee unseen groups. OpenAlex can wrap a key-ordered walk to earlier groups. Stop when a page's first key repeats an earlier key, or when a page is short or empty." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when a first call returns no groups (recovery suggestions), when a `cursor` continuation returns none because the traversal is already finished, when the page is full and more groups likely exist (truncation signal with narrowing advice), or when works are grouped by authorships.countries, which OpenAlex counts from only the first 100 authorships of each work. Absent otherwise."New value: +"Guidance notice. Set when per_page was clamped (requested and applied sizes), on every effective key-order call (upstream wrap warning and stopping conditions), when a first call returns no groups (recovery suggestions), when a cursor continuation returns none because the traversal is already finished, when a count-order page is full and more groups likely exist (truncation signal with narrowing advice), or when works are grouped by authorships.countries, which OpenAlex counts from only the first 100 authorships of each work. Absent otherwise."
- Changed
openalex_get_citation_graph10 fields changed- changed
Input schema / properties / filters / descriptionPrevious value: -"Additional filters to narrow the graph, same syntax as openalex_search_entities. Example: publication_year=\">2020\", is_oa=\"true\". Country fields take ISO 3166-1 alpha-2 codes (\"DE\") and `language` takes ISO 639-1 codes (\"en\"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so \"South Korea|Japan\" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, awards.funder_display_name, authorships.institutions.geo.city, raw_affiliation_strings) matches as one phrase (\"National Science Foundation\"; a comma, as in \"University of California, Berkeley\", is part of it, and it cannot contain a double quote of its own), \"!\" and \"|\" included, but cannot be ANDed with \"+\" in the same field. A value mixing \"|\" with an AND operator — a \"+\", or a space on a field where words mean AND — is rejected, since OpenAlex drops every \"|\" alternative that ANDs more than one value; put the AND in a second key instead. Do not include cites/cited_by/related_to, nor an alias of one such as cited_works — those keys are set by the `direction` parameter."New value: +"Additional filter record object to narrow the graph, using the same value syntax as openalex_search_entities; native string input is unavailable here. Example: publication_year=\">2020\", is_oa=\"true\". Country fields take ISO 3166-1 alpha-2 codes (\"DE\") and `language` takes ISO 639-1 codes (\"en\"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so \"South Korea|Japan\" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, awards.funder_display_name, authorships.institutions.geo.city, raw_affiliation_strings) matches as one phrase (\"National Science Foundation\"; a comma, as in \"University of California, Berkeley\", is part of it, and it cannot contain a double quote of its own), \"!\" and \"|\" included, but cannot be ANDed with \"+\" in the same field. A value sent unquoted must have paired double quotes; balanced search phrases remain valid. Filters are checked before the seed lookup. A value mixing \"|\" with an AND operator — a \"+\", or a space on a field where words mean AND — is rejected, since OpenAlex drops every \"|\" alternative that ANDs more than one value; put the AND in a second key instead. Do not include cites/cited_by/related_to, nor an alias of one such as cited_works — those keys are set by the `direction` parameter." - changed
Input schema / properties / per_page / descriptionPrevious value: -"Results per page (1-100). Default 25. A budget-cut page returns fewer (`omitted`)."New value: +"Results per page. Default 25; positive integers above 100 clamp to 100 with a notice unless OPENALEX_CLAMP_PER_PAGE=false restores rejection. A budget-cut page returns fewer (`omitted`)." - changed
Input schema / properties / per_page / maximumPrevious value: -100New value: +9007199254740991 - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, authorships.institutions.geo.city, authorships.institutions.geo.region, raw_affiliation_strings, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used but the citation-graph query has no active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `reserved_filter_key`: filters contains cites/cited_by/related_to, or an alias of one such as cited_works — the direction parameter reserves those keys. `id_type_mismatch`: seed_id is a native OpenAlex ID of another entity type — an author, source, institution, topic, publisher, funder, or concept ID rather than a work ID. `id_dot_segment`: seed_id holds a `.` or `..` path segment, written plainly or percent-encoded. `entity_not_found`: OpenAlex has no work matching the seed_id. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `unmatched_quote_in_filter_value`: A filter value sent unquoted has an unmatched double quote. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, authorships.institutions.geo.city, authorships.institutions.geo.region, raw_affiliation_strings, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used but the citation-graph query has no active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `reserved_filter_key`: filters contains cites/cited_by/related_to, or an alias of one such as cited_works — the direction parameter reserves those keys. `id_type_mismatch`: seed_id is a native OpenAlex ID of another entity type — an author, source, institution, topic, publisher, funder, or concept ID rather than a work ID. `id_dot_segment`: seed_id holds a `.` or `..` path segment, written plainly or percent-encoded. `entity_not_found`: OpenAlex has no work matching the seed_id. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "rate_limited", - "upstream_budget_exhausted", - "upstream_plan_required", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "invalid_country_code", - "mixed_and_or_in_filter_value", - "quote_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_sort_requires_search", - "upstream_invalid_params_other", - "reserved_filter_key", - "id_type_mismatch", - "id_dot_segment", - "entity_not_found" -]New value: +[ + "unmatched_quote_in_filter_value", + "rate_limited", + "upstream_budget_exhausted", + "upstream_plan_required", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "invalid_country_code", + "mixed_and_or_in_filter_value", + "quote_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "upstream_invalid_params_other", + "reserved_filter_key", + "id_type_mismatch", + "id_dot_segment", + "entity_not_found" +] - changed
Output schema / properties / meta / properties / per_page / descriptionPrevious value: -"Page size OpenAlex echoed for this request — the requested per_page, not the number of records returned. A short or exhausted page carries fewer records than this, as does a page the response budget cut (`omitted`)."New value: +"Page size OpenAlex echoed for this request — the applied per_page after clamping, not the number of records returned. A short or exhausted page carries fewer records than this, as does a page the response budget cut (`omitted`)." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when no edges are returned — a first call suggests verifying the seed_id, broadening filters, or trying a different direction; a `cursor` continuation says the walk is already past its last edge instead — when the response budget cut works, windowed an array, or ran over, and when a work carries exactly 100 authorships or author_list entries (possibly capped). Absent otherwise."New value: +"Guidance notice. Set when per_page was clamped (requested and applied sizes), when no edges are returned — a first call suggests verifying the seed_id, broadening filters, or trying a different direction; a cursor continuation says the walk is already past its last edge — when the response budget cut works, windowed an array, or ran over, and when a work carries exactly 100 authorships or author_list entries (possibly capped). Absent otherwise." - changed
Output schema / properties / windows / descriptionPrevious value: -"Arrays returned in part — windowed to fit the budget, paged by `slice`, or a possibly capped 100-entry `authorships` or `author_list` — each with its continuation. A `slice` call always carries its window, even for a whole array; otherwise absent when every array is whole."New value: +"Arrays windowed to fit the budget, paged by `slice`, or possibly capped at 100 list authors or 5,000 stored singleton authors. A `slice` call always carries its window, even for a whole array. `next` is null at the stored-array end, including a possibly capped singleton." - changed
Output schema / properties / windows / items / properties / possibly_capped / descriptionPrevious value: -"True for exactly 100 `authorships` or `author_list` entries on a list record (OpenAlex's cap): the list may be longer."New value: +"True for exactly 100 authorships or author_list entries on a list record, or 5,000 on a singleton lookup: the byline may be longer than the returned array." - changed
Output schema / properties / windows / items / properties / total / descriptionPrevious value: -"Array length as returned to this call."New value: +"Stored array length returned to this call, not a complete byline total."
- Changed
openalex_resolve_name3 fields changed- changed
Input schema / properties / filters / descriptionPrevious value: -"Narrow autocomplete results with filters, in the openalex_search_entities filter syntax. Example: restrict to a specific country or publication year range. Country fields take ISO 3166-1 alpha-2 codes ({\"country_code\": \"DE\"} on institutions) and `language` takes ISO 639-1 codes (\"en\"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so \"South Korea|Japan\" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, geo.city, geo.region, awards.funder_display_name) matches as one phrase ({\"geo.city\": \"New York\"} on institutions; a comma, as in \"University of California, Berkeley\", is part of it, and it cannot contain a double quote of its own), \"!\" and \"|\" included, but cannot be ANDed with \"+\" in the same field. A value mixing \"|\" with an AND operator — a \"+\", or a space on a field where words mean AND — is rejected, since OpenAlex drops every \"|\" alternative that ANDs more than one value; put the AND in a second key instead. Requires entity_type — filter fields belong to one entity type, so a name search across every type takes none, and a name query passing filters without entity_type is rejected. Applies to name queries only — an identifier lookup returns the records it addresses regardless."New value: +"Narrow autocomplete results with a filter record object, using the openalex_search_entities value syntax; native string input is unavailable here. Example: restrict to a specific country or publication year range. Country fields take ISO 3166-1 alpha-2 codes ({\"country_code\": \"DE\"} on institutions) and `language` takes ISO 639-1 codes (\"en\"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so \"South Korea|Japan\" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, geo.city, geo.region, awards.funder_display_name) matches as one phrase ({\"geo.city\": \"New York\"} on institutions; a comma, as in \"University of California, Berkeley\", is part of it, and it cannot contain a double quote of its own), \"!\" and \"|\" included, but cannot be ANDed with \"+\" in the same field. A value sent unquoted must have paired double quotes; balanced search phrases remain valid. A value mixing \"|\" with an AND operator — a \"+\", or a space on a field where words mean AND — is rejected, since OpenAlex drops every \"|\" alternative that ANDs more than one value; put the AND in a second key instead. Requires entity_type — filter fields belong to one entity type, so a name search across every type takes none, and a name query passing filters without entity_type is rejected. Applies to name queries only — an identifier lookup returns the records it addresses regardless." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `filters_without_entity_type`: A name `query` passed `filters` without `entity_type`. Filter fields belong to one entity type, and a name search across every type takes no filters. `rate_limited`: OpenAlex throttled the autocomplete request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to autocomplete (HTTP 403). `id_dot_segment`: An identifier `query` holds a `.` or `..` path segment, written plainly or percent-encoded. `comma_in_filter_value`: A `filters` value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as display_name.search) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A `filters` value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A `filters` value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter field name on the autocomplete query (HTTP 400). `upstream_invalid_id_value`: A `filters` entry expecting an entity ID received a value that is not an OpenAlex ID — usually a name (HTTP 400). `query_too_long`: OpenAlex autocomplete failed (HTTP 500) on a `query` longer than the 1,000 characters it accepts when entity_type is set. `upstream_invalid_params_other`: OpenAlex rejected the autocomplete request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the autocomplete request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `unmatched_quote_in_filter_value`: A filter value sent unquoted has an unmatched double quote. `filters_without_entity_type`: A name `query` passed `filters` without `entity_type`. Filter fields belong to one entity type, and a name search across every type takes no filters. `rate_limited`: OpenAlex throttled the autocomplete request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to autocomplete (HTTP 403). `id_dot_segment`: An identifier `query` holds a `.` or `..` path segment, written plainly or percent-encoded. `comma_in_filter_value`: A `filters` value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as display_name.search) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A `filters` value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A `filters` value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter field name on the autocomplete query (HTTP 400). `upstream_invalid_id_value`: A `filters` entry expecting an entity ID received a value that is not an OpenAlex ID — usually a name (HTTP 400). `query_too_long`: OpenAlex autocomplete failed (HTTP 500) on a `query` longer than the 1,000 characters it accepts when entity_type is set. `upstream_invalid_params_other`: OpenAlex rejected the autocomplete request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the autocomplete request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "filters_without_entity_type", - "rate_limited", - "upstream_budget_exhausted", - "upstream_plan_required", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "id_dot_segment", - "comma_in_filter_value", - "invalid_country_code", - "mixed_and_or_in_filter_value", - "quote_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "query_too_long", - "upstream_invalid_params_other", - "upstream_validation_failed" -]New value: +[ + "unmatched_quote_in_filter_value", + "filters_without_entity_type", + "rate_limited", + "upstream_budget_exhausted", + "upstream_plan_required", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "id_dot_segment", + "comma_in_filter_value", + "invalid_country_code", + "mixed_and_or_in_filter_value", + "quote_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "query_too_long", + "upstream_invalid_params_other", + "upstream_validation_failed" +]
- Changed
openalex_search_entities10 fields changed- changed
Input schema / properties / per_page / descriptionPrevious value: -"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). The cap applies to searches only; an `id` lookup returns its one record regardless of both. A budget-cut page returns fewer (`omitted`)."New value: +"Results per page. Default 25; positive integers above 100 clamp to 100 with a notice unless OPENALEX_CLAMP_PER_PAGE=false restores rejection. Semantic search caps at 50 — when search_mode=\"semantic\", set per_page ≤ 50 (also subject to a 1 req/sec rate limit upstream). The semantic cap checks the requested size. An `id` lookup ignores page size, and `sample` overrides it. A budget-cut page returns fewer (`omitted`)." - changed
Input schema / properties / per_page / maximumPrevious value: -100New value: +9007199254740991 - changed
Input schema / properties / slice / descriptionPrevious value: -"Page one array of the record at `id`: returns `id`, `display_name`, and `field` from `offset` onward, as many elements as fit the response budget (at least one), with the window and its `next` call in `windows`. Requires `id`; replaces `select`. An offset at or past the end returns an empty window. Walks any partial array, including a possibly capped 100-entry `authorships` or `author_list`."New value: +"Page one array of the record at `id`: returns `id`, `display_name`, and `field` from `offset` onward, as many elements as fit the response budget (at least one), with the window and its `next` call in `windows`. Requires `id`; replaces `select`. An offset at or past the end returns an empty window. A 100-author list cap can be continued on the singleton; at 5,000 stored authors the byline remains possibly capped, but `next` is null once stored entries are exhausted." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` under a search_mode other than \"semantic\". `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_with_page`: A search (no `id`) provided both `sample` and `page`. `sample_with_semantic`: A search (no `id`) provided `sample` with search_mode \"semantic\", which OpenAlex does not sample — it returns the same ranked candidates under every seed. `sample_with_sort`: A search (no `id`) provided both `sample` and `sort`, which OpenAlex refuses together. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `slice_without_id`: A search passed `slice` without `id` — slice pages one array of one record. `slice_field_not_array`: The `slice` field is `*`, or is not an array on the record at `id` — absent, null, a scalar, or an object. `id_type_mismatch`: `id` is a native OpenAlex ID whose letter names another entity type than `entity_type`, or a concept ID (C…), a type this server does not serve. `id_dot_segment`: `id` holds a `.` or `..` path segment, written plainly or percent-encoded. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, a body that was empty, HTML, or unparseable JSON, or a semantic search whose query embedding failed upstream (HTTP 400 `Failed to embed query:`, or semantic search not configured). `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `invalid_filter_string`: A native filter string has an incomplete clause or unmatched double quotes. `duplicate_filter_string_key`: A native filter string repeats an exact key. `unmatched_quote_in_filter_value`: A filter value sent unquoted has an unmatched double quote. `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` under a search_mode other than \"semantic\". `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_with_page`: A search (no `id`) provided both `sample` and `page`. `sample_with_semantic`: A search (no `id`) provided `sample` with search_mode \"semantic\", which OpenAlex does not sample — it returns the same ranked candidates under every seed. `sample_with_sort`: A search (no `id`) provided both `sample` and `sort`, which OpenAlex refuses together. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `slice_without_id`: A search passed `slice` without `id` — slice pages one array of one record. `slice_field_not_array`: The `slice` field is `*`, or is not an array on the record at `id` — absent, null, a scalar, or an object. `id_type_mismatch`: `id` is a native OpenAlex ID whose letter names another entity type than `entity_type`, or a concept ID (C…), a type this server does not serve. `id_dot_segment`: `id` holds a `.` or `..` path segment, written plainly or percent-encoded. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, a body that was empty, HTML, or unparseable JSON, or a semantic search whose query embedding failed upstream (HTTP 400 `Failed to embed query:`, or semantic search not configured). `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "semantic_per_page_cap", - "semantic_without_query", - "semantic_with_cursor", - "page_without_semantic", - "sample_with_cursor", - "sample_with_page", - "sample_with_semantic", - "sample_with_sort", - "seed_without_sample", - "slice_without_id", - "slice_field_not_array", - "id_type_mismatch", - "id_dot_segment", - "entity_not_found", - "rate_limited", - "upstream_budget_exhausted", - "upstream_plan_required", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "invalid_country_code", - "mixed_and_or_in_filter_value", - "quote_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_sort_requires_search", - "query_too_long", - "upstream_invalid_params_other", - "upstream_validation_failed" -]New value: +[ + "invalid_filter_string", + "duplicate_filter_string_key", + "unmatched_quote_in_filter_value", + "semantic_per_page_cap", + "semantic_without_query", + "semantic_with_cursor", + "page_without_semantic", + "sample_with_cursor", + "sample_with_page", + "sample_with_semantic", + "sample_with_sort", + "seed_without_sample", + "slice_without_id", + "slice_field_not_array", + "id_type_mismatch", + "id_dot_segment", + "entity_not_found", + "rate_limited", + "upstream_budget_exhausted", + "upstream_plan_required", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "invalid_country_code", + "mixed_and_or_in_filter_value", + "quote_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "query_too_long", + "upstream_invalid_params_other", + "upstream_validation_failed" +] - changed
Output schema / properties / meta / properties / per_page / descriptionPrevious value: -"Page size OpenAlex echoed for this request — the requested per_page, not the number of records returned. A short or exhausted page carries fewer records than this, as does a page the response budget cut (`omitted`)."New value: +"Page size OpenAlex echoed for this request — the applied per_page after clamping or sample override, not the number of records returned. A singleton reports 1. A short or exhausted page carries fewer records than this, as does a page the response budget cut (`omitted`)." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when a first call returns no results (echoes the criteria and suggests how to broaden), when a paginated call ran past its last page (says the traversal is finished instead of advising a broader query), when an `id` lookup was passed search criteria it does not apply (names them), on every semantic search to disclose that `meta.count` is a candidate total rather than a match total, when the response budget cut records, windowed an array, or ran over, when a list record carries exactly 100 authorships or author_list entries (possibly capped), when a `slice` offset is past the end of its array, and when `slice` was passed with `select`, which it replaces. Absent otherwise."New value: +"Guidance notice. Set when per_page was clamped (requested and applied sizes), a native filter string was converted, a first call has no matches, a continuation is exhausted, an id lookup ignores search criteria, semantic search reports a candidate total, the response budget cut records, windowed an array, or ran over, an author array is possibly capped (100 list entries or 5,000 stored singleton entries), a slice offset is past the end, or slice replaces select. Absent otherwise." - changed
Output schema / properties / windows / descriptionPrevious value: -"Arrays returned in part — windowed to fit the budget, paged by `slice`, or a possibly capped 100-entry `authorships` or `author_list` — each with its continuation. A `slice` call always carries its window, even for a whole array; otherwise absent when every array is whole."New value: +"Arrays windowed to fit the budget, paged by `slice`, or possibly capped at 100 list authors or 5,000 stored singleton authors. A `slice` call always carries its window, even for a whole array. `next` is null at the stored-array end, including a possibly capped singleton." - changed
Output schema / properties / windows / items / properties / possibly_capped / descriptionPrevious value: -"True for exactly 100 `authorships` or `author_list` entries on a list record (OpenAlex's cap): the list may be longer."New value: +"True for exactly 100 authorships or author_list entries on a list record, or 5,000 on a singleton lookup: the byline may be longer than the returned array." - changed
Output schema / properties / windows / items / properties / total / descriptionPrevious value: -"Array length as returned to this call."New value: +"Stored array length returned to this call, not a complete byline total."
5 tool updates
- Changed
openalex_analyze_trends3 fields changed- changed
Input schema / properties / filters / descriptionPrevious value: -"Filter criteria (same syntax as openalex_search_entities filters). Narrows the population before aggregation. For full-text within filters, use abstract.search, title.search, or default.search — there is no bare 'search' filter key. Example: group works by year filtered to a specific topic."New value: +"Filter criteria (same syntax as openalex_search_entities filters). Narrows the population before aggregation. Country fields take ISO 3166-1 alpha-2 codes (\"DE\") and `language` takes ISO 639-1 codes (\"en\"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so \"South Korea|Japan\" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, awards.funder_display_name, geo.city, raw_affiliation_strings) matches as one phrase (\"National Science Foundation\"; a comma, as in \"University of California, Berkeley\", is part of it, and it cannot contain a double quote of its own), \"!\" and \"|\" included, but cannot be ANDed with \"+\" in the same field. A value mixing \"|\" with an AND operator — a \"+\", or a space on a field where words mean AND — is rejected, since OpenAlex drops every \"|\" alternative that ANDs more than one value; put the AND in a second key instead. For full-text within filters, use abstract.search, title.search, or default.search — there is no bare 'search' filter key. Example: group works by year filtered to a specific topic." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid group_by or filter field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_ungroupable_group_by`: group_by targets a field OpenAlex cannot aggregate — a raw date, a decimal score, a *.search operator, a field such as display_name, doi, or referenced_works, or a concept key on authors, which OpenAlex reports as an invalid OpenAlex ID (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). `upstream_missing_group_by`: OpenAlex answered with its plain list shape, carrying no aggregation for the requested group_by. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid group_by or filter field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_ungroupable_group_by`: group_by targets a field OpenAlex cannot aggregate — a raw date, a decimal score, a *.search operator, a field such as display_name, doi, or referenced_works, or a concept key on authors, which OpenAlex reports as an invalid OpenAlex ID (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). `upstream_missing_group_by`: OpenAlex answered with its plain list shape, carrying no aggregation for the requested group_by. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "rate_limited", - "upstream_budget_exhausted", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_ungroupable_group_by", - "upstream_invalid_params_other", - "upstream_validation_failed", - "upstream_missing_group_by" -]New value: +[ + "rate_limited", + "upstream_budget_exhausted", + "upstream_plan_required", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "invalid_country_code", + "mixed_and_or_in_filter_value", + "quote_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_ungroupable_group_by", + "upstream_invalid_params_other", + "upstream_validation_failed", + "upstream_missing_group_by" +]
- Changed
openalex_describe_fields1 field changed- changed
Input schema / properties / context / descriptionPrevious value: -"Field usage context. \"filter\": fields accepted in the filter param. \"group_by\": fields accepted in group_by — a subset of the filter set that leaves out what OpenAlex refuses to aggregate (raw dates, *.search operators, decimal scores, display_name, and external-ID fields among them). \"select\": fields accepted in select."New value: +"Field usage context. \"filter\": fields accepted in the filter param; created_date, updated_date, and their from_/to_ forms, where listed, are ones OpenAlex serves only on a paid plan, and a filter on one fails without it. \"group_by\": fields accepted in group_by — a subset of the filter set that leaves out what OpenAlex refuses to aggregate (raw dates, *.search operators, decimal scores, display_name, external-ID fields, and fields OpenAlex looks up from a related entity, such as primary_location.source.country_code, among them). \"select\": fields accepted in select."
- Changed
openalex_get_citation_graph10 fields changed- changed
Input schema / properties / filters / descriptionPrevious value: -"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, nor an alias of one such as cited_works — those keys are set by the `direction` parameter."New value: +"Additional filters to narrow the graph, same syntax as openalex_search_entities. Example: publication_year=\">2020\", is_oa=\"true\". Country fields take ISO 3166-1 alpha-2 codes (\"DE\") and `language` takes ISO 639-1 codes (\"en\"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so \"South Korea|Japan\" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, awards.funder_display_name, authorships.institutions.geo.city, raw_affiliation_strings) matches as one phrase (\"National Science Foundation\"; a comma, as in \"University of California, Berkeley\", is part of it, and it cannot contain a double quote of its own), \"!\" and \"|\" included, but cannot be ANDed with \"+\" in the same field. A value mixing \"|\" with an AND operator — a \"+\", or a space on a field where words mean AND — is rejected, since OpenAlex drops every \"|\" alternative that ANDs more than one value; put the AND in a second key instead. Do not include cites/cited_by/related_to, nor an alias of one such as cited_works — those keys are set by the `direction` parameter." - changed
Input schema / properties / seed_id / descriptionPrevious value: -"Seed work identifier. Accepts OpenAlex ID (\"W2741809807\"), DOI (\"10.1038/nature12373\" or full URL), or PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"). A PMCID is recognized too, bare or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. Use openalex_resolve_name first if you only have a title."New value: +"Seed work identifier. Accepts OpenAlex work ID (\"W2741809807\", or its OpenAlex record-page or API URL such as \"https://openalex.org/works/W2741809807\"), DOI (\"10.1038/nature12373\" or full URL), or PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"). A PMCID is recognized too, bare or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. Use openalex_resolve_name first if you only have a title." - changed
Input schema / properties / select / descriptionPrevious value: -"OpenAlex work field names to return. Always returned: id, display_name. Defaults to the curated works select if omitted. Large projections may be cut to fit the response budget (`omitted`, `windows`)."New value: +"OpenAlex work field names to return. Always returned: id, display_name. Defaults to the curated works select if omitted. `author_list` returns each author in authorship order as `{id, display_name, orcid}` (`orcid` null when absent), a compact alternative to `authorships`, which also carries institutions and affiliations; neither the default nor `[\"*\"]` includes it. Large projections may be cut to fit the response budget (`omitted`, `windows`)." - changed
Output schema / properties / budget / properties / costUsd / descriptionPrevious value: -"USD this call spent, covering both upstream requests — the seed validation lookup (unbilled) and the graph page itself."New value: +"USD this call spent, covering both upstream requests — the seed validation lookup and the graph page itself. The seed lookup is unbilled unless seed_id carries characters past the identifier itself (`W2741809807#x` still resolves to W2741809807), which OpenAlex bills like one list request." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used but the citation-graph query has no active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `reserved_filter_key`: filters contains cites/cited_by/related_to, or an alias of one such as cited_works — the direction parameter reserves those keys. `entity_not_found`: OpenAlex has no work matching the seed_id. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, authorships.institutions.geo.city, authorships.institutions.geo.region, raw_affiliation_strings, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used but the citation-graph query has no active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `reserved_filter_key`: filters contains cites/cited_by/related_to, or an alias of one such as cited_works — the direction parameter reserves those keys. `id_type_mismatch`: seed_id is a native OpenAlex ID of another entity type — an author, source, institution, topic, publisher, funder, or concept ID rather than a work ID. `id_dot_segment`: seed_id holds a `.` or `..` path segment, written plainly or percent-encoded. `entity_not_found`: OpenAlex has no work matching the seed_id. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "rate_limited", - "upstream_budget_exhausted", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_sort_requires_search", - "upstream_invalid_params_other", - "reserved_filter_key", - "entity_not_found" -]New value: +[ + "rate_limited", + "upstream_budget_exhausted", + "upstream_plan_required", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "invalid_country_code", + "mixed_and_or_in_filter_value", + "quote_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "upstream_invalid_params_other", + "reserved_filter_key", + "id_type_mismatch", + "id_dot_segment", + "entity_not_found" +] - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when no edges are returned — a first call suggests verifying the seed_id, broadening filters, or trying a different direction; a `cursor` continuation says the walk is already past its last edge instead — when the response budget cut works, windowed an array, or ran over, and when a work carries exactly 100 authorships (possibly capped). Absent otherwise."New value: +"Guidance notice. Set when no edges are returned — a first call suggests verifying the seed_id, broadening filters, or trying a different direction; a `cursor` continuation says the walk is already past its last edge instead — when the response budget cut works, windowed an array, or ran over, and when a work carries exactly 100 authorships or author_list entries (possibly capped). Absent otherwise." - changed
Output schema / properties / results / descriptionPrevious value: -"Works on the citation graph in this direction. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them. Works cut by the response budget are in `omitted`; partial or possibly capped arrays are in `windows`."New value: +"Works on the citation graph in this direction. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them; an abstract arrives reconstructed as `abstract`, and a selected `author_list` as one `{id, display_name, orcid}` entry per author. Works cut by the response budget are in `omitted`; partial or possibly capped arrays are in `windows`." - changed
Output schema / properties / windows / descriptionPrevious value: -"Arrays returned in part — windowed to fit the budget, paged by `slice`, or 100 possibly capped authorships — each with its continuation. A `slice` call always carries its window, even for a whole array; otherwise absent when every array is whole."New value: +"Arrays returned in part — windowed to fit the budget, paged by `slice`, or a possibly capped 100-entry `authorships` or `author_list` — each with its continuation. A `slice` call always carries its window, even for a whole array; otherwise absent when every array is whole." - changed
Output schema / properties / windows / items / properties / possibly_capped / descriptionPrevious value: -"True for exactly 100 authorships on a list record (OpenAlex's cap): the list may be longer."New value: +"True for exactly 100 `authorships` or `author_list` entries on a list record (OpenAlex's cap): the list may be longer."
- Changed
openalex_resolve_name7 fields changed- changed
Input schema / properties / entity_type / descriptionPrevious value: -"Entity type to search. Omit for cross-entity search (useful when entity type is unknown). Not applied when `query` is an identifier — an identifier determines its own entity type."New value: +"Entity type to search. Omit for cross-entity search (useful when entity type is unknown). With an identifier `query` it narrows only an identifier that can address more than one type: a ROR to institutions, funders, or publishers (omit it to get every one of the three that exists), and a Funder Registry DOI (10.13039/…) to works instead of the funder. Every other identifier resolves as the type it belongs to, whatever this names — except under keywords, where a bare OpenAlex ID shape (\"P53\") is searched as a keyword name, since keyword IDs are slugs." - changed
Input schema / properties / filters / descriptionPrevious value: -"Narrow autocomplete results with filters. Example: restrict to a specific country or publication year range. Applies to name queries only — an identifier already addresses a single record."New value: +"Narrow autocomplete results with filters, in the openalex_search_entities filter syntax. Example: restrict to a specific country or publication year range. Country fields take ISO 3166-1 alpha-2 codes ({\"country_code\": \"DE\"} on institutions) and `language` takes ISO 639-1 codes (\"en\"); alpha-3, numeric, ISO 639-2, and English-name forms are converted — a multi-word name is one value, so \"South Korea|Japan\" ORs two countries — and a value that cannot be a country code is rejected. A multi-word value on a field matched as whole text (display_name, geo.city, geo.region, awards.funder_display_name) matches as one phrase ({\"geo.city\": \"New York\"} on institutions; a comma, as in \"University of California, Berkeley\", is part of it, and it cannot contain a double quote of its own), \"!\" and \"|\" included, but cannot be ANDed with \"+\" in the same field. A value mixing \"|\" with an AND operator — a \"+\", or a space on a field where words mean AND — is rejected, since OpenAlex drops every \"|\" alternative that ANDs more than one value; put the AND in a second key instead. Requires entity_type — filter fields belong to one entity type, so a name search across every type takes none, and a name query passing filters without entity_type is rejected. Applies to name queries only — an identifier lookup returns the records it addresses regardless." - changed
Input schema / properties / query / descriptionPrevious value: -"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\"), DOI (\"10.1038/nature12373\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\") — which resolves straight to that one record instead of running a name search. A keyword URL (\"https://openalex.org/keywords/groundwater\") resolves the same way; a bare keyword slug reads as a name and runs a name search, which finds it too. A PMCID (\"PMC1234567\" or a PubMed Central URL) is recognized but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead."New value: +"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\", or an OpenAlex record-page or API URL such as \"https://openalex.org/works/W2741809807\"), DOI (\"10.1038/nature12373\", or a funder's Funder Registry DOI such as \"10.13039/100000001\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\") — which resolves straight to the record it addresses, or for a ROR up to three (see entity_type), instead of running a name search. A bare OpenAlex ID that resolves nothing is then searched as a name — under entity_type when given, and not at all when filters come without entity_type — since short names share its shape (\"P53\" is a keyword); under entity_type keywords it is searched as a name from the start. A keyword URL (\"https://openalex.org/keywords/groundwater\") resolves the same way; a bare keyword slug reads as a name and runs a name search, which finds it too. A PMCID (\"PMC1234567\" or a PubMed Central URL) is recognized but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the autocomplete request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to autocomplete (HTTP 403). `comma_in_filter_value`: A `filters` value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter field name on the autocomplete query (HTTP 400). `upstream_invalid_id_value`: A `filters` entry expecting an entity ID received a value that is not an OpenAlex ID — usually a name (HTTP 400). `query_too_long`: OpenAlex autocomplete failed (HTTP 500) on a `query` longer than the 1,000 characters it accepts when entity_type is set. `upstream_invalid_params_other`: OpenAlex rejected the autocomplete request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the autocomplete request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `filters_without_entity_type`: A name `query` passed `filters` without `entity_type`. Filter fields belong to one entity type, and a name search across every type takes no filters. `rate_limited`: OpenAlex throttled the autocomplete request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to autocomplete (HTTP 403). `id_dot_segment`: An identifier `query` holds a `.` or `..` path segment, written plainly or percent-encoded. `comma_in_filter_value`: A `filters` value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as display_name.search) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A `filters` value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A `filters` value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter field name on the autocomplete query (HTTP 400). `upstream_invalid_id_value`: A `filters` entry expecting an entity ID received a value that is not an OpenAlex ID — usually a name (HTTP 400). `query_too_long`: OpenAlex autocomplete failed (HTTP 500) on a `query` longer than the 1,000 characters it accepts when entity_type is set. `upstream_invalid_params_other`: OpenAlex rejected the autocomplete request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the autocomplete request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "rate_limited", - "upstream_budget_exhausted", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "query_too_long", - "upstream_invalid_params_other", - "upstream_validation_failed" -]New value: +[ + "filters_without_entity_type", + "rate_limited", + "upstream_budget_exhausted", + "upstream_plan_required", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "id_dot_segment", + "comma_in_filter_value", + "invalid_country_code", + "mixed_and_or_in_filter_value", + "quote_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "query_too_long", + "upstream_invalid_params_other", + "upstream_validation_failed" +] - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when nothing matched (echoes the query and suggests corrections) or when an identifier query was passed name-search parameters that do not apply to it. Absent otherwise."New value: +"Guidance notice. Set when nothing matched (echoes the query, and the filters when a name search applied them, and suggests corrections), when a bare OpenAlex ID resolved nothing and the query was searched as a name instead (names both outcomes, or why the name search did not run or finish), when an identifier query was passed name-search parameters that do not apply to it, or when one of the lookups for a ROR failed upstream (names the entity type whose record may be missing). Absent otherwise." - changed
Output schema / properties / results / descriptionPrevious value: -"Autocomplete matches, up to 10."New value: +"Matches: up to 10 autocomplete matches for a name; for an identifier, the record it addresses — for a ROR, up to three, institution then funder then publisher — or none."
- Changed
openalex_search_entities12 fields changed- changed
Input schema / properties / filters / descriptionPrevious value: -"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. Two keys that resolve to the same upstream field (an alias and its canonical name, e.g. `year` and `publication_year`) are both applied and AND'd, so they narrow rather than override each other. 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`."New value: +"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 (\"us+gb\"); inside a `.search` value, a DOI, a date (a timestamp's \"+00:00\" offset), a URL field such as landing_page_url, an exactly matched name (display_name, awards.funder_display_name — \"C++\", \"Erasmus+\"), a biblio field (issue \"1+2\"), or awards.funder_award_id, \"+\" is a literal character. A value cannot mix \"|\" with an AND operator — a \"+\", or a space between values on an ID, code, or `language` key (a space inside a language name is part of the name, and a country field never reads a space as AND) — OpenAlex splits it on \"|\" first and drops every alternative that ANDs more than one value, so such a value is rejected; put the AND in a second key instead (\"institutions.country_code\": \"US\" beside \"authorships.institutions.country_code\": \"DE|FR\" on works). On a field matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, biblio fields), a space is part of the value: \"New York\", \"!New York\", and \"New York|Boston\" match as written, but quotes around one \"|\" alternative make that alternative match nothing. A comma is part of such a value too (\"University of California, Berkeley\" on raw_affiliation_strings): a value holding one is sent as one quoted phrase, its \"+\" a literal character. A value sent as a quoted phrase cannot contain a double quote of its own. A multi-word value there cannot be ANDed with another (\"New York+Boston\" matches nothing); to require two funders or institutions, AND their IDs (awards.funder_id, authorships.institutions.id). Country fields (keys ending in country_code, country_codes, or countries) take ISO 3166-1 alpha-2 codes (\"DE\"): an alpha-3 code (\"DEU\"), numeric code (\"276\"), or English name (\"Germany\", \"South Korea\") is converted, \"UK\" becomes \"GB\", and a value that cannot be a country code is rejected. A space there is part of a name, never a separator: \"South Korea|Japan\" ORs two countries, and \"DE US\" is rejected. `language` takes ISO 639-1 codes (\"en\"): an ISO 639-2 code (\"eng\") or English name (\"English\") is converted. Two keys that resolve to the same upstream field (an alias and its canonical name, e.g. `year` and `publication_year`) are both applied and AND'd, so they narrow rather than override each other. 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`." - changed
Input schema / properties / id / descriptionPrevious value: -"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\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\"). Keywords are identified by slug rather than a native ID — pass either the slug (\"groundwater\") or the URL a search returns (\"https://openalex.org/keywords/groundwater\"). A PMCID is recognized too, bare (\"PMC1234567\") or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). An array too long for the response budget comes back as a window (`windows`); page the rest with `slice`. To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown."New value: +"Retrieve a single entity by ID. Supports: OpenAlex ID (\"W2741809807\", or its OpenAlex record-page or API URL such as \"https://openalex.org/works/W2741809807\" or \"https://api.openalex.org/works/W2741809807\"), whose letter must name `entity_type` — W works, A authors, S sources, I institutions, T topics, P publishers, F funders; DOI (\"10.1038/nature12373\"; under entity_type \"funders\", a funder's Crossref Funder Registry DOI such as \"10.13039/100000001\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\" — one ROR can name an institution, a funder, and a publisher, and `entity_type` picks which), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\"). Keywords are identified by slug rather than a native ID — pass either the slug (\"groundwater\") or the URL a search returns (\"https://openalex.org/keywords/groundwater\"). A PMCID is recognized too, bare (\"PMC1234567\") or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). An array too long for the response budget comes back as a window (`windows`); page the rest with `slice`. To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown." - changed
Input schema / properties / select / descriptionPrevious value: -"OpenAlex top-level field names to return. Always returned: `id`, `display_name` — additional fields you list are appended. A curated default per entity type applies to both searches and single-entity (`id`) lookups; pass field names to override it, or `[\"*\"]` to retrieve the complete record (every field). Only top-level fields project, so a nested value is requested by its parent object: bibliometrics (`h_index`, `i10_index`, `2yr_mean_citedness`) live under `summary_stats` on authors, sources, institutions, publishers, and funders, and naming a leaf returns that object. Invalid field names produce an error identifying the rejected field. Large projections may be cut to fit the response budget (`omitted`, `windows`). Not applied with `slice`. Example: [\"doi\", \"authorships\", \"primary_topic\"]."New value: +"OpenAlex top-level field names to return. Always returned: `id`, `display_name` — additional fields you list are appended. A curated default per entity type applies to both searches and single-entity (`id`) lookups; pass field names to override it, or `[\"*\"]` to retrieve the complete record (every field). Only top-level fields project, so a nested value is requested by its parent object: bibliometrics (`h_index`, `i10_index`, `2yr_mean_citedness`) live under `summary_stats` on authors, sources, institutions, publishers, and funders, and naming a leaf returns that object. On sources, `publisher` returns `host_organization_name`: the publisher of a journal, the hosting institution of a repository, and null on most sources. On works, `author_list` returns each author in authorship order as `{id, display_name, orcid}` (`orcid` null when absent), a compact alternative to `authorships`, which also carries institutions and affiliations; neither the default nor `[\"*\"]` includes it. Invalid field names produce an error identifying the rejected field. Large projections may be cut to fit the response budget (`omitted`, `windows`). Not applied with `slice`. Example: [\"doi\", \"author_list\", \"primary_topic\"]." - changed
Input schema / properties / slice / descriptionPrevious value: -"Page one array of the record at `id`: returns `id`, `display_name`, and `field` from `offset` onward, as many elements as fit the response budget (at least one), with the window and its `next` call in `windows`. Requires `id`; replaces `select`. An offset at or past the end returns an empty window. Walks any partial array, including a possibly capped 100-authorship list."New value: +"Page one array of the record at `id`: returns `id`, `display_name`, and `field` from `offset` onward, as many elements as fit the response budget (at least one), with the window and its `next` call in `windows`. Requires `id`; replaces `select`. An offset at or past the end returns an empty window. Walks any partial array, including a possibly capped 100-entry `authorships` or `author_list`." - changed
Input schema / properties / slice / properties / field / descriptionPrevious value: -"Top-level array field to page, such as \"authorships\" or \"referenced_works\". Leave it empty to skip slicing."New value: +"Top-level array field to page, such as \"authorships\", \"author_list\", or \"referenced_works\". Leave it empty to skip slicing." - changed
Output schema / properties / budget / properties / costUsd / descriptionPrevious value: -"USD this call spent. 0 for an `id` lookup — OpenAlex does not bill single-entity fetches, so batching known IDs beats paging a filtered list."New value: +"USD this call spent. 0 for an `id` lookup by an OpenAlex ID, DOI, ORCID, ROR, PMID, or ISSN — OpenAlex does not bill those single-entity fetches, so batching known IDs beats paging a filtered list. OpenAlex bills like one list request a keyword looked up by its slug, an `id` carrying characters past the identifier itself (`W2741809807#x` still returns W2741809807), and a funder looked up by its Funder Registry DOI." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` under a search_mode other than \"semantic\". `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_with_page`: A search (no `id`) provided both `sample` and `page`. `sample_with_semantic`: A search (no `id`) provided `sample` with search_mode \"semantic\", which OpenAlex does not sample — it returns the same ranked candidates under every seed. `sample_with_sort`: A search (no `id`) provided both `sample` and `sort`, which OpenAlex refuses together. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `slice_without_id`: A search passed `slice` without `id` — slice pages one array of one record. `slice_field_not_array`: The `slice` field is `*`, or is not an array on the record at `id` — absent, null, a scalar, or an object. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` under a search_mode other than \"semantic\". `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_with_page`: A search (no `id`) provided both `sample` and `page`. `sample_with_semantic`: A search (no `id`) provided `sample` with search_mode \"semantic\", which OpenAlex does not sample — it returns the same ranked candidates under every seed. `sample_with_sort`: A search (no `id`) provided both `sample` and `sort`, which OpenAlex refuses together. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `slice_without_id`: A search passed `slice` without `id` — slice pages one array of one record. `slice_field_not_array`: The `slice` field is `*`, or is not an array on the record at `id` — absent, null, a scalar, or an object. `id_type_mismatch`: `id` is a native OpenAlex ID whose letter names another entity type than `entity_type`, or a concept ID (C…), a type this server does not serve. `id_dot_segment`: `id` holds a `.` or `..` path segment, written plainly or percent-encoded. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_plan_required`: A filter is one OpenAlex serves only on a paid plan — created_date, updated_date, or a from_/to_ form of either (HTTP 429 \"Plan upgrade required\"). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, a body that was empty, HTML, or unparseable JSON, or a semantic search whose query embedding failed upstream (HTTP 400 `Failed to embed query:`, or semantic search not configured). `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator, on a field that takes no phrase. Free-text search filters (any `.search` key, such as title.search or abstract.search.exact) and fields matched as whole text (display_name, awards.funder_display_name, awards.funder_award_id, geo.city, geo.region, raw_affiliation_strings, block_key, parsed_longest_name, biblio fields) are exempt: a comma there is sent quoted, as part of the phrase. `invalid_country_code`: A country filter (a key ending in country_code, country_codes, or countries) holds a segment that cannot be a country code, such as a misspelled name, an unassigned number, \"unknown\", or two codes joined by a space (\"DE US\"). `mixed_and_or_in_filter_value`: A filter value puts \"|\" (OR) beside an AND operator — a \"+\", or a space on a field where words mean AND (on a country field a space is always part of a country name, and inside a language name it is part of the name). OpenAlex splits the value on \"|\" first and drops every alternative that ANDs more than one value, so no single value can carry both. `quote_in_filter_value`: A filter value sent to OpenAlex double-quoted holds a double quote inside its outer pair — a value the server quotes (a multi-word value on a field matched as whole text, or a value holding a comma on such a field or on a free-text search filter), or one the caller wrapped in double quotes on any filter but a free-text search. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "semantic_per_page_cap", - "semantic_without_query", - "semantic_with_cursor", - "page_without_semantic", - "sample_with_cursor", - "sample_with_page", - "sample_with_semantic", - "sample_with_sort", - "seed_without_sample", - "slice_without_id", - "slice_field_not_array", - "entity_not_found", - "rate_limited", - "upstream_budget_exhausted", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_sort_requires_search", - "query_too_long", - "upstream_invalid_params_other", - "upstream_validation_failed" -]New value: +[ + "semantic_per_page_cap", + "semantic_without_query", + "semantic_with_cursor", + "page_without_semantic", + "sample_with_cursor", + "sample_with_page", + "sample_with_semantic", + "sample_with_sort", + "seed_without_sample", + "slice_without_id", + "slice_field_not_array", + "id_type_mismatch", + "id_dot_segment", + "entity_not_found", + "rate_limited", + "upstream_budget_exhausted", + "upstream_plan_required", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "invalid_country_code", + "mixed_and_or_in_filter_value", + "quote_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "query_too_long", + "upstream_invalid_params_other", + "upstream_validation_failed" +] - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when a first call returns no results (echoes the criteria and suggests how to broaden), when a paginated call ran past its last page (says the traversal is finished instead of advising a broader query), when an `id` lookup was passed search criteria it does not apply (names them), on every semantic search to disclose that `meta.count` is a candidate total rather than a match total, when the response budget cut records, windowed an array, or ran over, when a list record carries exactly 100 authorships (possibly capped), when a `slice` offset is past the end of its array, and when `slice` was passed with `select`, which it replaces. Absent otherwise."New value: +"Guidance notice. Set when a first call returns no results (echoes the criteria and suggests how to broaden), when a paginated call ran past its last page (says the traversal is finished instead of advising a broader query), when an `id` lookup was passed search criteria it does not apply (names them), on every semantic search to disclose that `meta.count` is a candidate total rather than a match total, when the response budget cut records, windowed an array, or ran over, when a list record carries exactly 100 authorships or author_list entries (possibly capped), when a `slice` offset is past the end of its array, and when `slice` was passed with `select`, which it replaces. Absent otherwise." - changed
Output schema / properties / results / descriptionPrevious value: -"OpenAlex entity objects. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them; an abstract arrives reconstructed as `abstract`. Additional fields depend on entity_type and select. Records cut by the response budget are in `omitted`; partial or possibly capped arrays are in `windows`."New value: +"OpenAlex entity objects. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them; an abstract arrives reconstructed as `abstract`, and a selected `author_list` as one `{id, display_name, orcid}` entry per author. Additional fields depend on entity_type and select. Records cut by the response budget are in `omitted`; partial or possibly capped arrays are in `windows`." - changed
Output schema / properties / windows / descriptionPrevious value: -"Arrays returned in part — windowed to fit the budget, paged by `slice`, or 100 possibly capped authorships — each with its continuation. A `slice` call always carries its window, even for a whole array; otherwise absent when every array is whole."New value: +"Arrays returned in part — windowed to fit the budget, paged by `slice`, or a possibly capped 100-entry `authorships` or `author_list` — each with its continuation. A `slice` call always carries its window, even for a whole array; otherwise absent when every array is whole." - changed
Output schema / properties / windows / items / properties / possibly_capped / descriptionPrevious value: -"True for exactly 100 authorships on a list record (OpenAlex's cap): the list may be longer."New value: +"True for exactly 100 `authorships` or `author_list` entries on a list record (OpenAlex's cap): the list may be longer."
3 tool updates
- Changed
openalex_analyze_trends2 fields changed- changed
Input schema / properties / group_by / descriptionPrevious value: -"Field to group by. Works examples: \"publication_year\", \"type\", \"oa_status\", \"primary_topic.field.id\", \"authorships.institutions.country_code\", \"is_retracted\". Authors: \"last_known_institutions.country_code\", \"has_orcid\". Sources: \"type\", \"is_oa\", \"country_code\". Not all fields support group_by — call openalex_describe_fields(entity_type, \"group_by\") for the groupable set."New value: +"Field to group by. Works examples: \"publication_year\", \"type\", \"oa_status\", \"primary_topic.field.id\", \"authorships.institutions.country_code\", \"is_retracted\". OpenAlex builds authorships.countries groups from only the first 100 authorships of each work; authorships.institutions.country_code counts every authorship. Authors: \"last_known_institutions.country_code\", \"has_orcid\". Sources: \"type\", \"is_oa\", \"country_code\". Not all fields support group_by — call openalex_describe_fields(entity_type, \"group_by\") for the groupable set." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when a first call returns no groups (recovery suggestions), when a `cursor` continuation returns none because the traversal is already finished, or when the page is full and more groups likely exist (truncation signal with narrowing advice). Absent otherwise."New value: +"Guidance notice. Set when a first call returns no groups (recovery suggestions), when a `cursor` continuation returns none because the traversal is already finished, when the page is full and more groups likely exist (truncation signal with narrowing advice), or when works are grouped by authorships.countries, which OpenAlex counts from only the first 100 authorships of each work. Absent otherwise."
- Changed
openalex_get_citation_graph9 fields changed- changed
Input schema / properties / per_page / descriptionPrevious value: -"Results per page (1-100). Default 25."New value: +"Results per page (1-100). Default 25. A budget-cut page returns fewer (`omitted`)." - changed
Input schema / properties / select / descriptionPrevious value: -"OpenAlex work field names to return. Always returned: id, display_name. Defaults to the curated works select if omitted."New value: +"OpenAlex work field names to return. Always returned: id, display_name. Defaults to the curated works select if omitted. Large projections may be cut to fit the response budget (`omitted`, `windows`)." - changed
Output schema / properties / meta / properties / next_cursor / descriptionPrevious value: -"Cursor for next page. null if no more results."New value: +"Cursor for next page. null if no more results. Continues after the full upstream page, `omitted` works included." - changed
Output schema / properties / meta / properties / per_page / descriptionPrevious value: -"Page size OpenAlex echoed for this request — the requested per_page, not the number of records returned. A short or exhausted page carries fewer records than this."New value: +"Page size OpenAlex echoed for this request — the requested per_page, not the number of records returned. A short or exhausted page carries fewer records than this, as does a page the response budget cut (`omitted`)." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance when no edges are returned. A first call suggests verifying the seed_id, broadening filters, or trying a different direction; a `cursor` continuation says the walk is already past its last edge instead. Absent when results are present."New value: +"Guidance notice. Set when no edges are returned — a first call suggests verifying the seed_id, broadening filters, or trying a different direction; a `cursor` continuation says the walk is already past its last edge instead — when the response budget cut works, windowed an array, or ran over, and when a work carries exactly 100 authorships (possibly capped). Absent otherwise." - added
Output schema / properties / omittedAdded value: +{ + "additionalProperties": false, + "description": "Present when the response budget cut whole records from the page end; pagination continues after the full upstream page.", + "properties": { + "ids": { + "description": "Bare IDs of the records left out, in page order (a keyword keeps its URL).", + "items": { + "type": "string" + }, + "type": "array" + }, + "next": { + "additionalProperties": false, + "description": "One call returning those records as a set, in OpenAlex's order, not page order. Budgeted too, so it may carry its own `omitted`.", + "properties": { + "arguments": { + "additionalProperties": {}, + "description": "Arguments to pass as-is.", + "properties": {}, + "type": "object" + }, + "tool": { + "const": "openalex_search_entities", + "description": "Tool to call.", + "type": "string" + } + }, + "required": [ + "tool", + "arguments" + ], + "type": "object" + } + }, + "required": [ + "ids", + "next" + ], + "type": "object" +} - added
Output schema / properties / over_budgetAdded value: +{ + "description": "True when even the least this call can return — the first record's non-array fields (its arrays windowed to empty), or one `slice` element — exceeds the budget.", + "type": "boolean" +} - changed
Output schema / properties / results / descriptionPrevious value: -"Works on the citation graph in this direction. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed."New value: +"Works on the citation graph in this direction. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them. Works cut by the response budget are in `omitted`; partial or possibly capped arrays are in `windows`." - added
Output schema / properties / windowsAdded value: +{ + "description": "Arrays returned in part — windowed to fit the budget, paged by `slice`, or 100 possibly capped authorships — each with its continuation. A `slice` call always carries its window, even for a whole array; otherwise absent when every array is whole.", + "items": { + "additionalProperties": false, + "description": "An array returned in part.", + "properties": { + "field": { + "description": "Array field.", + "type": "string" + }, + "id": { + "description": "Bare ID of the record.", + "type": "string" + }, + "next": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "arguments": { + "additionalProperties": {}, + "description": "Arguments to pass as-is.", + "properties": {}, + "type": "object" + }, + "tool": { + "const": "openalex_search_entities", + "description": "Tool to call.", + "type": "string" + } + }, + "required": [ + "tool", + "arguments" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "`id` + `slice` call for the next elements; null at the array end." + }, + "offset": { + "description": "Index of the first element shown.", + "type": "number" + }, + "possibly_capped": { + "description": "True for exactly 100 authorships on a list record (OpenAlex's cap): the list may be longer.", + "type": "boolean" + }, + "shown": { + "description": "Elements shown.", + "type": "number" + }, + "total": { + "description": "Array length as returned to this call.", + "type": "number" + } + }, + "required": [ + "id", + "field", + "offset", + "shown", + "total", + "possibly_capped", + "next" + ], + "type": "object" + }, + "type": "array" +}
- Changed
openalex_search_entities14 fields changed- changed
Input schema / properties / id / descriptionPrevious value: -"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\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\"). Keywords are identified by slug rather than a native ID — pass either the slug (\"groundwater\") or the URL a search returns (\"https://openalex.org/keywords/groundwater\"). A PMCID is recognized too, bare (\"PMC1234567\") or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown."New value: +"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\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\"). Keywords are identified by slug rather than a native ID — pass either the slug (\"groundwater\") or the URL a search returns (\"https://openalex.org/keywords/groundwater\"). A PMCID is recognized too, bare (\"PMC1234567\") or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). An array too long for the response budget comes back as a window (`windows`); page the rest with `slice`. To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown." - changed
Input schema / properties / per_page / descriptionPrevious value: -"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). The cap applies to searches only; an `id` lookup returns its one record regardless of both."New value: +"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). The cap applies to searches only; an `id` lookup returns its one record regardless of both. A budget-cut page returns fewer (`omitted`)." - changed
Input schema / properties / select / descriptionPrevious value: -"OpenAlex top-level field names to return. Always returned: `id`, `display_name` — additional fields you list are appended. A curated default per entity type applies to both searches and single-entity (`id`) lookups; pass field names to override it, or `[\"*\"]` to retrieve the complete record (every field). Only top-level fields project, so a nested value is requested by its parent object: bibliometrics (`h_index`, `i10_index`, `2yr_mean_citedness`) live under `summary_stats` on authors, sources, institutions, publishers, and funders, and naming a leaf returns that object. Invalid field names produce an error identifying the rejected field. Example: [\"doi\", \"authorships\", \"primary_topic\"]."New value: +"OpenAlex top-level field names to return. Always returned: `id`, `display_name` — additional fields you list are appended. A curated default per entity type applies to both searches and single-entity (`id`) lookups; pass field names to override it, or `[\"*\"]` to retrieve the complete record (every field). Only top-level fields project, so a nested value is requested by its parent object: bibliometrics (`h_index`, `i10_index`, `2yr_mean_citedness`) live under `summary_stats` on authors, sources, institutions, publishers, and funders, and naming a leaf returns that object. Invalid field names produce an error identifying the rejected field. Large projections may be cut to fit the response budget (`omitted`, `windows`). Not applied with `slice`. Example: [\"doi\", \"authorships\", \"primary_topic\"]." - added
Input schema / properties / sliceAdded value: +{ + "description": "Page one array of the record at `id`: returns `id`, `display_name`, and `field` from `offset` onward, as many elements as fit the response budget (at least one), with the window and its `next` call in `windows`. Requires `id`; replaces `select`. An offset at or past the end returns an empty window. Walks any partial array, including a possibly capped 100-authorship list.", + "properties": { + "field": { + "description": "Top-level array field to page, such as \"authorships\" or \"referenced_works\". Leave it empty to skip slicing.", + "type": "string" + }, + "offset": { + "default": 0, + "description": "0-based index of the first element to return.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "field" + ], + "type": "object" +} - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` under a search_mode other than \"semantic\". `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_with_page`: A search (no `id`) provided both `sample` and `page`. `sample_with_semantic`: A search (no `id`) provided `sample` with search_mode \"semantic\", which OpenAlex does not sample — it returns the same ranked candidates under every seed. `sample_with_sort`: A search (no `id`) provided both `sample` and `sort`, which OpenAlex refuses together. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` under a search_mode other than \"semantic\". `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_with_page`: A search (no `id`) provided both `sample` and `page`. `sample_with_semantic`: A search (no `id`) provided `sample` with search_mode \"semantic\", which OpenAlex does not sample — it returns the same ranked candidates under every seed. `sample_with_sort`: A search (no `id`) provided both `sample` and `sort`, which OpenAlex refuses together. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `slice_without_id`: A search passed `slice` without `id` — slice pages one array of one record. `slice_field_not_array`: The `slice` field is `*`, or is not an array on the record at `id` — absent, null, a scalar, or an object. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "semantic_per_page_cap", - "semantic_without_query", - "semantic_with_cursor", - "page_without_semantic", - "sample_with_cursor", - "sample_with_page", - "sample_with_semantic", - "sample_with_sort", - "seed_without_sample", - "entity_not_found", - "rate_limited", - "upstream_budget_exhausted", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_sort_requires_search", - "query_too_long", - "upstream_invalid_params_other", - "upstream_validation_failed" -]New value: +[ + "semantic_per_page_cap", + "semantic_without_query", + "semantic_with_cursor", + "page_without_semantic", + "sample_with_cursor", + "sample_with_page", + "sample_with_semantic", + "sample_with_sort", + "seed_without_sample", + "slice_without_id", + "slice_field_not_array", + "entity_not_found", + "rate_limited", + "upstream_budget_exhausted", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "query_too_long", + "upstream_invalid_params_other", + "upstream_validation_failed" +] - changed
Output schema / properties / meta / properties / next_cursor / descriptionPrevious value: -"Cursor for next page. null if no more results."New value: +"Cursor for next page. null if no more results. Continues after the full upstream page, `omitted` records included." - changed
Output schema / properties / meta / properties / per_page / descriptionPrevious value: -"Page size OpenAlex echoed for this request — the requested per_page, not the number of records returned. A short or exhausted page carries fewer records than this."New value: +"Page size OpenAlex echoed for this request — the requested per_page, not the number of records returned. A short or exhausted page carries fewer records than this, as does a page the response budget cut (`omitted`)." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when a first call returns no results (echoes the criteria and suggests how to broaden), when a paginated call ran past its last page (says the traversal is finished instead of advising a broader query), when an `id` lookup was passed search criteria it does not apply (names them), and on every semantic search to disclose that `meta.count` is a candidate total rather than a match total. Absent otherwise."New value: +"Guidance notice. Set when a first call returns no results (echoes the criteria and suggests how to broaden), when a paginated call ran past its last page (says the traversal is finished instead of advising a broader query), when an `id` lookup was passed search criteria it does not apply (names them), on every semantic search to disclose that `meta.count` is a candidate total rather than a match total, when the response budget cut records, windowed an array, or ran over, when a list record carries exactly 100 authorships (possibly capped), when a `slice` offset is past the end of its array, and when `slice` was passed with `select`, which it replaces. Absent otherwise." - added
Output schema / properties / omittedAdded value: +{ + "additionalProperties": false, + "description": "Present when the response budget cut whole records from the page end; pagination continues after the full upstream page.", + "properties": { + "ids": { + "description": "Bare IDs of the records left out, in page order (a keyword keeps its URL).", + "items": { + "type": "string" + }, + "type": "array" + }, + "next": { + "additionalProperties": false, + "description": "One call returning those records as a set, in OpenAlex's order, not page order. Budgeted too, so it may carry its own `omitted`.", + "properties": { + "arguments": { + "additionalProperties": {}, + "description": "Arguments to pass as-is.", + "properties": {}, + "type": "object" + }, + "tool": { + "const": "openalex_search_entities", + "description": "Tool to call.", + "type": "string" + } + }, + "required": [ + "tool", + "arguments" + ], + "type": "object" + } + }, + "required": [ + "ids", + "next" + ], + "type": "object" +} - added
Output schema / properties / over_budgetAdded value: +{ + "description": "True when even the least this call can return — the first record's non-array fields (its arrays windowed to empty), or one `slice` element — exceeds the budget.", + "type": "boolean" +} - changed
Output schema / properties / results / descriptionPrevious value: -"OpenAlex entity objects. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — and an abstract arrives reconstructed as `abstract`. Additional fields depend on entity_type and select."New value: +"OpenAlex entity objects. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — except identifier and URL fields such as `id`, `doi`, `ids`, and `*_url`, returned exactly as OpenAlex stores them; an abstract arrives reconstructed as `abstract`. Additional fields depend on entity_type and select. Records cut by the response budget are in `omitted`; partial or possibly capped arrays are in `windows`." - changed
Output schema / properties / results / items / properties / id / descriptionPrevious value: -"OpenAlex ID (e.g., \"W2741809807\", \"A1234567890\")."New value: +"OpenAlex ID URL (e.g., \"https://openalex.org/W2741809807\"). `windows` and `omitted` name records by the bare ID (\"W2741809807\"); a keyword keeps its URL." - added
Output schema / properties / windowsAdded value: +{ + "description": "Arrays returned in part — windowed to fit the budget, paged by `slice`, or 100 possibly capped authorships — each with its continuation. A `slice` call always carries its window, even for a whole array; otherwise absent when every array is whole.", + "items": { + "additionalProperties": false, + "description": "An array returned in part.", + "properties": { + "field": { + "description": "Array field.", + "type": "string" + }, + "id": { + "description": "Bare ID of the record.", + "type": "string" + }, + "next": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "arguments": { + "additionalProperties": {}, + "description": "Arguments to pass as-is.", + "properties": {}, + "type": "object" + }, + "tool": { + "const": "openalex_search_entities", + "description": "Tool to call.", + "type": "string" + } + }, + "required": [ + "tool", + "arguments" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "description": "`id` + `slice` call for the next elements; null at the array end." + }, + "offset": { + "description": "Index of the first element shown.", + "type": "number" + }, + "possibly_capped": { + "description": "True for exactly 100 authorships on a list record (OpenAlex's cap): the list may be longer.", + "type": "boolean" + }, + "shown": { + "description": "Elements shown.", + "type": "number" + }, + "total": { + "description": "Array length as returned to this call.", + "type": "number" + } + }, + "required": [ + "id", + "field", + "offset", + "shown", + "total", + "possibly_capped", + "next" + ], + "type": "object" + }, + "type": "array" +}
5 tool updates
- Changed
openalex_analyze_trends6 fields changed- changed
Input schema / properties / group_by / descriptionPrevious value: -"Field to group by. Works examples: \"publication_year\", \"type\", \"oa_status\", \"primary_topic.field.id\", \"authorships.institutions.country_code\", \"is_retracted\". Authors: \"last_known_institutions.country_code\", \"has_orcid\". Sources: \"type\", \"is_oa\", \"country_code\". Not all fields support group_by — check entity docs if unsure."New value: +"Field to group by. Works examples: \"publication_year\", \"type\", \"oa_status\", \"primary_topic.field.id\", \"authorships.institutions.country_code\", \"is_retracted\". Authors: \"last_known_institutions.country_code\", \"has_orcid\". Sources: \"type\", \"is_oa\", \"country_code\". Not all fields support group_by — call openalex_describe_fields(entity_type, \"group_by\") for the groupable set." - changed
Input schema / properties / include_unknown / descriptionPrevious value: -"Include a group for entities with no value for the grouped field. Hidden by default."New value: +"Add a group for entities with no value for the grouped field. Hidden by default. That group carries `is_unknown: true`; OpenAlex keys it -111 or -111.0 on numeric fields, \"unknown\" on text fields and under order \"key\", and an ID ending in /unknown on ID fields — a sentinel, not a measured value. The key is not a filter value: passing -111 as a filter matches a numeric range, not the entities with no value. Boolean fields have no separate group — a missing value counts as false." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid group_by or filter field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_ungroupable_group_by`: group_by targets a raw date, float, or *.search field OpenAlex cannot aggregate (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). `upstream_missing_group_by`: OpenAlex answered with its plain list shape, carrying no aggregation for the requested group_by. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid group_by or filter field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_ungroupable_group_by`: group_by targets a field OpenAlex cannot aggregate — a raw date, a decimal score, a *.search operator, a field such as display_name, doi, or referenced_works, or a concept key on authors, which OpenAlex reports as an invalid OpenAlex ID (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). `upstream_missing_group_by`: OpenAlex answered with its plain list shape, carrying no aggregation for the requested group_by. Other values are possible when a failure originates below the handler." - added
Output schema / properties / groups / items / properties / is_unknownAdded value: +{ + "const": true, + "description": "Present only on the group include_unknown adds for entities with no value; its key is an OpenAlex sentinel (-111, -111.0, unknown, or an ID ending in /unknown), not a measured value.", + "type": "boolean" +} - changed
Output schema / properties / groups / items / properties / key / descriptionPrevious value: -"Group key (OpenAlex ID or raw value)."New value: +"Group key (OpenAlex ID or raw value), exactly as OpenAlex returns it." - changed
Output schema / properties / groups / items / properties / key_display_name / descriptionPrevious value: -"Human-readable group label."New value: +"Human-readable group label as plain text, with HTML entities decoded and markup removed."
- Changed
openalex_describe_fields1 field changed- changed
Input schema / properties / context / descriptionPrevious value: -"Field usage context. \"filter\": fields accepted in the filter param. \"group_by\": fields accepted in group_by — a subset of the filter set (raw date and *.search fields are excluded; they cannot be grouped). \"select\": fields accepted in select."New value: +"Field usage context. \"filter\": fields accepted in the filter param. \"group_by\": fields accepted in group_by — a subset of the filter set that leaves out what OpenAlex refuses to aggregate (raw dates, *.search operators, decimal scores, display_name, and external-ID fields among them). \"select\": fields accepted in select."
- Changed
openalex_get_citation_graph1 field changed- changed
Output schema / properties / results / descriptionPrevious value: -"Works on the citation graph in this direction."New value: +"Works on the citation graph in this direction. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed."
- Changed
openalex_resolve_name4 fields changed- changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the autocomplete request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to autocomplete (HTTP 403). `comma_in_filter_value`: A `filters` value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter field name on the autocomplete query (HTTP 400). `upstream_invalid_id_value`: A `filters` entry expecting an entity ID received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the autocomplete request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the autocomplete request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the autocomplete request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to autocomplete (HTTP 403). `comma_in_filter_value`: A `filters` value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter field name on the autocomplete query (HTTP 400). `upstream_invalid_id_value`: A `filters` entry expecting an entity ID received a value that is not an OpenAlex ID — usually a name (HTTP 400). `query_too_long`: OpenAlex autocomplete failed (HTTP 500) on a `query` longer than the 1,000 characters it accepts when entity_type is set. `upstream_invalid_params_other`: OpenAlex rejected the autocomplete request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the autocomplete request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "rate_limited", - "upstream_budget_exhausted", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_invalid_params_other", - "upstream_validation_failed" -]New value: +[ + "rate_limited", + "upstream_budget_exhausted", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "query_too_long", + "upstream_invalid_params_other", + "upstream_validation_failed" +] - changed
Output schema / properties / results / items / properties / display_name / descriptionPrevious value: -"Human-readable name. null only for an identifier lookup that landed on a record OpenAlex holds no title for (paratext works and other untitled entries) — use `id` to identify it."New value: +"Human-readable name as plain text, with HTML entities decoded and markup removed. null only for an identifier lookup that landed on a record OpenAlex holds no title for (paratext works and other untitled entries) — use `id` to identify it." - changed
Output schema / properties / results / items / properties / hint / descriptionPrevious value: -"Disambiguation context — last institution (authors), host organization (sources), place or country (institutions); author names (works) from a name search, publication year from an identifier lookup. null when the record carries none."New value: +"Disambiguation context as plain text — last institution (authors), host organization (sources), place or country (institutions); author names (works) from a name search, publication year from an identifier lookup. null when the record carries none."
- Changed
openalex_search_entities9 fields changed- changed
Input schema / properties / page / descriptionPrevious value: -"Page number (1-based) for semantic search, the one mode that paginates with `page` instead of `cursor`. Semantic search ranks at most 50 candidates, so the last reachable page is ceil(50 / per_page) — e.g. page 17 with per_page=3. Passing it under any other search_mode is rejected."New value: +"Page number (1-based) for semantic search, the one mode that paginates with `page` instead of `cursor`. Semantic search ranks a query-dependent candidate set whose size `meta.count` reports, so the last reachable page is ceil(meta.count / per_page) — e.g. page 14 for a count of 70 with per_page=5. Passing it under any other search_mode is rejected." - changed
Input schema / properties / sample / descriptionPrevious value: -"Return a random sample of this many entities matching the filters (1-100). Single page only — neither `cursor` nor `page` pagination applies to sampling, and a search that passes either alongside it is rejected. Overrides `per_page`. Useful for unbiased exploration: spot-checking filter correctness, stratified review prompts, or generating exploration sets without bias toward most-cited."New value: +"Return a random sample of this many entities matching the filters (1-100). Single page only — neither `cursor` nor `page` pagination applies to sampling, and a search that passes either alongside it is rejected. Keyword and exact modes only: OpenAlex does not sample a semantic search, so `sample` with search_mode \"semantic\" is rejected. Cannot be combined with `sort` — a sample has no order, and a search passing both is rejected. Overrides `per_page`. Useful for unbiased exploration: spot-checking filter correctness, stratified review prompts, or generating exploration sets without bias toward most-cited." - changed
Input schema / properties / search_mode / descriptionPrevious value: -"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, ranking at most 50 candidates at ~1 req/sec and paginated with `page` rather than `cursor`."New value: +"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 over a query-dependent candidate set whose size `meta.count` reports, at ~1 req/sec, up to 50 per page, and paginated with `page` rather than `cursor`." - changed
Input schema / properties / sort / descriptionPrevious value: -"Sort field. Prefix with \"-\" for descending. Comma-separate for a multi-key sort, applied left to right, with the \"-\" prefix set per key (\"-publication_year,cited_by_count\" sorts by year descending, then citations ascending). 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."New value: +"Sort field. Prefix with \"-\" for descending. Comma-separate for a multi-key sort, applied left to right, with the \"-\" prefix set per key (\"-publication_year,cited_by_count\" sorts by year descending, then citations ascending). 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. Not combinable with `sample` — a search passing both is rejected." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` under a search_mode other than \"semantic\". `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_with_page`: A search (no `id`) provided both `sample` and `page`. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` under a search_mode other than \"semantic\". `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_with_page`: A search (no `id`) provided both `sample` and `page`. `sample_with_semantic`: A search (no `id`) provided `sample` with search_mode \"semantic\", which OpenAlex does not sample — it returns the same ranked candidates under every seed. `sample_with_sort`: A search (no `id`) provided both `sample` and `sort`, which OpenAlex refuses together. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "semantic_per_page_cap", - "semantic_without_query", - "semantic_with_cursor", - "page_without_semantic", - "sample_with_cursor", - "sample_with_page", - "seed_without_sample", - "entity_not_found", - "rate_limited", - "upstream_budget_exhausted", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_sort_requires_search", - "query_too_long", - "upstream_invalid_params_other", - "upstream_validation_failed" -]New value: +[ + "semantic_per_page_cap", + "semantic_without_query", + "semantic_with_cursor", + "page_without_semantic", + "sample_with_cursor", + "sample_with_page", + "sample_with_semantic", + "sample_with_sort", + "seed_without_sample", + "entity_not_found", + "rate_limited", + "upstream_budget_exhausted", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "query_too_long", + "upstream_invalid_params_other", + "upstream_validation_failed" +] - changed
Output schema / properties / meta / properties / count / descriptionPrevious value: -"Total results matching the query/filters. Under search_mode \"semantic\" it is instead the capped candidate count — at most 50 — not an exhaustive match total."New value: +"Total results matching the query/filters. Under search_mode \"semantic\" it is instead the size of the ranked candidate set — the most results `page` can reach — not an exhaustive match total." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when a first call returns no results (echoes the criteria and suggests how to broaden), when a paginated call ran past its last page (says the traversal is finished instead of advising a broader query), when an `id` lookup was passed search criteria it does not apply (names them), and on every semantic search to disclose that `meta.count` is a capped candidate total. Absent otherwise."New value: +"Guidance notice. Set when a first call returns no results (echoes the criteria and suggests how to broaden), when a paginated call ran past its last page (says the traversal is finished instead of advising a broader query), when an `id` lookup was passed search criteria it does not apply (names them), and on every semantic search to disclose that `meta.count` is a candidate total rather than a match total. Absent otherwise." - changed
Output schema / properties / results / descriptionPrevious value: -"OpenAlex entity objects passed through unchanged. Additional fields depend on entity_type and select."New value: +"OpenAlex entity objects. Text values are plain text — HTML entities decoded, HTML/JATS/MathML markup removed — and an abstract arrives reconstructed as `abstract`. Additional fields depend on entity_type and select."
4 tool updates
- Changed
openalex_analyze_trends6 fields changed- changed
Input schema / properties / cursor / descriptionPrevious value: -"Pagination cursor from a previous response. Only relevant when order is \"key\" — count-descending results have no next page. Pass the next_cursor from the previous response to advance."New value: +"Pagination cursor from a previous response. Only relevant when order is \"key\" — count-descending results have no next page. Pass the next_cursor from the previous response to advance. Omit it on the first call — an empty string is rejected, since a supplied-but-blank cursor is a caller mistake rather than a request for the first page." - added
Input schema / properties / cursor / minLengthAdded value: +1 - added
Input schema / properties / group_by / minLengthAdded value: +1 - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid group_by or filter field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_ungroupable_group_by`: group_by targets a raw date, float, or *.search field OpenAlex cannot aggregate (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid group_by or filter field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_ungroupable_group_by`: group_by targets a raw date, float, or *.search field OpenAlex cannot aggregate (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). `upstream_missing_group_by`: OpenAlex answered with its plain list shape, carrying no aggregation for the requested group_by. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "rate_limited", - "upstream_budget_exhausted", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_ungroupable_group_by", - "upstream_invalid_params_other", - "upstream_validation_failed" -]New value: +[ + "rate_limited", + "upstream_budget_exhausted", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_ungroupable_group_by", + "upstream_invalid_params_other", + "upstream_validation_failed", + "upstream_missing_group_by" +] - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when no groups are returned (recovery suggestions) or when the page is full and more groups likely exist (truncation signal with narrowing advice). Absent otherwise."New value: +"Guidance notice. Set when a first call returns no groups (recovery suggestions), when a `cursor` continuation returns none because the traversal is already finished, or when the page is full and more groups likely exist (truncation signal with narrowing advice). Absent otherwise."
- Changed
openalex_get_citation_graph6 fields changed- changed
Input schema / properties / cursor / descriptionPrevious value: -"Pagination cursor from a previous response. Pass to get the next page."New value: +"Pagination cursor from a previous response. Pass to get the next page. Omit it on the first call — an empty string is rejected, since a supplied-but-blank cursor is a caller mistake rather than a request for the first page." - added
Input schema / properties / cursor / minLengthAdded value: +1 - changed
Input schema / properties / filters / descriptionPrevious value: -"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."New value: +"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, nor an alias of one such as cited_works — those keys are set by the `direction` parameter." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used but the citation-graph query has no active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `reserved_filter_key`: filters contains cites/cited_by/related_to — the direction parameter reserves those keys. `entity_not_found`: OpenAlex has no work matching the seed_id. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used but the citation-graph query has no active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `reserved_filter_key`: filters contains cites/cited_by/related_to, or an alias of one such as cited_works — the direction parameter reserves those keys. `entity_not_found`: OpenAlex has no work matching the seed_id. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / meta / properties / per_page / descriptionPrevious value: -"Records on this page."New value: +"Page size OpenAlex echoed for this request — the requested per_page, not the number of records returned. A short or exhausted page carries fewer records than this." - changed
Output schema / properties / notice / descriptionPrevious value: -"Recovery guidance when no edges are returned — suggests verifying the seed_id, broadening filters, or trying a different direction. Absent when results are present."New value: +"Guidance when no edges are returned. A first call suggests verifying the seed_id, broadening filters, or trying a different direction; a `cursor` continuation says the walk is already past its last edge instead. Absent when results are present."
- Changed
openalex_resolve_name1 field changed- changed
Input schema / properties / query / descriptionPrevious value: -"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\"), DOI (\"10.1038/nature12373\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\") — which resolves straight to that one record instead of running a name search. A PMCID (\"PMC1234567\" or a PubMed Central URL) is recognized but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead."New value: +"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\"), DOI (\"10.1038/nature12373\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\") — which resolves straight to that one record instead of running a name search. A keyword URL (\"https://openalex.org/keywords/groundwater\") resolves the same way; a bare keyword slug reads as a name and runs a name search, which finds it too. A PMCID (\"PMC1234567\" or a PubMed Central URL) is recognized but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead."
- Changed
openalex_search_entities15 fields changed- changed
Input schema / properties / cursor / descriptionPrevious value: -"Pagination cursor from a previous response. Pass to get the next page."New value: +"Pagination cursor from a previous response. Pass to get the next page. Omit it on the first call — an empty string is rejected, since a supplied-but-blank cursor is a caller mistake rather than a request for page 1. Keyword and exact modes only — semantic search walks its candidates with `page`, and a `cursor` sent with it is rejected." - added
Input schema / properties / cursor / minLengthAdded value: +1 - changed
Input schema / properties / filters / descriptionPrevious value: -"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`."New value: +"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. Two keys that resolve to the same upstream field (an alias and its canonical name, e.g. `year` and `publication_year`) are both applied and AND'd, so they narrow rather than override each other. 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`." - changed
Input schema / properties / id / descriptionPrevious value: -"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\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\"). A PMCID is recognized too, bare (\"PMC1234567\") or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown."New value: +"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\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\"). Keywords are identified by slug rather than a native ID — pass either the slug (\"groundwater\") or the URL a search returns (\"https://openalex.org/keywords/groundwater\"). A PMCID is recognized too, bare (\"PMC1234567\") or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown." - added
Input schema / properties / id / minLengthAdded value: +1 - added
Input schema / properties / pageAdded value: +{ + "description": "Page number (1-based) for semantic search, the one mode that paginates with `page` instead of `cursor`. Semantic search ranks at most 50 candidates, so the last reachable page is ceil(50 / per_page) — e.g. page 17 with per_page=3. Passing it under any other search_mode is rejected.", + "maximum": 9007199254740991, + "minimum": 1, + "type": "integer" +} - changed
Input schema / properties / query / descriptionPrevious value: -"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."New value: +"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 — an empty string is rejected, since a blank search is a mistake rather than a request for the whole catalog." - added
Input schema / properties / query / minLengthAdded value: +1 - changed
Input schema / properties / sample / descriptionPrevious value: -"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."New value: +"Return a random sample of this many entities matching the filters (1-100). Single page only — neither `cursor` nor `page` pagination applies to sampling, and a search that passes either alongside it is rejected. Overrides `per_page`. Useful for unbiased exploration: spot-checking filter correctness, stratified review prompts, or generating exploration sets without bias toward most-cited." - changed
Input schema / properties / search_mode / descriptionPrevious value: -"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)."New value: +"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, ranking at most 50 candidates at ~1 req/sec and paginated with `page` rather than `cursor`." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `semantic_without_query`: A search set search_mode to \"semantic\" without supplying the `query` it embeds. `semantic_with_cursor`: A search set search_mode to \"semantic\" and supplied `cursor`, which OpenAlex rejects on a semantic query. `page_without_semantic`: A search supplied `page` under a search_mode other than \"semantic\". `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `sample_with_page`: A search (no `id`) provided both `sample` and `page`. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `query_too_long`: OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "semantic_per_page_cap", - "sample_with_cursor", - "seed_without_sample", - "entity_not_found", - "rate_limited", - "upstream_budget_exhausted", - "upstream_timeout", - "upstream_unavailable", - "upstream_unauthorized", - "upstream_forbidden", - "comma_in_filter_value", - "upstream_invalid_params", - "upstream_invalid_id_value", - "upstream_sort_requires_search", - "upstream_invalid_params_other", - "upstream_validation_failed" -]New value: +[ + "semantic_per_page_cap", + "semantic_without_query", + "semantic_with_cursor", + "page_without_semantic", + "sample_with_cursor", + "sample_with_page", + "seed_without_sample", + "entity_not_found", + "rate_limited", + "upstream_budget_exhausted", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "query_too_long", + "upstream_invalid_params_other", + "upstream_validation_failed" +] - changed
Output schema / properties / meta / properties / count / descriptionPrevious value: -"Total results matching the query/filters."New value: +"Total results matching the query/filters. Under search_mode \"semantic\" it is instead the capped candidate count — at most 50 — not an exhaustive match total." - changed
Output schema / properties / meta / properties / per_page / descriptionPrevious value: -"Results on this page."New value: +"Page size OpenAlex echoed for this request — the requested per_page, not the number of records returned. A short or exhausted page carries fewer records than this." - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance notice. Set when results are empty (echoes the criteria and suggests how to broaden) or when an `id` lookup was passed search criteria it does not apply (names them). Absent otherwise."New value: +"Guidance notice. Set when a first call returns no results (echoes the criteria and suggests how to broaden), when a paginated call ran past its last page (says the traversal is finished instead of advising a broader query), when an `id` lookup was passed search criteria it does not apply (names them), and on every semantic search to disclose that `meta.count` is a capped candidate total. Absent otherwise."
3 tool updates
- Changed
openalex_get_citation_graph1 field changed- changed
Input schema / properties / seed_id / descriptionPrevious value: -"Seed work identifier. Accepts OpenAlex ID (\"W2741809807\"), DOI (\"10.1038/nature12373\" or full URL), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), or PMCID. Use openalex_resolve_name first if you only have a title."New value: +"Seed work identifier. Accepts OpenAlex ID (\"W2741809807\"), DOI (\"10.1038/nature12373\" or full URL), or PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"). A PMCID is recognized too, bare or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. Use openalex_resolve_name first if you only have a title."
- Changed
openalex_resolve_name1 field changed- changed
Input schema / properties / query / descriptionPrevious value: -"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\"), DOI (\"10.1038/nature12373\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), PMCID (\"PMC1234567\"), ISSN (\"1234-5678\") — which resolves straight to that one record instead of running a name search."New value: +"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\"), DOI (\"10.1038/nature12373\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\") — which resolves straight to that one record instead of running a name search. A PMCID (\"PMC1234567\" or a PubMed Central URL) is recognized but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead."
- Changed
openalex_search_entities1 field changed- changed
Input schema / properties / id / descriptionPrevious value: -"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\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), PMCID (\"PMC1234567\"), ISSN (\"1234-5678\"). When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown."New value: +"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\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), ISSN (\"1234-5678\"). A PMCID is recognized too, bare (\"PMC1234567\") or as a PubMed Central URL, but OpenAlex indexes no PMCIDs, so it resolves nothing — pass the work's PMID or DOI instead. When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown."
4 tool updates
- Changed
openalex_describe_fields2 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"Optional partial or guessed field name to rank results by similarity. Pass the field you tried (e.g. \"funder\") to get the closest matches first. Omit to return all fields for the entity_type + context."New value: +"Optional partial or guessed field name to sort results by similarity. Pass the field you tried (e.g. \"funder\") to get the closest matches first. The complete field list is returned either way — a query reorders it, it does not filter it, so a nested value's parent object (e.g. `summary_stats` for \"h_index\") is still reachable further down." - changed
Output schema / properties / fields / descriptionPrevious value: -"Valid field names, ranked by similarity to query when provided."New value: +"Every valid field name for this entity_type + context — the complete pool, ranked by similarity when `query` is provided. Never truncated, so this always holds `total` entries."
- Changed
openalex_get_citation_graph1 field changed- changed
Input schema / properties / seed_id / descriptionPrevious value: -"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."New value: +"Seed work identifier. Accepts OpenAlex ID (\"W2741809807\"), DOI (\"10.1038/nature12373\" or full URL), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), or PMCID. Use openalex_resolve_name first if you only have a title."
- Changed
openalex_resolve_name1 field changed- changed
Input schema / properties / query / descriptionPrevious value: -"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\"), DOI (\"10.1038/nature12373\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\"), PMCID (\"PMC1234567\"), ISSN (\"1234-5678\") — which resolves straight to that one record instead of running a name search."New value: +"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\"), DOI (\"10.1038/nature12373\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), PMCID (\"PMC1234567\"), ISSN (\"1234-5678\") — which resolves straight to that one record instead of running a name search."
- Changed
openalex_search_entities2 fields changed- changed
Input schema / properties / id / descriptionPrevious value: -"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, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown."New value: +"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\" or \"https://pubmed.ncbi.nlm.nih.gov/12345678\"), PMCID (\"PMC1234567\"), ISSN (\"1234-5678\"). When provided, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown." - changed
Input schema / properties / select / descriptionPrevious value: -"OpenAlex top-level field names to return. Always returned: `id`, `display_name` — additional fields you list are appended. A curated default per entity type applies to both searches and single-entity (`id`) lookups; pass field names to override it, or `[\"*\"]` to retrieve the complete record (every field). Invalid field names produce an error identifying the rejected field. Example: [\"doi\", \"authorships\", \"primary_topic\"]."New value: +"OpenAlex top-level field names to return. Always returned: `id`, `display_name` — additional fields you list are appended. A curated default per entity type applies to both searches and single-entity (`id`) lookups; pass field names to override it, or `[\"*\"]` to retrieve the complete record (every field). Only top-level fields project, so a nested value is requested by its parent object: bibliometrics (`h_index`, `i10_index`, `2yr_mean_citedness`) live under `summary_stats` on authors, sources, institutions, publishers, and funders, and naming a leaf returns that object. Invalid field names produce an error identifying the rejected field. Example: [\"doi\", \"authorships\", \"primary_topic\"]."
4 tool updates
- Changed
openalex_analyze_trends4 fields changed- removed
Output schema / properties / meta / properties / groups_count / anyOfRemoved value: -[ - { - "type": "number" - }, - { - "type": "null" - } -] - added
Output schema / properties / meta / properties / groups_count / typeAdded value: +[ + "number", + "null" +] - removed
Output schema / properties / meta / properties / next_cursor / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - added
Output schema / properties / meta / properties / next_cursor / typeAdded value: +[ + "string", + "null" +]
- Changed
openalex_get_citation_graph4 fields changed- removed
Output schema / properties / meta / properties / next_cursor / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - added
Output schema / properties / meta / properties / next_cursor / typeAdded value: +[ + "string", + "null" +] - removed
Output schema / properties / results / items / properties / display_name / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - added
Output schema / properties / results / items / properties / display_name / typeAdded value: +[ + "string", + "null" +]
- Changed
openalex_resolve_name8 fields changed- removed
Output schema / properties / results / items / properties / display_name / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - added
Output schema / properties / results / items / properties / display_name / typeAdded value: +[ + "string", + "null" +] - removed
Output schema / properties / results / items / properties / external_id / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - added
Output schema / properties / results / items / properties / external_id / typeAdded value: +[ + "string", + "null" +] - removed
Output schema / properties / results / items / properties / hint / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - added
Output schema / properties / results / items / properties / hint / typeAdded value: +[ + "string", + "null" +] - removed
Output schema / properties / results / items / properties / works_count / anyOfRemoved value: -[ - { - "type": "number" - }, - { - "type": "null" - } -] - added
Output schema / properties / results / items / properties / works_count / typeAdded value: +[ + "number", + "null" +]
- Changed
openalex_search_entities4 fields changed- removed
Output schema / properties / meta / properties / next_cursor / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - added
Output schema / properties / meta / properties / next_cursor / typeAdded value: +[ + "string", + "null" +] - removed
Output schema / properties / results / items / properties / display_name / anyOfRemoved value: -[ - { - "type": "string" - }, - { - "type": "null" - } -] - added
Output schema / properties / results / items / properties / display_name / typeAdded value: +[ + "string", + "null" +]
5 tool updates
- Changed
openalex_analyze_trends6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "meta", + "groups", + "echo", + "totalCount" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid group_by or filter field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_ungroupable_group_by`: group_by targets a raw date, float, or *.search field OpenAlex cannot aggregate (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler.", + "examples": [ + "rate_limited", + "upstream_budget_exhausted", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_ungroupable_group_by", + "upstream_invalid_params_other", + "upstream_validation_failed" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "meta", - "groups", - "echo", - "totalCount" -]
- Changed
openalex_describe_fields6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "entity_type", + "context", + "fields", + "total" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode.", + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "entity_type", - "context", - "fields", - "total" -]
- Changed
openalex_get_citation_graph6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "meta", + "results", + "echo", + "totalCount" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used but the citation-graph query has no active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `reserved_filter_key`: filters contains cites/cited_by/related_to — the direction parameter reserves those keys. `entity_not_found`: OpenAlex has no work matching the seed_id. Other values are possible when a failure originates below the handler.", + "examples": [ + "rate_limited", + "upstream_budget_exhausted", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "upstream_invalid_params_other", + "reserved_filter_key", + "entity_not_found" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "meta", - "results", - "echo", - "totalCount" -]
- Changed
openalex_resolve_name6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "results" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `rate_limited`: OpenAlex throttled the autocomplete request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to autocomplete (HTTP 403). `comma_in_filter_value`: A `filters` value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter field name on the autocomplete query (HTTP 400). `upstream_invalid_id_value`: A `filters` entry expecting an entity ID received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the autocomplete request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the autocomplete request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler.", + "examples": [ + "rate_limited", + "upstream_budget_exhausted", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_invalid_params_other", + "upstream_validation_failed" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "results" -]
- Changed
openalex_search_entities6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "meta", + "results", + "echo", + "totalCount" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `semantic_per_page_cap`: A search (no `id`) set per_page above the semantic-search cap of 50. `sample_with_cursor`: A search (no `id`) provided both `sample` and `cursor`. `seed_without_sample`: A search (no `id`) provided `seed` without `sample`. `entity_not_found`: Lookup by id matched no OpenAlex entity. `rate_limited`: OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429). `upstream_budget_exhausted`: The OpenAlex daily usage budget is spent (HTTP 429). `upstream_timeout`: OpenAlex did not respond within the request deadline. `upstream_unavailable`: OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON. `upstream_unauthorized`: OpenAlex rejected the API key (HTTP 401). `upstream_forbidden`: OpenAlex denied access to the requested resource (HTTP 403). `comma_in_filter_value`: A filter value contains a comma, which collides with the OpenAlex filter separator. `upstream_invalid_params`: OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400). `upstream_invalid_id_value`: An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400). `upstream_sort_requires_search`: sort=-relevance_score was used without an active search (HTTP 400). `upstream_invalid_params_other`: OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name. `upstream_validation_failed`: OpenAlex rejected the request as semantically invalid (HTTP 422). Other values are possible when a failure originates below the handler.", + "examples": [ + "semantic_per_page_cap", + "sample_with_cursor", + "seed_without_sample", + "entity_not_found", + "rate_limited", + "upstream_budget_exhausted", + "upstream_timeout", + "upstream_unavailable", + "upstream_unauthorized", + "upstream_forbidden", + "comma_in_filter_value", + "upstream_invalid_params", + "upstream_invalid_id_value", + "upstream_sort_requires_search", + "upstream_invalid_params_other", + "upstream_validation_failed" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "meta", - "results", - "echo", - "totalCount" -]
4 tool updates
- Changed
openalex_analyze_trends1 field changed- added
Output schema / properties / budget / properties / prepaidRemainingUsdAdded value: +{ + "description": "USD left in the prepaid balance — a separate pool OpenAlex draws on only after the daily allowance runs out, and which the daily reset does not refill. Add it to `remainingUsd` for the full spendable amount. Absent when the account holds no prepaid balance.", + "type": "number" +}
- Changed
openalex_get_citation_graph1 field changed- added
Output schema / properties / budget / properties / prepaidRemainingUsdAdded value: +{ + "description": "USD left in the prepaid balance — a separate pool OpenAlex draws on only after the daily allowance runs out, and which the daily reset does not refill. Add it to `remainingUsd` for the full spendable amount. Absent when the account holds no prepaid balance.", + "type": "number" +}
- Changed
openalex_resolve_name9 fields changed- changed
Input schema / properties / entity_type / descriptionPrevious value: -"Entity type to search. Omit for cross-entity search (useful when entity type is unknown)."New value: +"Entity type to search. Omit for cross-entity search (useful when entity type is unknown). Not applied when `query` is an identifier — an identifier determines its own entity type." - changed
Input schema / properties / filters / descriptionPrevious value: -"Narrow autocomplete results with filters. Example: restrict to a specific country or publication year range."New value: +"Narrow autocomplete results with filters. Example: restrict to a specific country or publication year range. Applies to name queries only — an identifier already addresses a single record." - changed
Input schema / properties / query / descriptionPrevious value: -"Name or partial name to resolve. Also accepts DOIs for quick lookup."New value: +"Name or partial name to resolve. Also accepts an identifier, bare or in URL form — OpenAlex ID (\"W2741809807\", \"F4320332161\"), DOI (\"10.1038/nature12373\"), ORCID (\"0000-0002-1825-0097\"), ROR (\"https://ror.org/00hx57361\"), PMID (\"12345678\"), PMCID (\"PMC1234567\"), ISSN (\"1234-5678\") — which resolves straight to that one record instead of running a name search." - added
Output schema / properties / budget / properties / prepaidRemainingUsdAdded value: +{ + "description": "USD left in the prepaid balance — a separate pool OpenAlex draws on only after the daily allowance runs out, and which the daily reset does not refill. Add it to `remainingUsd` for the full spendable amount. Absent when the account holds no prepaid balance.", + "type": "number" +} - changed
Output schema / properties / notice / descriptionPrevious value: -"Recovery guidance when no matches were found — echoes the query and suggests corrections. Absent when results are present."New value: +"Guidance notice. Set when nothing matched (echoes the query and suggests corrections) or when an identifier query was passed name-search parameters that do not apply to it. Absent otherwise." - added
Output schema / properties / results / items / properties / display_name / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - changed
Output schema / properties / results / items / properties / display_name / descriptionPrevious value: -"Human-readable name."New value: +"Human-readable name. null only for an identifier lookup that landed on a record OpenAlex holds no title for (paratext works and other untitled entries) — use `id` to identify it." - removed
Output schema / properties / results / items / properties / display_name / typeRemoved value: -"string" - changed
Output schema / properties / results / items / properties / hint / descriptionPrevious value: -"Disambiguation context: author names (works), last institution (authors), host org (sources), location (institutions)."New value: +"Disambiguation context — last institution (authors), host organization (sources), place or country (institutions); author names (works) from a name search, publication year from an identifier lookup. null when the record carries none."
- Changed
openalex_search_entities6 fields changed- changed
Input schema / properties / id / descriptionPrevious value: -"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 — but `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). Use openalex_resolve_name to find the ID if unknown."New value: +"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, `query`, `search_mode`, `filters`, `sort`, `sample`, and `seed` are not applied — the returned record is the entity at that ID regardless of them, and the response `notice` names any you passed. `select` still applies: the curated per-entity-type default is returned unless you pass `select` (use `[\"*\"]` for the complete record). To filter, drop `id` and search. Use openalex_resolve_name to find the ID if unknown." - changed
Input schema / properties / per_page / descriptionPrevious value: -"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)."New value: +"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). The cap applies to searches only; an `id` lookup returns its one record regardless of both." - changed
Input schema / properties / seed / descriptionPrevious value: -"Deterministic seed for `sample`. Same seed + same filters = same results — pass when reproducibility matters. Has no effect (and is rejected) without `sample`."New value: +"Deterministic seed for `sample`. Same seed + same filters = same results — pass when reproducibility matters. Has no effect without `sample`, and a search that passes it alone is rejected." - added
Output schema / properties / budget / properties / prepaidRemainingUsdAdded value: +{ + "description": "USD left in the prepaid balance — a separate pool OpenAlex draws on only after the daily allowance runs out, and which the daily reset does not refill. Add it to `remainingUsd` for the full spendable amount. Absent when the account holds no prepaid balance.", + "type": "number" +} - changed
Output schema / properties / echo / descriptionPrevious value: -"Compact echo of the input criteria (entity_type, query, filters, sort, search_mode) — surfaces what was actually searched when results are empty."New value: +"Compact echo of the criteria that actually ran (entity_type, query, filters, sort, search_mode) — surfaces what was searched when results are empty. An `id` lookup echoes entity_type and id alone, because the search criteria are not applied on that path." - changed
Output schema / properties / notice / descriptionPrevious value: -"Recovery guidance when results are empty — echoes the criteria and suggests how to broaden. Absent on successful result pages."New value: +"Guidance notice. Set when results are empty (echoes the criteria and suggests how to broaden) or when an `id` lookup was passed search criteria it does not apply (names them). Absent otherwise."
4 tool updates
- Changed
openalex_analyze_trends1 field changed- added
Output schema / properties / budgetAdded value: +{ + "additionalProperties": false, + "description": "What this call cost against the OpenAlex daily budget and what is left of it — weigh `remainingUsd` against `costUsd` before enumerating every group with `order: \"key\"`. Absent when OpenAlex omitted the accounting headers.", + "properties": { + "costUsd": { + "description": "USD this call spent. Aggregation is priced far below paging the same entities, so a group_by is the cheap way to size a population before searching it.", + "type": "number" + }, + "remainingUsd": { + "description": "USD left in today's OpenAlex budget after this call.", + "type": "number" + }, + "resetsInSeconds": { + "description": "Seconds until the daily budget refills (midnight UTC).", + "type": "number" + } + }, + "required": [ + "costUsd", + "remainingUsd", + "resetsInSeconds" + ], + "type": "object" +}
- Changed
openalex_get_citation_graph1 field changed- added
Output schema / properties / budgetAdded value: +{ + "additionalProperties": false, + "description": "What this call cost against the OpenAlex daily budget and what is left of it. Price a full walk before committing to it: `totalCount` ÷ `per_page` × `costUsd` against `remainingUsd`. Absent when OpenAlex omitted the accounting headers.", + "properties": { + "costUsd": { + "description": "USD this call spent, covering both upstream requests — the seed validation lookup (unbilled) and the graph page itself.", + "type": "number" + }, + "remainingUsd": { + "description": "USD left in today's OpenAlex budget after this call.", + "type": "number" + }, + "resetsInSeconds": { + "description": "Seconds until the daily budget refills (midnight UTC).", + "type": "number" + } + }, + "required": [ + "costUsd", + "remainingUsd", + "resetsInSeconds" + ], + "type": "object" +}
- Changed
openalex_resolve_name1 field changed- added
Output schema / properties / budgetAdded value: +{ + "additionalProperties": false, + "description": "What this call cost against the OpenAlex daily budget and what is left of it. Read `remainingUsd` here to size the search or traversal this resolution feeds. Absent when OpenAlex omitted the accounting headers.", + "properties": { + "costUsd": { + "description": "USD this call spent. Autocomplete is priced at the floor — resolving a name before filtering costs far less than the failed searches an ambiguous name causes.", + "type": "number" + }, + "remainingUsd": { + "description": "USD left in today's OpenAlex budget after this call.", + "type": "number" + }, + "resetsInSeconds": { + "description": "Seconds until the daily budget refills (midnight UTC).", + "type": "number" + } + }, + "required": [ + "costUsd", + "remainingUsd", + "resetsInSeconds" + ], + "type": "object" +}
- Changed
openalex_search_entities1 field changed- added
Output schema / properties / budgetAdded value: +{ + "additionalProperties": false, + "description": "What this call cost against the OpenAlex daily budget and what is left of it. Price a full traversal before committing to it: `totalCount` ÷ `per_page` × `costUsd` against `remainingUsd`. Absent when OpenAlex omitted the accounting headers.", + "properties": { + "costUsd": { + "description": "USD this call spent. 0 for an `id` lookup — OpenAlex does not bill single-entity fetches, so batching known IDs beats paging a filtered list.", + "type": "number" + }, + "remainingUsd": { + "description": "USD left in today's OpenAlex budget after this call.", + "type": "number" + }, + "resetsInSeconds": { + "description": "Seconds until the daily budget refills (midnight UTC).", + "type": "number" + } + }, + "required": [ + "costUsd", + "remainingUsd", + "resetsInSeconds" + ], + "type": "object" +}
2 tool updates
- Changed
openalex_get_citation_graph4 fields changed- changed
Input schema / properties / sort / descriptionPrevious value: -"Sort field. Prefix with \"-\" for descending. Common: \"cited_by_count\", \"-publication_date\". Default is OpenAlex relevance."New value: +"Sort field. Prefix with \"-\" for descending. Comma-separate for a multi-key sort, applied left to right, with the \"-\" prefix set per key (\"-publication_year,cited_by_count\" sorts by year descending, then citations ascending). Common: \"cited_by_count\", \"-publication_date\". Default is OpenAlex relevance." - added
Output schema / properties / results / items / properties / display_name / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - changed
Output schema / properties / results / items / properties / display_name / descriptionPrevious value: -"Work title."New value: +"Work title. null when OpenAlex holds no title for the record (paratext works and other untitled entries) — use `id` to identify it." - removed
Output schema / properties / results / items / properties / display_name / typeRemoved value: -"string"
- Changed
openalex_search_entities5 fields changed- changed
Input schema / properties / sort / descriptionPrevious value: -"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."New value: +"Sort field. Prefix with \"-\" for descending. Comma-separate for a multi-key sort, applied left to right, with the \"-\" prefix set per key (\"-publication_year,cited_by_count\" sorts by year descending, then citations ascending). 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." - changed
Output schema / properties / results / items / descriptionPrevious value: -"A single OpenAlex entity record. Core `id` and `display_name` are guaranteed; additional fields vary by entity_type and `select`."New value: +"A single OpenAlex entity record. `id` is always present and `display_name` is always returned (though it may be null); additional fields vary by entity_type and `select`." - added
Output schema / properties / results / items / properties / display_name / anyOfAdded value: +[ + { + "type": "string" + }, + { + "type": "null" + } +] - changed
Output schema / properties / results / items / properties / display_name / descriptionPrevious value: -"Entity name or work title."New value: +"Entity name or work title. null when OpenAlex holds no title for the record (paratext works and other untitled entries) — use `id` to identify it." - removed
Output schema / properties / results / items / properties / display_name / typeRemoved value: -"string"
1 tool update
- Changed
openalex_describe_fields1 field changed- changed
Input schema / properties / context / descriptionPrevious value: -"Field usage context. \"filter\": fields accepted in the filter param. \"group_by\": fields accepted in group_by (same valid set as filter). \"select\": fields accepted in select."New value: +"Field usage context. \"filter\": fields accepted in the filter param. \"group_by\": fields accepted in group_by — a subset of the filter set (raw date and *.search fields are excluded; they cannot be grouped). \"select\": fields accepted in select."
Related MCP Connectors
Search 250M+ academic works, citation graphs, DOIs, and institutional research via OpenAlex.
Search 250M+ research papers, citations and author profiles. Free OpenAlex account; OAuth sign-in.
arXiv, PubMed, Crossref and OpenAlex scholarly metadata.
Academic literature search, retrieval, and private library management on top of OpenAlex.
Related MCP Servers
- AlicenseBqualityDmaintenanceProvides 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.11277 npm5MIT
- -licenseNot gradedqualityNot gradedmaintenanceProvides access to the OpenAlex API, enabling search and retrieval of scholarly works, authors, sources, and more.-
- FlicenseNot gradedqualityDmaintenanceEnables searching and retrieving academic papers, authors, institutions, and citations from the OpenAlex open scholarly index.-
- AlicenseNot gradedqualityDmaintenanceEnables searching and retrieving scholarly works, authors, institutions, and citation networks from the OpenAlex catalog via natural language.34 npmISC
Glama MCP Gateway
Add one secure layer between your agents and this server.