@cyanheads/openalex-mcp-server 0.7.14 → 0.7.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/AGENTS.md +8 -4
  2. package/CLAUDE.md +8 -4
  3. package/README.md +7 -6
  4. package/changelog/0.7.x/0.7.15.md +33 -0
  5. package/dist/mcp-server/prompts/definitions/literature-review.prompt.js +1 -1
  6. package/dist/mcp-server/prompts/definitions/literature-review.prompt.js.map +1 -1
  7. package/dist/mcp-server/tools/definitions/analyze-trends.tool.d.ts +19 -0
  8. package/dist/mcp-server/tools/definitions/analyze-trends.tool.d.ts.map +1 -1
  9. package/dist/mcp-server/tools/definitions/analyze-trends.tool.js +31 -3
  10. package/dist/mcp-server/tools/definitions/analyze-trends.tool.js.map +1 -1
  11. package/dist/mcp-server/tools/definitions/citation-graph.tool.d.ts +12 -1
  12. package/dist/mcp-server/tools/definitions/citation-graph.tool.d.ts.map +1 -1
  13. package/dist/mcp-server/tools/definitions/citation-graph.tool.js +55 -38
  14. package/dist/mcp-server/tools/definitions/citation-graph.tool.js.map +1 -1
  15. package/dist/mcp-server/tools/definitions/resolve-name.tool.d.ts +11 -0
  16. package/dist/mcp-server/tools/definitions/resolve-name.tool.d.ts.map +1 -1
  17. package/dist/mcp-server/tools/definitions/resolve-name.tool.js +12 -1
  18. package/dist/mcp-server/tools/definitions/resolve-name.tool.js.map +1 -1
  19. package/dist/mcp-server/tools/definitions/search-entities.tool.d.ts +40 -0
  20. package/dist/mcp-server/tools/definitions/search-entities.tool.d.ts.map +1 -1
  21. package/dist/mcp-server/tools/definitions/search-entities.tool.js +146 -39
  22. package/dist/mcp-server/tools/definitions/search-entities.tool.js.map +1 -1
  23. package/dist/services/openalex/openalex-service.d.ts +16 -0
  24. package/dist/services/openalex/openalex-service.d.ts.map +1 -1
  25. package/dist/services/openalex/openalex-service.js +103 -27
  26. package/dist/services/openalex/openalex-service.js.map +1 -1
  27. package/dist/services/openalex/types.d.ts +11 -0
  28. package/dist/services/openalex/types.d.ts.map +1 -1
  29. package/dist/services/openalex/types.js +7 -0
  30. package/dist/services/openalex/types.js.map +1 -1
  31. package/package.json +3 -3
  32. package/server.json +3 -3
@@ -16,9 +16,9 @@ const SAMPLE_MAX = 100;
16
16
  * alone, so every parameter named here is dropped on that path — by OpenAlex itself, which
17
17
  * answers an entity-by-ID URL identically whether or not search params ride along.
18
18
  *
19
- * Pagination (`per_page`, `cursor`) is deliberately absent: a singleton lookup is one record by
20
- * definition, and `per_page` always carries its schema default, so a caller's intent there
21
- * cannot be told apart from the absence of one. Naming it would be noise, not a warning.
19
+ * Pagination (`per_page`, `cursor`, `page`) is deliberately absent: a singleton lookup is one
20
+ * record by definition, and `per_page` always carries its schema default, so a caller's intent
21
+ * there cannot be told apart from the absence of one. Naming it would be noise, not a warning.
22
22
  */
