@cyanheads/openalex-mcp-server 0.8.0 → 0.10.0
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.
- package/AGENTS.md +25 -7
- package/CLAUDE.md +25 -7
- package/Dockerfile +17 -8
- package/README.md +28 -19
- package/changelog/0.10.x/0.10.0.md +30 -0
- package/changelog/0.9.x/0.9.0.md +48 -0
- package/dist/config/server-config.d.ts +2 -0
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +10 -0
- package/dist/config/server-config.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/prompts/definitions/literature-review.prompt.js +1 -1
- package/dist/mcp-server/prompts/definitions/research-landscape.prompt.js +1 -1
- package/dist/mcp-server/tools/definitions/analyze-trends.tool.d.ts +35 -4
- package/dist/mcp-server/tools/definitions/analyze-trends.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/analyze-trends.tool.js +86 -41
- package/dist/mcp-server/tools/definitions/analyze-trends.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/citation-graph.tool.d.ts +48 -5
- package/dist/mcp-server/tools/definitions/citation-graph.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/citation-graph.tool.js +77 -24
- package/dist/mcp-server/tools/definitions/citation-graph.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/describe-fields.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/describe-fields.tool.js +34 -4
- package/dist/mcp-server/tools/definitions/describe-fields.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/resolve-name.tool.d.ts +43 -1
- package/dist/mcp-server/tools/definitions/resolve-name.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/resolve-name.tool.js +182 -40
- package/dist/mcp-server/tools/definitions/resolve-name.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-entities.tool.d.ts +64 -6
- package/dist/mcp-server/tools/definitions/search-entities.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-entities.tool.js +138 -35
- package/dist/mcp-server/tools/definitions/search-entities.tool.js.map +1 -1
- package/dist/mcp-server/tools/page-size.d.ts +18 -0
- package/dist/mcp-server/tools/page-size.d.ts.map +1 -0
- package/dist/mcp-server/tools/page-size.js +28 -0
- package/dist/mcp-server/tools/page-size.js.map +1 -0
- package/dist/mcp-server/tools/render-budget.d.ts +4 -2
- package/dist/mcp-server/tools/render-budget.d.ts.map +1 -1
- package/dist/mcp-server/tools/render-budget.js +4 -2
- package/dist/mcp-server/tools/render-budget.js.map +1 -1
- package/dist/mcp-server/tools/response-budget.d.ts +3 -3
- package/dist/mcp-server/tools/response-budget.d.ts.map +1 -1
- package/dist/mcp-server/tools/response-budget.js +64 -35
- package/dist/mcp-server/tools/response-budget.js.map +1 -1
- package/dist/services/openalex/budget.d.ts +3 -1
- package/dist/services/openalex/budget.d.ts.map +1 -1
- package/dist/services/openalex/budget.js +3 -1
- package/dist/services/openalex/budget.js.map +1 -1
- package/dist/services/openalex/field-catalog.json +50 -1
- package/dist/services/openalex/filter-values.d.ts +48 -0
- package/dist/services/openalex/filter-values.d.ts.map +1 -0
- package/dist/services/openalex/filter-values.js +350 -0
- package/dist/services/openalex/filter-values.js.map +1 -0
- package/dist/services/openalex/iso-codes.json +1565 -0
- package/dist/services/openalex/openalex-service.d.ts +176 -20
- package/dist/services/openalex/openalex-service.d.ts.map +1 -1
- package/dist/services/openalex/openalex-service.js +573 -127
- package/dist/services/openalex/openalex-service.js.map +1 -1
- package/dist/services/openalex/provider-text.d.ts +7 -6
- package/dist/services/openalex/provider-text.d.ts.map +1 -1
- package/dist/services/openalex/provider-text.js +485 -61
- package/dist/services/openalex/provider-text.js.map +1 -1
- package/dist/services/openalex/types.d.ts +5 -2
- package/dist/services/openalex/types.d.ts.map +1 -1
- package/package.json +14 -12
- package/server.json +35 -21
|
@@ -4,21 +4,24 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
+
import { clampPageSize, pageSizeSchema } from '../page-size.js';
|
|
7
8
|
import { renderBudgetTrailer } from '../render-budget.js';
|
|
8
9
|
import { fitRecordsToBudget, formatRecordPage, joinNotices, measurePageFrame, omittedOutputSchema, overBudgetOutputSchema, windowsOutputSchema, } from '../response-budget.js';
|
|
9
|
-
import {
|
|
10
|
+
import { quoteCallerText } from '../../../services/openalex/filter-values.js';
|
|
11
|
+
import { buildSearchFilter, getOpenAlexService, translateFilterKey, } from '../../../services/openalex/openalex-service.js';
|
|
10
12
|
const OPENALEX_URL_PREFIX = 'https://openalex.org/';
|
|
11
13
|
/** What `meta.count` counts, in the rendered header. */
|
|
12
14
|
const EDGE_NOUN = 'edge(s)';
|
|
13
15
|
const DIRECTIONS = ['cites', 'cited_by', 'related_to'];
|
|
14
16
|
const RESERVED_FILTER_KEYS = new Set(DIRECTIONS);
|
|
17
|
+
/** The request as one line: caller text is JSON-encoded, so a line break in it stays escaped. */
|
|
15
18
|
function buildCitationEcho(input) {
|
|
16
|
-
const parts = [`seed_id=${input.seed_id}`, `direction=${input.direction}`];
|
|
19
|
+
const parts = [`seed_id=${JSON.stringify(input.seed_id)}`, `direction=${input.direction}`];
|
|
17
20
|
if (input.filters && Object.keys(input.filters).length > 0) {
|
|
18
21
|
parts.push(`filters=${JSON.stringify(input.filters)}`);
|
|
19
22
|
}
|
|
20
23
|
if (input.sort)
|
|
21
|
-
parts.push(`sort=${input.sort}`);
|
|
24
|
+
parts.push(`sort=${JSON.stringify(input.sort)}`);
|
|
22
25
|
return parts.join(' | ');
|
|
23
26
|
}
|
|
24
27
|
export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
@@ -26,6 +29,13 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
26
29
|
sourceUrl: 'https://github.com/cyanheads/openalex-mcp-server/blob/main/src/mcp-server/tools/definitions/citation-graph.tool.ts',
|
|
27
30
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
28
31
|
errors: [
|
|
32
|
+
{
|
|
33
|
+
reason: 'unmatched_quote_in_filter_value',
|
|
34
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
35
|
+
when: 'A filter value sent unquoted has an unmatched double quote.',
|
|
36
|
+
recovery: 'Pair double quotes used for a search phrase, or remove the stray quote.',
|
|
37
|
+
thrownBy: 'service',
|
|
38
|
+
},
|
|
29
39
|
{
|
|
30
40
|
reason: 'rate_limited',
|
|
31
41
|
code: JsonRpcErrorCode.RateLimited,
|
|
@@ -42,6 +52,14 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
42
52
|
recovery: "This server's daily OpenAlex budget is spent and refills at midnight UTC — retrying before then will not succeed.",
|
|
43
53
|
thrownBy: 'service',
|
|
44
54
|
},
|
|
55
|
+
{
|
|
56
|
+
reason: 'upstream_plan_required',
|
|
57
|
+
code: JsonRpcErrorCode.Forbidden,
|
|
58
|
+
when: '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").',
|
|
59
|
+
retryable: false,
|
|
60
|
+
recovery: 'Drop the plan-gated filter and rerun; retrying it unchanged will not succeed. To bound works by date, filter on publication_date, from_publication_date, or to_publication_date, which need no paid plan.',
|
|
61
|
+
thrownBy: 'service',
|
|
62
|
+
},
|
|
45
63
|
{
|
|
46
64
|
reason: 'upstream_timeout',
|
|
47
65
|
code: JsonRpcErrorCode.Timeout,
|
|
@@ -75,15 +93,36 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
75
93
|
{
|
|
76
94
|
reason: 'comma_in_filter_value',
|
|
77
95
|
code: JsonRpcErrorCode.InvalidParams,
|
|
78
|
-
when: 'A filter value contains a comma, which collides with the OpenAlex filter separator.',
|
|
79
|
-
recovery: 'Use `|` for OR within a filter value (e.g. "2020|2021"), or
|
|
96
|
+
when: '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.',
|
|
97
|
+
recovery: 'Use `|` for OR within a filter value (e.g. "2020|2021"), or move a phrase that contains commas into a free-text search filter such as title.search or raw_affiliation_strings.search.',
|
|
98
|
+
thrownBy: 'service',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
reason: 'invalid_country_code',
|
|
102
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
103
|
+
when: '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").',
|
|
104
|
+
recovery: 'Pass the country as an ISO 3166-1 alpha-2 code such as DE, US, or GB (an alpha-3 code, numeric code, or English name is converted), or null for works with no country.',
|
|
105
|
+
thrownBy: 'service',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
reason: 'mixed_and_or_in_filter_value',
|
|
109
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
110
|
+
when: '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.',
|
|
111
|
+
recovery: 'Keep "|" and the AND operator in separate filter keys: OR the alternatives in this key and put the AND in a second key that reaches the same values — {"authorships.institutions.country_code": "DE|FR", "institutions.country_code": "US"} matches works with (DE or FR) and US. The filters object holds each key once, so where no second key fits, run one call per alternative instead.',
|
|
112
|
+
thrownBy: 'service',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
reason: 'quote_in_filter_value',
|
|
116
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
117
|
+
when: '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.',
|
|
118
|
+
recovery: 'Remove the double quote from the value; a phrase is matched without quoting its own text.',
|
|
80
119
|
thrownBy: 'service',
|
|
81
120
|
},
|
|
82
121
|
{
|
|
83
122
|
reason: 'upstream_invalid_params',
|
|
84
123
|
code: JsonRpcErrorCode.InvalidParams,
|
|
85
|
-
when: 'OpenAlex rejected an invalid filter or sort field name (HTTP 400).',
|
|
86
|
-
recovery: 'The upstream message names the rejected token and suggests close matches. Pass a valid OpenAlex work ID (W…), DOI, or PMID for seed_id,
|
|
124
|
+
when: 'OpenAlex rejected an invalid filter, select, or sort field name (HTTP 400).',
|
|
125
|
+
recovery: 'The upstream message names the rejected token and suggests close matches. Pass a valid OpenAlex work ID (W…), DOI, or PMID for seed_id, and browse the valid work fields with openalex_describe_fields("works", "filter") for filters or openalex_describe_fields("works", "select") for select.',
|
|
87
126
|
thrownBy: 'service',
|
|
88
127
|
},
|
|
89
128
|
{
|
|
@@ -113,6 +152,20 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
113
152
|
when: 'filters contains cites/cited_by/related_to, or an alias of one such as cited_works — the direction parameter reserves those keys.',
|
|
114
153
|
recovery: 'Remove the reserved key from filters, or restate the relationship through direction.',
|
|
115
154
|
},
|
|
155
|
+
{
|
|
156
|
+
reason: 'id_type_mismatch',
|
|
157
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
158
|
+
when: '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.',
|
|
159
|
+
recovery: "seed_id must identify a work — pass the work's OpenAlex ID (W…), DOI, or PMID. To walk the works of an author or other entity, list them first with openalex_search_entities filters.",
|
|
160
|
+
thrownBy: 'service',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
reason: 'id_dot_segment',
|
|
164
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
165
|
+
when: 'seed_id holds a `.` or `..` path segment, written plainly or percent-encoded.',
|
|
166
|
+
recovery: "Pass the work's identifier itself — its OpenAlex ID (W…), DOI, or PMID — with no relative path segments.",
|
|
167
|
+
thrownBy: 'service',
|
|
168
|
+
},
|
|
116
169
|
{
|
|
117
170
|
reason: 'entity_not_found',
|
|
118
171
|
code: JsonRpcErrorCode.NotFound,
|
|
@@ -125,14 +178,14 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
125
178
|
seed_id: z
|
|
126
179
|
.string()
|
|
127
180
|
.min(1)
|
|
128
|
-
.describe('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.'),
|
|
181
|
+
.describe('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.'),
|
|
129
182
|
direction: z
|
|
130
183
|
.enum(DIRECTIONS)
|
|
131
184
|
.describe('"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).'),
|
|
132
185
|
filters: z
|
|
133
186
|
.record(z.string(), z.string())
|
|
134
187
|
.optional()
|
|
135
|
-
.describe('Additional
|
|
188
|
+
.describe('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.'),
|
|
136
189
|
sort: z
|
|
137
190
|
.string()
|
|
138
191
|
.optional()
|
|
@@ -140,14 +193,10 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
140
193
|
select: z
|
|
141
194
|
.array(z.string())
|
|
142
195
|
.optional()
|
|
143
|
-
.describe('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`).'),
|
|
144
|
-
per_page:
|
|
145
|
-
.number()
|
|
146
|
-
.int()
|
|
147
|
-
.min(1)
|
|
148
|
-
.max(100)
|
|
196
|
+
.describe('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`).'),
|
|
197
|
+
per_page: pageSizeSchema(100)
|
|
149
198
|
.default(25)
|
|
150
|
-
.describe('Results per page
|
|
199
|
+
.describe('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`).'),
|
|
151
200
|
cursor: z
|
|
152
201
|
.string()
|
|
153
202
|
.min(1)
|
|
@@ -162,7 +211,7 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
162
211
|
.describe('Total edges from seed_id in this direction (across all pages).'),
|
|
163
212
|
per_page: z
|
|
164
213
|
.number()
|
|
165
|
-
.describe('Page size OpenAlex echoed for this request — the
|
|
214
|
+
.describe('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`).'),
|
|
166
215
|
next_cursor: z
|
|
167
216
|
.string()
|
|
168
217
|
.nullable()
|
|
@@ -180,7 +229,7 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
180
229
|
})
|
|
181
230
|
.loose()
|
|
182
231
|
.describe('A single OpenAlex work record on the citation graph. Additional fields vary by `select`.'))
|
|
183
|
-
.describe('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`.'),
|
|
232
|
+
.describe('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`.'),
|
|
184
233
|
omitted: omittedOutputSchema,
|
|
185
234
|
windows: windowsOutputSchema,
|
|
186
235
|
over_budget: overBudgetOutputSchema,
|
|
@@ -196,12 +245,12 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
196
245
|
notice: z
|
|
197
246
|
.string()
|
|
198
247
|
.optional()
|
|
199
|
-
.describe('Guidance notice. Set when no edges are returned — a first call suggests verifying the seed_id, broadening filters, or trying a different direction; a
|
|
248
|
+
.describe('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.'),
|
|
200
249
|
budget: z
|
|
201
250
|
.object({
|
|
202
251
|
costUsd: z
|
|
203
252
|
.number()
|
|
204
|
-
.describe('USD this call spent, covering both upstream requests — the seed validation lookup
|
|
253
|
+
.describe('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.'),
|
|
205
254
|
remainingUsd: z.number().describe("USD left in today's OpenAlex budget after this call."),
|
|
206
255
|
resetsInSeconds: z
|
|
207
256
|
.number()
|
|
@@ -232,6 +281,9 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
232
281
|
const resolution = upstreamKey === reserved ? '' : ` — it resolves to \`${upstreamKey}\``;
|
|
233
282
|
throw ctx.fail('reserved_filter_key', `${reserved} cannot be passed in filters${resolution}, and direction reserves cites/cited_by/related_to.`, { reservedKey: reserved, direction: input.direction });
|
|
234
283
|
}
|
|
284
|
+
// A filter value the graph search would refuse fails here, before the seed lookup's request.
|
|
285
|
+
if (input.filters)
|
|
286
|
+
buildSearchFilter('works', input.filters);
|
|
235
287
|
const service = getOpenAlexService();
|
|
236
288
|
/**
|
|
237
289
|
* Resolve any accepted seed identifier to a bare W-ID and confirm it exists. The graph
|
|
@@ -244,9 +296,10 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
244
296
|
const seedLookup = await service.search({ entityType: 'works', id: input.seed_id, select: ['id'] }, ctx);
|
|
245
297
|
const seedRecord = seedLookup.results[0];
|
|
246
298
|
if (!seedRecord?.id) {
|
|
247
|
-
throw ctx.fail('entity_not_found', `Could not resolve seed_id
|
|
299
|
+
throw ctx.fail('entity_not_found', `Could not resolve seed_id ${quoteCallerText(input.seed_id)} to an OpenAlex work ID.`, { seedId: input.seed_id });
|
|
248
300
|
}
|
|
249
301
|
const workId = seedRecord.id.replace(OPENALEX_URL_PREFIX, '');
|
|
302
|
+
const pageSize = clampPageSize(input.per_page, 100, 'openalex_get_citation_graph', ctx);
|
|
250
303
|
const mergedFilters = {
|
|
251
304
|
...(input.filters ?? {}),
|
|
252
305
|
[input.direction]: workId,
|
|
@@ -256,7 +309,7 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
256
309
|
filters: mergedFilters,
|
|
257
310
|
sort: input.sort,
|
|
258
311
|
select: input.select,
|
|
259
|
-
perPage:
|
|
312
|
+
perPage: pageSize.applied,
|
|
260
313
|
cursor: input.cursor,
|
|
261
314
|
}, ctx);
|
|
262
315
|
ctx.log.info('Citation graph fetched', {
|
|
@@ -288,10 +341,10 @@ export const getCitationGraphTool = tool('openalex_get_citation_graph', {
|
|
|
288
341
|
echo,
|
|
289
342
|
totalCount: result.meta.count,
|
|
290
343
|
totalLabel: 'Total Edges',
|
|
291
|
-
notice: joinNotices([emptyNotice, budgetNotice]),
|
|
344
|
+
notice: joinNotices([pageSize.notice, emptyNotice, budgetNotice]),
|
|
292
345
|
}),
|
|
293
346
|
});
|
|
294
|
-
const notice = joinNotices([emptyNotice, page.notice]);
|
|
347
|
+
const notice = joinNotices([pageSize.notice, emptyNotice, page.notice]);
|
|
295
348
|
if (notice)
|
|
296
349
|
ctx.enrich.notice(notice);
|
|
297
350
|
return { meta, results: page.results, ...page.disclosure };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"citation-graph.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/citation-graph.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"citation-graph.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/citation-graph.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe-fields.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/describe-fields.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"describe-fields.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/describe-fields.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAyIjD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;wCAqE7B,CAAC"}
|
|
@@ -30,7 +30,14 @@ const NON_GROUPABLE_DATE_FIELDS = new Set([
|
|
|
30
30
|
* (`concepts.id` fails on authors and groups on works). The catalog stores names only, and name
|
|
31
31
|
* shape does not predict the outcome — `summary_stats.2yr_mean_citedness` and `publication_year`
|
|
32
32
|
* group while `fwci` and sources' `first_publication_year` do not — so the sweep is the rule.
|
|
33
|
-
*
|
|
33
|
+
*
|
|
34
|
+
* The fields the 2026-10-18 catalog regeneration added were each grouped once: the lookup fields
|
|
35
|
+
* below answered "Cannot group by <field>: it is looked up from the related <entity> at query
|
|
36
|
+
* time.", and the rest grouped. The split is per field, not per prefix —
|
|
37
|
+
* `primary_location.source.listed_in` groups while `primary_location.source.is_ojs` does not, and
|
|
38
|
+
* institutions' own `geo.city` groups while works' `authorships.institutions.geo.city` does not.
|
|
39
|
+
* Probe each new field after regenerating the field catalog; the generator rewrites only the JSON,
|
|
40
|
+
* so these exclusions survive it.
|
|
34
41
|
*/
|
|
35
42
|
const GROUP_BY_REJECTED_FIELDS = {
|
|
36
43
|
works: new Set([
|
|
@@ -51,8 +58,28 @@ const GROUP_BY_REJECTED_FIELDS = {
|
|
|
51
58
|
'related_to',
|
|
52
59
|
'sustainable_development_goals.score',
|
|
53
60
|
'topics_count',
|
|
61
|
+
// looked up from a related entity at query time (2026-10-18)
|
|
62
|
+
'authorships.institutions.geo.city',
|
|
63
|
+
'authorships.institutions.geo.region',
|
|
64
|
+
'funders.country_code',
|
|
65
|
+
'primary_location.source.country_code',
|
|
66
|
+
'primary_location.source.host_organization.country_code',
|
|
67
|
+
'primary_location.source.is_global_south',
|
|
68
|
+
'primary_location.source.is_high_oa_rate',
|
|
69
|
+
'primary_location.source.is_ojs',
|
|
70
|
+
'primary_location.source.is_preprint_repository',
|
|
71
|
+
'primary_location.source.summary_stats.2yr_mean_citedness',
|
|
72
|
+
'primary_location.source.summary_stats.h_index',
|
|
73
|
+
]),
|
|
74
|
+
authors: new Set([
|
|
75
|
+
'concept.id',
|
|
76
|
+
'concepts.id',
|
|
77
|
+
'display_name',
|
|
78
|
+
'x_concepts.id',
|
|
79
|
+
// looked up from a related entity at query time (2026-10-18)
|
|
80
|
+
'last_known_institutions.geo.city',
|
|
81
|
+
'last_known_institutions.geo.region',
|
|
54
82
|
]),
|
|
55
|
-
authors: new Set(['concept.id', 'concepts.id', 'display_name', 'x_concepts.id']),
|
|
56
83
|
sources: new Set([
|
|
57
84
|
'apc_prices.price',
|
|
58
85
|
'display_name',
|
|
@@ -63,6 +90,8 @@ const GROUP_BY_REJECTED_FIELDS = {
|
|
|
63
90
|
'is_in_jstage_since_year',
|
|
64
91
|
'last_publication_year',
|
|
65
92
|
'oa_flip_year',
|
|
93
|
+
// looked up from a related entity at query time (2026-10-18)
|
|
94
|
+
'host_organization.country_code',
|
|
66
95
|
]),
|
|
67
96
|
institutions: new Set(['display_name']),
|
|
68
97
|
topics: new Set(['display_name']),
|
|
@@ -114,7 +143,7 @@ export const describeFieldsTool = tool('openalex_describe_fields', {
|
|
|
114
143
|
entity_type: z.enum(ENTITY_TYPES).describe('OpenAlex entity type to list fields for.'),
|
|
115
144
|
context: z
|
|
116
145
|
.enum(CONTEXTS)
|
|
117
|
-
.describe('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,
|
|
146
|
+
.describe('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.'),
|
|
118
147
|
query: z
|
|
119
148
|
.string()
|
|
120
149
|
.optional()
|
|
@@ -138,7 +167,8 @@ export const describeFieldsTool = tool('openalex_describe_fields', {
|
|
|
138
167
|
const pool = input.context === 'group_by'
|
|
139
168
|
? catalogPool.filter((field) => isGroupableField(input.entity_type, field))
|
|
140
169
|
: catalogPool;
|
|
141
|
-
|
|
170
|
+
// A copy: `pool` is the shared catalog the "Did you mean" suggestions also read.
|
|
171
|
+
const fields = input.query ? rankAllFields(input.query, pool) : [...pool];
|
|
142
172
|
ctx.log.info('Field catalog lookup', {
|
|
143
173
|
entityType: input.entity_type,
|
|
144
174
|
context: input.context,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe-fields.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/describe-fields.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAmB,MAAM,8BAA8B,CAAC;AAE7E,mFAAmF;AACnF,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAU,CAAC;AAG3D,+FAA+F;AAC/F,SAAS,cAAc,CAAC,OAAqB;IAC3C,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpD,CAAC;AAED,wGAAwG;AACxG,MAAM,yBAAyB,GAAwB,IAAI,GAAG,CAAC;IAC7D,kBAAkB;IAClB,cAAc;IACd,cAAc;CACf,CAAC,CAAC;AAEH
|
|
1
|
+
{"version":3,"file":"describe-fields.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/describe-fields.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,6 +29,17 @@ export declare const resolveNameTool: import("@cyanheads/mcp-ts-core").ToolDefin
|
|
|
29
29
|
hint: z.ZodNullable<z.ZodString>;
|
|
30
30
|
}, z.core.$strip>>;
|
|
31
31
|
}, z.core.$strip>, readonly [{
|
|
32
|
+
readonly reason: "unmatched_quote_in_filter_value";
|
|
33
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
34
|
+
readonly when: "A filter value sent unquoted has an unmatched double quote.";
|
|
35
|
+
readonly recovery: "Pair double quotes used for a search phrase, or remove the stray quote.";
|
|
36
|
+
readonly thrownBy: "service";
|
|
37
|
+
}, {
|
|
38
|
+
readonly reason: "filters_without_entity_type";
|
|
39
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
40
|
+
readonly when: "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.";
|
|
41
|
+
readonly recovery: "Add entity_type naming the type the filter fields belong to, or drop `filters` to search every entity type by name.";
|
|
42
|
+
}, {
|
|
32
43
|
readonly reason: "rate_limited";
|
|
33
44
|
readonly code: JsonRpcErrorCode.RateLimited;
|
|
34
45
|
readonly when: "OpenAlex throttled the autocomplete request for exceeding its per-second ceiling (HTTP 429).";
|
|
@@ -42,6 +53,13 @@ export declare const resolveNameTool: import("@cyanheads/mcp-ts-core").ToolDefin
|
|
|
42
53
|
readonly retryable: false;
|
|
43
54
|
readonly recovery: "This server's daily OpenAlex budget is spent and refills at midnight UTC — retrying before then will not succeed.";
|
|
44
55
|
readonly thrownBy: "service";
|
|
56
|
+
}, {
|
|
57
|
+
readonly reason: "upstream_plan_required";
|
|
58
|
+
readonly code: JsonRpcErrorCode.Forbidden;
|
|
59
|
+
readonly when: "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\").";
|
|
60
|
+
readonly retryable: false;
|
|
61
|
+
readonly recovery: "Drop the plan-gated filter and rerun; retrying it unchanged will not succeed. To bound works by date, filter on publication_date, from_publication_date, or to_publication_date, which need no paid plan.";
|
|
62
|
+
readonly thrownBy: "service";
|
|
45
63
|
}, {
|
|
46
64
|
readonly reason: "upstream_timeout";
|
|
47
65
|
readonly code: JsonRpcErrorCode.Timeout;
|
|
@@ -68,12 +86,36 @@ export declare const resolveNameTool: import("@cyanheads/mcp-ts-core").ToolDefin
|
|
|
68
86
|
readonly when: "OpenAlex denied access to autocomplete (HTTP 403).";
|
|
69
87
|
readonly recovery: "Confirm the API key has access to autocomplete, then retry the request.";
|
|
70
88
|
readonly thrownBy: "service";
|
|
89
|
+
}, {
|
|
90
|
+
readonly reason: "id_dot_segment";
|
|
91
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
92
|
+
readonly when: "An identifier `query` holds a `.` or `..` path segment, written plainly or percent-encoded.";
|
|
93
|
+
readonly recovery: "Pass the identifier itself — an OpenAlex ID, DOI, ORCID, ROR, PMID, or ISSN — with no relative path segments, or pass a name to search for instead.";
|
|
94
|
+
readonly thrownBy: "service";
|
|
71
95
|
}, {
|
|
72
96
|
readonly reason: "comma_in_filter_value";
|
|
73
97
|
readonly code: JsonRpcErrorCode.InvalidParams;
|
|
74
|
-
readonly when: "A `filters` value contains a comma, which collides with the OpenAlex filter separator.";
|
|
98
|
+
readonly when: "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.";
|
|
75
99
|
readonly recovery: "Use `|` for OR within a filter value (e.g. \"2020|2021\"), or move a free-text phrase containing commas into the `query` parameter.";
|
|
76
100
|
readonly thrownBy: "service";
|
|
101
|
+
}, {
|
|
102
|
+
readonly reason: "invalid_country_code";
|
|
103
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
104
|
+
readonly when: "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\").";
|
|
105
|
+
readonly recovery: "Pass the country as an ISO 3166-1 alpha-2 code such as DE, US, or GB (an alpha-3 code, numeric code, or English name is converted), or null for records with no country.";
|
|
106
|
+
readonly thrownBy: "service";
|
|
107
|
+
}, {
|
|
108
|
+
readonly reason: "mixed_and_or_in_filter_value";
|
|
109
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
110
|
+
readonly when: "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.";
|
|
111
|
+
readonly recovery: "Keep \"|\" and the AND operator in separate filter keys: OR the alternatives in this key and put the AND in a second key that reaches the same values — on works, {\"authorships.institutions.country_code\": \"DE|FR\", \"institutions.country_code\": \"US\"} matches (DE or FR) and US. The filters object holds each key once, so where no second key fits, run one call per alternative instead.";
|
|
112
|
+
readonly thrownBy: "service";
|
|
113
|
+
}, {
|
|
114
|
+
readonly reason: "quote_in_filter_value";
|
|
115
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
116
|
+
readonly when: "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.";
|
|
117
|
+
readonly recovery: "Remove the double quote from the value; a phrase is matched without quoting its own text.";
|
|
118
|
+
readonly thrownBy: "service";
|
|
77
119
|
}, {
|
|
78
120
|
readonly reason: "upstream_invalid_params";
|
|
79
121
|
readonly code: JsonRpcErrorCode.InvalidParams;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-name.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/resolve-name.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve-name.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/resolve-name.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAqFjE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+Y1B,CAAC"}
|