@cyanheads/pubmed-mcp-server 2.10.17 → 2.10.19
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 +12 -14
- package/CLAUDE.md +12 -14
- package/Dockerfile +77 -36
- package/README.md +86 -109
- package/changelog/2.10.x/2.10.17.md +1 -1
- package/changelog/2.10.x/2.10.18.md +14 -0
- package/changelog/2.10.x/2.10.19.md +42 -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/resources/definitions/database-info.resource.d.ts +43 -1
- package/dist/mcp-server/resources/definitions/database-info.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/database-info.resource.js +2 -0
- package/dist/mcp-server/resources/definitions/database-info.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/_visible-text.d.ts +19 -0
- package/dist/mcp-server/tools/definitions/_visible-text.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/_visible-text.js +22 -0
- package/dist/mcp-server/tools/definitions/_visible-text.js.map +1 -0
- package/dist/mcp-server/tools/definitions/convert-ids.tool.d.ts +11 -4
- package/dist/mcp-server/tools/definitions/convert-ids.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/convert-ids.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/convert-ids.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-articles.tool.d.ts +20 -7
- package/dist/mcp-server/tools/definitions/fetch-articles.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-articles.tool.js +40 -5
- package/dist/mcp-server/tools/definitions/fetch-articles.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.d.ts +11 -4
- package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.js +18 -1
- 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 +39 -10
- package/dist/mcp-server/tools/definitions/find-related.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/format-citations.tool.d.ts +11 -4
- package/dist/mcp-server/tools/definitions/format-citations.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/lookup-citation.tool.d.ts +16 -15
- package/dist/mcp-server/tools/definitions/lookup-citation.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/lookup-citation.tool.js +40 -22
- package/dist/mcp-server/tools/definitions/lookup-citation.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/lookup-mesh.tool.d.ts +13 -6
- package/dist/mcp-server/tools/definitions/lookup-mesh.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/lookup-mesh.tool.js +8 -8
- package/dist/mcp-server/tools/definitions/lookup-mesh.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pubmed-europepmc-fetch.tool.d.ts +2 -2
- package/dist/mcp-server/tools/definitions/pubmed-europepmc-fetch.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pubmed-europepmc-fetch.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/pubmed-europepmc-fetch.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pubmed-europepmc-search.tool.d.ts +19 -5
- package/dist/mcp-server/tools/definitions/pubmed-europepmc-search.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/pubmed-europepmc-search.tool.js +37 -7
- package/dist/mcp-server/tools/definitions/pubmed-europepmc-search.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-articles.tool.d.ts +40 -18
- package/dist/mcp-server/tools/definitions/search-articles.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-articles.tool.js +193 -43
- package/dist/mcp-server/tools/definitions/search-articles.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/spell-check.tool.d.ts +13 -6
- package/dist/mcp-server/tools/definitions/spell-check.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/spell-check.tool.js +8 -8
- package/dist/mcp-server/tools/definitions/spell-check.tool.js.map +1 -1
- package/dist/services/error-contracts.d.ts +42 -71
- package/dist/services/error-contracts.d.ts.map +1 -1
- package/dist/services/error-contracts.js +43 -75
- package/dist/services/error-contracts.js.map +1 -1
- package/dist/services/europe-pmc/api-client.d.ts +8 -2
- package/dist/services/europe-pmc/api-client.d.ts.map +1 -1
- package/dist/services/europe-pmc/api-client.js +13 -8
- package/dist/services/europe-pmc/api-client.js.map +1 -1
- package/dist/services/europe-pmc/europe-pmc-service.d.ts +43 -14
- package/dist/services/europe-pmc/europe-pmc-service.d.ts.map +1 -1
- package/dist/services/europe-pmc/europe-pmc-service.js +165 -85
- 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/europe-pmc/types.d.ts +6 -1
- package/dist/services/europe-pmc/types.d.ts.map +1 -1
- package/dist/services/ncbi/api-client.d.ts.map +1 -1
- package/dist/services/ncbi/api-client.js +2 -3
- package/dist/services/ncbi/api-client.js.map +1 -1
- package/dist/services/ncbi/ncbi-service.d.ts +2 -1
- package/dist/services/ncbi/ncbi-service.d.ts.map +1 -1
- package/dist/services/ncbi/ncbi-service.js +67 -20
- package/dist/services/ncbi/ncbi-service.js.map +1 -1
- package/dist/services/ncbi/parsing/article-parser.d.ts +15 -1
- package/dist/services/ncbi/parsing/article-parser.d.ts.map +1 -1
- package/dist/services/ncbi/parsing/article-parser.js +29 -0
- package/dist/services/ncbi/parsing/article-parser.js.map +1 -1
- package/dist/services/ncbi/response-handler.d.ts.map +1 -1
- package/dist/services/ncbi/response-handler.js +22 -19
- package/dist/services/ncbi/response-handler.js.map +1 -1
- package/dist/services/ncbi/types.d.ts +33 -0
- package/dist/services/ncbi/types.d.ts.map +1 -1
- package/dist/services/openalex/api-client.d.ts.map +1 -1
- package/dist/services/openalex/api-client.js +6 -7
- package/dist/services/openalex/api-client.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 +18 -11
- package/dist/services/openalex/openalex-service.js.map +1 -1
- package/dist/services/unpaywall/unpaywall-service.d.ts.map +1 -1
- package/dist/services/unpaywall/unpaywall-service.js +1 -3
- package/dist/services/unpaywall/unpaywall-service.js.map +1 -1
- package/package.json +6 -5
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -7,9 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
|
|
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/)
|
|
10
|
+
[](./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
11
|
|
|
14
12
|
</div>
|
|
15
13
|
|
|
@@ -31,23 +29,23 @@
|
|
|
31
29
|
|
|
32
30
|
## Overview
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
Biomedical literature from PubMed, PubMed Central, and Europe PMC. Search it, fetch metadata and full text, resolve identifiers and partial citations, format references, and ground queries in MeSH vocabulary. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
|
|
35
33
|
|
|
36
34
|
### Tools
|
|
37
35
|
|
|
38
36
|
| Tool | Description |
|
|
39
37
|
|:---|:---|
|
|
40
|
-
| `pubmed_search_articles` | Search PubMed with full query syntax,
|
|
41
|
-
| `
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
| `pubmed_format_citations` |
|
|
46
|
-
| `pubmed_find_related` | Find similar articles, citing articles, or references for a
|
|
47
|
-
| `pubmed_spell_check` |
|
|
48
|
-
| `pubmed_lookup_mesh` |
|
|
49
|
-
| `pubmed_lookup_citation` | Resolve partial
|
|
50
|
-
| `pubmed_convert_ids` | Convert between DOI, PMID, and PMCID
|
|
38
|
+
| `pubmed_search_articles` | Search PubMed with full query syntax, structured filters, date ranges, and optional summaries |
|
|
39
|
+
| `pubmed_fetch_articles` | Fetch article metadata by PMID: abstract, authors, journal, MeSH terms, grants, linked retraction and correction notices |
|
|
40
|
+
| `pubmed_fetch_fulltext` | Fetch full text by PMID, PMCID, or DOI, falling back from PMC to Europe PMC to Unpaywall |
|
|
41
|
+
| `pubmed_europepmc_search` | Search Europe PMC for preprints, patents, Agricola, and open-access records PubMed doesn't carry |
|
|
42
|
+
| `pubmed_europepmc_fetch` | Fetch complete Europe PMC records, including the untruncated abstract, by `source` + `epmcId` |
|
|
43
|
+
| `pubmed_format_citations` | Format citations in APA 7th, MLA 9th, BibTeX, RIS, or Vancouver (ICMJE/NLM) |
|
|
44
|
+
| `pubmed_find_related` | Find similar articles, citing articles, or references for a PMID |
|
|
45
|
+
| `pubmed_spell_check` | Correct a misspelled PubMed query via NCBI ESpell |
|
|
46
|
+
| `pubmed_lookup_mesh` | Look up MeSH headings with tree numbers, scope notes, and entry terms |
|
|
47
|
+
| `pubmed_lookup_citation` | Resolve partial references, up to 25 at a time, to PMIDs via ECitMatch |
|
|
48
|
+
| `pubmed_convert_ids` | Convert between DOI, PMID, and PMCID via the PMC ID Converter |
|
|
51
49
|
|
|
52
50
|
### Resources
|
|
53
51
|
|
|
@@ -59,131 +57,103 @@ The biomedical literature via NCBI's E-utilities, PubMed Central, and Europe PMC
|
|
|
59
57
|
|
|
60
58
|
| Prompt | Description |
|
|
61
59
|
|:---|:---|
|
|
62
|
-
| `research_plan` | Generate a structured
|
|
60
|
+
| `research_plan` | Generate a structured four-phase biomedical research plan |
|
|
63
61
|
|
|
64
62
|
## Capability reference
|
|
65
63
|
|
|
66
64
|
### `pubmed_search_articles` <sub>tool</sub>
|
|
67
65
|
|
|
68
|
-
- Full PubMed
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
- Reports `totalCount`, stated in the header beside the page (`Returned: 3 of 2924`); echoes the original query, the fully applied PubMed query, and normalized filter metadata
|
|
73
|
-
- A query with no search term — blank, markup only, a bare field tag like `[pdat]`, or empty `()` — is rejected as `blank_query` rather than sent upstream
|
|
74
|
-
- `limit` is accepted for `maxResults`
|
|
66
|
+
- Full PubMed query syntax plus filters (author, journal, MeSH, publication type, language, species, abstract, free full text) and publication/modification/Entrez date ranges
|
|
67
|
+
- Up to 1,000 results per page and offsets up to 9,998; `summaryCount` adds briefs for up to 50 hits
|
|
68
|
+
- Reports `totalCount`, the `effectiveQuery` PubMed ran, and the `appliedFilters`
|
|
69
|
+
- Rejects blank filter values, impossible dates, and reversed date ranges before PubMed is called
|
|
75
70
|
|
|
76
71
|
---
|
|
77
72
|
|
|
78
73
|
### `pubmed_fetch_articles` <sub>tool</sub>
|
|
79
74
|
|
|
80
|
-
- Up to 200 PMIDs per call
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
- Tolerant of PubMed's inconsistent XML — structured abstracts, missing fields, varying date formats
|
|
84
|
-
- Bookshelf chapters and books are first-class: `recordType` (`journal-article` / `book-chapter` / `book`) plus a `book` object (title, publisher, editors, ISBNs, Bookshelf accession); `journalInfo` is absent on them
|
|
85
|
-
- Article-number journals report `journalInfo.elocationId` + `elocationIdType` rather than a page range
|
|
86
|
-
- Opt-in `maxResponseCharacters` keeps whole records in order until the ceiling, then defers the rest to `deferred.ids` for a follow-up call
|
|
75
|
+
- Up to 200 PMIDs per call; misses are listed in `unavailablePmids`
|
|
76
|
+
- Abstract, authors, journal, DOI, publication types, linked retraction/erratum/comment notices, and links; MeSH terms on by default, grants via `includeGrants`
|
|
77
|
+
- `recordType` separates journal articles from Bookshelf chapters and books; opt-in `maxResponseCharacters` defers overflow to `deferred.ids`
|
|
87
78
|
|
|
88
79
|
---
|
|
89
80
|
|
|
90
81
|
### `pubmed_fetch_fulltext` <sub>tool</sub>
|
|
91
82
|
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
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
|
|
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
|
|
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
|
|
83
|
+
- One of `pmcids`, `pmids`, or `dois`, up to 10 per call, tried against PMC, then Europe PMC, then Unpaywall (needs `UNPAYWALL_EMAIL`); `viaSource` names the tier that answered
|
|
84
|
+
- `source: "pmc"` returns sections, tables, and figures; `source: "unpaywall"` returns a best-effort HTML or PDF text body
|
|
85
|
+
- Misses carry a typed `reason` and `triedTiers`; `sections`, `maxCharacters`, `overflowMode`, and `maxResponseCharacters` bound the response, and `truncation` reports what was cut
|
|
100
86
|
|
|
101
87
|
---
|
|
102
88
|
|
|
103
89
|
### `pubmed_europepmc_search` <sub>tool</sub>
|
|
104
90
|
|
|
105
|
-
-
|
|
106
|
-
- Cursor pagination via `cursorMark`
|
|
107
|
-
- Hits carry `source` plus `pmid` / `pmcId` / `doi` when known; `abstractSnippet` is capped at 400 characters, with `abstractTruncated` flagging the cut
|
|
108
|
-
- `totalCount` reports the full hit count, stated in the header beside the page; `searchUrl` opens the same source-filtered query on europepmc.org
|
|
91
|
+
- Adds preprints (`PPR`), patents (`PAT`), and Agricola (`AGR`) to `MED` and `PMC`; defaults to `MED`, `PMC`, `PPR`
|
|
92
|
+
- Cursor pagination via `cursorMark` / `nextCursorMark`, up to 100 per page; abstracts arrive as 400-character snippets
|
|
109
93
|
- Not registered when `EUROPEPMC_ENABLED=false`
|
|
110
94
|
|
|
111
95
|
---
|
|
112
96
|
|
|
113
97
|
### `pubmed_europepmc_fetch` <sub>tool</sub>
|
|
114
98
|
|
|
115
|
-
-
|
|
116
|
-
- Up to 25 per call in one Europe PMC request; unresolved ids come back in `notFound` rather than failing the batch
|
|
99
|
+
- Up to 25 records per call, addressed by a search hit's `source` + `epmcId`, with the full abstract; unresolved ids land in `notFound`
|
|
117
100
|
- Not registered when `EUROPEPMC_ENABLED=false`
|
|
118
101
|
|
|
119
102
|
---
|
|
120
103
|
|
|
121
104
|
### `pubmed_format_citations` <sub>tool</sub>
|
|
122
105
|
|
|
123
|
-
-
|
|
124
|
-
- Bookshelf
|
|
125
|
-
- Hand-rolled formatters — zero dependencies, Workers-compatible
|
|
126
|
-
- Reports formatted counts and unavailable PMIDs; `ids` is accepted for `pmids`, and a zero-padded PMID resolves as the PMID it spells
|
|
106
|
+
- Up to 50 PMIDs per call, in any mix of `apa`, `mla`, `bibtex`, `ris`, and `vancouver`
|
|
107
|
+
- Bookshelf records cite as edited books; PMIDs that can't be fetched are reported as unavailable
|
|
127
108
|
|
|
128
109
|
---
|
|
129
110
|
|
|
130
111
|
### `pubmed_find_related` <sub>tool</sub>
|
|
131
112
|
|
|
132
|
-
- `similar`, `cited_by`, or `references
|
|
133
|
-
- Falls back to Europe PMC, then OpenAlex,
|
|
134
|
-
- `maxResults` up to 50 (`limit` also accepted) with offset pagination; `totalCount` reports the full match count, stated in the header beside the page
|
|
135
|
-
- A zero-padded source PMID resolves as the PMID it spells and is never listed among its own related articles
|
|
113
|
+
- `similar`, `cited_by`, or `references`, up to 50 per page with offset pagination
|
|
114
|
+
- Falls back to Europe PMC, then OpenAlex, and names the provider that answered; fails as `all_providers_failed` if none can
|
|
136
115
|
|
|
137
116
|
---
|
|
138
117
|
|
|
139
118
|
### `pubmed_spell_check` <sub>tool</sub>
|
|
140
119
|
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
- A blank or whitespace-only query is rejected rather than sent upstream
|
|
120
|
+
- Returns `original`, `corrected`, and `hasSuggestion`, fixing every misspelled token in one call
|
|
121
|
+
- Run it after a zero-hit or thin search, then retry `pubmed_search_articles` with `corrected`
|
|
144
122
|
|
|
145
123
|
---
|
|
146
124
|
|
|
147
125
|
### `pubmed_lookup_mesh` <sub>tool</sub>
|
|
148
126
|
|
|
149
|
-
-
|
|
150
|
-
- Records carry `meshId
|
|
151
|
-
- `maxResults` up to 50 (`limit` also accepted) with offset pagination via `nextOffset`; `totalCount` reports the upstream match count
|
|
127
|
+
- Descriptors by name or free-text term, with an exact heading match pinned first; up to 50 per page, continued via `nextOffset`
|
|
128
|
+
- Records carry `meshId`; `includeDetails` (default on) adds tree numbers, scope notes, and entry terms
|
|
152
129
|
|
|
153
130
|
---
|
|
154
131
|
|
|
155
132
|
### `pubmed_lookup_citation` <sub>tool</sub>
|
|
156
133
|
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
- Pipes and line breaks are rejected at the schema (ECitMatch's wire format is pipe-delimited); the free-form `key` label is exempt
|
|
160
|
-
- Explicit `matched`, `not_found`, and `ambiguous` statuses with recovery detail
|
|
134
|
+
- Up to 25 partial citations per call; journal or year is required, and volume, first page, and author sharpen the match
|
|
135
|
+
- Each comes back `matched`, `not_found`, or `ambiguous`, with recovery detail
|
|
161
136
|
|
|
162
137
|
---
|
|
163
138
|
|
|
164
139
|
### `pubmed_convert_ids` <sub>tool</sub>
|
|
165
140
|
|
|
166
|
-
- Up to 50
|
|
167
|
-
- One
|
|
168
|
-
- One success/error row per submitted element, in order, with `requestedId` exactly as sent — repeats, a bare-digit PMCID, and a DOI's casing included; a partial batch never fails as a whole
|
|
169
|
-
- A zero-padded PMID resolves as the PMID it spells
|
|
141
|
+
- Up to 50 ids per call, all of one declared `idType` (`doi`, `pmid`, `pmcid`); only PMC-indexed articles resolve
|
|
142
|
+
- One success or error row per id, in order, so a partial batch never fails
|
|
170
143
|
|
|
171
144
|
---
|
|
172
145
|
|
|
173
146
|
### `pubmed://database/info` <sub>resource</sub>
|
|
174
147
|
|
|
175
148
|
- Live EInfo call for the `pubmed` database, returned as `application/json`
|
|
176
|
-
- `
|
|
177
|
-
- No parameters
|
|
149
|
+
- `count`, `lastUpdate`, and `fields[]`, whose names are the search tags `pubmed_search_articles` accepts
|
|
178
150
|
|
|
179
151
|
---
|
|
180
152
|
|
|
181
153
|
### `research_plan` <sub>prompt</sub>
|
|
182
154
|
|
|
183
|
-
- Arguments: `title`, `goal`, `keywords`
|
|
184
|
-
- Returns
|
|
185
|
-
- The plan walks four phases — Conception & Planning, Data Collection & Processing, Analysis & Interpretation, Dissemination — with sub-steps under each
|
|
186
|
-
- `includeAgentPrompts: "true"` adds an agent-guidance block under each sub-step, several of which point at `pubmed_search_articles` and `pubmed_lookup_mesh`
|
|
155
|
+
- Arguments: `title`, `goal`, and `keywords` required; `organism` and `includeAgentPrompts` optional
|
|
156
|
+
- Returns a four-phase research plan; `includeAgentPrompts: "true"` adds an agent-guidance block under each of its nine sub-steps, two of which point at tools: the literature review names `pubmed_search_articles` and `pubmed_lookup_mesh`, and the interpretation step names `pubmed_search_articles`
|
|
187
157
|
|
|
188
158
|
## Features
|
|
189
159
|
|
|
@@ -191,16 +161,17 @@ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): s
|
|
|
191
161
|
|
|
192
162
|
PubMed-specific:
|
|
193
163
|
|
|
194
|
-
-
|
|
195
|
-
- Shared NCBI request queue
|
|
196
|
-
-
|
|
197
|
-
-
|
|
164
|
+
- NCBI E-utilities (ESearch, EFetch, ESummary, ELink, ESpell, EInfo, ECitMatch) and the PMC ID Converter, with Europe PMC, OpenAlex, and Unpaywall filling the gaps
|
|
165
|
+
- Shared NCBI request queue: paced request starts, capped concurrency, a cooldown that holds every caller after an NCBI 429, and one deadline covering queue wait and retries
|
|
166
|
+
- XML parsing built for PubMed's inconsistent records: structured abstracts, missing fields, varying date formats
|
|
167
|
+
- Forgiving identifiers: a zero-padded PMID resolves as the PMID it spells in every tool that takes one; `pubmed_fetch_fulltext` also matches DOIs case-insensitively and PMC IDs with or without the `PMC` prefix
|
|
168
|
+
- Hand-rolled citation formatters (APA, MLA, BibTeX, RIS, Vancouver) with no dependencies
|
|
198
169
|
|
|
199
170
|
Agent-friendly output:
|
|
200
171
|
|
|
201
|
-
- Provenance on every response
|
|
202
|
-
- Graceful partial failure
|
|
203
|
-
- Discriminated output contracts
|
|
172
|
+
- Provenance on every response: source labels, license fields, best-effort warnings on Unpaywall results, and effective-query echo on searches, so agents can judge what to trust
|
|
173
|
+
- Graceful partial failure: batch tools return per-item success/error rows instead of failing the request, with structured status codes and actionable next-step text
|
|
174
|
+
- Discriminated output contracts: `source: "pmc" | "unpaywall"`, typed `unavailable` reasons, `viaSource` and `triedTiers` fields, so callers branch on data, not string parsing
|
|
204
175
|
|
|
205
176
|
## Getting started
|
|
206
177
|
|
|
@@ -282,8 +253,8 @@ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
|
|
|
282
253
|
|
|
283
254
|
### Prerequisites
|
|
284
255
|
|
|
285
|
-
- [Bun v1.4.0](https://bun.sh/) or higher.
|
|
286
|
-
- Optional: [NCBI API key](https://www.ncbi.nlm.nih.gov/account/settings/)
|
|
256
|
+
- [Bun v1.4.0](https://bun.sh/) or higher (or Node.js v24+).
|
|
257
|
+
- Optional: an [NCBI API key](https://www.ncbi.nlm.nih.gov/account/settings/) raises the rate limit from 3 to 10 requests per second.
|
|
287
258
|
|
|
288
259
|
### Installation
|
|
289
260
|
|
|
@@ -305,37 +276,41 @@ cd pubmed-mcp-server
|
|
|
305
276
|
bun install
|
|
306
277
|
```
|
|
307
278
|
|
|
308
|
-
|
|
279
|
+
4. **Configure environment:**
|
|
309
280
|
|
|
310
|
-
|
|
281
|
+
```sh
|
|
282
|
+
cp .env.example .env
|
|
283
|
+
# edit .env and set NCBI_API_KEY, NCBI_ADMIN_EMAIL, and UNPAYWALL_EMAIL as needed
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Configuration
|
|
311
287
|
|
|
312
288
|
| Variable | Description | Default |
|
|
313
289
|
|:---|:---|:---|
|
|
314
|
-
| `
|
|
315
|
-
| `
|
|
316
|
-
| `
|
|
317
|
-
| `
|
|
318
|
-
| `
|
|
319
|
-
| `
|
|
320
|
-
| `
|
|
321
|
-
| `
|
|
322
|
-
| `
|
|
323
|
-
| `
|
|
324
|
-
| `
|
|
325
|
-
| `
|
|
326
|
-
| `
|
|
327
|
-
| `
|
|
328
|
-
| `
|
|
329
|
-
| `
|
|
330
|
-
| `
|
|
331
|
-
| `
|
|
332
|
-
| `
|
|
333
|
-
| `
|
|
334
|
-
| `
|
|
335
|
-
| `
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
| `OTEL_ENABLED` | Enable OpenTelemetry | `false` |
|
|
290
|
+
| `NCBI_API_KEY` | NCBI API key; raises the rate limit from 3 to 10 req/s. | none |
|
|
291
|
+
| `NCBI_ADMIN_EMAIL` | Contact email sent with NCBI requests, as NCBI recommends. | none |
|
|
292
|
+
| `NCBI_REQUEST_DELAY_MS` | Minimum gap between NCBI request starts, in ms. | `400` (`100` with a key) |
|
|
293
|
+
| `NCBI_MAX_CONCURRENT` | Max concurrent in-flight NCBI requests. | `8` |
|
|
294
|
+
| `NCBI_MAX_RETRIES` | Retry attempts for failed NCBI requests. | `6` |
|
|
295
|
+
| `NCBI_TIMEOUT_MS` | Per-request HTTP timeout, in ms. | `30000` |
|
|
296
|
+
| `NCBI_TOTAL_DEADLINE_MS` | Deadline for one NCBI call across queue wait, retries, and backoff, in ms. A call that can't start in time is rejected at once. | `60000` |
|
|
297
|
+
| `UNPAYWALL_EMAIL` | Contact email for Unpaywall. Setting it enables the Unpaywall tier of `pubmed_fetch_fulltext` for non-PMC DOIs. | none |
|
|
298
|
+
| `UNPAYWALL_TIMEOUT_MS` | Per-request timeout for Unpaywall lookups and content fetches, in ms. | `20000` |
|
|
299
|
+
| `EUROPEPMC_ENABLED` | Set `false` to disable every Europe PMC call: both Europe PMC tools go unregistered, `pubmed_fetch_fulltext` skips that tier, and `pubmed_find_related` skips that fallback. | `true` |
|
|
300
|
+
| `EUROPEPMC_EMAIL` | Optional contact email sent with Europe PMC requests. | none |
|
|
301
|
+
| `EUROPEPMC_REQUEST_DELAY_MS` | Minimum gap between Europe PMC request starts, in ms. | `200` |
|
|
302
|
+
| `EUROPEPMC_MAX_RETRIES` | Retry attempts for failed Europe PMC requests. | `3` |
|
|
303
|
+
| `EUROPEPMC_TIMEOUT_MS` | Per-request timeout for Europe PMC calls, in ms. | `20000` |
|
|
304
|
+
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
305
|
+
| `MCP_HTTP_PORT` | HTTP server port. | `3010` |
|
|
306
|
+
| `MCP_SESSION_MODE` | HTTP session mode: `stateless`, `stateful`, or `auto`. | `stateless` |
|
|
307
|
+
| `MCP_AUTH_MODE` | Authentication: `none`, `jwt`, or `oauth`. | `none` |
|
|
308
|
+
| `MCP_LOG_LEVEL` | Log level (`debug`, `info`, `warning`, `error`, etc.). | `info` |
|
|
309
|
+
| `LOGS_DIR` | Directory for log files (Node.js only). | `<app-root>/logs` |
|
|
310
|
+
| `STORAGE_PROVIDER_TYPE` | Storage backend: `in-memory`, `filesystem`, `supabase`, `cloudflare-kv/r2/d1`. | `in-memory` |
|
|
311
|
+
| `OTEL_ENABLED` | Enable [OpenTelemetry](https://github.com/cyanheads/mcp-ts-core/tree/main/docs/telemetry). | `false` |
|
|
312
|
+
|
|
313
|
+
See [`.env.example`](./.env.example) for every server setting and the common framework overrides.
|
|
339
314
|
|
|
340
315
|
## Running the server
|
|
341
316
|
|
|
@@ -369,6 +344,7 @@ Key environment variables:
|
|
|
369
344
|
| `src/services/ncbi` | NCBI E-utilities service layer — API client, queue, parser, formatter. |
|
|
370
345
|
| `src/services/europe-pmc` | Europe PMC service — search + `fullTextXML` JATS retrieval. Reuses the NCBI JATS parser. |
|
|
371
346
|
| `src/services/unpaywall` | Unpaywall service — DOI → OA location resolution and content fetch (HTML/PDF). |
|
|
347
|
+
| `src/services/openalex` | OpenAlex service — last-resort provider for `pubmed_find_related`. |
|
|
372
348
|
| `src/config` | Server-specific environment variable parsing and validation with Zod. |
|
|
373
349
|
| `tests/` | Unit and integration tests, mirroring the `src/` structure. |
|
|
374
350
|
|
|
@@ -378,7 +354,8 @@ See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rule
|
|
|
378
354
|
|
|
379
355
|
- Handlers throw, framework catches — no `try/catch` in tool logic
|
|
380
356
|
- Use `ctx.log` for logging, `ctx.state` for storage
|
|
381
|
-
- Register new tools and resources in the `createApp()` arrays
|
|
357
|
+
- Register new tools and resources in the `createApp()` arrays in `src/index.ts`
|
|
358
|
+
- Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
|
|
382
359
|
|
|
383
360
|
## Contributing
|
|
384
361
|
|
|
@@ -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)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "pubmed_fetch_articles returns the retraction, erratum, and comment notices NCBI links to a record, and the search tools reject blank queries, filters, and cursors and impossible or reversed date ranges instead of returning unfiltered or falsely empty results."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 2.10.19 — 2026-09-27
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`commentsCorrections[]` on `pubmed_fetch_articles`** ([#178](https://github.com/cyanheads/pubmed-mcp-server/issues/178)) — the notices NCBI links from `CommentsCorrectionsList` (`refType`, `refSource`, optional `pmid` and `note`), `Cites` entries excluded, in NCBI's order. `content[]` lists them under `#### Comments and Corrections (N)` ahead of the abstract; the field is absent when a record links nothing else.
|
|
12
|
+
- **`ncbi_rate_limited`** (`RateLimited`, retryable) in the NCBI error contract, which `pubmed://database/info` now declares too — an NCBI 429 the call stops on carries it with NCBI's `retryAfter`, and its hint names `NCBI_API_KEY` as an operator setting.
|
|
13
|
+
|
|
14
|
+
## Changed
|
|
15
|
+
|
|
16
|
+
- **`pubmed_lookup_citation` advertises `citations` as `type: "array"` (1–25) again** ([#173](https://github.com/cyanheads/pubmed-mcp-server/issues/173)) — a lone citation object, or one sent as `citation`, is wrapped into a one-element array before validation, so a field error names its element (`citations.0.journal`).
|
|
17
|
+
- **An NCBI JSON `error` field arrives as `data.ncbiErrors: [message]`**, as an XML `<ERROR>` does, in place of `data.ncbiError`.
|
|
18
|
+
- **Cancelling `pubmed_fetch_fulltext` or `pubmed_find_related` ends the call** instead of falling through to the next full-text tier or related-articles provider.
|
|
19
|
+
- **Error envelopes carry `data.requestId`, and a tool error's `content[]` ends with `request <id>`** (mcp-ts-core 0.13.10). Error `data` no longer carries server stack traces or request-context fields such as `operation` (mcp-ts-core 0.13.7, 0.13.8).
|
|
20
|
+
- **An integer sent for a string field, or a JSON-stringified object, is repaired before validation**, and a rejection names the alias rewrite it applied (`Validated limit as maxResults.`) (mcp-ts-core 0.13.9).
|
|
21
|
+
- **Streamable HTTP refusals** (MCP SDK 2.1.0, via mcp-ts-core 0.13.9) — a 2026-07-28 POST without `MCP-Protocol-Version` is refused `400` / `-32020`, and a JSON-RPC batch of more than 100 messages `400` / `-32600`.
|
|
22
|
+
- **Docker image** — production dependencies install in a `$BUILDPLATFORM` deps stage through `scripts/install-otel.ts`; the image gains a `HEALTHCHECK` on `/healthz` and an `org.opencontainers.image.version` label from `APP_VERSION`, and drops `MCP_FORCE_CONSOLE_LOGGING`.
|
|
23
|
+
- **Docs:** the README's tool table and capability reference are condensed to what each tool does and its limits; `.env.example` documents the Europe PMC settings and `NCBI_TOOL_IDENTIFIER`; `framework-skills/` synced to mcp-ts-core 0.13.10.
|
|
24
|
+
|
|
25
|
+
## Fixed
|
|
26
|
+
|
|
27
|
+
- **An NCBI call that stops short of its deadline reports its last attempt** ([#174](https://github.com/cyanheads/pubmed-mcp-server/issues/174)) — `ncbi_unreachable` with NCBI's message, `ncbiErrors`, and `attempts` when the next backoff would not fit. A real expiry stays `ncbi_deadline_exceeded` and now keeps `ncbiErrors`; its hint leads with a retry and names batch size only for a large batch.
|
|
28
|
+
- **A one-source `pubmed_europepmc_search` filter keeps `EXT_ID` matches** ([#175](https://github.com/cyanheads/pubmed-mcp-server/issues/175)) — a single source is sent as `SRC:"X" OR SRC:"X"`, so a quoted or unquoted `EXT_ID` lookup matches.
|
|
29
|
+
- **An unreadable `cursorMark` is reported as bad input, not an outage** ([#180](https://github.com/cyanheads/pubmed-mcp-server/issues/180)) — a second HTTP 503 on a caller's cursor, while the first page of the same query is served, fails as non-retryable `europepmc_invalid_input` naming `cursorMark`.
|
|
30
|
+
- **Newly rejected inputs** — each used to reach the upstream and return unfiltered results, a false empty result, or an outage ([#176](https://github.com/cyanheads/pubmed-mcp-server/issues/176), [#177](https://github.com/cyanheads/pubmed-mcp-server/issues/177)):
|
|
31
|
+
- `pubmed_search_articles` `blank_filter`: an `author`, `journal`, or `language` value, or a `publicationTypes` / `meshTerms` element, of only whitespace, invisible characters, markup, `()`, `[]`, or `""`. `data.fields` names each (`meshTerms.1`); an exactly-empty string still sets no filter.
|
|
32
|
+
- `pubmed_search_articles` `invalid_date_range`: a `dateRange` bound that is no real calendar date (`2023/02/29`, month `13`, day `00`), or a `minDate` after `maxDate` once PubMed expands each partial date.
|
|
33
|
+
- `pubmed_search_articles`, `pubmed_spell_check`, `pubmed_lookup_mesh` `blank_query`: a `query` of only invisible characters, such as a zero-width space.
|
|
34
|
+
- `pubmed_europepmc_search` `blank_query`: a `query` with no term (`" "`, `()`, `<b></b>`, ` `). `blank_cursor`: a `cursorMark` of only whitespace or invisible characters.
|
|
35
|
+
- **Minor:** an exhausted retry after one attempt reads `(failed after 1 attempt)`; `europepmc_invalid_input` errors carry `retryable: false`; the `openalex_invalid_response` contract declares `ServiceUnavailable`, the code it is thrown with.
|
|
36
|
+
|
|
37
|
+
## Dependencies
|
|
38
|
+
|
|
39
|
+
- `@cyanheads/mcp-ts-core` ^0.13.6 → ^0.13.10
|
|
40
|
+
- `@socketsecurity/bun-security-scanner` ^1.1.2 → ^1.1.3 (dev)
|
|
41
|
+
- `ignore` ^7.0.9 → ^7.0.10 (dev)
|
|
42
|
+
- `packageManager` bun@1.4.0 → bun@1.4.2, with the Docker base images
|
|
@@ -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":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;IACtD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC;IACxF,UAAU,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;IAChE,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC;IAChG,aAAa,EAAE,CAAC,CAAC,MAAM;SACpB,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;SACP,OAAO,CAAC,CAAC,CAAC;SACV,QAAQ,CAAC,wCAAwC,CAAC;IACrD,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IACtF,SAAS,EAAE,CAAC,CAAC,MAAM;SAChB,MAAM,EAAE;SACR,GAAG,CAAC,IAAI,CAAC;SACT,GAAG,CAAC,MAAM,CAAC;SACX,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,gCAAgC,CAAC;IAC7C,eAAe,EAAE,CAAC,CAAC,MAAM;SACtB,MAAM,EAAE;SACR,GAAG,CAAC,IAAI,CAAC;SACT,GAAG,CAAC,MAAM,CAAC;SACX,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,mEAAmE,CAAC;IAChF,cAAc,EAAE,CAAC;SACd,KAAK,EAAE;SACP,QAAQ,EAAE;SACV,QAAQ,CAAC,uEAAuE,CAAC;IACpF,kBAAkB,EAAE,CAAC,CAAC,MAAM;SACzB,MAAM,EAAE;SACR,GAAG,CAAC,IAAI,CAAC;SACT,GAAG,CAAC,MAAM,CAAC;SACX,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,2EAA2E,CAAC;IACxF,gBAAgB,EAAE,CAAC;SAChB,UAAU,EAAE;SACZ,OAAO,CAAC,IAAI,CAAC;SACb,QAAQ,CACP,uHAAuH,CACxH;IACH,cAAc,EAAE,CAAC;SACd,KAAK,EAAE;SACP,QAAQ,EAAE;SACV,QAAQ,CAAC,sDAAsD,CAAC;IACnE,uBAAuB,EAAE,CAAC,CAAC,MAAM;SAC9B,MAAM,EAAE;SACR,GAAG,CAAC,EAAE,CAAC;SACP,GAAG,CAAC,IAAI,CAAC;SACT,OAAO,CAAC,GAAG,CAAC;SACZ,QAAQ,CAAC,qDAAqD,CAAC;IAClE,mBAAmB,EAAE,CAAC,CAAC,MAAM;SAC1B,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;SACP,OAAO,CAAC,CAAC,CAAC;SACV,QAAQ,CAAC,mDAAmD,CAAC;IAChE,kBAAkB,EAAE,CAAC,CAAC,MAAM;SACzB,MAAM,EAAE;SACR,GAAG,CAAC,IAAI,CAAC;SACT,GAAG,CAAC,MAAM,CAAC;SACX,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,sDAAsD,CAAC;CACpE,CAAC,CAAC;AAIH,IAAI,OAAiC,CAAC;AAEtC,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,cAAc,CAAC,kBAAkB,EAAE;YAChD,MAAM,EAAE,cAAc;YACtB,cAAc,EAAE,sBAAsB;YACtC,UAAU,EAAE,kBAAkB;YAC9B,cAAc,EAAE,uBAAuB;YACvC,aAAa,EAAE,qBAAqB;YACpC,UAAU,EAAE,kBAAkB;YAC9B,SAAS,EAAE,iBAAiB;YAC5B,eAAe,EAAE,wBAAwB;YACzC,cAAc,EAAE,iBAAiB;YACjC,kBAAkB,EAAE,sBAAsB;YAC1C,gBAAgB,EAAE,mBAAmB;YACrC,cAAc,EAAE,iBAAiB;YACjC,uBAAuB,EAAE,4BAA4B;YACrD,mBAAmB,EAAE,uBAAuB;YAC5C,kBAAkB,EAAE,sBAAsB;SAC3C,CAAC,CAAC;QACH
|
|
1
|
+
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,5 +14,47 @@ export declare const databaseInfoResource: import("@cyanheads/mcp-ts-core").Reso
|
|
|
14
14
|
fullName: z.ZodOptional<z.ZodString>;
|
|
15
15
|
description: z.ZodOptional<z.ZodString>;
|
|
16
16
|
}, z.core.$strip>>>;
|
|
17
|
-
}, z.core.$strip>,
|
|
17
|
+
}, z.core.$strip>, readonly [{
|
|
18
|
+
readonly reason: 'queue_full';
|
|
19
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.RateLimited;
|
|
20
|
+
readonly when: 'The local NCBI request queue shed the call — the queue is full, or the call cannot start before its total deadline (for example behind the cooldown that follows an NCBI 429).';
|
|
21
|
+
readonly recovery: 'Wait the number of seconds in `retryAfter`, then retry; the NCBI request queue is saturated or cooling down after a rate limit.';
|
|
22
|
+
readonly retryable: true;
|
|
23
|
+
readonly thrownBy: 'service';
|
|
24
|
+
}, {
|
|
25
|
+
readonly reason: 'ncbi_unreachable';
|
|
26
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
27
|
+
readonly when: 'NCBI E-utilities failed on every attempt the retry budget allowed — retries ran out, or the next backoff would overrun the total deadline.';
|
|
28
|
+
readonly recovery: 'Retry after a brief delay; NCBI failed on every attempt this call made.';
|
|
29
|
+
readonly retryable: true;
|
|
30
|
+
readonly thrownBy: 'service';
|
|
31
|
+
}, {
|
|
32
|
+
readonly reason: 'ncbi_rate_limited';
|
|
33
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.RateLimited;
|
|
34
|
+
readonly when: 'NCBI answered HTTP 429 (too many requests) and the call stopped on it — retries ran out, the next backoff would overrun the total deadline, or the Retry-After NCBI named outlasts the time left or the 30-second backoff cap.';
|
|
35
|
+
readonly recovery: "Wait as long as `retryAfter` says when present (a number of seconds or an HTTP date), otherwise a few seconds, then retry; NCBI is throttling this server's requests. If the server runs without NCBI_API_KEY, setting it raises the E-utilities ceiling from about 3 to about 10 requests per second and shortens the default gap between requests — an operator setting in the server's environment, not a tool input.";
|
|
36
|
+
readonly retryable: true;
|
|
37
|
+
readonly thrownBy: 'service';
|
|
38
|
+
}, {
|
|
39
|
+
readonly reason: 'ncbi_deadline_exceeded';
|
|
40
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.Timeout;
|
|
41
|
+
readonly when: 'The total NCBI request deadline expired before NCBI answered successfully — mid-request, while queued, or during a retry backoff.';
|
|
42
|
+
readonly recovery: 'Retry after a brief delay; NCBI may be under temporary load. For a large batch, split it into smaller calls.';
|
|
43
|
+
readonly retryable: true;
|
|
44
|
+
readonly thrownBy: 'service';
|
|
45
|
+
}, {
|
|
46
|
+
readonly reason: 'ncbi_invalid_response';
|
|
47
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.SerializationError;
|
|
48
|
+
readonly when: 'NCBI returned a body that could not be parsed (invalid XML/JSON).';
|
|
49
|
+
readonly recovery: 'Retry the request; NCBI returned a malformed response that could not be parsed.';
|
|
50
|
+
readonly retryable: true;
|
|
51
|
+
readonly thrownBy: 'service';
|
|
52
|
+
}, {
|
|
53
|
+
readonly reason: 'ncbi_resource_not_found';
|
|
54
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
55
|
+
readonly when: 'NCBI returned a structured "not found" error for the requested ID(s).';
|
|
56
|
+
readonly recovery: 'Verify the ID exists in PubMed; the resource was not found in NCBI and retrying will not help.';
|
|
57
|
+
readonly retryable: false;
|
|
58
|
+
readonly thrownBy: 'service';
|
|
59
|
+
}]>;
|
|
18
60
|
//# sourceMappingURL=database-info.resource.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database-info.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/database-info.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"database-info.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/database-info.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAqBrD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgD/B,CAAC"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* @module src/mcp-server/resources/definitions/database-info.resource
|
|
5
5
|
*/
|
|
6
6
|
import { resource, z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { NCBI_SERVICE_ERRORS } from '../../../services/error-contracts.js';
|
|
7
8
|
import { getNcbiService } from '../../../services/ncbi/ncbi-service.js';
|
|
8
9
|
import { ensureArray, getOptionalText, getText } from '../../../services/ncbi/parsing/xml-helpers.js';
|
|
9
10
|
const FieldSchema = z
|
|
@@ -27,6 +28,7 @@ export const databaseInfoResource = resource('pubmed://database/info', {
|
|
|
27
28
|
mimeType: 'application/json',
|
|
28
29
|
params: z.object({}),
|
|
29
30
|
output: OutputSchema,
|
|
31
|
+
errors: [...NCBI_SERVICE_ERRORS],
|
|
30
32
|
async handler(_params, ctx) {
|
|
31
33
|
ctx.log.info('Fetching PubMed database info');
|
|
32
34
|
const raw = (await getNcbiService().eInfo({ db: 'pubmed' }, { signal: ctx.signal }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database-info.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/database-info.resource.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,wCAAwC,CAAC;AAE/F,MAAM,WAAW,GAAG,CAAC;KAClB,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IAC7D,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;IAC7D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;CACjE,CAAC;KACD,QAAQ,CAAC,wBAAwB,CAAC,CAAC;AAEtC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;IAC5C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;IACnE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IAC3D,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;IACnE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;CACjG,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG,QAAQ,CAAC,wBAAwB,EAAE;IACrE,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,sBAAsB;IAC7B,WAAW,EAAE,oFAAoF;IACjG,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACpB,MAAM,EAAE,YAAY;
|
|
1
|
+
{"version":3,"file":"database-info.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/database-info.resource.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The one test every blank-input rejection shares: does a value
|
|
3
|
+
* hold any character a reader could see? `String.prototype.trim` is not enough —
|
|
4
|
+
* it keeps U+0085 (NEL), control characters such as U+0001 and U+007F (`\p{Cc}`),
|
|
5
|
+
* every format character (`\p{Cf}`: zero-width space, word joiner, soft
|
|
6
|
+
* hyphen, …), and the other default-ignorable code points (Hangul fillers such
|
|
7
|
+
* as U+3164, variation selectors, the combining grapheme joiner), so a value
|
|
8
|
+
* made only of those reads as nonblank and reaches the upstream as an invisible
|
|
9
|
+
* term. (#176)
|
|
10
|
+
* @module src/mcp-server/tools/definitions/_visible-text
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* True when `value` has at least one character outside `\p{White_Space}`,
|
|
14
|
+
* `\p{Cc}`, `\p{Cf}`, and `\p{Default_Ignorable_Code_Point}`. Pure: it strips no
|
|
15
|
+
* markup and decodes no entities, so a caller that sanitizes input runs this on
|
|
16
|
+
* the sanitized copy.
|
|
17
|
+
*/
|
|
18
|
+
export declare function hasVisibleText(value: string): boolean;
|
|
19
|
+
//# sourceMappingURL=_visible-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_visible-text.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/_visible-text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAErD"}
|