23
23
  function searchOnlyParams(input) {
24
24
  const parts = [];
@@ -51,31 +51,16 @@ function buildSearchEcho(input) {
51
51
  return [...parts, ...searchOnlyParams(input).map((part) => part.rendered)].join(' | ');
52
52
  }
53
53
  /**
54
- * Reject list-query parameter combinations OpenAlex cannot serve. All three checks constrain a
55
- * *list* query. `id` takes the singleton path in `OpenAlexService.search()`, which reads only
56
- * `entity_type`, `id`, and `select` — so search_mode, per_page, cursor, sample, and seed are
57
- * unread there, and rejecting an ID lookup over how they relate to each other fails it on
58
- * constraints it never met. The handler's dropped-parameter notice reports them instead. The
59
- * `id` predicate is truthiness, not `!== undefined`, to match the service branch: an
60
- * empty-string `id` parses and lists.
54
+ * Is this call continuing a paginated traversal rather than opening one? A `cursor` is the
55
+ * keyword/exact signal — the schema rejects a blank one, so its presence is always a real
56
+ * continuation rather than a mistake OpenAlex answers with page 1; a `page` past the first is
57
+ * the semantic signal, and `page` only survives the handler's preconditions under semantic
58
+ * mode. Only on a continuing call does a page of
59
+ * zero results mean the traversal is finished — on a first call it means nothing matched, and
60
+ * the two want opposite advice.
61
61
  */
62
- function assertListQueryConstraints(input, ctx) {
63
- if (input.id)
64
- return;
65
- if (input.search_mode === 'semantic' && input.per_page > SEMANTIC_PER_PAGE_CAP) {
66
- throw ctx.fail('semantic_per_page_cap', `Semantic search supports at most ${SEMANTIC_PER_PAGE_CAP} results per page. Reduce per_page or switch search_mode.`, {
67
- ...ctx.recoveryFor('semantic_per_page_cap'),
68
- searchMode: input.search_mode,
69
- perPage: input.per_page,
70
- cap: SEMANTIC_PER_PAGE_CAP,
71
- });
72
- }
73
- if (input.sample !== undefined && input.cursor !== undefined) {
74
- throw ctx.fail('sample_with_cursor', 'Sampling returns one page only — `sample` cannot be combined with `cursor` pagination.', { ...ctx.recoveryFor('sample_with_cursor'), sample: input.sample, cursor: input.cursor });
75
- }
76
- if (input.seed !== undefined && input.sample === undefined) {
77
- throw ctx.fail('seed_without_sample', '`seed` is only meaningful with `sample` — pass `sample` to enable random sampling.', { ...ctx.recoveryFor('seed_without_sample'), seed: input.seed });
78
- }
62
+ function isContinuationPage(input) {
63
+ return input.cursor !== undefined || (input.page ?? 1) > 1;
79
64
  }
80
65
  export const searchEntitiesTool = tool('openalex_search_entities', {
81
66
  description: 'Search, filter, sort, or retrieve by ID. Covers all OpenAlex entity types (works, authors, sources, institutions, topics, keywords, publishers, funders). Pass `id` to retrieve a single entity. Otherwise, use `query` and/or `filters` for discovery. Supports keyword search with boolean operators, exact phrase matching, and AI semantic search. Use openalex_resolve_name to resolve names to IDs before filtering. Searches and ID lookups return a curated set of fields by default; pass `select` to override with specific fields, or `["*"]` for the full record.',
@@ -88,12 +73,36 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
88
73
  when: `A search (no \`id\`) set per_page above the semantic-search cap of ${SEMANTIC_PER_PAGE_CAP}.`,
89
74
  recovery: `Reduce per_page to ${SEMANTIC_PER_PAGE_CAP} or less, or switch search_mode to keyword.`,
90
75
  },
76
+ {
77
+ reason: 'semantic_without_query',
78
+ code: JsonRpcErrorCode.ValidationError,
79
+ when: 'A search set search_mode to "semantic" without supplying the `query` it embeds.',
80
+ recovery: 'Pass the text to match in `query`, or switch search_mode to keyword for a filter-only listing.',
81
+ },
82
+ {
83
+ reason: 'semantic_with_cursor',
84
+ code: JsonRpcErrorCode.ValidationError,
85
+ when: 'A search set search_mode to "semantic" and supplied `cursor`, which OpenAlex rejects on a semantic query.',
86
+ recovery: 'Drop `cursor` and walk semantic results with `page` (1-based), or switch search_mode to keyword or exact, which paginate by cursor.',
87
+ },
88
+ {
89
+ reason: 'page_without_semantic',
90
+ code: JsonRpcErrorCode.ValidationError,
91
+ when: 'A search supplied `page` under a search_mode other than "semantic".',
92
+ recovery: 'Drop `page` and paginate with `cursor`, or set search_mode to "semantic" — the only mode `page` applies to.',
93
+ },
91
94
  {
92
95
  reason: 'sample_with_cursor',
93
96
  code: JsonRpcErrorCode.ValidationError,
94
97
  when: 'A search (no `id`) provided both `sample` and `cursor`.',
95
98
  recovery: 'Sampling returns a single page only; remove `cursor` or remove `sample`.',
96
99
  },
100
+ {
101
+ reason: 'sample_with_page',
102
+ code: JsonRpcErrorCode.ValidationError,
103
+ when: 'A search (no `id`) provided both `sample` and `page`.',
104
+ recovery: 'Sampling returns a single page only; remove `page` or remove `sample`.',
105
+ },
97
106
  {
98
107
  reason: 'seed_without_sample',
99
108
  code: JsonRpcErrorCode.ValidationError,
@@ -105,6 +114,7 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
105
114
  code: JsonRpcErrorCode.NotFound,
106
115
  when: 'Lookup by id matched no OpenAlex entity.',
107
116
  recovery: 'Verify the ID format or call openalex_resolve_name to find the correct ID.',
117
+ thrownBy: 'service',
108
118
  },
109
119
  {
110
120
  reason: 'rate_limited',
@@ -112,6 +122,7 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
112
122
  when: 'OpenAlex throttled the request for exceeding its per-second ceiling (HTTP 429).',
113
123
  retryable: true,
114
124
  recovery: 'Wait several seconds and retry; consider lowering request frequency for this caller.',
125
+ thrownBy: 'service',
115
126
  },
116
127
  {
117
128
  reason: 'upstream_budget_exhausted',
@@ -119,6 +130,7 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
119
130
  when: 'The OpenAlex daily usage budget is spent (HTTP 429).',
120
131
  retryable: false,
121
132
  recovery: 'The daily budget refills at midnight UTC — retrying sooner will not succeed. Set OPENALEX_API_KEY to a free key (https://openalex.org/settings/api) for a larger daily budget than anonymous access, or wait for the reset.',
133
+ thrownBy: 'service',
122
134
  },
123
135
  {
124
136
  reason: 'upstream_timeout',
@@ -126,6 +138,7 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
126
138
  when: 'OpenAlex did not respond within the request deadline.',
127
139
  retryable: true,
128
140
  recovery: 'Retry after a short delay; if timeouts persist, narrow the request with tighter filters to reduce upstream load.',
141
+ thrownBy: 'service',
129
142
  },
130
143
  {
131
144
  reason: 'upstream_unavailable',
@@ -133,54 +146,70 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
133
146
  when: 'OpenAlex was unreachable or unusable — HTTP 503, a connection failure, or a body that was empty, HTML, or unparseable JSON.',
134
147
  retryable: true,
135
148
  recovery: 'Wait and retry; check https://openalex.org for service status if the outage persists.',
149
+ thrownBy: 'service',
136
150
  },
137
151
  {
138
152
  reason: 'upstream_unauthorized',
139
153
  code: JsonRpcErrorCode.Unauthorized,
140
154
  when: 'OpenAlex rejected the API key (HTTP 401).',
141
155
  recovery: 'Check that OPENALEX_API_KEY is set to a valid OpenAlex account API key (free from https://openalex.org/settings/api).',
156
+ thrownBy: 'service',
142
157
  },
143
158
  {
144
159
  reason: 'upstream_forbidden',
145
160
  code: JsonRpcErrorCode.Forbidden,
146
161
  when: 'OpenAlex denied access to the requested resource (HTTP 403).',
147
162
  recovery: 'Confirm the API key has access to this entity type or endpoint, then retry the request.',
163
+ thrownBy: 'service',
148
164
  },
149
165
  {
150
166
  reason: 'comma_in_filter_value',
151
167
  code: JsonRpcErrorCode.InvalidParams,
152
168
  when: 'A filter value contains a comma, which collides with the OpenAlex filter separator.',
153
169
  recovery: 'Use `|` for OR within a filter value (e.g. "2020|2021"), or use a `.search` filter or the `query` parameter for free-text phrases that contain commas.',
170
+ thrownBy: 'service',
154
171
  },
155
172
  {
156
173
  reason: 'upstream_invalid_params',
157
174
  code: JsonRpcErrorCode.InvalidParams,
158
175
  when: 'OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400).',
159
176
  recovery: 'The upstream message names the rejected field and suggests close matches. Use openalex_describe_fields(entity_type, context) to browse all valid fields for the given entity type and context.',
177
+ thrownBy: 'service',
160
178
  },
161
179
  {
162
180
  reason: 'upstream_invalid_id_value',
163
181
  code: JsonRpcErrorCode.InvalidParams,
164
182
  when: 'An entity-ID filter received a value that is not an OpenAlex ID — usually a name (HTTP 400).',
165
183
  recovery: 'Call openalex_resolve_name to turn the name into an OpenAlex ID, then filter by that ID. Entity filters such as authorships.author.id, primary_topic.id, and cites accept IDs only.',
184
+ thrownBy: 'service',
166
185
  },
167
186
  {
168
187
  reason: 'upstream_sort_requires_search',
169
188
  code: JsonRpcErrorCode.InvalidParams,
170
189
  when: 'sort=-relevance_score was used without an active search (HTTP 400).',
171
190
  recovery: 'Sorting by relevance_score requires an active search — add a `query` or a `*.search` filter (e.g. title.search), or choose a concrete sort field such as -cited_by_count or -publication_date.',
191
+ thrownBy: 'service',
192
+ },
193
+ {
194
+ reason: 'query_too_long',
195
+ code: JsonRpcErrorCode.InvalidParams,
196
+ when: 'OpenAlex rejected `query` as longer than the search length it accepts (HTTP 400).',
197
+ recovery: 'Shorten `query` to the character limit the upstream message names, or split the text into several shorter searches and merge their results.',
198
+ thrownBy: 'service',
172
199
  },
173
200
  {
174
201
  reason: 'upstream_invalid_params_other',
175
202
  code: JsonRpcErrorCode.InvalidParams,
176
203
  when: 'OpenAlex rejected the request (HTTP 400) for a reason other than an invalid field name.',
177
204
  recovery: 'Read the upstream message in the error above and adjust the request — check filter operators, value formats, and cursor/per_page bounds.',
205
+ thrownBy: 'service',
178
206
  },
179
207
  {
180
208
  reason: 'upstream_validation_failed',
181
209
  code: JsonRpcErrorCode.ValidationError,
182
210
  when: 'OpenAlex rejected the request as semantically invalid (HTTP 422).',
183
211
  recovery: 'Read the upstream message for the specific field, then adjust the request to satisfy validation.',
212
+ thrownBy: 'service',
184
213
  },
185
214
  ],
186
215
  inputAliases: { search: 'query', filter: 'filters' },
@@ -188,20 +217,22 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
188
217
  entity_type: z.enum(ENTITY_TYPES).describe('Type of scholarly entity to search.'),
189
218
  id: z
190
219
  .string()
220
+ .min(1)
191
221
  .optional()
192
- .describe('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.'),
222
+ .describe('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.'),
193
223
  query: z
194
224
  .string()
225
+ .min(1)
195
226
  .optional()
196
- .describe('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.'),
227
+ .describe('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.'),
197
228
  search_mode: z
198
229
  .enum(['keyword', 'exact', 'semantic'])
199
230
  .default('keyword')
200
- .describe('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).'),
231
+ .describe(`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 ${SEMANTIC_PER_PAGE_CAP} candidates at ~1 req/sec and paginated with \`page\` rather than \`cursor\`.`),
201
232
  filters: z
202
233
  .record(z.string(), z.string())
203
234
  .optional()
204
- .describe('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`.'),
235
+ .describe('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`.'),
205
236
  sort: z
206
237
  .string()
207
238
  .optional()
@@ -219,15 +250,22 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
219
250
  .describe('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.'),
220
251
  cursor: z
221
252
  .string()
253
+ .min(1)
222
254
  .optional()
223
- .describe('Pagination cursor from a previous response. Pass to get the next page.'),
255
+ .describe('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.'),
256
+ page: z
257
+ .number()
258
+ .int()
259
+ .min(1)
260
+ .optional()
261
+ .describe(`Page number (1-based) for semantic search, the one mode that paginates with \`page\` instead of \`cursor\`. Semantic search ranks at most ${SEMANTIC_PER_PAGE_CAP} candidates, so the last reachable page is ceil(${SEMANTIC_PER_PAGE_CAP} / per_page) — e.g. page 17 with per_page=3. Passing it under any other search_mode is rejected.`),
224
262
  sample: z
225
263
  .number()
226
264
  .int()
227
265
  .min(1)
228
266
  .max(SAMPLE_MAX)
229
267
  .optional()
230
- .describe(`Return a random sample of this many entities matching the filters (1-${SAMPLE_MAX}). 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.`),
268
+ .describe(`Return a random sample of this many entities matching the filters (1-${SAMPLE_MAX}). 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.`),
231
269
  seed: z
232
270
  .string()
233
271
  .optional()
@@ -236,8 +274,12 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
236
274
  output: z.object({
237
275
  meta: z
238
276
  .object({
239
- count: z.number().describe('Total results matching the query/filters.'),
240
- per_page: z.number().describe('Results on this page.'),
277
+ count: z
278
+ .number()
279
+ .describe(`Total results matching the query/filters. Under search_mode "semantic" it is instead the capped candidate count — at most ${SEMANTIC_PER_PAGE_CAP} — not an exhaustive match total.`),
280
+ per_page: z
281
+ .number()
282
+ .describe('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.'),
241
283
  next_cursor: z
242
284
  .string()
243
285
  .nullable()
@@ -268,7 +310,7 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
268
310
  notice: z
269
311
  .string()
270
312
  .optional()
271
- .describe('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.'),
313
+ .describe('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.'),
272
314
  budget: z
273
315
  .object({
274
316
  costUsd: z
@@ -292,7 +334,60 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
292
334
  budget: { render: renderBudgetTrailer },
293
335
  },
294
336
  async handler(input, ctx) {
295
- assertListQueryConstraints(input, ctx);
337
+ /**
338
+ * Reject list-query parameter combinations OpenAlex cannot serve. Every check here
339
+ * constrains a *list* query. `id` takes the singleton path in `OpenAlexService.search()`,
340
+ * which reads only `entity_type`, `id`, and `select` — so search_mode, per_page, cursor,
341
+ * page, sample, and seed are unread there, and rejecting an ID lookup over how they relate
342
+ * to each other fails it on constraints it never met. The dropped-parameter notice below
343
+ * reports them instead. The `id` predicate mirrors the service's own truthiness branch.
344
+ */
345
+ if (!input.id) {
346
+ // Semantic search matches an embedding of the query text, so with no query there is
347
+ // nothing to embed — the request silently degraded to a plain unfiltered listing whose
348
+ // echo still advertised `search_mode=semantic`.
349
+ if (input.search_mode === 'semantic' && !input.query) {
350
+ throw ctx.fail('semantic_without_query', 'Semantic search needs `query` text to embed — none was supplied.', { ...ctx.recoveryFor('semantic_without_query'), searchMode: input.search_mode });
351
+ }
352
+ if (input.search_mode === 'semantic' && input.per_page > SEMANTIC_PER_PAGE_CAP) {
353
+ throw ctx.fail('semantic_per_page_cap', `Semantic search supports at most ${SEMANTIC_PER_PAGE_CAP} results per page. Reduce per_page or switch search_mode.`, {
354
+ ...ctx.recoveryFor('semantic_per_page_cap'),
355
+ searchMode: input.search_mode,
356
+ perPage: input.per_page,
357
+ cap: SEMANTIC_PER_PAGE_CAP,
358
+ });
359
+ }
360
+ // OpenAlex answers `search.semantic` plus a cursor with a 400 ("Cursor pagination is not
361
+ // supported with semantic search"), so forwarding it spends a round trip to learn that.
362
+ if (input.search_mode === 'semantic' && input.cursor !== undefined) {
363
+ throw ctx.fail('semantic_with_cursor', 'Semantic search does not accept `cursor` — walk its candidates with `page` (1-based) instead.', {
364
+ ...ctx.recoveryFor('semantic_with_cursor'),
365
+ searchMode: input.search_mode,
366
+ cursor: input.cursor,
367
+ });
368
+ }
369
+ // The inverse: `page` is the semantic-only knob, and OpenAlex ignores it on a cursor
370
+ // traversal — silently returning page 1 again rather than the page that was asked for.
371
+ if (input.page !== undefined && input.search_mode !== 'semantic') {
372
+ throw ctx.fail('page_without_semantic', `\`page\` applies to semantic search only — search_mode is "${input.search_mode}", which paginates with \`cursor\`.`, {
373
+ ...ctx.recoveryFor('page_without_semantic'),
374
+ searchMode: input.search_mode,
375
+ page: input.page,
376
+ });
377
+ }
378
+ if (input.sample !== undefined && input.cursor !== undefined) {
379
+ throw ctx.fail('sample_with_cursor', 'Sampling returns one page only — `sample` cannot be combined with `cursor` pagination.', { ...ctx.recoveryFor('sample_with_cursor'), sample: input.sample, cursor: input.cursor });
380
+ }
381
+ // Sampling pins `per_page` to `sample` and returns that one page, so there is no second
382
+ // page for `page` to address — the same exclusion `cursor` has above. Reachable under
383
+ // semantic mode alone; every other mode rejects `page` at the check before this one.
384
+ if (input.sample !== undefined && input.page !== undefined) {
385
+ throw ctx.fail('sample_with_page', 'Sampling returns one page only — `sample` cannot be combined with `page` pagination.', { ...ctx.recoveryFor('sample_with_page'), sample: input.sample, page: input.page });
386
+ }
387
+ if (input.seed !== undefined && input.sample === undefined) {
388
+ throw ctx.fail('seed_without_sample', '`seed` is only meaningful with `sample` — pass `sample` to enable random sampling.', { ...ctx.recoveryFor('seed_without_sample'), seed: input.seed });
389
+ }
390
+ }
296
391
  const service = getOpenAlexService();
297
392
  const result = await service.search({
298
393
  entityType: input.entity_type,
@@ -304,6 +399,7 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
304
399
  select: input.select,
305
400
  perPage: input.per_page,
306
401
  cursor: input.cursor,
402
+ page: input.page,
307
403
  sample: input.sample,
308
404
  seed: input.seed,
309
405
  }, ctx);
@@ -316,17 +412,28 @@ export const searchEntitiesTool = tool('openalex_search_entities', {
316
412
  });
317
413
  const echo = buildSearchEcho(input);
318
414
  ctx.enrich({ echo, totalCount: result.meta.count });
415
+ const notices = [];
319
416
  // An `id` lookup always returns its one record or throws, so it never reaches the
320
417
  // empty-results notice — the two branches are exclusive, and the dropped-parameter
321
418
  // warning is the more useful of the two on that path.
322
419
  const ignored = input.id ? searchOnlyParams(input).map((part) => part.name) : [];
323
420
  if (ignored.length > 0) {
324
421
  const [verb, pronoun] = ignored.length === 1 ? ['was', 'it'] : ['were', 'them'];
325
- ctx.enrich.notice(`\`id\` takes precedence — ${ignored.join(', ')} ${verb} not applied, and the record below is the entity at that ID regardless of ${pronoun}. Drop \`id\` to run ${pronoun} as a search.`);
422
+ notices.push(`\`id\` takes precedence — ${ignored.join(', ')} ${verb} not applied, and the record below is the entity at that ID regardless of ${pronoun}. Drop \`id\` to run ${pronoun} as a search.`);
326
423
  }
327
424
  else if (result.results.length === 0) {
328
- ctx.enrich.notice(`No matches for ${echo}. Try broadening the query, removing filters, or switching search_mode.`);
425
+ notices.push(isContinuationPage(input)
426
+ ? `Pagination exhausted for ${echo} — the previous page was the last, so this one came back empty. Stop paging rather than broadening the search.`
427
+ : `No matches for ${echo}. Try broadening the query, removing filters, or switching search_mode.`);
428
+ }
429
+ // `meta.count` reports the ranked candidate set under semantic search, not the population
430
+ // matching the query — a caller reading it as a match total plans a traversal that ends
431
+ // at the cap.
432
+ if (!input.id && input.search_mode === 'semantic') {
433
+ notices.push(`Semantic search ranks a capped candidate set, so \`meta.count\` (${result.meta.count}) is that ceiling — at most ${SEMANTIC_PER_PAGE_CAP} — not the total number of matching records. Reach the rest of the candidates with \`page\`.`);
329
434
  }
435
+ if (notices.length > 0)
436
+ ctx.enrich.notice(notices.join(' '));
330
437
  return {
331
438
  meta: {
332
439
  count: result.meta.count,
@@ -1 +1 @@
1
- {"version":3,"file":"search-entities.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-entities.tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search-entities.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-entities.tool.ts"],"names":[],"mappings":"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"}
@@ -25,6 +25,7 @@ export declare const PMCID_NOT_INDEXED_HINT = "OpenAlex indexes no PMCIDs, so a
25
25
  * "https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1234567/" → "pmcid:PMC1234567"
26
26
  * "https://pubmed.ncbi.nlm.nih.gov/21491125" → "pmid:21491125"
27
27
  * "PMID:21491125" → "pmid:21491125"
28
+ * "https://openalex.org/keywords/groundwater" → "groundwater"
28
29
  * "W2741809807" → "W2741809807"
29
30
  */
30
31
  export declare function normalizeId(id: string): string;
@@ -43,6 +44,11 @@ export interface ResolvedIdentifier {
43
44
  * and stamps external ones with their scheme prefix — so detection reduces to reading back what
44
45
  * it produced. Names never survive that: a name with a colon in it yields a prefix that is in no
45
46
  * scheme table, and anything else fails the native-ID pattern.
47
+ *
48
+ * Keywords are the exception, and are read from the raw query instead: their IDs are slugs, so
49
+ * `normalizeId()` reduces the URL to a bare word that no longer names an entity type. The URL
50
+ * form is the only keyword spelling that identifies itself — a bare slug is indistinguishable
51
+ * from any other name, and autocomplete is the right answer for it.
46
52
  */
47
53
  export declare function inferIdentifier(query: string): ResolvedIdentifier | undefined;
48
54
  /**
@@ -52,6 +58,16 @@ export declare function inferIdentifier(query: string): ResolvedIdentifier | und
52
58
  * a work has no works of its own, which is the same thing autocomplete reports.
53
59
  */
54
60
  export declare function toAutocompleteRecord(entityType: EntityType, record: EntityRecord): AutocompleteRecord;
61
+ /**
62
+ * Rewrite one caller-supplied filter key to the upstream OpenAlex name, before the
63
+ * value-dependent `id` rewrite. Exported so the citation-graph tool can check a caller's key
64
+ * against the ones `direction` reserves: checking the raw key alone let `cited_works` past the
65
+ * guard, and it then aliased onto `cites` and collided with the direction's own value.
66
+ *
67
+ * Misses fall through unchanged so upstream's 400 with the valid-field list still fires for
68
+ * typos no map can preempt.
69
+ */
70
+ export declare function translateFilterKey(entityType: SearchParams['entityType'], key: string): string;
55
71
  declare class OpenAlexService {
56
72
  private readonly baseUrl;
57
73
  private readonly apiKey;
@@ -1 +1 @@
1
- {"version":3,"file":"openalex-service.d.ts","sourceRoot":"","sources":["../../../src/services/openalex/openalex-service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAsBtD,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAGvB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAiFpB;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,8OACgM,CAAC;AAgBpO;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAgF9C;AAsBD,8FAA8F;AAC9F,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,UAAU,CAAC;IACvB,gGAAgG;IAChG,EAAE,EAAE,MAAM,CAAC;IACX,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAa7E;AAuJD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,YAAY,GACnB,kBAAkB,CAUpB;AAmeD,cAAM,eAAe;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEhC,cAKC;IAED,yFAAyF;IACzF,OAAO,CAAC,OAAO;IAgDf,OAAO,CAAC,2BAA2B;IA2EnC,OAAO,CAAC,aAAa;IAqCrB,sEAAsE;IAChE,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CA0FtE;IAED,4BAA4B;IACtB,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAkDzE;IAED;;;;;;;;;;;;OAYG;IACG,iBAAiB,CACrB,UAAU,EAAE,kBAAkB,EAC9B,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,kBAAkB,CAAC,CAkB7B;IAED,oCAAoC;IAC9B,YAAY,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAsBxF;CACF;AAID,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wBAAgB,kBAAkB,IAAI,eAAe,CAIpD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAE5F"}
1
+ {"version":3,"file":"openalex-service.d.ts","sourceRoot":"","sources":["../../../src/services/openalex/openalex-service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAsBtD,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAGvB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAwFpB;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,8OACgM,CAAC;AA0BpO;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAuF9C;AAuBD,8FAA8F;AAC9F,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,UAAU,CAAC;IACvB,gGAAgG;IAChG,EAAE,EAAE,MAAM,CAAC;IACX,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAkB7E;AAuJD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,YAAY,GACnB,kBAAkB,CAUpB;AAoHD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9F;AAiYD,cAAM,eAAe;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEhC,cAKC;IAED,yFAAyF;IACzF,OAAO,CAAC,OAAO;IAgDf,OAAO,CAAC,2BAA2B;IA2EnC,OAAO,CAAC,aAAa;IAqCrB,sEAAsE;IAChE,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CA6FtE;IAED,4BAA4B;IACtB,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAkEzE;IAED;;;;;;;;;;;;OAYG;IACG,iBAAiB,CACrB,UAAU,EAAE,kBAAkB,EAC9B,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,kBAAkB,CAAC,CAkB7B;IAED,oCAAoC;IAC9B,YAAY,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAsBxF;CACF;AAID,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wBAAgB,kBAAkB,IAAI,eAAe,CAIpD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAE5F"}