@cyanheads/pubmed-mcp-server 2.1.1 → 2.1.3
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/README.md +3 -3
- package/dist/index.js +39 -37
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](https://www.npmjs.com/package/@cyanheads/pubmed-mcp-server) [](https://www.npmjs.com/package/@cyanheads/pubmed-mcp-server) [](./CHANGELOG.md) [](https://modelcontextprotocol.io/specification/2025-11-25)
|
|
11
11
|
|
|
12
12
|
[](https://modelcontextprotocol.io/) [](./LICENSE) [](https://github.com/cyanheads/pubmed-mcp-server/issues) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
13
13
|
|
|
@@ -23,7 +23,7 @@ Seven tools for working with PubMed and NCBI data:
|
|
|
23
23
|
|:---|:---|
|
|
24
24
|
| `pubmed_search` | Search PubMed with full query syntax, field-specific filters, date ranges, pagination, and optional brief summaries |
|
|
25
25
|
| `pubmed_fetch` | Fetch full article metadata by PMIDs — abstract, authors, journal, MeSH terms, grants |
|
|
26
|
-
| `
|
|
26
|
+
| `pubmed_pmc_fetch` | Fetch full-text articles from PubMed Central — body sections, references, and metadata for open-access articles |
|
|
27
27
|
| `pubmed_cite` | Generate formatted citations in APA 7th, MLA 9th, BibTeX, or RIS |
|
|
28
28
|
| `pubmed_related` | Find similar articles, citing articles, or references for a given PMID |
|
|
29
29
|
| `pubmed_spell` | Spell-check biomedical queries using NCBI's ESpell service |
|
|
@@ -56,7 +56,7 @@ Fetch full article metadata by PubMed IDs.
|
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
59
|
-
### `
|
|
59
|
+
### `pubmed_pmc_fetch`
|
|
60
60
|
|
|
61
61
|
Fetch full-text articles from PubMed Central (PMC).
|
|
62
62
|
|
package/dist/index.js
CHANGED
|
@@ -15776,7 +15776,7 @@ var require_util = __commonJS((exports) => {
|
|
|
15776
15776
|
}
|
|
15777
15777
|
path = url2.path;
|
|
15778
15778
|
}
|
|
15779
|
-
var
|
|
15779
|
+
var isAbsolute2 = exports.isAbsolute(path);
|
|
15780
15780
|
var parts = [];
|
|
15781
15781
|
var start = 0;
|
|
15782
15782
|
var i = 0;
|
|
@@ -15811,7 +15811,7 @@ var require_util = __commonJS((exports) => {
|
|
|
15811
15811
|
}
|
|
15812
15812
|
path = parts.join("/");
|
|
15813
15813
|
if (path === "") {
|
|
15814
|
-
path =
|
|
15814
|
+
path = isAbsolute2 ? "/" : ".";
|
|
15815
15815
|
}
|
|
15816
15816
|
if (url2) {
|
|
15817
15817
|
url2.path = path;
|
|
@@ -15820,7 +15820,7 @@ var require_util = __commonJS((exports) => {
|
|
|
15820
15820
|
return path;
|
|
15821
15821
|
});
|
|
15822
15822
|
exports.normalize = normalize;
|
|
15823
|
-
function
|
|
15823
|
+
function join2(aRoot, aPath) {
|
|
15824
15824
|
if (aRoot === "") {
|
|
15825
15825
|
aRoot = ".";
|
|
15826
15826
|
}
|
|
@@ -15852,7 +15852,7 @@ var require_util = __commonJS((exports) => {
|
|
|
15852
15852
|
}
|
|
15853
15853
|
return joined;
|
|
15854
15854
|
}
|
|
15855
|
-
exports.join =
|
|
15855
|
+
exports.join = join2;
|
|
15856
15856
|
exports.isAbsolute = function(aPath) {
|
|
15857
15857
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
15858
15858
|
};
|
|
@@ -16066,7 +16066,7 @@ var require_util = __commonJS((exports) => {
|
|
|
16066
16066
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
16067
16067
|
}
|
|
16068
16068
|
}
|
|
16069
|
-
sourceURL =
|
|
16069
|
+
sourceURL = join2(urlGenerate(parsed), sourceURL);
|
|
16070
16070
|
}
|
|
16071
16071
|
return normalize(sourceURL);
|
|
16072
16072
|
}
|
|
@@ -17440,7 +17440,7 @@ var require_source_map = __commonJS((exports) => {
|
|
|
17440
17440
|
// node_modules/postcss/lib/previous-map.js
|
|
17441
17441
|
var require_previous_map = __commonJS((exports, module) => {
|
|
17442
17442
|
var { existsSync, readFileSync } = __require("fs");
|
|
17443
|
-
var { dirname, join } = __require("path");
|
|
17443
|
+
var { dirname: dirname2, join: join2 } = __require("path");
|
|
17444
17444
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
17445
17445
|
function fromBase64(str) {
|
|
17446
17446
|
if (Buffer) {
|
|
@@ -17462,7 +17462,7 @@ var require_previous_map = __commonJS((exports, module) => {
|
|
|
17462
17462
|
this.mapFile = opts.from;
|
|
17463
17463
|
}
|
|
17464
17464
|
if (this.mapFile)
|
|
17465
|
-
this.root =
|
|
17465
|
+
this.root = dirname2(this.mapFile);
|
|
17466
17466
|
if (text)
|
|
17467
17467
|
this.text = text;
|
|
17468
17468
|
}
|
|
@@ -17507,7 +17507,7 @@ var require_previous_map = __commonJS((exports, module) => {
|
|
|
17507
17507
|
}
|
|
17508
17508
|
}
|
|
17509
17509
|
loadFile(path) {
|
|
17510
|
-
this.root =
|
|
17510
|
+
this.root = dirname2(path);
|
|
17511
17511
|
if (existsSync(path)) {
|
|
17512
17512
|
this.mapFile = path;
|
|
17513
17513
|
return readFileSync(path, "utf-8").toString().trim();
|
|
@@ -17542,7 +17542,7 @@ var require_previous_map = __commonJS((exports, module) => {
|
|
|
17542
17542
|
} else if (this.annotation) {
|
|
17543
17543
|
let map2 = this.annotation;
|
|
17544
17544
|
if (file2)
|
|
17545
|
-
map2 =
|
|
17545
|
+
map2 = join2(dirname2(file2), map2);
|
|
17546
17546
|
return this.loadFile(map2);
|
|
17547
17547
|
}
|
|
17548
17548
|
}
|
|
@@ -17562,15 +17562,15 @@ var require_previous_map = __commonJS((exports, module) => {
|
|
|
17562
17562
|
// node_modules/postcss/lib/input.js
|
|
17563
17563
|
var require_input = __commonJS((exports, module) => {
|
|
17564
17564
|
var { nanoid: nanoid3 } = require_non_secure();
|
|
17565
|
-
var { isAbsolute, resolve } = __require("path");
|
|
17565
|
+
var { isAbsolute: isAbsolute2, resolve } = __require("path");
|
|
17566
17566
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
17567
|
-
var { fileURLToPath, pathToFileURL } = __require("url");
|
|
17567
|
+
var { fileURLToPath: fileURLToPath2, pathToFileURL } = __require("url");
|
|
17568
17568
|
var CssSyntaxError = require_css_syntax_error();
|
|
17569
17569
|
var PreviousMap = require_previous_map();
|
|
17570
17570
|
var terminalHighlight = require_terminal_highlight();
|
|
17571
17571
|
var lineToIndexCache = Symbol("lineToIndexCache");
|
|
17572
17572
|
var sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator);
|
|
17573
|
-
var pathAvailable = Boolean(resolve &&
|
|
17573
|
+
var pathAvailable = Boolean(resolve && isAbsolute2);
|
|
17574
17574
|
function getLineToIndex(input) {
|
|
17575
17575
|
if (input[lineToIndexCache])
|
|
17576
17576
|
return input[lineToIndexCache];
|
|
@@ -17605,7 +17605,7 @@ var require_input = __commonJS((exports, module) => {
|
|
|
17605
17605
|
if (opts.document)
|
|
17606
17606
|
this.document = opts.document.toString();
|
|
17607
17607
|
if (opts.from) {
|
|
17608
|
-
if (!pathAvailable || /^\w+:\/\//.test(opts.from) ||
|
|
17608
|
+
if (!pathAvailable || /^\w+:\/\//.test(opts.from) || isAbsolute2(opts.from)) {
|
|
17609
17609
|
this.file = opts.from;
|
|
17610
17610
|
} else {
|
|
17611
17611
|
this.file = resolve(opts.from);
|
|
@@ -17723,7 +17723,7 @@ var require_input = __commonJS((exports, module) => {
|
|
|
17723
17723
|
to = consumer.originalPositionFor({ column: endColumn, line: endLine });
|
|
17724
17724
|
}
|
|
17725
17725
|
let fromUrl;
|
|
17726
|
-
if (
|
|
17726
|
+
if (isAbsolute2(from.source)) {
|
|
17727
17727
|
fromUrl = pathToFileURL(from.source);
|
|
17728
17728
|
} else {
|
|
17729
17729
|
fromUrl = new URL(from.source, this.map.consumer().sourceRoot || pathToFileURL(this.map.mapFile));
|
|
@@ -17736,8 +17736,8 @@ var require_input = __commonJS((exports, module) => {
|
|
|
17736
17736
|
url: fromUrl.toString()
|
|
17737
17737
|
};
|
|
17738
17738
|
if (fromUrl.protocol === "file:") {
|
|
17739
|
-
if (
|
|
17740
|
-
result.file =
|
|
17739
|
+
if (fileURLToPath2) {
|
|
17740
|
+
result.file = fileURLToPath2(fromUrl);
|
|
17741
17741
|
} else {
|
|
17742
17742
|
throw new Error(`file: protocol is not available in this PostCSS build`);
|
|
17743
17743
|
}
|
|
@@ -17963,12 +17963,12 @@ var require_fromJSON = __commonJS((exports, module) => {
|
|
|
17963
17963
|
|
|
17964
17964
|
// node_modules/postcss/lib/map-generator.js
|
|
17965
17965
|
var require_map_generator = __commonJS((exports, module) => {
|
|
17966
|
-
var { dirname, relative, resolve, sep } = __require("path");
|
|
17966
|
+
var { dirname: dirname2, relative, resolve, sep } = __require("path");
|
|
17967
17967
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
17968
17968
|
var { pathToFileURL } = __require("url");
|
|
17969
17969
|
var Input = require_input();
|
|
17970
17970
|
var sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator);
|
|
17971
|
-
var pathAvailable = Boolean(
|
|
17971
|
+
var pathAvailable = Boolean(dirname2 && resolve && relative && sep);
|
|
17972
17972
|
|
|
17973
17973
|
class MapGenerator {
|
|
17974
17974
|
constructor(stringify, root, opts, cssString) {
|
|
@@ -18005,7 +18005,7 @@ var require_map_generator = __commonJS((exports, module) => {
|
|
|
18005
18005
|
applyPrevMaps() {
|
|
18006
18006
|
for (let prev of this.previous()) {
|
|
18007
18007
|
let from = this.toUrl(this.path(prev.file));
|
|
18008
|
-
let root = prev.root ||
|
|
18008
|
+
let root = prev.root || dirname2(prev.file);
|
|
18009
18009
|
let map2;
|
|
18010
18010
|
if (this.mapOpts.sourcesContent === false) {
|
|
18011
18011
|
map2 = new SourceMapConsumer(prev.text);
|
|
@@ -18212,9 +18212,9 @@ var require_map_generator = __commonJS((exports, module) => {
|
|
|
18212
18212
|
let cached2 = this.memoizedPaths.get(file2);
|
|
18213
18213
|
if (cached2)
|
|
18214
18214
|
return cached2;
|
|
18215
|
-
let from = this.opts.to ?
|
|
18215
|
+
let from = this.opts.to ? dirname2(this.opts.to) : ".";
|
|
18216
18216
|
if (typeof this.mapOpts.annotation === "string") {
|
|
18217
|
-
from =
|
|
18217
|
+
from = dirname2(resolve(from, this.mapOpts.annotation));
|
|
18218
18218
|
}
|
|
18219
18219
|
let path = relative(from, file2);
|
|
18220
18220
|
this.memoizedPaths.set(file2, path);
|
|
@@ -40573,7 +40573,7 @@ var require_register = __commonJS((exports) => {
|
|
|
40573
40573
|
var require_import_in_the_middle = __commonJS((exports, module) => {
|
|
40574
40574
|
var path2 = __require("path");
|
|
40575
40575
|
var moduleDetailsFromPath = require_module_details_from_path();
|
|
40576
|
-
var { fileURLToPath } = __require("url");
|
|
40576
|
+
var { fileURLToPath: fileURLToPath2 } = __require("url");
|
|
40577
40577
|
var { MessageChannel } = __require("worker_threads");
|
|
40578
40578
|
var { isBuiltin } = __require("module");
|
|
40579
40579
|
if (!isBuiltin) {
|
|
@@ -40661,7 +40661,7 @@ var require_import_in_the_middle = __commonJS((exports, module) => {
|
|
|
40661
40661
|
const stackTraceLimit = Error.stackTraceLimit;
|
|
40662
40662
|
Error.stackTraceLimit = 0;
|
|
40663
40663
|
try {
|
|
40664
|
-
filePath =
|
|
40664
|
+
filePath = fileURLToPath2(name2);
|
|
40665
40665
|
name2 = filePath;
|
|
40666
40666
|
} catch (e) {}
|
|
40667
40667
|
Error.stackTraceLimit = stackTraceLimit;
|
|
@@ -91725,12 +91725,12 @@ var require_fetch2 = __commonJS((exports, module) => {
|
|
|
91725
91725
|
// node_modules/@protobufjs/path/index.js
|
|
91726
91726
|
var require_path = __commonJS((exports) => {
|
|
91727
91727
|
var path2 = exports;
|
|
91728
|
-
var
|
|
91728
|
+
var isAbsolute2 = path2.isAbsolute = function isAbsolute(path3) {
|
|
91729
91729
|
return /^(?:\/|\w+:)/.test(path3);
|
|
91730
91730
|
};
|
|
91731
91731
|
var normalize = path2.normalize = function normalize(path3) {
|
|
91732
91732
|
path3 = path3.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
|
|
91733
|
-
var parts = path3.split("/"), absolute =
|
|
91733
|
+
var parts = path3.split("/"), absolute = isAbsolute2(path3), prefix = "";
|
|
91734
91734
|
if (absolute)
|
|
91735
91735
|
prefix = parts.shift() + "/";
|
|
91736
91736
|
for (var i2 = 0;i2 < parts.length; ) {
|
|
@@ -91751,7 +91751,7 @@ var require_path = __commonJS((exports) => {
|
|
|
91751
91751
|
path2.resolve = function resolve(originPath, includePath, alreadyNormalized) {
|
|
91752
91752
|
if (!alreadyNormalized)
|
|
91753
91753
|
includePath = normalize(includePath);
|
|
91754
|
-
if (
|
|
91754
|
+
if (isAbsolute2(includePath))
|
|
91755
91755
|
return includePath;
|
|
91756
91756
|
if (!alreadyNormalized)
|
|
91757
91757
|
originPath = normalize(originPath);
|
|
@@ -121965,6 +121965,8 @@ if (shouldShowDeprecationWarning())
|
|
|
121965
121965
|
|
|
121966
121966
|
// src/config/index.ts
|
|
121967
121967
|
var import_dotenv = __toESM(require_main4(), 1);
|
|
121968
|
+
import { dirname, isAbsolute, join } from "node:path";
|
|
121969
|
+
import { fileURLToPath } from "node:url";
|
|
121968
121970
|
|
|
121969
121971
|
// node_modules/zod/v4/classic/external.js
|
|
121970
121972
|
var exports_external = {};
|
|
@@ -135501,7 +135503,7 @@ config(en_default());
|
|
|
135501
135503
|
// package.json
|
|
135502
135504
|
var package_default = {
|
|
135503
135505
|
name: "@cyanheads/pubmed-mcp-server",
|
|
135504
|
-
version: "2.1.
|
|
135506
|
+
version: "2.1.2",
|
|
135505
135507
|
mcpName: "io.github.cyanheads/pubmed-mcp-server",
|
|
135506
135508
|
description: "MCP server for PubMed/NCBI E-utilities integration. Search articles, fetch metadata, generate citations, explore MeSH terms, and discover related research.",
|
|
135507
135509
|
main: "dist/index.js",
|
|
@@ -135579,7 +135581,7 @@ var package_default = {
|
|
|
135579
135581
|
rollup: "4.59.0"
|
|
135580
135582
|
},
|
|
135581
135583
|
devDependencies: {
|
|
135582
|
-
"@cloudflare/workers-types": "^4.
|
|
135584
|
+
"@cloudflare/workers-types": "^4.20260305.1",
|
|
135583
135585
|
"@biomejs/biome": "2.4.5",
|
|
135584
135586
|
"@hono/mcp": "^0.2.4",
|
|
135585
135587
|
"@traversable/registry": "^0.0.49",
|
|
@@ -136003,13 +136005,13 @@ var parseConfig = () => {
|
|
|
136003
136005
|
...rawConfig,
|
|
136004
136006
|
pkg: parsedPkg,
|
|
136005
136007
|
logsPath: hasFileSystemAccess ? (() => {
|
|
136006
|
-
const
|
|
136007
|
-
const
|
|
136008
|
-
const root =
|
|
136008
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
136009
|
+
const depth = /[\\/]dist[\\/]/.test(thisFile) ? ".." : "../..";
|
|
136010
|
+
const root = join(dirname(thisFile), depth);
|
|
136009
136011
|
const logsDir = rawConfig.logsPath ?? "logs";
|
|
136010
|
-
if (logsDir
|
|
136012
|
+
if (isAbsolute(logsDir))
|
|
136011
136013
|
return logsDir;
|
|
136012
|
-
return
|
|
136014
|
+
return join(root, logsDir);
|
|
136013
136015
|
})() : undefined,
|
|
136014
136016
|
mcpServerName: env.MCP_SERVER_NAME ?? parsedPkg.name,
|
|
136015
136017
|
mcpServerVersion: env.MCP_SERVER_VERSION ?? parsedPkg.version,
|
|
@@ -151274,7 +151276,7 @@ function markdown() {
|
|
|
151274
151276
|
|
|
151275
151277
|
// src/mcp-server/tools/definitions/pmc-fetch.tool.ts
|
|
151276
151278
|
var ncbi2 = () => container.resolve(NcbiServiceToken);
|
|
151277
|
-
var TOOL_NAME = "
|
|
151279
|
+
var TOOL_NAME = "pubmed_pmc_fetch";
|
|
151278
151280
|
var TOOL_TITLE = "PMC Full-Text Fetch";
|
|
151279
151281
|
var TOOL_DESCRIPTION = "Fetch full-text articles from PubMed Central (PMC). Returns complete article body text, sections, and references for open-access articles. Accepts PMC IDs directly or PubMed IDs (auto-resolved via ELink). Only articles available in PMC will return full text.";
|
|
151280
151282
|
var TOOL_ANNOTATIONS = {
|
|
@@ -151383,7 +151385,7 @@ function filterSections(sections, sectionFilter) {
|
|
|
151383
151385
|
});
|
|
151384
151386
|
}
|
|
151385
151387
|
async function logic(input, appContext, _sdkContext) {
|
|
151386
|
-
logger.info("Executing
|
|
151388
|
+
logger.info("Executing pubmed_pmc_fetch tool", {
|
|
151387
151389
|
...appContext,
|
|
151388
151390
|
hasPmcids: !!input.pmcids,
|
|
151389
151391
|
hasPmids: !!input.pmids,
|
|
@@ -151444,7 +151446,7 @@ async function logic(input, appContext, _sdkContext) {
|
|
|
151444
151446
|
return rest;
|
|
151445
151447
|
});
|
|
151446
151448
|
}
|
|
151447
|
-
logger.notice("
|
|
151449
|
+
logger.notice("pubmed_pmc_fetch completed", {
|
|
151448
151450
|
...appContext,
|
|
151449
151451
|
requested: pmcIds.length,
|
|
151450
151452
|
returned: articles.length
|
|
@@ -151516,7 +151518,7 @@ var pmcFetchTool = {
|
|
|
151516
151518
|
annotations: TOOL_ANNOTATIONS,
|
|
151517
151519
|
description: TOOL_DESCRIPTION,
|
|
151518
151520
|
inputSchema: InputSchema,
|
|
151519
|
-
logic: withToolAuth(["tool:
|
|
151521
|
+
logic: withToolAuth(["tool:pubmed_pmc_fetch:read"], logic),
|
|
151520
151522
|
name: TOOL_NAME,
|
|
151521
151523
|
outputSchema: OutputSchema2,
|
|
151522
151524
|
responseFormatter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/pubmed-mcp-server",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"mcpName": "io.github.cyanheads/pubmed-mcp-server",
|
|
5
5
|
"description": "MCP server for PubMed/NCBI E-utilities integration. Search articles, fetch metadata, generate citations, explore MeSH terms, and discover related research.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"rollup": "4.59.0"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@cloudflare/workers-types": "^4.
|
|
81
|
+
"@cloudflare/workers-types": "^4.20260305.1",
|
|
82
82
|
"@biomejs/biome": "2.4.5",
|
|
83
83
|
"@hono/mcp": "^0.2.4",
|
|
84
84
|
"@traversable/registry": "^0.0.49",
|