@cyanheads/pubmed-mcp-server 2.9.8 → 2.9.9
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 +30 -8
- package/CLAUDE.md +30 -8
- package/Dockerfile +13 -7
- package/README.md +1 -1
- package/dist/mcp-server/prompts/definitions/research-plan.prompt.d.ts +1 -1
- package/dist/mcp-server/tools/definitions/convert-ids.tool.d.ts +17 -17
- package/dist/mcp-server/tools/definitions/fetch-articles.tool.d.ts +18 -18
- package/dist/mcp-server/tools/definitions/fetch-articles.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-fulltext.tool.d.ts +40 -40
- package/dist/mcp-server/tools/definitions/find-related.tool.d.ts +33 -33
- package/dist/mcp-server/tools/definitions/format-citations.tool.d.ts +17 -17
- package/dist/mcp-server/tools/definitions/format-citations.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/format-citations.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/lookup-citation.tool.d.ts +16 -16
- package/dist/mcp-server/tools/definitions/lookup-citation.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/lookup-citation.tool.js +9 -12
- package/dist/mcp-server/tools/definitions/lookup-citation.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/lookup-mesh.tool.d.ts +20 -16
- package/dist/mcp-server/tools/definitions/lookup-mesh.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/lookup-mesh.tool.js +73 -22
- package/dist/mcp-server/tools/definitions/lookup-mesh.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/pubmed-europepmc-search.tool.d.ts +18 -18
- package/dist/mcp-server/tools/definitions/pubmed-europepmc-search.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-articles.tool.d.ts +22 -22
- package/dist/mcp-server/tools/definitions/spell-check.tool.d.ts +15 -15
- package/dist/mcp-server/tools/definitions/spell-check.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/spell-check.tool.js +2 -2
- package/dist/mcp-server/tools/definitions/spell-check.tool.js.map +1 -1
- package/dist/services/error-contracts.d.ts +33 -33
- package/dist/services/error-contracts.d.ts.map +1 -1
- package/dist/services/europe-pmc/api-client.d.ts.map +1 -1
- package/dist/services/europe-pmc/api-client.js +1 -0
- package/dist/services/europe-pmc/api-client.js.map +1 -1
- package/dist/services/europe-pmc/europe-pmc-service.d.ts.map +1 -1
- package/dist/services/europe-pmc/europe-pmc-service.js.map +1 -1
- package/dist/services/europe-pmc/request-queue.d.ts.map +1 -1
- package/dist/services/europe-pmc/request-queue.js.map +1 -1
- package/dist/services/europe-pmc/types.d.ts +2 -2
- 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.map +1 -1
- package/dist/services/ncbi/ncbi-service.d.ts.map +1 -1
- package/dist/services/ncbi/ncbi-service.js.map +1 -1
- package/dist/services/ncbi/parsing/article-parser.js.map +1 -1
- package/dist/services/ncbi/parsing/esummary-parser.d.ts.map +1 -1
- package/dist/services/ncbi/parsing/esummary-parser.js +3 -0
- package/dist/services/ncbi/parsing/esummary-parser.js.map +1 -1
- package/dist/services/ncbi/parsing/xml-helpers.js.map +1 -1
- package/dist/services/ncbi/request-queue.d.ts.map +1 -1
- package/dist/services/ncbi/request-queue.js.map +1 -1
- package/dist/services/ncbi/response-handler.d.ts.map +1 -1
- package/dist/services/ncbi/types.d.ts +6 -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 +1 -0
- package/dist/services/openalex/api-client.js.map +1 -1
- package/dist/services/openalex/openalex-service.d.ts.map +1 -1
- 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 -0
- package/dist/services/unpaywall/unpaywall-service.js.map +1 -1
- package/package.json +24 -17
- package/server.json +3 -3
package/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/pubmed-mcp-server
|
|
4
|
-
**Version:** 2.9.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.
|
|
6
|
-
**Engines:** Bun ≥1.3.
|
|
4
|
+
**Version:** 2.9.9
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.11.0`
|
|
6
|
+
**Engines:** Bun ≥1.3.0, Node ≥24.0.0
|
|
7
7
|
|
|
8
8
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
9
9
|
|
|
@@ -137,6 +137,8 @@ export function getServerConfig(): z.infer<typeof ServerConfigSchema> {
|
|
|
137
137
|
|
|
138
138
|
`parseEnvConfig` maps Zod schema paths → env var names so validation errors name the actual variable (`NCBI_REQUEST_DELAY_MS` must be a number) rather than the internal path (`requestDelayMs: expected number`).
|
|
139
139
|
|
|
140
|
+
For env booleans use `z.stringbool()`, never `z.coerce.boolean()` — `Boolean("false")` is `true`, so a coerced flag can't be disabled through the environment. `z.stringbool()` parses `true/false/1/0/yes/no/on/off` and rejects anything else, so `=false` actually disables.
|
|
141
|
+
|
|
140
142
|
### Server identity and instructions
|
|
141
143
|
|
|
142
144
|
`createApp()` accepts optional identity fields forwarded to the SDK's `initialize` response and the server manifest (`/.well-known/mcp.json`):
|
|
@@ -163,9 +165,11 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
163
165
|
| Property | Description |
|
|
164
166
|
|:---------|:------------|
|
|
165
167
|
| `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. |
|
|
166
|
-
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
168
|
+
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.getMany(keys)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
167
169
|
| `ctx.elicit` | Ask user for structured input — form call `(message, schema)` or `.url(message, url)` for an external link. **Check for presence first:** `if (ctx.elicit) { ... }` |
|
|
168
170
|
| `ctx.progress` | Task progress (present when `task: true`) — `.setTotal(n)`, `.increment()`, `.update(message)`. |
|
|
171
|
+
| `ctx.enrich` | Success-path agent context (empty-result notices, query echo, pagination totals) — `ctx.enrich(...)` or `.notice()` / `.total()` / `.echo()` / `.truncated()`. Reaches `structuredContent` and `content[]`; lands only when the definition declares an `enrichment` block (no-op otherwise). |
|
|
172
|
+
| `ctx.content` | Non-text content blocks — `.image(data, mimeType)`, `.audio(data, mimeType)`, or `ctx.content(block)` for a raw block. Prepended to `content[]` after `format()`; never enters `structuredContent`. |
|
|
169
173
|
| `ctx.recoveryFor(reason)` | Typed lookup of the contract `recovery` for a declared reason. Returns `{ recovery: { hint } }` for known reasons, `{}` otherwise. Spread into `ctx.fail` data to mirror the contract hint into `content[]`. |
|
|
170
174
|
| `ctx.signal` | `AbortSignal` for cancellation. |
|
|
171
175
|
| `ctx.requestId` | Unique request ID. |
|
|
@@ -197,6 +201,8 @@ async handler(input, ctx) {
|
|
|
197
201
|
}
|
|
198
202
|
```
|
|
199
203
|
|
|
204
|
+
**Declare contracts inline on each tool.** The contract is part of the tool's public surface — one file should give the full picture. Don't extract a shared `errors[]` constant; per-tool repetition is the intended cost of locality.
|
|
205
|
+
|
|
200
206
|
**Fallback (no contract entry fits):** error factories or plain `Error`.
|
|
201
207
|
|
|
202
208
|
```ts
|
|
@@ -280,7 +286,6 @@ Available skills:
|
|
|
280
286
|
| `tool-defs-analysis` | Read-only audit of definition language: voice, leaks, defaults, recovery hints, examples |
|
|
281
287
|
| `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
|
|
282
288
|
| `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
|
|
283
|
-
| `devcheck` | Lint, format, typecheck, audit |
|
|
284
289
|
| `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
|
|
285
290
|
| `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
|
|
286
291
|
| `git-wrapup` | Land working-tree changes as a versioned commit + annotated tag — version bump, changelog, verify, tag. Local only. |
|
|
@@ -318,8 +323,11 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
318
323
|
| `bun run devcheck` | Lint + format + typecheck + security + packaging alignment |
|
|
319
324
|
| `bun run audit:refresh` | Delete `bun.lock`, reinstall, and re-run `bun audit`. Use when `devcheck` flags a transitive advisory — `bun update` is sticky on transitive resolutions, so the advisory may be a stale-lockfile false positive. If it survives the refresh, it's real. |
|
|
320
325
|
| `bun run tree` | Generate directory structure doc |
|
|
321
|
-
| `bun run format` | Auto-fix formatting |
|
|
322
|
-
| `bun run
|
|
326
|
+
| `bun run format` | Auto-fix formatting (safe fixes only) |
|
|
327
|
+
| `bun run format:unsafe` | Also apply Biome's unsafe autofixes — review the diff; they can change behavior |
|
|
328
|
+
| `bun run test` | Run tests (Vitest — use `bun run test`, not `bun test`) |
|
|
329
|
+
| `bun run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
|
|
330
|
+
| `bun run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
|
|
323
331
|
| `bun run lint:mcp` | Validate MCP definitions against spec |
|
|
324
332
|
| `bun run lint:packaging` | Validate env var alignment between `manifest.json` and `server.json` (skipped cleanly when `manifest.json` is absent) |
|
|
325
333
|
| `bun run list-skills` | List skills in `skills/` with name + description |
|
|
@@ -332,12 +340,26 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
332
340
|
|
|
333
341
|
## Bundling
|
|
334
342
|
|
|
335
|
-
`bun run bundle` produces `dist/pubmed-mcp-server.mcpb` for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips dependency-shipped agent docs (`
|
|
343
|
+
`bun run bundle` produces `dist/pubmed-mcp-server.mcpb` for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips two classes of `node_modules/**` content that root-anchored `.mcpbignore` patterns cannot reach: dependency-shipped agent docs (`skills/`, `.claude/`, `.agents/`, `SKILL.md`) and platform-specific native bindings, which would otherwise lock the bundle to the platform it was packed on. MCPB is stdio-only — HTTP and Docker deployments are unaffected. The `release-and-publish` skill attaches the bundle to the GitHub Release at a stable `releases/latest/download/pubmed-mcp-server.mcpb` URL that powers the README install badge.
|
|
336
344
|
|
|
337
345
|
**Adding an env var requires both files**: `server.json` stdio `environmentVariables[]` (registry discovery) and `manifest.json` `mcp_config.env` (bundle install UX, plus `user_config` if user-prompted). `bun run lint:packaging` (run by `devcheck`) verifies the env var names align.
|
|
338
346
|
|
|
339
347
|
---
|
|
340
348
|
|
|
349
|
+
## Changelog
|
|
350
|
+
|
|
351
|
+
Directory-based, grouped by minor series via the `.x` semver-wildcard convention. Source of truth: `changelog/<major.minor>.x/<version>.md` (e.g. `changelog/2.9.x/2.9.8.md`) — one file per release. At release, author the per-version file with a concrete version and date, then run `bun run changelog:build` to regenerate the rollup. `changelog/template.md` is a **pristine format reference** — never edited or moved; read it for the frontmatter + section layout when scaffolding. `CHANGELOG.md` is a **navigation index** (header + link + summary per version), regenerated by `bun run changelog:build` — devcheck hard-fails on drift; never hand-edit it.
|
|
352
|
+
|
|
353
|
+
`breaking: true` renders a `· ⚠️ Breaking` badge — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames). `security: true` renders a `· 🛡️ Security` badge and pairs with a `## Security` body section — set it only for a security fix in this server's *own source code*, never for a routine dependency or transitive CVE bump (record those under `## Dependencies`).
|
|
354
|
+
|
|
355
|
+
`agent-notes` is an optional free-form field consumed by agents running the `maintenance` skill downstream — adoption instructions that don't fit the human-facing sections. Omit entirely when there's nothing to say.
|
|
356
|
+
|
|
357
|
+
**Section order** (Keep a Changelog): Added, Changed, Deprecated, Removed, Fixed, Security. Include only sections with entries.
|
|
358
|
+
|
|
359
|
+
**Tag annotations** render as GitHub Release bodies via `--notes-from-tag`. They must be structured markdown — never a flat comma-separated string. Subject omits the version number (GitHub prepends it). See `changelog/template.md` for the full format reference.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
341
363
|
## Publishing
|
|
342
364
|
|
|
343
365
|
Run the `release-and-publish` skill after git wrapup — it runs the verification gate (`devcheck`, `rebuild`, `test`), pushes commits and tags, and publishes to npm, the MCP Registry, GHCR, and attaches the `.mcpb` bundle to the GitHub Release, halting on the first failure. For reference, the underlying commands are:
|
package/CLAUDE.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** @cyanheads/pubmed-mcp-server
|
|
4
|
-
**Version:** 2.9.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.
|
|
6
|
-
**Engines:** Bun ≥1.3.
|
|
4
|
+
**Version:** 2.9.9
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.11.0`
|
|
6
|
+
**Engines:** Bun ≥1.3.0, Node ≥24.0.0
|
|
7
7
|
|
|
8
8
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
9
9
|
|
|
@@ -137,6 +137,8 @@ export function getServerConfig(): z.infer<typeof ServerConfigSchema> {
|
|
|
137
137
|
|
|
138
138
|
`parseEnvConfig` maps Zod schema paths → env var names so validation errors name the actual variable (`NCBI_REQUEST_DELAY_MS` must be a number) rather than the internal path (`requestDelayMs: expected number`).
|
|
139
139
|
|
|
140
|
+
For env booleans use `z.stringbool()`, never `z.coerce.boolean()` — `Boolean("false")` is `true`, so a coerced flag can't be disabled through the environment. `z.stringbool()` parses `true/false/1/0/yes/no/on/off` and rejects anything else, so `=false` actually disables.
|
|
141
|
+
|
|
140
142
|
### Server identity and instructions
|
|
141
143
|
|
|
142
144
|
`createApp()` accepts optional identity fields forwarded to the SDK's `initialize` response and the server manifest (`/.well-known/mcp.json`):
|
|
@@ -163,9 +165,11 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
163
165
|
| Property | Description |
|
|
164
166
|
|:---------|:------------|
|
|
165
167
|
| `ctx.log` | Request-scoped logger — `.debug()`, `.info()`, `.notice()`, `.warning()`, `.error()`. Auto-correlates requestId, traceId, tenantId. |
|
|
166
|
-
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
168
|
+
| `ctx.state` | Tenant-scoped KV — `.get(key)`, `.set(key, value, { ttl? })`, `.delete(key)`, `.getMany(keys)`, `.list(prefix, { cursor, limit })`. Accepts any serializable value. |
|
|
167
169
|
| `ctx.elicit` | Ask user for structured input — form call `(message, schema)` or `.url(message, url)` for an external link. **Check for presence first:** `if (ctx.elicit) { ... }` |
|
|
168
170
|
| `ctx.progress` | Task progress (present when `task: true`) — `.setTotal(n)`, `.increment()`, `.update(message)`. |
|
|
171
|
+
| `ctx.enrich` | Success-path agent context (empty-result notices, query echo, pagination totals) — `ctx.enrich(...)` or `.notice()` / `.total()` / `.echo()` / `.truncated()`. Reaches `structuredContent` and `content[]`; lands only when the definition declares an `enrichment` block (no-op otherwise). |
|
|
172
|
+
| `ctx.content` | Non-text content blocks — `.image(data, mimeType)`, `.audio(data, mimeType)`, or `ctx.content(block)` for a raw block. Prepended to `content[]` after `format()`; never enters `structuredContent`. |
|
|
169
173
|
| `ctx.recoveryFor(reason)` | Typed lookup of the contract `recovery` for a declared reason. Returns `{ recovery: { hint } }` for known reasons, `{}` otherwise. Spread into `ctx.fail` data to mirror the contract hint into `content[]`. |
|
|
170
174
|
| `ctx.signal` | `AbortSignal` for cancellation. |
|
|
171
175
|
| `ctx.requestId` | Unique request ID. |
|
|
@@ -197,6 +201,8 @@ async handler(input, ctx) {
|
|
|
197
201
|
}
|
|
198
202
|
```
|
|
199
203
|
|
|
204
|
+
**Declare contracts inline on each tool.** The contract is part of the tool's public surface — one file should give the full picture. Don't extract a shared `errors[]` constant; per-tool repetition is the intended cost of locality.
|
|
205
|
+
|
|
200
206
|
**Fallback (no contract entry fits):** error factories or plain `Error`.
|
|
201
207
|
|
|
202
208
|
```ts
|
|
@@ -280,7 +286,6 @@ Available skills:
|
|
|
280
286
|
| `tool-defs-analysis` | Read-only audit of definition language: voice, leaks, defaults, recovery hints, examples |
|
|
281
287
|
| `security-pass` | Audit server for MCP-flavored security gaps: output injection, scope blast radius, input sinks, tenant isolation |
|
|
282
288
|
| `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
|
|
283
|
-
| `devcheck` | Lint, format, typecheck, audit |
|
|
284
289
|
| `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
|
|
285
290
|
| `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
|
|
286
291
|
| `git-wrapup` | Land working-tree changes as a versioned commit + annotated tag — version bump, changelog, verify, tag. Local only. |
|
|
@@ -318,8 +323,11 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
318
323
|
| `bun run devcheck` | Lint + format + typecheck + security + packaging alignment |
|
|
319
324
|
| `bun run audit:refresh` | Delete `bun.lock`, reinstall, and re-run `bun audit`. Use when `devcheck` flags a transitive advisory — `bun update` is sticky on transitive resolutions, so the advisory may be a stale-lockfile false positive. If it survives the refresh, it's real. |
|
|
320
325
|
| `bun run tree` | Generate directory structure doc |
|
|
321
|
-
| `bun run format` | Auto-fix formatting |
|
|
322
|
-
| `bun run
|
|
326
|
+
| `bun run format` | Auto-fix formatting (safe fixes only) |
|
|
327
|
+
| `bun run format:unsafe` | Also apply Biome's unsafe autofixes — review the diff; they can change behavior |
|
|
328
|
+
| `bun run test` | Run tests (Vitest — use `bun run test`, not `bun test`) |
|
|
329
|
+
| `bun run changelog:build` | Regenerate `CHANGELOG.md` from `changelog/*.md` |
|
|
330
|
+
| `bun run changelog:check` | Verify `CHANGELOG.md` is in sync (used by devcheck) |
|
|
323
331
|
| `bun run lint:mcp` | Validate MCP definitions against spec |
|
|
324
332
|
| `bun run lint:packaging` | Validate env var alignment between `manifest.json` and `server.json` (skipped cleanly when `manifest.json` is absent) |
|
|
325
333
|
| `bun run list-skills` | List skills in `skills/` with name + description |
|
|
@@ -332,12 +340,26 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
332
340
|
|
|
333
341
|
## Bundling
|
|
334
342
|
|
|
335
|
-
`bun run bundle` produces `dist/pubmed-mcp-server.mcpb` for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips dependency-shipped agent docs (`
|
|
343
|
+
`bun run bundle` produces `dist/pubmed-mcp-server.mcpb` for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips two classes of `node_modules/**` content that root-anchored `.mcpbignore` patterns cannot reach: dependency-shipped agent docs (`skills/`, `.claude/`, `.agents/`, `SKILL.md`) and platform-specific native bindings, which would otherwise lock the bundle to the platform it was packed on. MCPB is stdio-only — HTTP and Docker deployments are unaffected. The `release-and-publish` skill attaches the bundle to the GitHub Release at a stable `releases/latest/download/pubmed-mcp-server.mcpb` URL that powers the README install badge.
|
|
336
344
|
|
|
337
345
|
**Adding an env var requires both files**: `server.json` stdio `environmentVariables[]` (registry discovery) and `manifest.json` `mcp_config.env` (bundle install UX, plus `user_config` if user-prompted). `bun run lint:packaging` (run by `devcheck`) verifies the env var names align.
|
|
338
346
|
|
|
339
347
|
---
|
|
340
348
|
|
|
349
|
+
## Changelog
|
|
350
|
+
|
|
351
|
+
Directory-based, grouped by minor series via the `.x` semver-wildcard convention. Source of truth: `changelog/<major.minor>.x/<version>.md` (e.g. `changelog/2.9.x/2.9.8.md`) — one file per release. At release, author the per-version file with a concrete version and date, then run `bun run changelog:build` to regenerate the rollup. `changelog/template.md` is a **pristine format reference** — never edited or moved; read it for the frontmatter + section layout when scaffolding. `CHANGELOG.md` is a **navigation index** (header + link + summary per version), regenerated by `bun run changelog:build` — devcheck hard-fails on drift; never hand-edit it.
|
|
352
|
+
|
|
353
|
+
`breaking: true` renders a `· ⚠️ Breaking` badge — use it when consumers must update code on upgrade (signature changes, removed APIs, config renames). `security: true` renders a `· 🛡️ Security` badge and pairs with a `## Security` body section — set it only for a security fix in this server's *own source code*, never for a routine dependency or transitive CVE bump (record those under `## Dependencies`).
|
|
354
|
+
|
|
355
|
+
`agent-notes` is an optional free-form field consumed by agents running the `maintenance` skill downstream — adoption instructions that don't fit the human-facing sections. Omit entirely when there's nothing to say.
|
|
356
|
+
|
|
357
|
+
**Section order** (Keep a Changelog): Added, Changed, Deprecated, Removed, Fixed, Security. Include only sections with entries.
|
|
358
|
+
|
|
359
|
+
**Tag annotations** render as GitHub Release bodies via `--notes-from-tag`. They must be structured markdown — never a flat comma-separated string. Subject omits the version number (GitHub prepends it). See `changelog/template.md` for the full format reference.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
341
363
|
## Publishing
|
|
342
364
|
|
|
343
365
|
Run the `release-and-publish` skill after git wrapup — it runs the verification gate (`devcheck`, `rebuild`, `test`), pushes commits and tags, and publishes to npm, the MCP Registry, GHCR, and attaches the `.mcpb` bundle to the GitHub Release, halting on the first failure. For reference, the underlying commands are:
|
package/Dockerfile
CHANGED
|
@@ -4,15 +4,19 @@
|
|
|
4
4
|
# This stage installs all dependencies (including dev), builds the TypeScript
|
|
5
5
|
# source code into JavaScript, and prepares the production assets.
|
|
6
6
|
# ==============================================================================
|
|
7
|
-
FROM oven/bun:1.3 AS build
|
|
7
|
+
FROM oven/bun:1.3.14 AS build
|
|
8
8
|
|
|
9
9
|
WORKDIR /usr/src/app
|
|
10
10
|
|
|
11
11
|
# Copy dependency manifests for optimized layer caching
|
|
12
12
|
COPY package.json bun.lock ./
|
|
13
13
|
|
|
14
|
-
# Install all dependencies (including dev dependencies for building)
|
|
15
|
-
|
|
14
|
+
# Install all dependencies (including dev dependencies for building). Lifecycle
|
|
15
|
+
# scripts are skipped — the build only runs `tsc`, which needs type declarations,
|
|
16
|
+
# not compiled native bindings.
|
|
17
|
+
# The BuildKit cache mount persists Bun's global package cache across builds.
|
|
18
|
+
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
19
|
+
bun install --frozen-lockfile --ignore-scripts
|
|
16
20
|
|
|
17
21
|
# Copy the rest of the source code
|
|
18
22
|
COPY . .
|
|
@@ -28,7 +32,7 @@ RUN bun run build
|
|
|
28
32
|
# application. It uses a slim base image and only includes production
|
|
29
33
|
# dependencies and build artifacts.
|
|
30
34
|
# ==============================================================================
|
|
31
|
-
FROM oven/bun:1.3-slim AS production
|
|
35
|
+
FROM oven/bun:1.3.14-slim AS production
|
|
32
36
|
|
|
33
37
|
WORKDIR /usr/src/app
|
|
34
38
|
|
|
@@ -47,14 +51,16 @@ COPY package.json bun.lock ./
|
|
|
47
51
|
|
|
48
52
|
# Install only production dependencies, ignoring any lifecycle scripts (like 'prepare')
|
|
49
53
|
# that are not needed in the final production image.
|
|
50
|
-
RUN bun
|
|
54
|
+
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
55
|
+
bun install --production --frozen-lockfile --ignore-scripts
|
|
51
56
|
|
|
52
57
|
# Conditionally install OpenTelemetry optional peer dependencies (Tier 3).
|
|
53
58
|
# These are not bundled by default to keep the base image lean. Enable at build time
|
|
54
59
|
# with: docker build --build-arg OTEL_ENABLED=true
|
|
55
60
|
ARG OTEL_ENABLED=true
|
|
56
|
-
RUN
|
|
57
|
-
|
|
61
|
+
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
62
|
+
if [ "$OTEL_ENABLED" = "true" ]; then \
|
|
63
|
+
bun add --omit=dev --ignore-scripts @hono/otel \
|
|
58
64
|
@opentelemetry/instrumentation-http \
|
|
59
65
|
@opentelemetry/exporter-metrics-otlp-http \
|
|
60
66
|
@opentelemetry/exporter-trace-otlp-http \
|
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
|
|
|
@@ -11,8 +11,8 @@ export declare const researchPlanPrompt: import("@cyanheads/mcp-ts-core").Prompt
|
|
|
11
11
|
keywords: z.ZodString;
|
|
12
12
|
organism: z.ZodOptional<z.ZodString>;
|
|
13
13
|
includeAgentPrompts: z.ZodDefault<z.ZodEnum<{
|
|
14
|
-
true: "true";
|
|
15
14
|
false: "false";
|
|
15
|
+
true: "true";
|
|
16
16
|
}>>;
|
|
17
17
|
}, z.core.$strip>>;
|
|
18
18
|
//# sourceMappingURL=research-plan.prompt.d.ts.map
|
|
@@ -7,9 +7,9 @@ import { z } from '@cyanheads/mcp-ts-core';
|
|
|
7
7
|
export declare const convertIdsTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
8
|
ids: z.ZodArray<z.ZodString>;
|
|
9
9
|
idType: z.ZodEnum<{
|
|
10
|
-
pmid: "pmid";
|
|
11
|
-
pmcid: "pmcid";
|
|
12
10
|
doi: "doi";
|
|
11
|
+
pmcid: "pmcid";
|
|
12
|
+
pmid: "pmid";
|
|
13
13
|
}>;
|
|
14
14
|
}, z.core.$strip>, z.ZodObject<{
|
|
15
15
|
records: z.ZodArray<z.ZodObject<{
|
|
@@ -22,34 +22,34 @@ export declare const convertIdsTool: import("@cyanheads/mcp-ts-core").ToolDefini
|
|
|
22
22
|
totalConverted: z.ZodNumber;
|
|
23
23
|
totalSubmitted: z.ZodNumber;
|
|
24
24
|
}, z.core.$strip>, readonly [{
|
|
25
|
-
readonly reason:
|
|
25
|
+
readonly reason: 'queue_full';
|
|
26
26
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.RateLimited;
|
|
27
|
-
readonly when:
|
|
28
|
-
readonly recovery:
|
|
27
|
+
readonly when: 'Local NCBI request queue is at capacity.';
|
|
28
|
+
readonly recovery: 'Retry after 1-2 seconds; the request queue hit the NCBI rate limit.';
|
|
29
29
|
readonly retryable: true;
|
|
30
30
|
}, {
|
|
31
|
-
readonly reason:
|
|
31
|
+
readonly reason: 'ncbi_unreachable';
|
|
32
32
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
33
|
-
readonly when:
|
|
34
|
-
readonly recovery:
|
|
33
|
+
readonly when: 'NCBI E-utilities is unreachable after all retry attempts.';
|
|
34
|
+
readonly recovery: 'Retry after a brief delay; NCBI was unreachable across all retry attempts.';
|
|
35
35
|
readonly retryable: true;
|
|
36
36
|
}, {
|
|
37
|
-
readonly reason:
|
|
37
|
+
readonly reason: 'ncbi_deadline_exceeded';
|
|
38
38
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.Timeout;
|
|
39
|
-
readonly when:
|
|
40
|
-
readonly recovery:
|
|
39
|
+
readonly when: 'Total request deadline expired before NCBI returned a response.';
|
|
40
|
+
readonly recovery: 'Reduce batch size or retry; NCBI may be under temporary load.';
|
|
41
41
|
readonly retryable: true;
|
|
42
42
|
}, {
|
|
43
|
-
readonly reason:
|
|
43
|
+
readonly reason: 'ncbi_invalid_response';
|
|
44
44
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.SerializationError;
|
|
45
|
-
readonly when:
|
|
46
|
-
readonly recovery:
|
|
45
|
+
readonly when: 'NCBI returned a body that could not be parsed (invalid XML/JSON).';
|
|
46
|
+
readonly recovery: 'Retry the request; NCBI returned a malformed response that could not be parsed.';
|
|
47
47
|
readonly retryable: true;
|
|
48
48
|
}, {
|
|
49
|
-
readonly reason:
|
|
49
|
+
readonly reason: 'ncbi_resource_not_found';
|
|
50
50
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
51
|
-
readonly when:
|
|
52
|
-
readonly recovery:
|
|
51
|
+
readonly when: 'NCBI returned a structured "not found" error for the requested ID(s).';
|
|
52
|
+
readonly recovery: 'Verify the ID exists in PubMed; the resource was not found in NCBI and retrying will not help.';
|
|
53
53
|
readonly retryable: false;
|
|
54
54
|
}], undefined>;
|
|
55
55
|
//# sourceMappingURL=convert-ids.tool.d.ts.map
|
|
@@ -70,40 +70,40 @@ export declare const fetchArticlesTool: import("@cyanheads/mcp-ts-core").ToolDef
|
|
|
70
70
|
totalReturned: z.ZodNumber;
|
|
71
71
|
unavailablePmids: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
72
72
|
}, z.core.$strip>, readonly [{
|
|
73
|
-
readonly reason:
|
|
73
|
+
readonly reason: 'queue_full';
|
|
74
74
|
readonly code: JsonRpcErrorCode.RateLimited;
|
|
75
|
-
readonly when:
|
|
76
|
-
readonly recovery:
|
|
75
|
+
readonly when: 'Local NCBI request queue is at capacity.';
|
|
76
|
+
readonly recovery: 'Retry after 1-2 seconds; the request queue hit the NCBI rate limit.';
|
|
77
77
|
readonly retryable: true;
|
|
78
78
|
}, {
|
|
79
|
-
readonly reason:
|
|
79
|
+
readonly reason: 'ncbi_unreachable';
|
|
80
80
|
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
81
|
-
readonly when:
|
|
82
|
-
readonly recovery:
|
|
81
|
+
readonly when: 'NCBI E-utilities is unreachable after all retry attempts.';
|
|
82
|
+
readonly recovery: 'Retry after a brief delay; NCBI was unreachable across all retry attempts.';
|
|
83
83
|
readonly retryable: true;
|
|
84
84
|
}, {
|
|
85
|
-
readonly reason:
|
|
85
|
+
readonly reason: 'ncbi_deadline_exceeded';
|
|
86
86
|
readonly code: JsonRpcErrorCode.Timeout;
|
|
87
|
-
readonly when:
|
|
88
|
-
readonly recovery:
|
|
87
|
+
readonly when: 'Total request deadline expired before NCBI returned a response.';
|
|
88
|
+
readonly recovery: 'Reduce batch size or retry; NCBI may be under temporary load.';
|
|
89
89
|
readonly retryable: true;
|
|
90
90
|
}, {
|
|
91
|
-
readonly reason:
|
|
91
|
+
readonly reason: 'ncbi_invalid_response';
|
|
92
92
|
readonly code: JsonRpcErrorCode.SerializationError;
|
|
93
|
-
readonly when:
|
|
94
|
-
readonly recovery:
|
|
93
|
+
readonly when: 'NCBI returned a body that could not be parsed (invalid XML/JSON).';
|
|
94
|
+
readonly recovery: 'Retry the request; NCBI returned a malformed response that could not be parsed.';
|
|
95
95
|
readonly retryable: true;
|
|
96
96
|
}, {
|
|
97
|
-
readonly reason:
|
|
97
|
+
readonly reason: 'ncbi_resource_not_found';
|
|
98
98
|
readonly code: JsonRpcErrorCode.NotFound;
|
|
99
|
-
readonly when:
|
|
100
|
-
readonly recovery:
|
|
99
|
+
readonly when: 'NCBI returned a structured "not found" error for the requested ID(s).';
|
|
100
|
+
readonly recovery: 'Verify the ID exists in PubMed; the resource was not found in NCBI and retrying will not help.';
|
|
101
101
|
readonly retryable: false;
|
|
102
102
|
}, {
|
|
103
|
-
readonly reason:
|
|
103
|
+
readonly reason: 'invalid_efetch_response';
|
|
104
104
|
readonly code: JsonRpcErrorCode.SerializationError;
|
|
105
|
-
readonly when:
|
|
106
|
-
readonly recovery:
|
|
105
|
+
readonly when: 'NCBI EFetch returned a payload missing the PubmedArticleSet wrapper.';
|
|
106
|
+
readonly recovery: 'Retry once; if it persists, NCBI returned malformed data — try fewer PMIDs at once.';
|
|
107
107
|
}], {
|
|
108
108
|
readonly notice: z.ZodOptional<z.ZodString>;
|
|
109
109
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-articles.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fetch-articles.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAyGjE,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"fetch-articles.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/fetch-articles.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAyGjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAWhB,yBAAyB;;mBAE3B,sEAAsE;uBAE1E,qFAAqF;;;EAsK3F,CAAC"}
|
|
@@ -40,8 +40,8 @@ export declare const fetchFulltextTool: import("@cyanheads/mcp-ts-core").ToolDef
|
|
|
40
40
|
articles: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
41
41
|
source: z.ZodLiteral<"pmc">;
|
|
42
42
|
viaSource: z.ZodEnum<{
|
|
43
|
-
pmc: "pmc";
|
|
44
43
|
europepmc: "europepmc";
|
|
44
|
+
pmc: "pmc";
|
|
45
45
|
}>;
|
|
46
46
|
pmcId: z.ZodOptional<z.ZodString>;
|
|
47
47
|
pmcUrl: z.ZodOptional<z.ZodString>;
|
|
@@ -110,92 +110,92 @@ export declare const fetchFulltextTool: import("@cyanheads/mcp-ts-core").ToolDef
|
|
|
110
110
|
unavailable: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
111
111
|
id: z.ZodString;
|
|
112
112
|
idType: z.ZodEnum<{
|
|
113
|
-
pmid: "pmid";
|
|
114
|
-
pmcid: "pmcid";
|
|
115
113
|
doi: "doi";
|
|
114
|
+
pmcid: "pmcid";
|
|
115
|
+
pmid: "pmid";
|
|
116
116
|
}>;
|
|
117
117
|
reason: z.ZodEnum<{
|
|
118
|
+
"fetch-failed": "fetch-failed";
|
|
119
|
+
"no-doi": "no-doi";
|
|
120
|
+
"no-epmc-fulltext": "no-epmc-fulltext";
|
|
118
121
|
"no-oa": "no-oa";
|
|
119
|
-
"not-found": "not-found";
|
|
120
122
|
"no-pmc-fallback-disabled": "no-pmc-fallback-disabled";
|
|
121
|
-
"
|
|
122
|
-
"no-doi": "no-doi";
|
|
123
|
-
"fetch-failed": "fetch-failed";
|
|
123
|
+
"not-found": "not-found";
|
|
124
124
|
"parse-failed": "parse-failed";
|
|
125
125
|
"service-error": "service-error";
|
|
126
126
|
}>;
|
|
127
127
|
triedTiers: z.ZodArray<z.ZodObject<{
|
|
128
128
|
tier: z.ZodEnum<{
|
|
129
|
-
pmc: "pmc";
|
|
130
129
|
europepmc: "europepmc";
|
|
130
|
+
pmc: "pmc";
|
|
131
131
|
unpaywall: "unpaywall";
|
|
132
132
|
}>;
|
|
133
133
|
outcome: z.ZodEnum<{
|
|
134
|
-
"no-oa": "no-oa";
|
|
135
|
-
"no-doi": "no-doi";
|
|
136
134
|
"fetch-failed": "fetch-failed";
|
|
137
|
-
"parse-failed": "parse-failed";
|
|
138
|
-
"service-error": "service-error";
|
|
139
|
-
"not-attempted": "not-attempted";
|
|
140
135
|
miss: "miss";
|
|
136
|
+
"no-doi": "no-doi";
|
|
141
137
|
"no-fulltext": "no-fulltext";
|
|
138
|
+
"no-oa": "no-oa";
|
|
139
|
+
"not-attempted": "not-attempted";
|
|
140
|
+
"parse-failed": "parse-failed";
|
|
141
|
+
"service-error": "service-error";
|
|
142
142
|
}>;
|
|
143
143
|
detail: z.ZodOptional<z.ZodString>;
|
|
144
144
|
}, z.core.$strip>>;
|
|
145
145
|
}, z.core.$strip>>>;
|
|
146
146
|
}, z.core.$strip>, readonly [{
|
|
147
|
-
readonly reason:
|
|
147
|
+
readonly reason: 'queue_full';
|
|
148
148
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.RateLimited;
|
|
149
|
-
readonly when:
|
|
150
|
-
readonly recovery:
|
|
149
|
+
readonly when: 'Local NCBI request queue is at capacity.';
|
|
150
|
+
readonly recovery: 'Retry after 1-2 seconds; the request queue hit the NCBI rate limit.';
|
|
151
151
|
readonly retryable: true;
|
|
152
152
|
}, {
|
|
153
|
-
readonly reason:
|
|
153
|
+
readonly reason: 'ncbi_unreachable';
|
|
154
154
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
155
|
-
readonly when:
|
|
156
|
-
readonly recovery:
|
|
155
|
+
readonly when: 'NCBI E-utilities is unreachable after all retry attempts.';
|
|
156
|
+
readonly recovery: 'Retry after a brief delay; NCBI was unreachable across all retry attempts.';
|
|
157
157
|
readonly retryable: true;
|
|
158
158
|
}, {
|
|
159
|
-
readonly reason:
|
|
159
|
+
readonly reason: 'ncbi_deadline_exceeded';
|
|
160
160
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.Timeout;
|
|
161
|
-
readonly when:
|
|
162
|
-
readonly recovery:
|
|
161
|
+
readonly when: 'Total request deadline expired before NCBI returned a response.';
|
|
162
|
+
readonly recovery: 'Reduce batch size or retry; NCBI may be under temporary load.';
|
|
163
163
|
readonly retryable: true;
|
|
164
164
|
}, {
|
|
165
|
-
readonly reason:
|
|
165
|
+
readonly reason: 'ncbi_invalid_response';
|
|
166
166
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.SerializationError;
|
|
167
|
-
readonly when:
|
|
168
|
-
readonly recovery:
|
|
167
|
+
readonly when: 'NCBI returned a body that could not be parsed (invalid XML/JSON).';
|
|
168
|
+
readonly recovery: 'Retry the request; NCBI returned a malformed response that could not be parsed.';
|
|
169
169
|
readonly retryable: true;
|
|
170
170
|
}, {
|
|
171
|
-
readonly reason:
|
|
171
|
+
readonly reason: 'ncbi_resource_not_found';
|
|
172
172
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
173
|
-
readonly when:
|
|
174
|
-
readonly recovery:
|
|
173
|
+
readonly when: 'NCBI returned a structured "not found" error for the requested ID(s).';
|
|
174
|
+
readonly recovery: 'Verify the ID exists in PubMed; the resource was not found in NCBI and retrying will not help.';
|
|
175
175
|
readonly retryable: false;
|
|
176
176
|
}, {
|
|
177
|
-
readonly reason:
|
|
177
|
+
readonly reason: 'unpaywall_unreachable';
|
|
178
178
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
179
|
-
readonly when:
|
|
180
|
-
readonly recovery:
|
|
179
|
+
readonly when: 'Unpaywall was unreachable when resolving a DOI or fetching content.';
|
|
180
|
+
readonly recovery: 'Retry after a brief delay; Unpaywall was unreachable. The PMC source remains the primary path.';
|
|
181
181
|
readonly retryable: true;
|
|
182
182
|
}, {
|
|
183
|
-
readonly reason:
|
|
183
|
+
readonly reason: 'europepmc_unreachable';
|
|
184
184
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
185
|
-
readonly when:
|
|
186
|
-
readonly recovery:
|
|
185
|
+
readonly when: 'Europe PMC was unreachable after all retry attempts.';
|
|
186
|
+
readonly recovery: 'Retry after a brief delay; Europe PMC was unreachable. NCBI PMC and Unpaywall remain available.';
|
|
187
187
|
readonly retryable: true;
|
|
188
188
|
}, {
|
|
189
|
-
readonly reason:
|
|
189
|
+
readonly reason: 'europepmc_invalid_response';
|
|
190
190
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.SerializationError;
|
|
191
|
-
readonly when:
|
|
192
|
-
readonly recovery:
|
|
191
|
+
readonly when: 'Europe PMC returned a body that could not be parsed (invalid JSON or XML).';
|
|
192
|
+
readonly recovery: 'Retry the request; Europe PMC returned a malformed response that could not be parsed.';
|
|
193
193
|
readonly retryable: true;
|
|
194
194
|
}, {
|
|
195
|
-
readonly reason:
|
|
195
|
+
readonly reason: 'europepmc_invalid_input';
|
|
196
196
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
197
|
-
readonly when:
|
|
198
|
-
readonly recovery:
|
|
197
|
+
readonly when: 'Europe PMC rejected the request input (empty query, unknown sort field, malformed parameter).';
|
|
198
|
+
readonly recovery: 'Adjust the input — usually the query or sort field — before retrying; the same input will be rejected again.';
|
|
199
199
|
readonly retryable: false;
|
|
200
200
|
}], {
|
|
201
201
|
readonly notice: z.ZodOptional<z.ZodString>;
|