@cyanheads/pubmed-mcp-server 2.10.16 → 2.10.18
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 +2 -2
- package/CLAUDE.md +2 -2
- package/README.md +7 -5
- package/changelog/2.10.x/2.10.17.md +19 -0
- package/changelog/2.10.x/2.10.18.md +14 -0
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +7 -3
- package/dist/config/server-config.js.map +1 -1
- package/dist/mcp-server/tools/definitions/_text.d.ts +20 -3
- package/dist/mcp-server/tools/definitions/_text.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/_text.js +35 -3
- package/dist/mcp-server/tools/definitions/_text.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.d.ts +23 -31
- package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.js +349 -130
- package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/find-related.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/find-related.tool.js +22 -7
- package/dist/mcp-server/tools/definitions/find-related.tool.js.map +1 -1
- package/dist/services/error-contracts.d.ts +5 -3
- package/dist/services/error-contracts.d.ts.map +1 -1
- package/dist/services/error-contracts.js +5 -3
- package/dist/services/error-contracts.js.map +1 -1
- package/dist/services/europe-pmc/europe-pmc-service.d.ts +18 -12
- package/dist/services/europe-pmc/europe-pmc-service.d.ts.map +1 -1
- package/dist/services/europe-pmc/europe-pmc-service.js +82 -67
- package/dist/services/europe-pmc/europe-pmc-service.js.map +1 -1
- package/dist/services/europe-pmc/request-queue.d.ts +11 -27
- package/dist/services/europe-pmc/request-queue.d.ts.map +1 -1
- package/dist/services/europe-pmc/request-queue.js +17 -104
- package/dist/services/europe-pmc/request-queue.js.map +1 -1
- package/dist/services/ncbi/parsing/pmc-article-parser.d.ts +8 -0
- package/dist/services/ncbi/parsing/pmc-article-parser.d.ts.map +1 -1
- package/dist/services/ncbi/parsing/pmc-article-parser.js +159 -16
- package/dist/services/ncbi/parsing/pmc-article-parser.js.map +1 -1
- package/dist/services/openalex/openalex-service.d.ts +11 -1
- package/dist/services/openalex/openalex-service.d.ts.map +1 -1
- package/dist/services/openalex/openalex-service.js +19 -10
- package/dist/services/openalex/openalex-service.js.map +1 -1
- package/dist/services/unpaywall/types.d.ts +16 -2
- package/dist/services/unpaywall/types.d.ts.map +1 -1
- package/dist/services/unpaywall/unpaywall-service.d.ts +4 -3
- package/dist/services/unpaywall/unpaywall-service.d.ts.map +1 -1
- package/dist/services/unpaywall/unpaywall-service.js +15 -4
- package/dist/services/unpaywall/unpaywall-service.js.map +1 -1
- package/package.json +1 -1
- package/server.json +3 -3
package/AGENTS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/pubmed-mcp-server
|
|
4
|
-
**Version:** 2.10.
|
|
4
|
+
**Version:** 2.10.18
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.6`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
|
|
@@ -115,7 +115,7 @@ const ServerConfigSchema = z.object({
|
|
|
115
115
|
apiKey: z.string().optional().describe('NCBI API key'),
|
|
116
116
|
toolIdentifier: z.string().default('pubmed-mcp-server').describe('NCBI tool identifier'),
|
|
117
117
|
adminEmail: z.email().optional().describe('Admin contact email'),
|
|
118
|
-
requestDelayMs: z.coerce.number().min(50).max(5000).default(
|
|
118
|
+
requestDelayMs: z.coerce.number().min(50).max(5000).default(400).describe('Request delay in ms'),
|
|
119
119
|
maxRetries: z.coerce.number().min(0).max(10).default(6).describe('Max retry attempts'),
|
|
120
120
|
timeoutMs: z.coerce.number().min(1000).max(120000).default(30000).describe('Request timeout in ms'),
|
|
121
121
|
});
|
package/CLAUDE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/pubmed-mcp-server
|
|
4
|
-
**Version:** 2.10.
|
|
4
|
+
**Version:** 2.10.18
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.6`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
|
|
@@ -115,7 +115,7 @@ const ServerConfigSchema = z.object({
|
|
|
115
115
|
apiKey: z.string().optional().describe('NCBI API key'),
|
|
116
116
|
toolIdentifier: z.string().default('pubmed-mcp-server').describe('NCBI tool identifier'),
|
|
117
117
|
adminEmail: z.email().optional().describe('Admin contact email'),
|
|
118
|
-
requestDelayMs: z.coerce.number().min(50).max(5000).default(
|
|
118
|
+
requestDelayMs: z.coerce.number().min(50).max(5000).default(400).describe('Request delay in ms'),
|
|
119
119
|
maxRetries: z.coerce.number().min(0).max(10).default(6).describe('Max retry attempts'),
|
|
120
120
|
timeoutMs: z.coerce.number().min(1000).max(120000).default(30000).describe('Request timeout in ms'),
|
|
121
121
|
});
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/pubmed-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/pubmed-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
13
13
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
@@ -89,12 +89,14 @@ The biomedical literature via NCBI's E-utilities, PubMed Central, and Europe PMC
|
|
|
89
89
|
|
|
90
90
|
### `pubmed_fetch_fulltext` <sub>tool</sub>
|
|
91
91
|
|
|
92
|
-
- Exactly one of `pmcids`, `pmids`, or `dois` (one id per element), up to 10 per request; a zero-padded PMID resolves as the
|
|
92
|
+
- Exactly one of `pmcids`, `pmids`, or `dois` (one id per element), up to 10 per request; a zero-padded PMID or PMC ID resolves as the ID it spells, DOIs match case-insensitively, and PMC IDs match with or without the `PMC` prefix in any case. Each record is fetched once however many spellings name it; `unavailable[].id` keeps your PMID or DOI spelling, and reports a PMC ID as `PMC<digits>`
|
|
93
93
|
- Three-tier chain: NCBI PMC EFetch → Europe PMC `fullTextXML` (`EUROPEPMC_ENABLED`, default on) → Unpaywall (needs `UNPAYWALL_EMAIL`); `viaSource` names which tier served each article
|
|
94
94
|
- Preprints, patents, and Agricola records have metadata via `pubmed_europepmc_search` but no full text through this chain — Europe PMC's `fullTextXML` is PMC-keyed
|
|
95
|
-
- `source: "pmc"` returns structured sections plus `tables[]` (cells, caption, label, footnotes) and `assets[]` (figures and supplementary material, with `[Figure: <label>]` markers left in the body); `source: "unpaywall"` returns a best-effort body with `contentFormat` (`html-markdown` / `pdf-text`)
|
|
95
|
+
- `source: "pmc"` returns structured sections plus `tables[]` (cells, caption, label, footnotes) and `assets[]` (figures and supplementary material, with `[Figure: <label>]` markers left in the body, and the file pointer read through `<alternatives>` when a figure offers several formats); `source: "unpaywall"` returns a best-effort body with `contentFormat` (`html-markdown` / `pdf-text`), a `title` from Unpaywall's record (else the Europe PMC record, else the HTML page), and `journalName` / `year` when Unpaywall has them
|
|
96
|
+
- A titled list, definition list, or boxed text that sits in the body outside any section, or is the only content of an untitled section, such as an abbreviations list, becomes a section under its own title, and a figure or table inside it names that section; a section with no title is headed `untitled section`, the same name the `truncation` ledger gives it, and section titles in headings and ledger lines are Markdown-escaped
|
|
96
97
|
- Unavailable entries carry a typed `reason` (`not-found`, `no-doi`, `doi-lookup-failed`, `no-oa`, `service-error`, …), `idType`, `triedTiers` (per-tier outcome in execution order), and `unqueriedTiers` when an unconfigured tier could have served the id
|
|
97
|
-
- Filters and budgets: `sections` (case-insensitive title match), `maxSections`, `includeTables`, `includeAssets`, `maxCharacters`, `maxCharactersPerSection`, `overflowMode` (`truncate` / `outline`), and `maxResponseCharacters`, which defers whole articles past the ceiling to `deferred.ids`; a `truncation` object reports what was shortened or omitted
|
|
98
|
+
- Filters and budgets: `sections` (case-insensitive title match), `maxSections`, `includeTables`, `includeAssets`, `maxCharacters`, `maxCharactersPerSection`, `overflowMode` (`truncate` / `outline`), and `maxResponseCharacters`, which defers whole articles past the ceiling to `deferred.ids`; a `truncation` object reports what was shortened or omitted, per section and subsection
|
|
99
|
+
- A budget cut ends at a word boundary; `truncate` drops every section and subsection past the cut, while `outline` keeps each heading and marks one the budget left empty
|
|
98
100
|
|
|
99
101
|
---
|
|
100
102
|
|
|
@@ -321,7 +323,7 @@ Key environment variables:
|
|
|
321
323
|
| `STORAGE_PROVIDER_TYPE` | Storage backend: `in-memory`, `filesystem`, `supabase`, `cloudflare-kv/r2/d1` | `in-memory` |
|
|
322
324
|
| `NCBI_API_KEY` | NCBI API key for higher rate limits (10 req/s vs 3 req/s) | none |
|
|
323
325
|
| `NCBI_ADMIN_EMAIL` | Contact email sent with NCBI requests (recommended by NCBI) | none |
|
|
324
|
-
| `NCBI_REQUEST_DELAY_MS` | Minimum gap between NCBI request starts in ms |
|
|
326
|
+
| `NCBI_REQUEST_DELAY_MS` | Minimum gap between NCBI request starts in ms | 400 (100 with key) |
|
|
325
327
|
| `NCBI_MAX_CONCURRENT` | Max concurrent in-flight NCBI requests | `8` |
|
|
326
328
|
| `NCBI_MAX_RETRIES` | Retry attempts for failed NCBI requests | 6 |
|
|
327
329
|
| `NCBI_TIMEOUT_MS` | Per-request HTTP timeout in ms | `30000` |
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Fixes pubmed_fetch_fulltext body parsing (alternatives figures, titled body-level blocks), word-boundary truncation with per-subsection accounting, Unpaywall title/journal/year, and case-insensitive DOI and zero-padded PMC ID matching."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 2.10.17 — 2026-09-22
|
|
8
|
+
|
|
9
|
+
## Fixed
|
|
10
|
+
|
|
11
|
+
- **`pubmed_fetch_fulltext` reads a figure's or supplementary file's pointer from `<alternatives>`** when it has no direct `<graphic>`/`<media>`, preferring the rendering whose `specific-use` names the web, else the first. Its `href`, and a label or caption hung on that pointer, are no longer lost. [#142](https://github.com/cyanheads/pubmed-mcp-server/issues/142)
|
|
12
|
+
- **Character-budget cuts end at the last word boundary inside the allowance**, in sections and Unpaywall bodies alike; a single token longer than the allowance is still cut at it. In `truncate` mode every subsection past the cut is dropped and counted in `omittedSections`, where only whole top-level sections were before; `outline` mode keeps those headings and marks them in `content[]`. The `truncation` ledger lists a shortened section's `subsections` with their own accounting, and each entry carries its `label`. [#143](https://github.com/cyanheads/pubmed-mcp-server/issues/143)
|
|
13
|
+
- **Unpaywall articles carry a `title`**, from Unpaywall's own DOI record, else the Europe PMC record the chain searched, else — for HTML content only — the page's own title, **plus `journalName` and `year`** when Unpaywall's record has them. [#144](https://github.com/cyanheads/pubmed-mcp-server/issues/144)
|
|
14
|
+
- **A titled list, definition list, or boxed text sitting outside any `<sec>`, or alone inside an untitled one, becomes a section under its own title** instead of an untitled block with no heading to separate it from its neighbors. A figure or table inside a titled box names that section as its `sectionTitle`, so a `sections` filter on the box keeps them. [#148](https://github.com/cyanheads/pubmed-mcp-server/issues/148), [#169](https://github.com/cyanheads/pubmed-mcp-server/issues/169)
|
|
15
|
+
- **Every section gets a heading in `content[]`**: an untitled one is headed `untitled section` and a label-only one by its label, the same name its truncation-ledger line uses, and section titles are Markdown-escaped in both places. [#148](https://github.com/cyanheads/pubmed-mcp-server/issues/148), [#169](https://github.com/cyanheads/pubmed-mcp-server/issues/169)
|
|
16
|
+
- **A `<boxed-text>` caption's title and paragraph render as separate lines** instead of running together. [#169](https://github.com/cyanheads/pubmed-mcp-server/issues/169)
|
|
17
|
+
- **DOI input matches case-insensitively**: every casing of one DOI runs the chain once, and `unavailable[]` reports each casing as submitted. Two different DOIs the ID Converter places on one PMC record also share one chain, and that record is fetched once. [#166](https://github.com/cyanheads/pubmed-mcp-server/issues/166)
|
|
18
|
+
- **`errors[]` no longer declares Unpaywall or Europe PMC failure reasons the handler never throws** — both are folded into each id's `triedTiers` instead of propagated. [#168](https://github.com/cyanheads/pubmed-mcp-server/issues/168)
|
|
19
|
+
- **A zero-padded PMC ID (`PMC0123`) resolves as the record it spells** instead of being returned and reported unavailable in the same response. Every spelling of one PMC ID — with or without the `PMC` prefix, in any case, zero-padded or not — is fetched once and reported in `PMC<digits>` form. [#170](https://github.com/cyanheads/pubmed-mcp-server/issues/170)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Moves Europe PMC's request queue onto the framework pacer with retries outside it, so a backoff no longer holds a concurrency slot and an upstream Retry-After is honored; also widens the unkeyed NCBI request delay to 400ms and limits openalex_unreachable to exhausted ServiceUnavailable errors."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 2.10.18 — 2026-09-22
|
|
8
|
+
|
|
9
|
+
## Fixed
|
|
10
|
+
|
|
11
|
+
- **Europe PMC's request queue moves onto the framework pacer, with retries outside it.** A backoff no longer holds one of the four concurrency slots, and every attempt waits out the start gap from the last request any caller started. An upstream `Retry-After` now sets the retry wait; one over the 30 s backoff cap fails without another attempt, `retryAfter` included. [#163](https://github.com/cyanheads/pubmed-mcp-server/issues/163)
|
|
12
|
+
- **The unkeyed `NCBI_REQUEST_DELAY_MS` default rises from 334ms to 400ms.** 334ms sat exactly at NCBI's 3 req/s ceiling, so small bursts drew 429s that closed the request queue's cooldown gate. The keyed 100ms default and an explicit override still apply. [#162](https://github.com/cyanheads/pubmed-mcp-server/issues/162)
|
|
13
|
+
- **OpenAlex stamps `openalex_unreachable` only on an exhausted `ServiceUnavailable`.** An exhausted `Timeout` or `RateLimited` keeps its own code with no reason, and every exhausted error keeps its upstream `retryAfter`. [#160](https://github.com/cyanheads/pubmed-mcp-server/issues/160)
|
|
14
|
+
- **`pubmed_find_related` names a provider failure that carries no reason by its code** — `rate_limited` or `timed_out`, not `unclassified_error` — in the coverage summary and the all-providers-failed `data.attempted`. The coverage summary takes such a failure's retryability from its own `retryable` flag. [#160](https://github.com/cyanheads/pubmed-mcp-server/issues/160)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;iBA8DtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,
|
|
1
|
+
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;iBA8DtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,CAmC9C"}
|
|
@@ -10,7 +10,7 @@ const ServerConfigSchema = z.object({
|
|
|
10
10
|
apiKey: z.string().optional().describe('NCBI API key'),
|
|
11
11
|
toolIdentifier: z.string().default('pubmed-mcp-server').describe('NCBI tool identifier'),
|
|
12
12
|
adminEmail: z.email().optional().describe('Admin contact email'),
|
|
13
|
-
requestDelayMs: z.coerce.number().min(50).max(5000).default(
|
|
13
|
+
requestDelayMs: z.coerce.number().min(50).max(5000).default(400).describe('Request delay in ms'),
|
|
14
14
|
maxConcurrent: z.coerce
|
|
15
15
|
.number()
|
|
16
16
|
.min(1)
|
|
@@ -89,9 +89,13 @@ export function getServerConfig() {
|
|
|
89
89
|
});
|
|
90
90
|
/**
|
|
91
91
|
* An API key raises NCBI's rate ceiling from ~3 req/s to ~10 req/s. If the
|
|
92
|
-
* operator hasn't explicitly overridden the delay, tighten from the
|
|
93
|
-
*
|
|
92
|
+
* operator hasn't explicitly overridden the delay, tighten from the 400ms
|
|
93
|
+
* keyless default to 100ms when a key is present. A set-but-blank delay counts
|
|
94
94
|
* as not overridden, matching how `parseEnvConfig` reads it.
|
|
95
|
+
*
|
|
96
|
+
* The keyless default sits above the 334ms that 3 req/s works out to, leaving
|
|
97
|
+
* margin for arrival jitter: spaced at exactly the ceiling, a small burst of
|
|
98
|
+
* concurrent calls draws 429s.
|
|
95
99
|
*/
|
|
96
100
|
_config =
|
|
97
101
|
parsed.apiKey && !process.env.NCBI_REQUEST_DELAY_MS?.trim()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Text helpers shared by the tool definitions: the surrogate-safe
|
|
3
|
-
* character cut
|
|
4
|
-
* Markdown escapes applied to upstream strings
|
|
5
|
-
* one for an inline position, one for a table
|
|
3
|
+
* character cut and the word-boundary cut built on it, which bound returned text
|
|
4
|
+
* to a budget, and the render-time Markdown escapes applied to upstream strings
|
|
5
|
+
* interpolated into `format()` — one for an inline position, one for a table
|
|
6
|
+
* cell.
|
|
6
7
|
* @module src/mcp-server/tools/definitions/_text
|
|
7
8
|
*/
|
|
8
9
|
/**
|
|
@@ -21,6 +22,22 @@
|
|
|
21
22
|
* than assume the allowance was spent exactly. (#93)
|
|
22
23
|
*/
|
|
23
24
|
export declare function sliceCodeUnits(text: string, limit: number): string;
|
|
25
|
+
/**
|
|
26
|
+
* Take at most `limit` UTF-16 code units from `text`, ending at the last word
|
|
27
|
+
* boundary inside the allowance rather than partway through a word.
|
|
28
|
+
*
|
|
29
|
+
* The cut is {@link sliceCodeUnits}' cut, backed off past the partial word it
|
|
30
|
+
* would end on — unless the character after it is whitespace, in which case
|
|
31
|
+
* the last word is already whole — with the whitespace before that word
|
|
32
|
+
* trimmed. A cut is therefore never mid-word and never ends in whitespace.
|
|
33
|
+
* `limit` stays a ceiling: the result can come back several units short of it,
|
|
34
|
+
* so callers reporting character counts measure the returned string. (#143)
|
|
35
|
+
*
|
|
36
|
+
* An allowance holding no boundary at all — one token longer than the
|
|
37
|
+
* allowance, such as a sequence or a URL — is cut at the allowance instead:
|
|
38
|
+
* backing off would return nothing, dropping a field that has text to give.
|
|
39
|
+
*/
|
|
40
|
+
export declare function sliceAtWordBoundary(text: string, limit: number): string;
|
|
24
41
|
/**
|
|
25
42
|
* Escape the Markdown-significant characters in an upstream string that is
|
|
26
43
|
* about to be interpolated *inline* into a `format()` line — a `### `/`#### `
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_text.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/_text.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"_text.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/_text.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlE;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUvE;AA2CD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAazD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5D"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Text helpers shared by the tool definitions: the surrogate-safe
|
|
3
|
-
* character cut
|
|
4
|
-
* Markdown escapes applied to upstream strings
|
|
5
|
-
* one for an inline position, one for a table
|
|
3
|
+
* character cut and the word-boundary cut built on it, which bound returned text
|
|
4
|
+
* to a budget, and the render-time Markdown escapes applied to upstream strings
|
|
5
|
+
* interpolated into `format()` — one for an inline position, one for a table
|
|
6
|
+
* cell.
|
|
6
7
|
* @module src/mcp-server/tools/definitions/_text
|
|
7
8
|
*/
|
|
8
9
|
const HIGH_SURROGATE_FIRST = 0xd800;
|
|
@@ -31,6 +32,37 @@ export function sliceCodeUnits(text, limit) {
|
|
|
31
32
|
const splitsPair = last >= HIGH_SURROGATE_FIRST && last <= HIGH_SURROGATE_LAST;
|
|
32
33
|
return text.slice(0, splitsPair ? limit - 1 : limit);
|
|
33
34
|
}
|
|
35
|
+
/** A whitespace character — the boundary a word-boundary cut backs off to. */
|
|
36
|
+
const WHITESPACE_RE = /\s/;
|
|
37
|
+
const isWhitespace = (text, index) => WHITESPACE_RE.test(text.charAt(index));
|
|
38
|
+
/**
|
|
39
|
+
* Take at most `limit` UTF-16 code units from `text`, ending at the last word
|
|
40
|
+
* boundary inside the allowance rather than partway through a word.
|
|
41
|
+
*
|
|
42
|
+
* The cut is {@link sliceCodeUnits}' cut, backed off past the partial word it
|
|
43
|
+
* would end on — unless the character after it is whitespace, in which case
|
|
44
|
+
* the last word is already whole — with the whitespace before that word
|
|
45
|
+
* trimmed. A cut is therefore never mid-word and never ends in whitespace.
|
|
46
|
+
* `limit` stays a ceiling: the result can come back several units short of it,
|
|
47
|
+
* so callers reporting character counts measure the returned string. (#143)
|
|
48
|
+
*
|
|
49
|
+
* An allowance holding no boundary at all — one token longer than the
|
|
50
|
+
* allowance, such as a sequence or a URL — is cut at the allowance instead:
|
|
51
|
+
* backing off would return nothing, dropping a field that has text to give.
|
|
52
|
+
*/
|
|
53
|
+
export function sliceAtWordBoundary(text, limit) {
|
|
54
|
+
const cut = sliceCodeUnits(text, limit);
|
|
55
|
+
if (cut.length === text.length)
|
|
56
|
+
return cut;
|
|
57
|
+
let end = cut.length;
|
|
58
|
+
if (!isWhitespace(text, end)) {
|
|
59
|
+
while (end > 0 && !isWhitespace(cut, end - 1))
|
|
60
|
+
end -= 1;
|
|
61
|
+
}
|
|
62
|
+
while (end > 0 && isWhitespace(cut, end - 1))
|
|
63
|
+
end -= 1;
|
|
64
|
+
return end > 0 ? cut.slice(0, end) : cut.trimEnd();
|
|
65
|
+
}
|
|
34
66
|
/** Any line break, including the Unicode line and paragraph separators. */
|
|
35
67
|
const LINE_BREAK_RE = /[\r\n\u2028\u2029]+/g;
|
|
36
68
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_text.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/_text.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"_text.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/_text.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,19 +3,29 @@
|
|
|
3
3
|
* three-stage chain: NCBI PMC EFetch → Europe PMC `fullTextXML` → Unpaywall.
|
|
4
4
|
* Accepts three mutually-exclusive input shapes:
|
|
5
5
|
*
|
|
6
|
-
* - `pmcids` — fetch directly by PMC ID
|
|
7
|
-
*
|
|
6
|
+
* - `pmcids` — fetch directly by PMC ID, once per record however it is
|
|
7
|
+
* spelled (`PMC123`, `pmc123`, `123`, zero-padded `PMC0123`), and reported
|
|
8
|
+
* in `PMC<digits>` form. Articles not in PMC fall through to EPMC by PMC ID,
|
|
9
|
+
* then to Unpaywall when the DOI is available.
|
|
8
10
|
* - `pmids` — resolve PMID → PMCID via PMC ID Converter, then run the chain.
|
|
9
11
|
* A zero-padded PMID runs as the PMID it spells; `unavailable[]` and
|
|
10
12
|
* `deferred.ids` report it as the caller wrote it.
|
|
11
13
|
* - `dois` — resolve DOI → PMCID via the PMC ID Converter (mirroring `pmids`),
|
|
12
14
|
* then run the chain. DOIs with no PMC counterpart fall through to EPMC
|
|
13
15
|
* search-by-DOI → fullTextXML, then Unpaywall (EPMC-only OA, preprints).
|
|
16
|
+
* DOIs are case-insensitive: every casing of one DOI runs the chain once,
|
|
17
|
+
* and `unavailable[]` reports each casing as the caller wrote it.
|
|
14
18
|
*
|
|
15
19
|
* Output uses a discriminated union on `source` (`pmc` | `unpaywall`) with an
|
|
16
20
|
* extra `viaSource` discriminator that records which layer produced the
|
|
17
21
|
* content. EPMC's JATS reuses the `pmc` schema shape because it's the same
|
|
18
|
-
* DTD; `viaSource: 'europepmc'` distinguishes it from PMC EFetch output.
|
|
22
|
+
* DTD; `viaSource: 'europepmc'` distinguishes it from PMC EFetch output. An
|
|
23
|
+
* Unpaywall article takes its title from Unpaywall's record, else the Europe
|
|
24
|
+
* PMC record the chain searched, else (HTML only) the page itself.
|
|
25
|
+
*
|
|
26
|
+
* Europe PMC and Unpaywall failures are folded into each id's `triedTiers`
|
|
27
|
+
* rather than thrown, so the declared `errors[]` covers the NCBI ID routing
|
|
28
|
+
* alone.
|
|
19
29
|
*
|
|
20
30
|
* @module src/mcp-server/tools/definitions/fetch-fulltext.tool
|
|
21
31
|
*/
|
|
@@ -137,6 +147,8 @@ export declare const fetchFulltextTool: import("@cyanheads/mcp-ts-core").ToolDef
|
|
|
137
147
|
doi: z.ZodString;
|
|
138
148
|
sourceUrl: z.ZodString;
|
|
139
149
|
title: z.ZodOptional<z.ZodString>;
|
|
150
|
+
journalName: z.ZodOptional<z.ZodString>;
|
|
151
|
+
year: z.ZodOptional<z.ZodNumber>;
|
|
140
152
|
content: z.ZodString;
|
|
141
153
|
wordCount: z.ZodOptional<z.ZodNumber>;
|
|
142
154
|
totalPages: z.ZodOptional<z.ZodNumber>;
|
|
@@ -211,9 +223,17 @@ export declare const fetchFulltextTool: import("@cyanheads/mcp-ts-core").ToolDef
|
|
|
211
223
|
returnedCharacters: z.ZodNumber;
|
|
212
224
|
sections: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
213
225
|
title: z.ZodOptional<z.ZodString>;
|
|
226
|
+
label: z.ZodOptional<z.ZodString>;
|
|
214
227
|
originalCharacters: z.ZodNumber;
|
|
215
228
|
returnedCharacters: z.ZodNumber;
|
|
216
229
|
truncated: z.ZodBoolean;
|
|
230
|
+
subsections: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
231
|
+
title: z.ZodOptional<z.ZodString>;
|
|
232
|
+
label: z.ZodOptional<z.ZodString>;
|
|
233
|
+
originalCharacters: z.ZodNumber;
|
|
234
|
+
returnedCharacters: z.ZodNumber;
|
|
235
|
+
truncated: z.ZodBoolean;
|
|
236
|
+
}, z.core.$strip>>>;
|
|
217
237
|
}, z.core.$strip>>>;
|
|
218
238
|
omittedTables: z.ZodOptional<z.ZodNumber>;
|
|
219
239
|
omittedTableNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -268,34 +288,6 @@ export declare const fetchFulltextTool: import("@cyanheads/mcp-ts-core").ToolDef
|
|
|
268
288
|
readonly recovery: 'Verify the ID exists in PubMed; the resource was not found in NCBI and retrying will not help.';
|
|
269
289
|
readonly retryable: false;
|
|
270
290
|
readonly thrownBy: 'service';
|
|
271
|
-
}, {
|
|
272
|
-
readonly reason: 'unpaywall_unreachable';
|
|
273
|
-
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
274
|
-
readonly when: 'Unpaywall was unreachable when resolving a DOI or fetching content.';
|
|
275
|
-
readonly recovery: 'Retry after a brief delay; Unpaywall was unreachable. The PMC source remains the primary path.';
|
|
276
|
-
readonly retryable: true;
|
|
277
|
-
readonly thrownBy: 'service';
|
|
278
|
-
}, {
|
|
279
|
-
readonly reason: 'europepmc_unreachable';
|
|
280
|
-
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
281
|
-
readonly when: 'Europe PMC failed on every retry attempt — unreachable, an HTTP 404 or 5xx other than a 504 timeout from its search endpoint, or an empty response with no results.';
|
|
282
|
-
readonly recovery: 'Retry after a brief delay; Europe PMC was unreachable. NCBI PMC and Unpaywall remain available.';
|
|
283
|
-
readonly retryable: true;
|
|
284
|
-
readonly thrownBy: 'service';
|
|
285
|
-
}, {
|
|
286
|
-
readonly reason: 'europepmc_invalid_response';
|
|
287
|
-
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.SerializationError;
|
|
288
|
-
readonly when: 'Europe PMC returned a body that could not be parsed (invalid JSON or XML).';
|
|
289
|
-
readonly recovery: 'Retry the request; Europe PMC returned a malformed response that could not be parsed.';
|
|
290
|
-
readonly retryable: true;
|
|
291
|
-
readonly thrownBy: 'service';
|
|
292
|
-
}, {
|
|
293
|
-
readonly reason: 'europepmc_invalid_input';
|
|
294
|
-
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
295
|
-
readonly when: 'Europe PMC rejected the request input — an error message such as an empty query, an empty response to a sort with an undocumented field or no asc/desc direction, or an empty response to a pagination cursor on every attempt.';
|
|
296
|
-
readonly recovery: 'Adjust the input — the query, the sort, or the cursorMark — before retrying; the same input will be rejected again.';
|
|
297
|
-
readonly retryable: false;
|
|
298
|
-
readonly thrownBy: 'service';
|
|
299
291
|
}], {
|
|
300
292
|
readonly notice: z.ZodOptional<z.ZodString>;
|
|
301
293
|
readonly truncated: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-fulltext.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fetch-fulltext.tool.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fetch-fulltext.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fetch-fulltext.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAsB,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAi7C/D;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB,GAAG,MAAM,CAiCT;AAID,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA66B5B,CAAC"}
|