pubmed-mcp-server
The PubMed MCP Server integrates with PubMed's biomedical literature database, enabling AI agents and research tools to search, retrieve, analyze, and visualize scientific publications:
Search PubMed Articles: Query articles using keywords, filters, date ranges, and sorting options
Fetch PubMed Content: Retrieve article information by PMID or search history, with customizable detail levels (abstract, full XML, MEDLINE text) and pagination
Find Related Articles: Identify similar articles, citations, or references to a given PMID
Generate Citations: Create formatted citations in RIS, BibTeX, APA, or MLA styles
Generate Research Plans: Create structured JSON research plans with detailed inputs
Visualize Data: Generate customizable charts (bar, line, scatter) from publication metadata as PNG images
Automate Research Workflows: Programmatically access PubMed data for AI-driven research and evidence-based decision-making
Integrate with NCBI APIs: Leverage NCBI E-utilities with built-in error handling and rate limit compliance
Connects AI agents to NCBI's PubMed and E-utilities, enabling search, retrieval, and analysis of biomedical literature. Provides tools for searching articles, fetching detailed content, finding related articles, generating citations, creating research plans, and visualizing data through charts.
Generates SVG chart visualizations from PubMed data, supporting bar, line, and scatter chart types for data representation.
Built with TypeScript for type safety and robust input validation, ensuring secure and reliable interactions with PubMed's biomedical data.
Utilizes Vega-Lite specifications to render SVG charts from PubMed data, enabling visualization of biomedical research trends and statistics.
Processes PubMed article data in XML format, providing JSON representation of the PubMedArticle XML structure through the fetch_pubmed_content tool.
Uses Zod for schema validation of inputs and outputs when interacting with PubMed, ensuring type safety and proper data formatting.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pubmed-mcp-serversearch for recent articles about CRISPR gene editing in cancer therapy"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://pubmed.caseyjhand.com/mcp
Tools
11 tools for working with PubMed, PubMed Central, and Europe PMC data:
Tool | Description |
| Search PubMed with full query syntax, field-specific filters, date ranges, pagination, and optional brief summaries |
| Search Europe PMC for preprints, patents, Agricola, and EPMC-only OA records that don't surface in PubMed. Cursor-based pagination. |
| Fetch complete Europe PMC records — including the untruncated abstract — by |
| Fetch full article metadata by PMIDs — abstract, authors, journal, MeSH terms, grants |
| Fetch full-text articles via a chain: NCBI PMC EFetch → Europe PMC |
| Generate formatted citations in APA 7th, MLA 9th, BibTeX, RIS, or Vancouver (ICMJE/NLM) |
| Find similar articles, citing articles, or references for a given PMID |
| Spell-check biomedical queries using NCBI's ESpell service |
| Search and explore MeSH vocabulary — tree numbers, scope notes, entry terms |
| Resolve partial bibliographic references to PubMed IDs via ECitMatch |
| Convert between DOI, PMID, and PMCID using the PMC ID Converter API |
pubmed_search_articles
Search PubMed with full NCBI query syntax and filters.
Free-text queries with PubMed's full boolean and field-tag syntax
Field-specific filters: author, journal, MeSH terms, language, species
Common filters: has abstract, free full text
Date range filtering by publication, modification, or Entrez date
Publication type filtering (Review, Clinical Trial, Meta-Analysis, etc.)
Sort by relevance, publication date, author, or journal
Pagination via offset for paging through large result sets
Optional brief summaries for top N results via ESummary
NCBI Bookshelf results carry their own venue —
bookTitle,publisherName, anddocType(chapter,book, orcitation) — because PubMed leavessourceempty on them; the book's editors are reported ineditors, apart from the chapter's own authorsReturns the original query plus the fully applied PubMed query and normalized filter metadata
pubmed_fetch_articles
Fetch full article metadata by PubMed IDs.
Batch fetch up to 200 articles at once (auto-switches to POST for batches >= 100)
Returns structured data: title, abstract, authors with deduplicated affiliations, journal info, DOI
Direct links to PubMed and PubMed Central (when available)
Optional MeSH terms, grant information, and publication types
Handles PubMed's inconsistent XML (structured abstracts, missing fields, varying date formats)
NCBI Bookshelf chapters and whole books are returned as first-class records, not reported unavailable:
recordType(journal-article,book-chapter,book) tells them apart, and abookobject carries the book title, publisher, place, dates, medium, edition, series, ISBNs, book DOI, editors, and Bookshelf accession.journalInfois absent on those records — a book title is never reported as a journalJournals that assign article numbers instead of page ranges often carry no pagination at all; the number is reported as
journalInfo.elocationIdwith itsjournalInfo.elocationIdType(pii), never merged intojournalInfo.pagesand never confused with the DOIOpt-in whole-response ceiling:
maxResponseCharacterskeeps complete article records in response order until the next one would cross it, then defers the rest whole and lists their PMIDs indeferred.ids. Re-call with those PMIDs to resume exactly where the response stopped — no article is split, skipped, or duplicated. Each article is measured as the JSON record it is returned as, so a ceiling under the first article returns zero articles, the full deferred list, and the size to clear
pubmed_fetch_fulltext
Fetch full-text articles via a three-stage chain: NCBI PMC EFetch → Europe PMC fullTextXML → Unpaywall.
Accepts exactly one of
pmcids(direct PMC IDs),pmids(PubMed IDs, auto-resolved), ordois(auto-resolved to PMC via the ID Converter; preprints and EPMC-only OA fall through to Europe PMC / Unpaywall). One identifier per element in every branch — a DOI carrying a comma or whitespace is rejected at the schemaNCBI PMC and Europe PMC both return structured JATS; output records origin via
viaSource: "pmc" | "europepmc" | "unpaywall"Europe PMC layer (enabled by default; disable with
EUROPEPMC_ENABLED=false) recovers PMC-counterpart records that NCBI PMC EFetch missed, and resolves DOI input to PMC counterparts when one exists. EPMC'sfullTextXMLis PMC-keyed, so preprints (PPR), patents (PAT), and Agricola (AGR) are reachable viapubmed_europepmc_searchfor metadata but have no full text via this chain.Unpaywall layer (enabled by setting
UNPAYWALL_EMAIL) resolves DOIs to legal OA copies; extracts HTML landing pages to Markdown via Defuddle or PDFs to text via unpdfDiscriminated output contract —
source: "pmc"(structured sections, regardless of whether it came from PMC or EPMC) orsource: "unpaywall"(best-effort body +contentFormat:html-markdownorpdf-text)Structured unavailable reasons (
not-found,no-pmc-fallback-disabled,no-epmc-fulltext,no-body,no-doi,doi-lookup-failed,no-oa,fetch-failed,parse-failed,service-error) so callers can retry or explain to users without parsing text.no-doianddoi-lookup-failedare the settled and unsettled halves of the same gap: the first means the DOI lookup ran and the record has none, the second that the lookup itself errored, so a DOI may well exist and the request is worth retryingAn
unavailableentry also carriesunqueriedTierswhen the chain skipped a tier this deployment has not configured and that tier could have served the id — the search was incomplete, and a deployment with those tiers configured may still resolve itEach
unavailableentry carriesidType(pmid/pmcid/doi) andtriedTiers— per-tier outcomes (not-attempted,miss,no-fulltext,service-error, …) in execution order, so callers can see which stage failed and whySection filtering by title (case-insensitive substring match at any nesting depth, e.g.
["methods", "results"]) and configurable max sections apply to PMC output. A section that matches directly is returned whole; one kept only because a nested subsection matched keeps its heading as a breadcrumb with its own text clearedTables are returned as structured cells (
tables[]on each PMC article — rows, caption, label, footnotes, and the enclosing section, named for back-matter and appendix tables as well as body ones), covering<floats-group>,<back>and appendix deposits alongside body tables.colspanandrowspanare expanded to one entry per grid column, so a value stays under the header it belongs to on both output surfaces; a cell spanning several columns or rows repeats across the cells it covers. A deposit with no readable markup comes back labelled with anunextractableReasonrather than silently missing. Turn them off withincludeTables: falseFigures and supplementary material come back as structured entries (
assets[]on each PMC article —assetType, label, caption, the enclosing section, and the<graphic>/<media>pointer exactly as deposited, which is a name inside the PMC deposit rather than a fetchable URL), covering<floats-group>,<back>and appendix placements alongside body ones. Each one lifted out of the body leaves a[Figure: <label>]/[Supplementary: <label>]marker at its position, so reading order survives the lift. Turn them off withincludeAssets: false, which removes the markers with them. Prose-shaped blocks — lists, definition lists, block quotes, boxed text, preformatted blocks, displayed formulae — render into the section text at their document position instead, and no block is ever concatenated into a neighbouring sentenceCharacter budgets keep context size predictable:
maxCharacterscaps body text per article (PMC sections and subsections, inline blocks included, plus table content — cell, caption, label and footnote text, not the Markdown grid rendered around it — and asset label, caption and pointer text; or the Unpaywall body),maxCharactersPerSectioncaps a single PMC section, andoverflowModepicks betweentruncate(fill sections in document order) andoutline(split the budget evenly so every heading survives with an excerpt). Sections are served first, then tables, then assets, each spending what is left in document order until one does not fit; that entry and the rest are dropped whole rather than cut mid-row or returned with a shortened caption, and named intruncation.articles[].omittedTableNames/omittedAssetNames. Budgets run after the semantic filters, and atruncationobject reports per-article and per-section character counts whenever anything was shortenedmaxResponseCharactersbounds the whole response instead of each body: every field of a returned record counts (abstract, references, metadata, body), one ledger across PMC-, Europe PMC-, and Unpaywall-served articles. Articles past the ceiling are deferred whole, with their ids — in the branch they were requested under — indeferred.idsfor a follow-up callUp to 10 articles per request
pubmed_europepmc_search
Search Europe PMC (EBI/EMBL-EBI), a broader open-access biomedical corpus than PubMed alone.
Surfaces records PubMed search can't reach — preprints (
source: PPR), patents (source: PAT), Agricola (source: AGR), plus everything in PubMed (MED) and PMC (PMC). On recent queries this can mean dozens of relevant hits with zero PubMed overlap.Default sources
["MED", "PMC", "PPR"]; passsourcesto includePAT/AGRCursor-based pagination via
cursorMark(unlikepubmed_search_articles, which uses offset) —*for the first page, returnnextCursorMarkfor the nextOutput discriminator on
sourceplus optionalpmid/pmcId/doicross-walkingabstractSnippetis capped at 400 characters to keep a page bounded;abstractTruncatedsays whether it was cut, andpubmed_europepmc_fetchreturns the whole abstract for the records worth reading in fullDisabled when
EUROPEPMC_ENABLED=false; tool is not registered in that case
pubmed_europepmc_fetch
Fetch complete Europe PMC records by source + epmcId, the detail counterpart to pubmed_europepmc_search.
Returns the full, untruncated abstract as display-ready plain text — markup stripped, HTML entities decoded
Addressed by the
sourceandepmcIdof a search hit, the only identifier preprint (PPR), patent (PAT), and Agricola (AGR) records reliably carry —pubmed_fetch_articlesneeds a PMID andpubmed_fetch_fulltextneeds a PMCID, PMID, or DOIUp to 25 records per call, resolved in a single Europe PMC request
Pairs unresolved requests back to the caller in
notFoundinstead of failing the batchDisabled when
EUROPEPMC_ENABLED=false; tool is not registered in that case
pubmed_format_citations
Generate formatted citations for articles.
Five citation styles: APA 7th, MLA 9th, BibTeX, RIS, Vancouver (ICMJE/NLM)
NCBI Bookshelf chapters and whole books cite in their own form in every style — Vancouver's
In: … editorscontribution pattern, APA's chapter-in-edited-book, MLA'sedited by, BibTeX@incollection/@book, RISCHAP/BOOK— carrying the book title, editors, publisher, place, ISBNs and Bookshelf URLAn article with no page range cites by its electronic article locator in each style's own convention — Vancouver's trailing
pii:note, APA'sArticle <n>, MLA'sart. <n>, biblatexeid, RISC7— rather than dropping it or writing it into a page fieldRequest multiple styles per article in a single call
Hand-rolled formatters — zero external dependencies, fully Workers-compatible
Up to 50 articles per request
Reports formatted counts and unavailable PMIDs for partial-result handling
pubmed_find_related
Find articles related to a source article via ELink.
Three relationship types:
similar(content similarity),cited_by,referencesResults enriched with title, authors, publication date, and source via ESummary — or, for an NCBI Bookshelf record, its book title, publisher, and doc type in place of the empty source
Results returned in NCBI's relevance order
Falls back to Europe PMC, then OpenAlex, when NCBI cannot answer; the response names which provider served it. A request no provider can answer fails with a typed
all_providers_failederror instead of an empty result
pubmed_spell_check
Spell-check a biomedical query using NCBI's ESpell.
Returns the original query, corrected query, and whether a suggestion was found
Useful for query refinement before searching
pubmed_lookup_mesh
Search and explore the MeSH (Medical Subject Headings) vocabulary.
Search MeSH terms by name with exact-heading matching
Detailed records with tree numbers, scope notes, and entry terms by default
Useful for building precise PubMed queries with controlled vocabulary
pubmed_lookup_citation
Resolve partial bibliographic references to PubMed IDs via NCBI ECitMatch.
Match citations by journal, year, volume, first page, and/or author name
More fields = better match accuracy; at least one field required
Bibliographic fields cannot contain a pipe (
|) or a line break — ECitMatch's wire format is pipe-delimited, so those characters are rejected at the schema; the free-formkeylabel is exemptBatch up to 25 citations per request
Deterministic matching — more reliable than free-text search for known references
Returns explicit
matched,not_found, andambiguousstatuses with recovery detail
pubmed_convert_ids
Convert between article identifiers (DOI, PMID, PMCID) using the PMC ID Converter API.
Batch up to 50 IDs per request
Accepts DOIs, PMIDs, or PMCIDs (all IDs must be the same type)
One identifier per array element, checked against
idTypebefore the request — a packed value like"23193287,37952131"is rejected rather than expanded into extra records, since a comma is the converter's list delimiter in any encodingOnly resolves articles indexed in PubMed Central
Per-ID success/error reporting — partial batches return resolved mappings alongside structured errors for unresolvable IDs, not a batch-level failure
Related MCP server: PubMed MCP Server
Resource and prompt
Type | Name | Description |
Resource |
| PubMed database metadata via EInfo (field list, record count, last update) |
Prompt |
| Generate a structured 4-phase biomedical research plan outline |
Features
Built on @cyanheads/mcp-ts-core:
Declarative tool definitions — single file per tool, framework handles registration and validation
Unified error handling across all tools
Pluggable auth (
none,jwt,oauth)Swappable storage backends:
in-memory,filesystem,Supabase,Cloudflare KV/R2/D1Structured logging with optional OpenTelemetry tracing
Runs locally (stdio/HTTP) or on Cloudflare Workers from the same codebase
PubMed-specific:
Complete NCBI E-utilities integration (ESearch, EFetch, ESummary, ELink, ESpell, EInfo, ECitMatch) plus PMC ID Converter
Sequential request queue with configurable delay for NCBI rate limit compliance
NCBI-specific XML parser with
isArrayhints for PubMed's inconsistent XML structureHand-rolled citation formatters (APA, MLA, BibTeX, RIS, Vancouver) — zero deps, Workers-compatible
Agent-friendly output:
Provenance on every response — source labels, license fields, best-effort warnings on Unpaywall results, and effective-query echo on searches so agents can reason about trust
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
Discriminated output contracts —
source: "pmc" | "unpaywall", typedunavailablereasons,viaSourceandtriedTiersfields — callers branch on data, not string parsing
Getting started
Public Hosted Instance
A public instance is available at https://pubmed.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"pubmed-mcp-server": {
"type": "streamable-http",
"url": "https://pubmed.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"pubmed-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/pubmed-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"NCBI_API_KEY": "your-key-here"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"pubmed-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/pubmed-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"NCBI_API_KEY": "your-key-here"
}
}
}
}Or with Docker:
{
"mcpServers": {
"pubmed-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/pubmed-mcp-server:latest"]
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcpPrerequisites
Bun v1.3.2 or higher.
Optional: NCBI API key for higher rate limits (10 req/s vs 3 req/s).
Installation
Clone the repository:
git clone https://github.com/cyanheads/pubmed-mcp-server.gitNavigate into the directory:
cd pubmed-mcp-serverInstall dependencies:
bun installConfiguration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
Variable | Description | Default |
| Transport: |
|
| HTTP server port |
|
| HTTP endpoint path where the MCP server is mounted |
|
| HTTP session mode: |
|
| Public origin override for TLS-terminating reverse-proxy deployments (landing page, Server Card, RFC 9728 metadata). | none |
| Authentication: |
|
| Log level ( |
|
| Opt-in Bun-only forced-GC pressure loop (ms). Drains the per-request |
|
| Directory for log files (Node.js only). Relative paths resolve against the application root. |
|
| Storage backend: |
|
| NCBI API key for higher rate limits (10 req/s vs 3 req/s) | none |
| Contact email sent with NCBI requests (recommended by NCBI) | none |
| Minimum gap between NCBI request starts in ms | 334 (100 with key) |
| Max concurrent in-flight NCBI requests |
|
| Retry attempts for failed NCBI requests | 6 |
| Per-request HTTP timeout in ms |
|
| Total deadline across all retry attempts for one NCBI call, in ms |
|
| Contact email for Unpaywall. When set, | none |
| Per-request HTTP timeout for Unpaywall lookups and content fetches, in ms |
|
| Enable Europe PMC search tool and the |
|
| Optional contact email sent with Europe PMC requests (EBI courtesy). | none |
| Minimum gap between Europe PMC request starts in ms |
|
| Retry attempts for failed Europe PMC requests |
|
| Per-request HTTP timeout for Europe PMC calls, in ms |
|
| Enable OpenTelemetry |
|
Running the server
Local development
Build and run the production version:
# One-time build bun run rebuild # Run the built server bun run start:http # or bun run start:stdioRun checks and tests:
bun run devcheck # Lints, formats, type-checks, and more bun run test # Runs the test suite
Project structure
Directory | Purpose |
| Tool definitions ( |
| Resource definitions. Database info resource. |
| Prompt definitions. Research plan prompt. |
| NCBI E-utilities service layer — API client, queue, parser, formatter. |
| Europe PMC service — search + |
| Unpaywall service — DOI → OA location resolution and content fetch (HTML/PDF). |
| Server-specific environment variable parsing and validation with Zod. |
| Unit and integration tests, mirroring the |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor logging,ctx.statefor storageRegister new tools and resources in the
createApp()arrays
Contributing
Issues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
Available Tools
11 toolspubmed_convert_idsPubmed Convert IdsARead-onlyInspect
Convert between article identifiers (DOI, PMID, PMCID). Accepts up to 50 IDs of a single type per request. Only resolves articles indexed in PubMed Central — for articles not in PMC, use pubmed_search_articles instead.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | Article identifiers to convert — one identifier per element, all of the same type. Each element is checked against `idType` before the request: `doi` starts with "10." and carries a "/" ("10.1093/nar/gks1195"); `pmid` is digits ("23193287"); `pmcid` is digits with an optional "PMC" prefix ("PMC3531190" or "3531190"). No element may contain a comma or whitespace — a packed value like "23193287,37952131" is rejected, so split it across elements. | |
| idType | Yes | The type of IDs being submitted. Required so the API can unambiguously resolve them. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| records | No | Conversion results, one per input ID |
| totalConverted | No | Number of IDs successfully converted |
| totalSubmitted | No | Number of IDs submitted |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so safety is covered. The description adds real behavioral context beyond that: the 50-ID ceiling, the single-idType-per-request rule, and the PMC-only resolution scope, which materially changes what results the agent should expect. It stops short of describing unmapped-ID or partial-failure behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core purpose, then the constraints, then the alternative. Every sentence carries a distinct piece of actionable information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the description covers scope, limits, and routing. The only omission is what happens to individually unresolvable IDs within an accepted batch, which is minor given the output schema covers results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema already spells out per-element format validation for doi/pmid/pmcid, the maxItems of 50, and the same-type rule. The description's 'up to 50 IDs of a single type' restates the schema rather than adding syntax or edge-case meaning, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — 'Convert between article identifiers (DOI, PMID, PMCID)' — and enumerates the identifier types handled. It also explicitly separates itself from pubmed_search_articles for the non-PMC case, so an agent can route correctly without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit precondition (articles must be indexed in PubMed Central), a hard operational limit (up to 50 IDs, single type per request), and names the concrete alternative (pubmed_search_articles) for the excluded case. Both when-to-use and when-not-to-use are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pubmed_europepmc_fetchPubmed Europepmc FetchARead-onlyInspect
Fetch complete Europe PMC records — including the full, untruncated abstract — for records addressed by source plus epmcId. Pairs with pubmed_europepmc_search, which returns bounded abstractSnippet values and flags cut ones with abstractTruncated: true; pass those hits' source and epmcId here to read the whole abstract. This is the retrieval path for preprint (PPR), patent (PAT), and Agricola (AGR) records, which frequently carry no PMID and no DOI, so pubmed_fetch_articles and pubmed_fetch_fulltext cannot address them. Up to 25 records per call.
| Name | Required | Description | Default |
|---|---|---|---|
| records | Yes | Records to retrieve, each addressed by the `source` and `epmcId` of a `pubmed_europepmc_search` hit. The whole batch resolves in one Europe PMC request. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| notice | No | Guidance when one or more requested records could not be resolved. Absent when every record came back. |
| records | No | Resolved records, in the order Europe PMC returned them |
| notFound | No | Requested `source` + `epmcId` pairs Europe PMC returned no record for |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description discloses that this tool returns untruncated abstracts, processes up to 25 records per call, and resolves the whole batch in one Europe PMC request. It also explains the MED-versus-PMC behavior in the schema and how truncated search snippets map to this tool, giving agents concrete behavioral expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: core purpose, truncation relationship, alternative tool exclusion, and batch limit. The key behavior is front-loaded, and the description is informative without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return-value documentation is unnecessary, and the description covers the essential operational context: what to pass, when to use it, why it exists versus siblings, and the batch limit. There are no obvious gaps an agent would face when selecting or invoking this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents `source` and `epmcId` with enum values, patterns, and copy-from-search-hit guidance. The description adds workflow-level semantic value by telling the agent to pass the search hit's `source` and `epmcId`, and reinforces the batch limit, but it does not substantially redefine the parameter meanings.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Fetch complete Europe PMC records — including the full, untruncated abstract — for records addressed by `source` plus `epmcId`.' It clearly distinguishes itself from `pubmed_europepmc_search` and from `pubmed_fetch_articles`/`pubmed_fetch_fulltext` by naming exactly what makes this tool the right retrieval path.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: pair it with `pubmed_europepmc_search`, pass the hit's `source` and `epmcId`, and use it for PPR/PAT/AGR records that lack PMID/DOI and therefore cannot be handled by sibling fetch tools. It also states the 25-record per-call limit, making the usage boundary unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pubmed_europepmc_searchPubmed Europepmc SearchARead-onlyInspect
Search Europe PMC, a broad open-access biomedical corpus. Surfaces preprints (source: PPR), patents (source: PAT), Agricola (source: AGR), plus everything in PubMed (MED) and PMC. Use when additional coverage is needed — preprints and EPMC-only OA records are the typical recovery. Paginate via cursorMark. Defaults to MED, PMC, and PPR; pass sources to include PAT / AGR. Abstracts arrive as a bounded abstractSnippet with abstractTruncated marking the cut ones — pass a hit’s source and epmcId to pubmed_europepmc_fetch for the complete abstract.
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | Optional EPMC sort: `<field> asc|desc`. Documented sortable fields: `P_PDATE_D` (publication date), `CITED` (citation count), `AUTH_FIRST` (first author surname), `PUB_YEAR` (publication year). Examples: `P_PDATE_D desc` (newest first), `CITED desc` (most cited). Omit for relevance ranking. Fields outside the documented set are rejected by EPMC. Note: `P_PDATE_D` is ignored for preprint-only (`sources: ["PPR"]`) result sets — preprints have no populated publication date, so use `PUB_YEAR` to order preprints by date. | |
| query | Yes | Europe PMC search query. Supports field tokens like `AUTH:"<name>"`, `JOURNAL:"<title>"`, `TITLE:"<words>"`, `PUB_YEAR:[2020 TO 2024]`, `DOI:"..."`, `EXT_ID:<pmid> AND SRC:MED`, `PMCID:PMC<digits>`. Identifier tokens combined with `AND SRC:` must be unquoted — the quoted form matches nothing. Free text is matched broadly across abstract/title/keywords. | |
| sources | No | Filter to specific EPMC sources. Defaults to MED, PMC, PPR when omitted. Pass an explicit array including PAT or AGR to broaden coverage. Allowed values: MED, PMC, PPR, PAT, AGR. | |
| pageSize | No | Results per page. Max 100 per EPMC API. | |
| cursorMark | No | Pagination cursor. Use `*` (default) for the first page; pass the previous response's `nextCursorMark` for subsequent pages. | * |
| resultType | No | `core` returns abstract, IDs, dates, license; `lite` is a smaller payload with IDs and titles only. | core |
Output Schema
| Name | Required | Description |
|---|---|---|
| hits | No | Matching Europe PMC records, in the order EPMC returned them |
| error | No | Present when the call failed. Absent on success. |
| query | No | Effective query string echoed by Europe PMC |
| notice | No | Optional guidance when results are empty or paging overshot |
| searchUrl | No | Europe PMC's website search URL for this query |
| cursorMark | No | Cursor used for this response (echoed from the request) |
| totalCount | No | Total matching records across all pages |
| appliedSources | No | Sources the query was filtered against (defaults applied) |
| nextCursorMark | No | Cursor to pass back as `cursorMark` for the next page. Absent on the final page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint and openWorldHint already declared, the baseline burden is lower, and the description adds substantial behavior beyond them: cursorMark-based pagination, the default source set (MED/PMC/PPR), and the output contract of a bounded abstractSnippet with abstractTruncated flagging cut results. It also routes to pubmed_europepmc_fetch for the full abstract — genuinely actionable behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences with purpose and scope front-loaded ahead of usage, pagination, and output behavior; every sentence earns its place. The final sentence is dense but packs critical truncation semantics and the follow-up fetch routing. Minor repetition of schema-documented defaults keeps it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter read-only search tool with an output schema, the description covers corpus scope, the when-to-use condition, pagination, default sources, abstract truncation behavior, and the sibling tool for complete abstracts. Nothing material is left for the agent to infer or discover at call time.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema itself is exceptionally detailed (sortable-field caveats, the P_PDATE_D preprint quirk, the unquoted-identifier-token rule, max pageSize). The description's mentions of defaults and cursorMark largely restate what the schema already documents, so it adds little parameter meaning beyond the established baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource: 'Search Europe PMC, a broad open-access biomedical corpus,' and enumerates the exact coverage (preprints, patents, Agricola, plus all PubMed and PMC content). This cleanly distinguishes it from sibling pubmed_search_articles, which targets the narrower PubMed corpus, without needing to open either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger condition: 'Use when additional coverage is needed — preprints and EPMC-only OA records are the typical recovery,' and explains how to widen scope ('pass sources to include PAT/AGR'). It does not explicitly name the when-not alternative (e.g., 'use pubmed_search_articles for PubMed-only queries'), but the coverage-based contrast makes the routing decision clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pubmed_fetch_articlesPubmed Fetch ArticlesARead-onlyInspect
Fetch full article metadata by PubMed IDs. Returns detailed article information including abstract, authors, journal, MeSH terms. Set maxResponseCharacters to bound the whole response: articles past the ceiling are deferred whole and listed in deferred.ids for a follow-up call.
| Name | Required | Description | Default |
|---|---|---|---|
| pmids | Yes | PubMed IDs to fetch | |
| includeMesh | No | Include MeSH terms | |
| includeGrants | No | Include grant information | |
| maxResponseCharacters | No | Opt-in ceiling for the whole response, in characters. Each article is measured as the JSON record it is returned as — title, abstract, authors, journal, MeSH terms, grants, identifiers, every field it carries. Articles are kept in response order until the next one would cross the ceiling; that article and the rest are deferred whole (never partially populated) and listed in `deferred.ids`. Response envelope fields — counts, `unavailablePmids`, `deferred` itself — are not counted. Omit to return every resolved article. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| notice | No | Optional guidance when no articles were returned — points to discovery tools — or when `maxResponseCharacters` deferred articles, naming how to retrieve them. Absent on successful unbudgeted fetches. |
| articles | No | Parsed articles |
| deferred | No | Continuation state for articles the whole-response budget withheld. Present only when `maxResponseCharacters` deferred at least one article. |
| truncated | No | True when `maxResponseCharacters` withheld at least one resolved article. Absent when the response carries every article that resolved. The continuation state is in `deferred`. |
| totalReturned | No | Number of articles in this response. Under a `maxResponseCharacters` budget this counts the kept articles only; `deferred.deferredCount` covers the rest. |
| unavailablePmids | No | PMIDs PubMed returned no record for. That is all this reports: PubMed omits an unknown PMID silently, with no error and no reason, so the absence says nothing about whether the PMID exists. Reported in full regardless of where a `maxResponseCharacters` cutoff lands — these are misses, not deferrals. Use `pubmed_search_articles` to find PMIDs that do resolve. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish the safe read-only, open-world profile, so the bar is lower; the description still adds real behavior: responses may be truncated under maxResponseCharacters, articles are deferred whole (never partially populated), and the follow-up set appears in deferred.ids. It does not disclose rate limits or the 200-PMID cap, but the deferral semantics are the meaningful addition.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences: purpose first, return contents second, the truncation/follow-up mechanic third. No filler, nothing repeated from the schema, and the actionable constraint is not buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value documentation is not required, and the description still covers the one non-obvious behavior (deferral). It omits the batch-size bound (max 200 pmids) and does not point to full-text retrieval when metadata is insufficient, leaving minor gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description nonetheless explains the practical consequence of maxResponseCharacters (articles past the ceiling are deferred whole and surfaced in deferred.ids for a follow-up call), which adds operational meaning beyond the schema's field-level wording.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Fetch full article metadata by PubMed IDs') and enumerates what comes back (abstract, authors, journal, MeSH terms). By calling out metadata in contrast to the sibling pubmed_fetch_fulltext, an agent can distinguish the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the required pmids input ('by PubMed IDs'), and the follow-up loop for deferred ids is described, but there is no explicit when-to-use/when-not guidance or named alternative (e.g., use pubmed_fetch_fulltext when you need the body text). Adequate but with a clear routing gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pubmed_fetch_fulltextPubmed Fetch FulltextARead-onlyInspect
Fetch full-text articles from PubMed Central with structured sections, tables, and references. When PMC misses, transparently falls back to Europe PMC fullTextXML (structured JATS for records with a PMC counterpart). Provide exactly one of pmcids (PMC IDs directly), pmids (PubMed IDs, auto-resolved), or dois (DOIs, auto-resolved to PMC via the ID Converter; preprints with a PMC counterpart recover via Europe PMC). Two independent character controls: maxCharacters caps body text per article, maxResponseCharacters caps the whole response and defers articles past the ceiling whole, listing them in deferred.ids for a follow-up call.
| Name | Required | Description | Default |
|---|---|---|---|
| dois | No | DOIs to resolve (e.g. ["10.21203/rs.3.rs-9010375/v1"]), one per element. Provide exactly one of `pmcids`, `pmids`, or `dois`. Resolved to a PMCID via the PMC ID Converter and returned as structured JATS when the article is in PMC; DOIs with no PMC counterpart (preprints, EPMC-only OA) fall through to Europe PMC, then Unpaywall, when those layers are enabled. | |
| pmids | No | PubMed IDs. Provide exactly one of `pmcids`, `pmids`, or `dois`. Articles in PMC are returned as structured JATS; articles not in PMC fall through to Europe PMC (when EPMC has a `fullTextXML`), then to Unpaywall when `UNPAYWALL_EMAIL` is set and a DOI is available. | |
| pmcids | No | PMC IDs to fetch (e.g. ["PMC9575052"]). Provide exactly one of `pmcids`, `pmids`, or `dois`. PMC IDs with no retrievable full text fall through to Europe PMC, then to Unpaywall on the DOI the chain resolves for them. | |
| sections | No | Filter to specific sections by title (e.g. ["Introduction", "Methods", "Results", "Discussion"]). A term matches a section or subsection title at any nesting depth, case-insensitively, as a substring — "resul" matches "Results". A section whose own title matches is returned whole; one kept only because a nested subsection matched keeps its heading as a breadcrumb, with its own text cleared and only the matching branch beneath it. Tables and assets narrow with the filter: one whose section did not survive, or that names no section, is dropped. Applies to `source=pmc` results only. | |
| maxSections | No | Maximum top-level body sections. Applies to `source=pmc` results only. | |
| overflowMode | No | How to spend `maxCharacters` across an article that exceeds it. truncate: fill sections in document order, so early sections stay whole and sections past the budget are dropped (counted in `truncation.omittedSections`). outline: split the budget evenly so every section keeps its heading, and an excerpt as far as the budget reaches — use it to survey what an article contains before requesting specific `sections`. Ignored when no budget is set, and identical for `source=unpaywall` bodies, which have no headings to preserve. | truncate |
| includeAssets | No | Include the article's figures and supplementary material — `assets[]`, each with its label, caption, enclosing section and deposit pointer. On by default because it is cheaper than tables: a median asset-bearing article grows about 10%, and the body prose already refers to these by label. Set false to omit them, which also removes the `[Figure: …]` / `[Supplementary: …]` markers from the section text, since without the array they point at nothing. Prose-shaped blocks — lists, definition lists, block quotes, boxed text, preformatted blocks, displayed formulae — are section text rather than assets and this switch never affects them. Applies to `source=pmc` results only. | |
| includeTables | No | Include the article's tables — cells, captions, labels and footnotes. On by default because a dropped table takes its numbers with it. Table-dense articles pay for it: rendered tables typically add 12–17% to an article record and can more than double it. Set false to omit them, or cap the cost with `maxCharacters`, which drops tables it cannot fit whole. Applies to `source=pmc` results only. | |
| maxCharacters | No | Per-article budget for body text, in characters. Counts `source=pmc` section and subsection text — which carries the inline blocks the parser renders in place, such as lists, definition lists, block quotes, boxed text, preformatted blocks and displayed formulae — plus table label, caption, cell and footnote text and asset label, caption and `href` text; or the `source=unpaywall` `content` body. Titles, abstracts, identifiers, and references are never counted or shortened. The counted unit is that text alone — the Markdown grid `content[]` renders around the cells (pipes, padding, the divider row, headings) is scaffolding this budget does not measure, so a table renders longer than it costs here. Sections are served first, then tables, then assets, each spending what is left, in document order — admission stops at the first entry that does not fit, and every entry from there on is dropped whole rather than cut mid-row or returned with a shortened caption, counted in `truncation.omittedTables` / `truncation.omittedAssets` and named in `truncation.articles[].omittedTableNames` / `omittedAssetNames`. Applied after `sections`, `maxSections`, `includeReferences`, `includeTables`, and `includeAssets`, so semantic filtering is unaffected. This knob alone bounds only bodies: the response-wide ceiling it implies is this value times the number of articles returned, plus every uncounted field. Use `maxResponseCharacters` for a true whole-response ceiling. Omit for the full body. | |
| includeReferences | No | Include reference list. Applies to `source=pmc` results only. | |
| maxResponseCharacters | No | Opt-in ceiling for the whole response, in characters — the true response-wide counterpart to the per-article `maxCharacters`. Each article is measured as the JSON record it is returned as, after every filter and the per-article body budget: title, abstract, body sections, references, identifiers, license and source metadata — every field it carries. One ledger covers all tiers, so PMC-, Europe PMC-, and Unpaywall-served articles spend the same budget. Articles are kept in response order until the next one would cross the ceiling; that article and the rest are deferred whole (never partially populated) and listed in `deferred.ids`. Response envelope fields — counts, `unavailable`, `truncation`, `deferred` itself — are not counted. Omit to return every resolved article. | |
| maxCharactersPerSection | No | Budget for a single top-level body section, in characters, counting the section text plus its subsections. Combine with `maxCharacters` to cap both one section and the article; the tighter of the two wins. Applies to `source=pmc` results only. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| notice | No | Optional guidance for a partial or empty body. A `sections`-filter miss names the requested terms and affected article id(s) and suggests retrying without `sections` or using broader headings. A metadata-only record names the id(s) the chain could retrieve as front matter only and points at `pubmed_fetch_articles` for the abstract. A table returned with no cell values names the affected table(s), the article each came from, and why the cells cannot be recovered. A budgeted response names the characters returned versus carried and points at `truncation`. A response-wide budget that deferred articles names the ids to re-request. Absent when none of those applies. |
| articles | No | Full-text articles |
| deferred | No | Continuation state for articles the whole-response budget withheld. Present only when `maxResponseCharacters` deferred at least one article. |
| truncated | No | True when a character budget shortened at least one returned body, or withheld a whole article. Absent when every resolved article is present with its full post-filter body. The per-article body accounting is in `truncation`; the withheld ids are in `deferred`. |
| truncation | No | Character accounting for full text the budget shortened. Present only when a budget actually removed characters — its absence means every returned article carries its full post-filter body. |
| unavailable | No | Per-identifier explanations for any requested PMIDs, PMCIDs, or DOIs with no returnable full text. `idType` discriminates which branch the id came from. Distinct from `deferred`: nothing here is retrievable by re-calling, and an id never appears in both. |
| totalReturned | No | Number of articles in this response. Under a `maxResponseCharacters` budget this counts the kept articles only; `deferred.deferredCount` covers the rest. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint and openWorldHint annotations, the description goes beyond by detailing the multi-source fallback chain, character budget behaviors (truncation vs outline, deferral in deferred.ids), and resource controls like includeAssets/includeTables defaults. It explains what gets dropped and how, which is valuable context not in annotations. Missing: rate limits, authentication needs, or timeout behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with front-loaded core purpose followed by fallback and parameter highlights. Every sentence carries weight, though it's somewhat long given the complexity. No wasted words, but could be slightly more scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex tool with 12 parameters, a rich schema, and an output schema, the description is complete. It covers purpose, fallbacks, parameter interactions, and budget semantics. Since an output schema exists, it doesn't need to explain return values. An agent has enough to invoke correctly and understand behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 12 parameters thoroughly. The description adds some high-level context about exactly one of pmcids/pmids/dois must be provided and the two character controls, but doesn't add syntax details beyond what's already in the schema. Baseline 3 is appropriate when schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (fetch) and resource (full-text articles from PubMed Central) with structured sections, tables, and references. It also distinguishes itself from siblings like pubmed_fetch_articles and pubmed_europepmc_fetch by naming the fallback to Europe PMC fullTextXML, making scope clear without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly states the context: use this to get full-text when needed, and describes fallback behavior when PMC misses (Europe PMC, then Unpaywall if enabled). However, it doesn't explicitly contrast with sibling tools like pubmed_fetch_articles (likely abstracts) or pubmed_europepmc_fetch, leaving some ambiguity about when to choose this over those alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pubmed_format_citationsPubmed Format CitationsARead-onlyInspect
Get formatted citations for PubMed articles in one or more formats (apa, mla, bibtex, ris, vancouver). Pass a single format as a string or multiple as an array.
| Name | Required | Description | Default |
|---|---|---|---|
| pmids | Yes | PubMed IDs to cite | |
| format | No | Citation format(s) to generate — single style as a string or multiple as an array. Allowed values: apa, mla, bibtex, ris, vancouver. | apa |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| notice | No | Optional guidance when no citations were produced — points to discovery tools. Absent when at least one citation was produced. |
| citations | No | Citations per article |
| totalFormatted | No | Number of PMIDs successfully formatted |
| totalSubmitted | No | Number of PMIDs submitted for citation formatting |
| unavailablePmids | No | PMIDs PubMed returned no record for, so nothing could be cited for them. That is all this reports: PubMed omits a PMID it does not recognize silently, with no error and no reason, so the absence says nothing about whether the PMID exists. Use `pubmed_search_articles` to find PMIDs that do resolve. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered structurally. The description adds the format-selection flexibility (single vs array), which is useful, but does not disclose whether output is a string, dict keyed by format, pagination, or error behavior for invalid PMIDs. Adequate but thin for a networked lookup.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no waste, front-loaded with the primary purpose followed immediately by the format flexibility. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return shape need not be explained, and annotations cover the safety profile. The description is complete enough to invoke correctly, though it omits any note about when to prefer this tool over pubmed_lookup_citation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema already documents pmids, format enum values, and the anyOf string/array flexibility in detail. The description restates the same single-vs-array pattern the schema already specifies, so it adds no meaning beyond structured fields. Baseline 3 is correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Get formatted citations) and resource (PubMed articles) with the exact formats supported. An agent can distinguish this from siblings like pubmed_lookup_citation (which likely does the reverse – citation to PMID) without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage (get formatted citations for given PMIDs) but offers no explicit when-to-use guidance or mention of alternatives. In a crowded sibling set including pubmed_lookup_citation, the lack of routing guidance is a clear gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pubmed_lookup_citationPubmed Lookup CitationARead-onlyInspect
Look up PubMed IDs from partial bibliographic citations. Useful when you have a reference (journal, year, volume, page, author) and need the PMID — deterministic citation matching, more reliable than free-text search for structured references. Each citation must include at least journal or year (ECitMatch primary-keys on journal+volume+page; author-only or volume-only inputs guarantee no match); more fields = better match accuracy.
| Name | Required | Description | Default |
|---|---|---|---|
| citations | Yes | Citations to look up. More fields = better match accuracy. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| results | No | Match results, one per input citation |
| totalMatched | No | Number of citations with PMID matches |
| totalWarnings | No | Number of matched citations that carry at least one warning |
| totalSubmitted | No | Number of citations submitted |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so safety is covered. The description adds real behavioral context: deterministic citation matching via ECitMatch, primary-keying on journal+volume+page, and the guarantee that author-only or volume-only inputs yield no match — non-obvious traits an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the action and purpose before constraints. The dense parenthetical about ECitMatch keying is information-rich rather than wasteful, though slightly compact for quick parsing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation. The description covers the matching mechanism, input requirements, and accuracy tradeoffs; combined with readOnly/openWorld annotations, an agent has everything needed to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the nested citation schema already documents each field plus the journal-or-year requirement and the primary-key behavior, so the description largely repeats structured content. It reinforces field-selection strategy ("more fields = better match accuracy") but adds little beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (look up PubMed IDs from partial bibliographic citations) and clearly scopes the input shape (journal, year, volume, page, author). It also contrasts itself with free-text search for structured references, letting an agent distinguish it from pubmed_search_articles.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Useful when you have a reference ... and need the PMID" gives explicit when-to-use context and positions it against free-text search. It does not name the sibling (pubmed_search_articles) directly or state when-not to use it, so it falls short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pubmed_lookup_meshPubmed Lookup MeshARead-onlyInspect
Search and explore the MeSH (Medical Subject Headings) controlled vocabulary. Returns descriptor records with tree numbers, scope notes, and entry terms, plus pagination via offset for paging past the maxResults cap.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | MeSH descriptor name or free-text term to look up. Must carry a term: a blank or whitespace-only value is rejected rather than searched. | |
| offset | No | Result offset for pagination (0-based). Pass the `nextOffset` from the previous response to get the following page; the exact-descriptor match is pinned to the first page only. | |
| maxResults | No | Maximum results | |
| includeDetails | No | Fetch full MeSH records (scope notes, tree numbers, entry terms) |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| query | No | Original search query |
| notice | No | Optional guidance when no descriptors matched or the offset overshot the result set — suggests spell-check, free-text search, or resetting the offset. Absent on successful result pages. |
| offset | No | Result offset this page was read from |
| results | No | Matching MeSH records |
| nextOffset | No | Offset to request for the next page. Omitted when this is the last page, so its absence is the end-of-results signal. |
| totalCount | No | Total MeSH descriptors matching the query upstream, before the maxResults cap |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds behavioral details beyond the readOnlyHint/openWorldHint annotations by explaining the return contents and the pagination mechanism for paging past the maxResults cap. No contradictions with the annotations are present.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence with no filler: it front-loads the action and result type, then adds pagination behavior. Every clause contributes useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the rich input schema, existing output schema, and readOnly/openWorld annotations, the description is complete for agent selection and invocation. It covers the core use case, return contents, and pagination nuance without needing to restate structured fields.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter already has a detailed description. The description's mention of pagination and offset restates the schema's own guidance without adding significant new parameter-level meaning, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Search and explore') and a specific resource ('MeSH controlled vocabulary'), and it names the return payload (descriptor records with tree numbers, scope notes, entry terms). This clearly differentiates it from siblings like pubmed_search_articles or pubmed_lookup_citation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly implies this tool is for MeSH vocabulary lookups rather than article or citation searches, which is a distinct use case from the siblings. It does not explicitly name alternatives or state when not to use it, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pubmed_search_articlesPubmed Search ArticlesARead-onlyInspect
Search PubMed with full query syntax, filters, and date ranges. Returns PMIDs and optional brief summaries. Supports field-specific filters (author, journal, MeSH terms), common filters (language, species, free full text), and pagination via offset for paging through large result sets.
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | Sort order: relevance (default), pub_date (newest first), author, or journal | relevance |
| query | Yes | PubMed search query (supports full NCBI syntax). Must carry a search term: a value that is blank once markup is stripped is rejected rather than sent to PubMed as an empty term. | |
| author | No | Filter by author name (e.g. "Smith J") | |
| offset | No | Result offset for pagination (0-based). PubMed serves at most the first 9999 records of a result set, so this caps at 9998; narrow the query or add filters to reach anything beyond it. | |
| journal | No | Filter by journal name | |
| species | No | Filter by species | |
| language | No | Filter by language (e.g. "english") | |
| dateRange | No | Filter by date range. The filter is applied only when both `minDate` and `maxDate` are non-empty; either one empty disables the entire date range. | |
| meshTerms | No | Filter by MeSH terms. Multiple terms are AND'd — all must match. | |
| maxResults | No | Maximum results to return | |
| hasAbstract | No | Only include articles with abstracts | |
| freeFullText | No | Only include free full text articles | |
| summaryCount | No | Fetch brief summaries for top N results (0 = PMIDs only). Above the 50 cap, pass the remaining PMIDs to pubmed_fetch_articles. | |
| publicationTypes | No | Filter by publication type (e.g. "Review", "Clinical Trial", "Meta-Analysis"). Multiple values are OR'd — any match qualifies. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| pmids | No | PubMed IDs |
| query | No | Original query |
| notice | No | Optional guidance when the result set does not reflect what was asked for — a field tag PubMed ignored, a phrase it matched nothing for, a dateRange dropped for having one bound, no matches at all, or paging past the end. Absent when nothing applies. |
| offset | No | Result offset used |
| searchUrl | No | PubMed search URL |
| summaries | No | Brief summaries (empty array when summaryCount is 0) |
| totalCount | No | Total matching articles |
| appliedFilters | No | Normalized filter values that were applied to the PubMed query |
| effectiveQuery | No | Sanitized query sent to PubMed after applying all active filters |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover readOnlyHint and openWorldHint, so the safety profile is handled. The description adds real behavioral context: return format (PMIDs + optional summaries), pagination via offset for large sets, and the general shape of results. It doesn't mention rate limits or the 9999-record PubMed cap (that lives in the schema), but as a read-only search this is solid.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the core action and resource, then capabilities. Zero filler; every clause carries information (filters, return shape, pagination).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 14 params with full schema coverage, an output schema, and annotations, the description is appropriately scoped. It explains return shape and pagination. Missing: explicit routing to sibling tools (europepmc_search, fetch_articles handoff) for a tool whose ecosystem has many near-neighbors, which is a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description adds marginal value by summarizing filter categories (field-specific: author, journal, MeSH; common: language, species, free full text) and pagination, but every parameter is already fully documented in the schema, so it doesn't add beyond what's structured.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Search PubMed") and enumerates the capabilities: full query syntax, filters, date ranges, and return shape (PMIDs with optional summaries). It clearly distinguishes itself from siblings like pubmed_fetch_articles and pubmed_europepmc_search by positioning as the primary PubMed search entry point.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Implied usage is clear for a search tool, but there's no explicit when-not guidance or routing to siblings (e.g., europepmc_search vs pubmed_search_articles, or the summaryCount→fetch_articles handoff beyond the schema's own note). The description omits any alternative-selection guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pubmed_spell_checkPubmed Spell CheckARead-onlyInspect
Spell-check a query and get NCBI's suggested correction. Useful for refining search queries.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | PubMed search query to spell-check. Must carry a term: a blank or whitespace-only value is rejected rather than sent to ESpell. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| original | No | Original query |
| corrected | No | Corrected query (same as original if no suggestion) |
| hasSuggestion | No | Whether NCBI suggested a correction |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, covering safety and open-endedness. The description adds the nature of the output ('NCBI's suggested correction') but does not disclose additional behavioral traits like rate limits or error handling. Given the annotation coverage, this is adequate but not enriched beyond them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences with zero filler. The core action and purpose are front-loaded, and the usage hint follows naturally. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple with a single parameter, a full output schema, and annotations covering read-only and open-world behavior. The description covers the purpose and usage. Nothing essential for calling the tool is missing, though it could mention the exact format of the correction, which the output schema presumably handles.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema description coverage is 100%, so the parameter 'query' is fully documented in the schema itself. The tool description adds no extra parameter details, which is acceptable per the baseline since the schema carries the full semantic load.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific action ('Spell-check a query') and the result ('get NCBI's suggested correction'). It unambiguously distinguishes this tool from siblings like pubmed_search_articles or pubmed_fetch_articles, which handle searching and retrieval rather than spelling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'Useful for refining search queries' provides clear context on when to use the tool. It does not explicitly mention alternatives or exclusions, but the intent is evident and sufficient for an agent to select it appropriately among the sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
9 tool updates
v2.10.12- Changed
pubmed_convert_ids3 fields changed- changed
Input schema / properties / ids / descriptionPrevious value: -"Article identifiers to convert. All IDs must be the same type. DOIs: \"10.1093/nar/gks1195\", PMIDs: \"23193287\", PMCIDs: \"PMC3531190\" (the \"PMC\" prefix is optional — bare digits like \"3531190\" are also accepted)."New value: +"Article identifiers to convert — one identifier per element, all of the same type. Each element is checked against `idType` before the request: `doi` starts with \"10.\" and carries a \"/\" (\"10.1093/nar/gks1195\"); `pmid` is digits (\"23193287\"); `pmcid` is digits with an optional \"PMC\" prefix (\"PMC3531190\" or \"3531190\"). No element may contain a comma or whitespace — a packed value like \"23193287,37952131\" is rejected, so split it across elements." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). `malformed_id`: An `ids` element does not match the declared `idType` — most often several identifiers packed into one element, which the comma-delimited upstream batch would split into extra records. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "queue_full", - "ncbi_unreachable", - "ncbi_deadline_exceeded", - "ncbi_invalid_response", - "ncbi_resource_not_found" -]New value: +[ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found", + "malformed_id" +]
- Changed
pubmed_fetch_articles9 fields changed- changed
Output schema / properties / articles / items / properties / authors / descriptionPrevious value: -"Author list"New value: +"Author list. On a `book-chapter` these are the chapter's own authors, never the book's editors, which are in `book.editors`. Empty on a Bookshelf record that credits neither." - added
Output schema / properties / articles / items / properties / bookAdded value: +{ + "additionalProperties": false, + "description": "The containing book of a `book-chapter`, or the book itself on a `book` record. Present only on those two record types, and never a stand-in for `journalInfo`.", + "properties": { + "accession": { + "description": "NCBI Bookshelf accession from `ArticleIdList` (`bookaccession`), e.g. \"NBK1247\". The record is readable at `https://www.ncbi.nlm.nih.gov/books/<accession>/`.", + "type": "string" + }, + "beginningDate": { + "description": "First year of a continuously-updated book, from `Book/BeginningDate` (GeneReviews runs from 1993). Absent on a book published once.", + "type": "string" + }, + "collectionTitle": { + "description": "Series the book belongs to, from `Book/CollectionTitle` (e.g. \"ADA Clinical Compendia Series\"). Absent for a book outside a series.", + "type": "string" + }, + "doi": { + "description": "The book's own DOI, from `Book/ELocationID` with `EIdType=\"doi\"`. Distinct from the record-level `doi`, which is the chapter's: a chapter does not inherit this one.", + "type": "string" + }, + "edition": { + "description": "Edition statement from `Book/Edition`. Rare on Bookshelf titles — absent unless NCBI supplies one.", + "type": "string" + }, + "editors": { + "description": "Editors of the containing book, from `Book/AuthorList` marked `Type=\"editors\"`. Kept out of `authors`, which carries the chapter's own writers. Absent when the book credits no editors.", + "items": { + "additionalProperties": false, + "description": "One editor of the containing book. Name parts only — editors are a citation credit, not a contributor record, so no affiliations or ORCID are reported for them.", + "properties": { + "collectiveName": { + "description": "Group or committee credited as editor, when the entry names an organization rather than a person. Mutually exclusive with the name-part fields.", + "type": "string" + }, + "firstName": { + "description": "Editor given name as NCBI supplies it (`ForeName`, often \"Margaret P\"). Absent when NCBI carries initials only, or on a group editor.", + "type": "string" + }, + "initials": { + "description": "Editor initials with no separators (e.g. \"MP\"). Absent when NCBI supplies none, or on a group editor.", + "type": "string" + }, + "lastName": { + "description": "Editor surname, from the book's `Book/AuthorList Type=\"editors\"` entry. Absent on a group editor, which carries `collectiveName` instead.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "endingDate": { + "description": "Last year of a closed date range, from `Book/EndingDate`. Absent while a book is still being updated, which leaves the range open-ended.", + "type": "string" + }, + "isbns": { + "description": "Every `Book/Isbn` on the record. A book commonly carries a print and an electronic ISBN, so this is a list. Absent for a Bookshelf title with no ISBN, which is most of them.", + "items": { + "description": "One ISBN, verbatim as NCBI reports it — leading zeros intact", + "type": "string" + }, + "type": "array" + }, + "medium": { + "description": "Medium the book is published in, from `Book/Medium` — \"Internet\" wherever NCBI supplies it. Absent when NCBI supplies none; it is never defaulted.", + "type": "string" + }, + "pubDate": { + "description": "Publication year from `Book/PubDate`. Year only — NCBI's month and day are not reported, since no citation style uses them for a book.", + "type": "string" + }, + "publisher": { + "description": "Publisher of the book, from `Book/Publisher/PublisherName`.", + "type": "string" + }, + "publisherLocation": { + "description": "Place of publication, from `Book/Publisher/PublisherLocation` (e.g. \"Seattle (WA)\"). Absent when NCBI supplies no place.", + "type": "string" + }, + "title": { + "description": "Title of the containing book, from `Book/BookTitle` (e.g. \"GeneReviews®\"). On a `book` record this is the same value as the record's own `title`.", + "type": "string" + } + }, + "type": "object" +} - changed
Output schema / properties / articles / items / properties / journalInfo / descriptionPrevious value: -"Journal information"New value: +"Journal information. Present on `journal-article` records only — absent on `book-chapter` and `book` records, because a Bookshelf record has no journal and its book title is never reported as one; read `book` for those. (#114)" - added
Output schema / properties / articles / items / properties / journalInfo / properties / elocationIdAdded value: +{ + "description": "Electronic article locator from NCBI `ELocationID` — the publisher-assigned article number (e.g. \"2400512\"). Journals that assign article numbers instead of pages often omit pagination entirely, leaving this the only locator. Never a substitute for `pages`, and never the DOI: a DOI-typed `ELocationID` is reported in `doi` instead. Absent when the only locator NCBI supplies is marked invalid.", + "type": "string" +} - added
Output schema / properties / articles / items / properties / journalInfo / properties / elocationIdTypeAdded value: +{ + "description": "Type of `elocationId`, from NCBI's `EIdType` attribute — \"pii\" in practice. Free-form: NCBI does not close the set, so treat an unfamiliar value as opaque.", + "type": "string" +} - added
Output schema / properties / articles / items / properties / recordTypeAdded value: +{ + "description": "Which kind of PubMed record this is, set from the XML element it arrived in: `journal-article` for an ordinary article, `book-chapter` for an NCBI Bookshelf chapter, `book` for a whole Bookshelf book. Read this to tell the three apart — `publicationTypes` cannot, because PubMed labels a Bookshelf record \"Review\" or \"Study Guide\". `journalInfo` is present only on `journal-article`; `book` only on the other two.", + "enum": [ + "journal-article", + "book-chapter", + "book" + ], + "type": "string" +} - changed
Output schema / properties / articles / items / properties / title / descriptionPrevious value: -"Article title"New value: +"Article title — the chapter title on a `book-chapter`, and the book title on a `book` record, where it repeats `book.title`." - added
Output schema / properties / articles / items / requiredAdded value: +[ + "recordType" +] - changed
Output schema / properties / unavailablePmids / descriptionPrevious value: -"PMIDs that returned no article data. Reported in full regardless of where a `maxResponseCharacters` cutoff lands — these are misses, not deferrals, and re-requesting them returns nothing."New value: +"PMIDs PubMed returned no record for. That is all this reports: PubMed omits an unknown PMID silently, with no error and no reason, so the absence says nothing about whether the PMID exists. Reported in full regardless of where a `maxResponseCharacters` cutoff lands — these are misses, not deferrals. Use `pubmed_search_articles` to find PMIDs that do resolve."
- Changed
pubmed_fetch_fulltext19 fields changed- changed
Input schema / properties / dois / descriptionPrevious value: -"DOIs to resolve (e.g. [\"10.21203/rs.3.rs-9010375/v1\"]). Provide exactly one of `pmcids`, `pmids`, or `dois`. Resolved to a PMCID via the PMC ID Converter and returned as structured JATS when the article is in PMC; DOIs with no PMC counterpart (preprints, EPMC-only OA) fall through to Europe PMC, then Unpaywall, when those layers are enabled."New value: +"DOIs to resolve (e.g. [\"10.21203/rs.3.rs-9010375/v1\"]), one per element. Provide exactly one of `pmcids`, `pmids`, or `dois`. Resolved to a PMCID via the PMC ID Converter and returned as structured JATS when the article is in PMC; DOIs with no PMC counterpart (preprints, EPMC-only OA) fall through to Europe PMC, then Unpaywall, when those layers are enabled." - removed
Input schema / properties / dois / items / minLengthRemoved value: -3 - added
Input schema / properties / dois / items / patternAdded value: +"^10\\.[^\\s,]+\\/[^\\s,]+$" - added
Input schema / properties / includeAssetsAdded value: +{ + "default": true, + "description": "Include the article's figures and supplementary material — `assets[]`, each with its label, caption, enclosing section and deposit pointer. On by default because it is cheaper than tables: a median asset-bearing article grows about 10%, and the body prose already refers to these by label. Set false to omit them, which also removes the `[Figure: …]` / `[Supplementary: …]` markers from the section text, since without the array they point at nothing. Prose-shaped blocks — lists, definition lists, block quotes, boxed text, preformatted blocks, displayed formulae — are section text rather than assets and this switch never affects them. Applies to `source=pmc` results only.", + "type": "boolean" +} - added
Input schema / properties / includeTablesAdded value: +{ + "default": true, + "description": "Include the article's tables — cells, captions, labels and footnotes. On by default because a dropped table takes its numbers with it. Table-dense articles pay for it: rendered tables typically add 12–17% to an article record and can more than double it. Set false to omit them, or cap the cost with `maxCharacters`, which drops tables it cannot fit whole. Applies to `source=pmc` results only.", + "type": "boolean" +} - changed
Input schema / properties / maxCharacters / descriptionPrevious value: -"Per-article budget for body text, in characters. Counts `source=pmc` section and subsection text, or the `source=unpaywall` `content` body; titles, abstracts, identifiers, and references are never counted or shortened. Applied after `sections`, `maxSections`, and `includeReferences`, so semantic filtering is unaffected. This knob alone bounds only bodies: the response-wide ceiling it implies is this value times the number of articles returned, plus every uncounted field. Use `maxResponseCharacters` for a true whole-response ceiling. Omit for the full body."New value: +"Per-article budget for body text, in characters. Counts `source=pmc` section and subsection text — which carries the inline blocks the parser renders in place, such as lists, definition lists, block quotes, boxed text, preformatted blocks and displayed formulae — plus table label, caption, cell and footnote text and asset label, caption and `href` text; or the `source=unpaywall` `content` body. Titles, abstracts, identifiers, and references are never counted or shortened. The counted unit is that text alone — the Markdown grid `content[]` renders around the cells (pipes, padding, the divider row, headings) is scaffolding this budget does not measure, so a table renders longer than it costs here. Sections are served first, then tables, then assets, each spending what is left, in document order — admission stops at the first entry that does not fit, and every entry from there on is dropped whole rather than cut mid-row or returned with a shortened caption, counted in `truncation.omittedTables` / `truncation.omittedAssets` and named in `truncation.articles[].omittedTableNames` / `omittedAssetNames`. Applied after `sections`, `maxSections`, `includeReferences`, `includeTables`, and `includeAssets`, so semantic filtering is unaffected. This knob alone bounds only bodies: the response-wide ceiling it implies is this value times the number of articles returned, plus every uncounted field. Use `maxResponseCharacters` for a true whole-response ceiling. Omit for the full body." - changed
Input schema / properties / sections / descriptionPrevious value: -"Filter to specific sections by title, case-insensitive (e.g. [\"Introduction\", \"Methods\", \"Results\", \"Discussion\"]). Applies to `source=pmc` results only."New value: +"Filter to specific sections by title (e.g. [\"Introduction\", \"Methods\", \"Results\", \"Discussion\"]). A term matches a section or subsection title at any nesting depth, case-insensitively, as a substring — \"resul\" matches \"Results\". A section whose own title matches is returned whole; one kept only because a nested subsection matched keeps its heading as a breadcrumb, with its own text cleared and only the matching branch beneath it. Tables and assets narrow with the filter: one whose section did not survive, or that names no section, is dropped. Applies to `source=pmc` results only." - changed
Output schema / properties / articles / items / oneOfPrevious value: -[ - { - "additionalProperties": false, - "description": "Structured JATS full-text article. `viaSource` records whether the JATS came from NCBI PMC or Europe PMC.", - "properties": { - "abstract": { - "description": "Abstract", - "type": "string" - }, - "affiliations": { - "description": "Author affiliations", - "items": { - "type": "string" - }, - "type": "array" - }, - "articleType": { - "description": "Article type", - "type": "string" - }, - "authors": { - "description": "Authors", - "items": { - "additionalProperties": false, - "description": "Author entry", - "properties": { - "collectiveName": { - "description": "Group name", - "type": "string" - }, - "givenNames": { - "description": "Given names", - "type": "string" - }, - "lastName": { - "description": "Last name", - "type": "string" - } - }, - "type": "object" - }, - "type": "array" - }, - "doi": { - "description": "DOI, cased as the tier that served this record reports it (NCBI PMC, Europe PMC, or Unpaywall). DOIs are case-insensitive by spec and no case normalization is applied here, so casing can differ between tiers and from other tools — compare case-insensitively.", - "type": "string" - }, - "epmcId": { - "description": "Europe PMC record id — present when `viaSource` is `europepmc`", - "type": "string" - }, - "epmcSource": { - "description": "Europe PMC source code when `viaSource` is `europepmc`. Common values: `MED` (PubMed-derived), `PMC` (PMC counterpart), `PPR` (preprint), `PAT` (patent), `AGR` (Agricola), plus less common codes (`CTX`, `CBA`, `ETH`, `HIR`). Treat as opaque — EPMC may introduce new codes.", - "type": "string" - }, - "journal": { - "additionalProperties": false, - "description": "Journal information", - "properties": { - "issn": { - "description": "ISSN", - "type": "string" - }, - "issue": { - "description": "Issue number", - "type": "string" - }, - "pages": { - "description": "Page range", - "type": "string" - }, - "title": { - "description": "Journal title", - "type": "string" - }, - "volume": { - "description": "Volume number", - "type": "string" - } - }, - "type": "object" - }, - "keywords": { - "description": "Keywords", - "items": { - "type": "string" - }, - "type": "array" - }, - "pmcId": { - "description": "PMC ID — present for NCBI PMC records and Europe PMC entries that have a PMC counterpart. Absent for EPMC-only records like preprints; use `epmcId` in that case.", - "type": "string" - }, - "pmcUrl": { - "description": "PMC URL — derived from `pmcId` when present", - "type": "string" - }, - "pmid": { - "description": "PubMed ID", - "type": "string" - }, - "publicationDate": { - "additionalProperties": false, - "description": "Publication date", - "properties": { - "day": { - "description": "Publication day", - "type": "string" - }, - "month": { - "description": "Publication month", - "type": "string" - }, - "year": { - "description": "Publication year", - "type": "string" - } - }, - "type": "object" - }, - "pubmedUrl": { - "description": "PubMed URL", - "type": "string" - }, - "references": { - "description": "Reference list", - "items": { - "additionalProperties": false, - "description": "Reference entry", - "properties": { - "citation": { - "description": "Citation text", - "type": "string" - }, - "id": { - "description": "Reference ID", - "type": "string" - }, - "label": { - "description": "Reference label", - "type": "string" - } - }, - "required": [ - "citation" - ], - "type": "object" - }, - "type": "array" - }, - "sections": { - "description": "Article body sections", - "items": { - "additionalProperties": false, - "description": "Article body section", - "properties": { - "label": { - "description": "Section label", - "type": "string" - }, - "subsections": { - "description": "Nested subsections", - "items": { - "additionalProperties": false, - "description": "Article subsection", - "properties": { - "label": { - "description": "Subsection label", - "type": "string" - }, - "text": { - "description": "Subsection body text. Sections nested deeper than this level are folded in here in document order, each heading rendered on its own line above its text.", - "type": "string" - }, - "title": { - "description": "Subsection heading", - "type": "string" - } - }, - "required": [ - "text" - ], - "type": "object" - }, - "type": "array" - }, - "text": { - "description": "Section body text", - "type": "string" - }, - "title": { - "description": "Section heading", - "type": "string" - } - }, - "required": [ - "text" - ], - "type": "object" - }, - "type": "array" - }, - "source": { - "const": "pmc", - "description": "Structured JATS — same DTD whether sourced from NCBI PMC or Europe PMC", - "type": "string" - }, - "title": { - "description": "Article title", - "type": "string" - }, - "viaSource": { - "description": "Which layer produced the JATS: `pmc` for NCBI PMC EFetch (db=pmc), `europepmc` for Europe PMC `fullTextXML`. Both paths return the same JATS shape; the discriminator records origin for observability and license attribution.", - "enum": [ - "pmc", - "europepmc" - ], - "type": "string" - } - }, - "required": [ - "source", - "viaSource", - "sections" - ], - "type": "object" - }, - { - "additionalProperties": false, - "description": "Best-effort full text from an open-access copy", - "properties": { - "content": { - "description": "Full article text — Markdown or plain text per `contentFormat`", - "type": "string" - }, - "contentFormat": { - "description": "How `content` was extracted. html-markdown: Defuddle extracted Markdown from an HTML landing page; light section structure may survive but is not guaranteed. pdf-text: unpdf extracted plain text from a PDF; no section, reference, or heading structure.", - "enum": [ - "html-markdown", - "pdf-text" - ], - "type": "string" - }, - "doi": { - "description": "DOI used to locate the open-access copy", - "type": "string" - }, - "hostType": { - "description": "`publisher` or `repository` — where the OA copy is hosted", - "type": "string" - }, - "license": { - "description": "License identifier from Unpaywall (e.g. cc-by, cc0)", - "type": "string" - }, - "pmcId": { - "description": "PMC ID this article was requested under, in `PMC<digits>` form — present for `pmcids` input, absent for `pmids` and `dois` input. Ties the article back to the requested identifier, which `unavailable[]` keys on for the ids that found nothing.", - "type": "string" - }, - "pmid": { - "description": "PubMed ID when input was `pmids`; absent for `pmcids` and `dois` input", - "type": "string" - }, - "pubmedUrl": { - "description": "PubMed URL — present when `pmid` is set", - "type": "string" - }, - "source": { - "const": "unpaywall", - "description": "Content fetched from an open-access copy indexed by Unpaywall. Best-effort — structural fidelity depends on `contentFormat`.", - "type": "string" - }, - "sourceUrl": { - "description": "URL the content was fetched from", - "type": "string" - }, - "title": { - "description": "Detected article title when present", - "type": "string" - }, - "totalPages": { - "description": "Page count reported by the PDF extractor; absent for HTML", - "type": "number" - }, - "version": { - "description": "OA version: submittedVersion | acceptedVersion | publishedVersion", - "type": "string" - }, - "viaSource": { - "const": "unpaywall", - "description": "Layer that produced this article. Constant `unpaywall` for this branch.", - "type": "string" - }, - "wordCount": { - "description": "Approximate word count reported by the HTML extractor; absent for PDFs", - "type": "number" - } - }, - "required": [ - "source", - "viaSource", - "contentFormat", - "doi", - "sourceUrl", - "content" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "description": "Structured JATS full-text article. `viaSource` records whether the JATS came from NCBI PMC or Europe PMC.", + "properties": { + "abstract": { + "description": "Abstract", + "type": "string" + }, + "affiliations": { + "description": "Author affiliations", + "items": { + "type": "string" + }, + "type": "array" + }, + "articleType": { + "description": "Article type", + "type": "string" + }, + "assets": { + "description": "Every `<fig>` and `<supplementary-material>` the article carries, in document order — from the body and from `<floats-group>`, `<back>` and appendices alike. Each one lifted from the body leaves a `[Figure: <label>]` or `[Supplementary: <label>]` marker at its position in the section text, so reading order survives the lift. Absent when the article deposits none, when `includeAssets` is false, or when a `sections` filter left none standing.", + "items": { + "additionalProperties": false, + "description": "One figure or supplementary-material item, with its caption, pointer, and section", + "properties": { + "assetType": { + "description": "Which captioned element this came from — `figure` for a `<fig>`, `supplementary-material` for a `<supplementary-material>` deposit", + "enum": [ + "figure", + "supplementary-material" + ], + "type": "string" + }, + "caption": { + "description": "Caption text, with the label excluded", + "type": "string" + }, + "href": { + "description": "The `<graphic>`/`<media>` `@xlink:href` exactly as deposited — a pointer into the PMC deposit (`MOL2-20-1253-g001.jpg`), not a fetchable URL. No absolute form of it resolves; read the rendered article at `pmcUrl` instead. Absent when the deposit names no file.", + "type": "string" + }, + "id": { + "description": "JATS `id` attribute — the target body-text cross-references point at", + "type": "string" + }, + "label": { + "description": "Display label as printed, e.g. `Fig. 1`", + "type": "string" + }, + "sectionTitle": { + "description": "Title of the innermost section enclosing the asset, wherever that section sits — body, `<back>` matter, or an appendix all count. Absent for an asset inside no section at all, such as a `<floats-group>` deposit.", + "type": "string" + } + }, + "required": [ + "assetType" + ], + "type": "object" + }, + "type": "array" + }, + "authors": { + "description": "Authors", + "items": { + "additionalProperties": false, + "description": "Author entry", + "properties": { + "collectiveName": { + "description": "Group name", + "type": "string" + }, + "givenNames": { + "description": "Given names", + "type": "string" + }, + "lastName": { + "description": "Last name", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "doi": { + "description": "DOI, cased as the tier that served this record reports it (NCBI PMC, Europe PMC, or Unpaywall). DOIs are case-insensitive by spec and no case normalization is applied here, so casing can differ between tiers and from other tools — compare case-insensitively.", + "type": "string" + }, + "epmcId": { + "description": "Europe PMC record id — present when `viaSource` is `europepmc`", + "type": "string" + }, + "epmcSource": { + "description": "Europe PMC source code when `viaSource` is `europepmc`. Common values: `MED` (PubMed-derived), `PMC` (PMC counterpart), `PPR` (preprint), `PAT` (patent), `AGR` (Agricola), plus less common codes (`CTX`, `CBA`, `ETH`, `HIR`). Treat as opaque — EPMC may introduce new codes.", + "type": "string" + }, + "journal": { + "additionalProperties": false, + "description": "Journal information", + "properties": { + "elocationId": { + "description": "Electronic article locator from JATS `<elocation-id>` — the publisher-assigned article number (e.g. \"e20542\"). Journals that assign article numbers deposit no `<fpage>`, so this is the only locator on roughly half of PMC records. Never a substitute for `pages`; JATS carries no type attribute, so there is no counterpart to the `elocationIdType` that `pubmed_fetch_articles` reports.", + "type": "string" + }, + "issn": { + "description": "ISSN", + "type": "string" + }, + "issue": { + "description": "Issue number", + "type": "string" + }, + "pages": { + "description": "Page range", + "type": "string" + }, + "title": { + "description": "Journal title", + "type": "string" + }, + "volume": { + "description": "Volume number", + "type": "string" + } + }, + "type": "object" + }, + "keywords": { + "description": "Keywords", + "items": { + "type": "string" + }, + "type": "array" + }, + "pmcId": { + "description": "PMC ID — present for NCBI PMC records and Europe PMC entries that have a PMC counterpart. Absent for EPMC-only records like preprints; use `epmcId` in that case.", + "type": "string" + }, + "pmcUrl": { + "description": "PMC URL — derived from `pmcId` when present", + "type": "string" + }, + "pmid": { + "description": "PubMed ID", + "type": "string" + }, + "publicationDate": { + "additionalProperties": false, + "description": "Publication date", + "properties": { + "day": { + "description": "Publication day", + "type": "string" + }, + "month": { + "description": "Publication month", + "type": "string" + }, + "year": { + "description": "Publication year", + "type": "string" + } + }, + "type": "object" + }, + "pubmedUrl": { + "description": "PubMed URL", + "type": "string" + }, + "references": { + "description": "Reference list", + "items": { + "additionalProperties": false, + "description": "Reference entry", + "properties": { + "citation": { + "description": "Citation text", + "type": "string" + }, + "id": { + "description": "Reference ID", + "type": "string" + }, + "label": { + "description": "Reference label", + "type": "string" + } + }, + "required": [ + "citation" + ], + "type": "object" + }, + "type": "array" + }, + "sections": { + "description": "Article body sections", + "items": { + "additionalProperties": false, + "description": "Article body section", + "properties": { + "label": { + "description": "Section label", + "type": "string" + }, + "subsections": { + "description": "Nested subsections", + "items": { + "additionalProperties": false, + "description": "Article subsection", + "properties": { + "label": { + "description": "Subsection label", + "type": "string" + }, + "text": { + "description": "Subsection body text. Sections nested deeper than this level are folded in here in document order, each heading rendered on its own line above its text.", + "type": "string" + }, + "title": { + "description": "Subsection heading", + "type": "string" + } + }, + "required": [ + "text" + ], + "type": "object" + }, + "type": "array" + }, + "text": { + "description": "Section body text", + "type": "string" + }, + "title": { + "description": "Section heading", + "type": "string" + } + }, + "required": [ + "text" + ], + "type": "object" + }, + "type": "array" + }, + "source": { + "const": "pmc", + "description": "Structured JATS — same DTD whether sourced from NCBI PMC or Europe PMC", + "type": "string" + }, + "tables": { + "description": "Every `<table-wrap>` the article carries, in document order — from the body and from `<floats-group>`, `<back>` and appendices alike. Absent when the article deposits none, when `includeTables` is false, or when a `sections` filter left none standing.", + "items": { + "additionalProperties": false, + "description": "One table from the article, with its cells, caption, and owning section", + "properties": { + "caption": { + "description": "Caption text, with the label excluded", + "type": "string" + }, + "footnotes": { + "description": "`<table-wrap-foot>` text, flattened to one string", + "type": "string" + }, + "headerRowCount": { + "description": "How many leading `rows` entries are header rows — a `<thead>` block, or leading rows made entirely of `<th>`. 0 when the table declares none. Several header rows stack: read one column top to bottom for its full header path.", + "type": "number" + }, + "id": { + "description": "JATS `id` attribute — the target body-text cross-references point at", + "type": "string" + }, + "label": { + "description": "Table label as printed, e.g. `TABLE 1`", + "type": "string" + }, + "rows": { + "description": "Cell text by row, in document order, one entry per grid column. `colspan` and `rowspan` are expanded, so a cell covering several columns or rows repeats its text across each cell it covers and a well-formed table is rectangular — align on position from the left, and read a repeated value as one spanning cell rather than several measurements. Empty when `unextractableReason` is set.", + "items": { + "description": "One row, as cell text by grid column", + "items": { + "type": "string" + }, + "type": "array" + }, + "type": "array" + }, + "sectionTitle": { + "description": "Title of the innermost section enclosing the table, wherever that section sits — body, `<back>` matter, or an appendix all count, and in back matter the section name is the only positional cue there is. Absent only for a table inside no section at all, such as a `<floats-group>` deposit.", + "type": "string" + }, + "unextractableReason": { + "description": "Why `rows` is empty — set only then. graphic-only: the table was deposited as an image with no underlying markup. cals-tgroup: the table uses the CALS `<tgroup>` model, which this server does not extract (0 of 283 tables in an open-access survey used it). no-rows: the markup carried no rows. The label and caption are still returned, so a table that could not be read is visible rather than silently missing.", + "enum": [ + "cals-tgroup", + "graphic-only", + "no-rows" + ], + "type": "string" + } + }, + "required": [ + "headerRowCount", + "rows" + ], + "type": "object" + }, + "type": "array" + }, + "title": { + "description": "Article title", + "type": "string" + }, + "viaSource": { + "description": "Which layer produced the JATS: `pmc` for NCBI PMC EFetch (db=pmc), `europepmc` for Europe PMC `fullTextXML`. Both paths return the same JATS shape; the discriminator records origin for observability and license attribution.", + "enum": [ + "pmc", + "europepmc" + ], + "type": "string" + } + }, + "required": [ + "source", + "viaSource", + "sections" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "Best-effort full text from an open-access copy", + "properties": { + "content": { + "description": "Full article text — Markdown or plain text per `contentFormat`", + "type": "string" + }, + "contentFormat": { + "description": "How `content` was extracted. html-markdown: Defuddle extracted Markdown from an HTML landing page; light section structure may survive but is not guaranteed. pdf-text: unpdf extracted plain text from a PDF; no section, reference, or heading structure.", + "enum": [ + "html-markdown", + "pdf-text" + ], + "type": "string" + }, + "doi": { + "description": "DOI used to locate the open-access copy", + "type": "string" + }, + "hostType": { + "description": "`publisher` or `repository` — where the OA copy is hosted", + "type": "string" + }, + "license": { + "description": "License identifier from Unpaywall (e.g. cc-by, cc0)", + "type": "string" + }, + "pmcId": { + "description": "PMC ID this article was requested under, in `PMC<digits>` form — present for `pmcids` input, absent for `pmids` and `dois` input. Ties the article back to the requested identifier, which `unavailable[]` keys on for the ids that found nothing.", + "type": "string" + }, + "pmid": { + "description": "PubMed ID when input was `pmids`; absent for `pmcids` and `dois` input", + "type": "string" + }, + "pubmedUrl": { + "description": "PubMed URL — present when `pmid` is set", + "type": "string" + }, + "source": { + "const": "unpaywall", + "description": "Content fetched from an open-access copy indexed by Unpaywall. Best-effort — structural fidelity depends on `contentFormat`.", + "type": "string" + }, + "sourceUrl": { + "description": "URL the content was fetched from", + "type": "string" + }, + "title": { + "description": "Detected article title when present", + "type": "string" + }, + "totalPages": { + "description": "Page count reported by the PDF extractor; absent for HTML", + "type": "number" + }, + "version": { + "description": "OA version: submittedVersion | acceptedVersion | publishedVersion", + "type": "string" + }, + "viaSource": { + "const": "unpaywall", + "description": "Layer that produced this article. Constant `unpaywall` for this branch.", + "type": "string" + }, + "wordCount": { + "description": "Approximate word count reported by the HTML extractor; absent for PDFs", + "type": "number" + } + }, + "required": [ + "source", + "viaSource", + "contentFormat", + "doi", + "sourceUrl", + "content" + ], + "type": "object" + } +] - changed
Output schema / properties / notice / descriptionPrevious value: -"Optional guidance for a partial or empty body. A `sections`-filter miss names the requested terms and affected article id(s) and suggests retrying without `sections` or using broader headings. A metadata-only record names the id(s) the chain could retrieve as front matter only and points at `pubmed_fetch_articles` for the abstract. A budgeted response names the characters returned versus carried and points at `truncation`. A response-wide budget that deferred articles names the ids to re-request. Absent when none of those applies."New value: +"Optional guidance for a partial or empty body. A `sections`-filter miss names the requested terms and affected article id(s) and suggests retrying without `sections` or using broader headings. A metadata-only record names the id(s) the chain could retrieve as front matter only and points at `pubmed_fetch_articles` for the abstract. A table returned with no cell values names the affected table(s), the article each came from, and why the cells cannot be recovered. A budgeted response names the characters returned versus carried and points at `truncation`. A response-wide budget that deferred articles names the ids to re-request. Absent when none of those applies." - added
Output schema / properties / truncation / properties / articles / items / properties / omittedAssetNamesAdded value: +{ + "description": "The dropped assets by name, in document order — each asset's label, else its `id`, else `asset <n>` for its position in the article. Contiguous for the same reason `omittedTableNames` is: admission stops at the first asset that did not fit rather than skipping ahead to a smaller one. Absent when none were dropped.", + "items": { + "type": "string" + }, + "type": "array" +} - added
Output schema / properties / truncation / properties / articles / items / properties / omittedAssetsAdded value: +{ + "description": "Figures and supplementary items this article dropped whole because the budget left no room once sections and tables were served. An asset is never returned with a truncated caption, so it is either returned complete or counted here. Absent when none were dropped.", + "type": "number" +} - added
Output schema / properties / truncation / properties / articles / items / properties / omittedTableNamesAdded value: +{ + "description": "The dropped tables by name, in document order — each table's label, else its `id`, else `table <n>` for its position in the article. Names the tables a bare count only hints at, the way `deferred.ids` names deferred articles. Every table from the first that did not fit onward is here: admission stops at that table rather than skipping ahead to a smaller one, so these are contiguous. Absent when none were dropped.", + "items": { + "type": "string" + }, + "type": "array" +} - added
Output schema / properties / truncation / properties / articles / items / properties / omittedTablesAdded value: +{ + "description": "Tables this article dropped whole because the budget left no room for them. A table is never cut mid-row, so it is either returned complete or counted here. Absent when none were dropped.", + "type": "number" +} - added
Output schema / properties / truncation / properties / omittedAssetsAdded value: +{ + "description": "Figures and supplementary items dropped whole across every budgeted article, because the budget left no room once body sections and tables were served. Absent when none were dropped. Re-request the affected articles with a higher `maxCharacters`, or with `sections` narrowed, to receive them.", + "type": "number" +} - added
Output schema / properties / truncation / properties / omittedTablesAdded value: +{ + "description": "Tables dropped whole across every budgeted article, because the budget left no room once body sections were served. Absent when none were dropped. Re-request the affected articles with a higher `maxCharacters`, or with `sections` narrowed, to receive them.", + "type": "number" +} - changed
Output schema / properties / unavailable / items / properties / reason / descriptionPrevious value: -"Why no full text was returned — the most specific signal any tier that answered reported. not-found: upstream returned no record for this ID. no-pmc-fallback-disabled: every tier was skipped (`triedTiers` is all `not-attempted`) — typically because EPMC (`EUROPEPMC_ENABLED`) and Unpaywall (`UNPAYWALL_EMAIL`) are not configured. no-epmc-fulltext: EPMC indexed the record but publishes no fullTextXML. no-body: the record was retrieved but carries front matter and abstract only, with no body sections — use `pubmed_fetch_articles` for the metadata. no-doi: no DOI to query Unpaywall. no-oa: Unpaywall has no OA copy. fetch-failed: download failed. parse-failed: extraction empty. service-error: upstream server failure (threw, timed out, or returned malformed data). A reason never means the chain ran to completion — read `unqueriedTiers` for that."New value: +"Why no full text was returned — the most specific signal any tier that answered reported. not-found: upstream returned no record for this ID. no-pmc-fallback-disabled: every tier was skipped (`triedTiers` is all `not-attempted`) — typically because EPMC (`EUROPEPMC_ENABLED`) and Unpaywall (`UNPAYWALL_EMAIL`) are not configured. no-epmc-fulltext: EPMC indexed the record but publishes no fullTextXML. no-body: the record was retrieved but carries front matter and abstract only, with no body sections — use `pubmed_fetch_articles` for the metadata. no-doi: the DOI lookup ran and this record has none, so Unpaywall could not be queried. doi-lookup-failed: the DOI lookup itself errored, so whether a DOI exists is unknown and Unpaywall was never reached — retry the request; unlike no-doi this is a transient failure, not a settled answer. no-oa: Unpaywall has no OA copy. fetch-failed: download failed. parse-failed: extraction empty. service-error: upstream server failure (threw, timed out, or returned malformed data). A reason never means the chain ran to completion — read `unqueriedTiers` for that." - changed
Output schema / properties / unavailable / items / properties / reason / enumPrevious value: -[ - "not-found", - "no-pmc-fallback-disabled", - "no-epmc-fulltext", - "no-body", - "no-doi", - "no-oa", - "fetch-failed", - "parse-failed", - "service-error" -]New value: +[ + "not-found", + "no-pmc-fallback-disabled", + "no-epmc-fulltext", + "no-body", + "no-doi", + "doi-lookup-failed", + "no-oa", + "fetch-failed", + "parse-failed", + "service-error" +] - changed
Output schema / properties / unavailable / items / properties / triedTiers / items / properties / outcome / descriptionPrevious value: -"Per-tier outcome. not-attempted: tier was skipped. miss: tier returned no record. no-fulltext: EPMC indexed the record but publishes no fullTextXML. no-body: the tier returned a record with front matter and abstract but no body sections, so the chain continued. no-doi: no DOI to query Unpaywall. no-oa: Unpaywall reports no open-access copy. fetch-failed: OA copy download failed. parse-failed: extraction produced empty content. service-error: tier service threw."New value: +"Per-tier outcome. not-attempted: tier was skipped. miss: tier returned no record. no-fulltext: EPMC indexed the record but publishes no fullTextXML. no-body: the tier returned a record with front matter and abstract but no body sections, so the chain continued. no-doi: the DOI lookup ran and this record has none, so Unpaywall could not be queried. doi-lookup-failed: the DOI lookup itself errored, so whether a DOI exists is unknown and Unpaywall was never reached — retry the request. no-oa: Unpaywall reports no open-access copy. fetch-failed: OA copy download failed. parse-failed: extraction produced empty content. service-error: tier service threw." - changed
Output schema / properties / unavailable / items / properties / triedTiers / items / properties / outcome / enumPrevious value: -[ - "not-attempted", - "miss", - "no-fulltext", - "no-body", - "no-doi", - "no-oa", - "fetch-failed", - "parse-failed", - "service-error" -]New value: +[ + "not-attempted", + "miss", + "no-fulltext", + "no-body", + "no-doi", + "doi-lookup-failed", + "no-oa", + "fetch-failed", + "parse-failed", + "service-error" +]
- Changed
pubmed_find_related9 fields changed- changed
Output schema / properties / articles / items / properties / authors / descriptionPrevious value: -"Author string"New value: +"Author string — the first three of the record's own authors, then \"et al.\". On an NCBI Bookshelf chapter these are the chapter's authors; the book's editors are in `editors`." - added
Output schema / properties / articles / items / properties / bookTitleAdded value: +{ + "description": "Title of the book an NCBI Bookshelf record belongs to. Present instead of `source` on a book record; absent on a journal article.", + "type": "string" +} - added
Output schema / properties / articles / items / properties / docTypeAdded value: +{ + "description": "What PubMed classifies this record as: \"chapter\" or \"book\" for an NCBI Bookshelf record, \"citation\" for an ordinary journal article. Absent when PubMed supplies none.", + "type": "string" +} - added
Output schema / properties / articles / items / properties / editorsAdded value: +{ + "description": "Editors of the containing book, kept out of `authors` so they cannot displace the record's own authors. Absent on a journal article and on a book that credits no editors.", + "items": { + "description": "One editor, \"Surname Initials\" as ESummary renders it", + "type": "string" + }, + "type": "array" +} - added
Output schema / properties / articles / items / properties / publisherNameAdded value: +{ + "description": "Publisher of the book an NCBI Bookshelf record belongs to. Present only on a book record; absent on a journal article.", + "type": "string" +} - changed
Output schema / properties / articles / items / properties / source / descriptionPrevious value: -"Journal source"New value: +"Journal the article appeared in. Absent on an NCBI Bookshelf record, which has no journal — its venue is in `bookTitle` and `publisherName` instead, and `docType` says which kind of record it is." - added
Output schema / properties / coverageFailuresAdded value: +{ + "description": "Reference-coverage fallbacks that failed instead of answering, so the reference set is unverified rather than confirmed absent. Absent when every provider consulted answered.", + "items": { + "additionalProperties": false, + "description": "One coverage provider that could not be checked", + "properties": { + "provider": { + "description": "Reference-coverage provider that failed", + "enum": [ + "europepmc", + "openalex" + ], + "type": "string" + }, + "reason": { + "description": "Declared failure reason, e.g. europepmc_unreachable or provider_disabled", + "type": "string" + }, + "retryable": { + "description": "Whether a retry can reach this provider", + "type": "boolean" + } + }, + "required": [ + "provider", + "reason", + "retryable" + ], + "type": "object" + }, + "type": "array" +} - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance when results are empty, a fallback provider answered, offset overshot, or Europe PMC rows were excluded for carrying no PubMed PMID. Absent on a clean NCBI result page."New value: +"Guidance when results are empty, a fallback provider answered, offset overshot, a fallback provider could not be reached, or upstream rows were excluded for carrying no PubMed PMID. Absent on a clean NCBI result page." - changed
Output schema / properties / totalCount / descriptionPrevious value: -"Total related articles found before windowing. A Europe PMC total may shrink to the PubMed-addressable count once a request window covers the whole upstream set, since rows without a PubMed PMID cannot be returned."New value: +"Total related articles found before windowing. A Europe PMC or OpenAlex total may shrink to the PubMed-addressable count once a request window covers the whole upstream set, since rows without a PubMed PMID cannot be returned."
- Changed
pubmed_format_citations1 field changed- changed
Output schema / properties / unavailablePmids / descriptionPrevious value: -"Requested PMIDs that did not return article metadata"New value: +"PMIDs PubMed returned no record for, so nothing could be cited for them. That is all this reports: PubMed omits a PMID it does not recognize silently, with no error and no reason, so the absence says nothing about whether the PMID exists. Use `pubmed_search_articles` to find PMIDs that do resolve."
- Changed
pubmed_lookup_citation11 fields changed- changed
Input schema / properties / citations / items / properties / authorName / descriptionPrevious value: -"Author name, typically \"lastname initials\" (e.g., \"mann bj\")"New value: +"Author name, typically \"lastname initials\" (e.g., \"mann bj\"). Cannot contain a pipe (\"|\") or a line break." - added
Input schema / properties / citations / items / properties / authorName / patternAdded value: +"^[^|\\r\\n]*$" - changed
Input schema / properties / citations / items / properties / firstPage / descriptionPrevious value: -"First page number"New value: +"First page number. Cannot contain a pipe (\"|\") or a line break." - added
Input schema / properties / citations / items / properties / firstPage / patternAdded value: +"^[^|\\r\\n]*$" - changed
Input schema / properties / citations / items / properties / journal / descriptionPrevious value: -"Journal title or ISO abbreviation (e.g., \"proc natl acad sci u s a\")"New value: +"Journal title or ISO abbreviation (e.g., \"proc natl acad sci u s a\"). Cannot contain a pipe (\"|\") or a line break." - added
Input schema / properties / citations / items / properties / journal / patternAdded value: +"^[^|\\r\\n]*$" - changed
Input schema / properties / citations / items / properties / key / descriptionPrevious value: -"Arbitrary label to track this citation in results. Auto-assigned if omitted."New value: +"Arbitrary label to track this citation in results. Auto-assigned if omitted. Echoed back unchanged and never sent to NCBI, so any character is accepted here." - changed
Input schema / properties / citations / items / properties / volume / descriptionPrevious value: -"Volume number"New value: +"Volume number. Cannot contain a pipe (\"|\") or a line break." - added
Input schema / properties / citations / items / properties / volume / patternAdded value: +"^[^|\\r\\n]*$" - changed
Input schema / properties / citations / items / properties / year / descriptionPrevious value: -"Publication year (e.g., \"1991\")"New value: +"Publication year (e.g., \"1991\"). Cannot contain a pipe (\"|\") or a line break." - added
Input schema / properties / citations / items / properties / year / patternAdded value: +"^[^|\\r\\n]*$"
- Changed
pubmed_lookup_mesh3 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"MeSH descriptor name or free-text term to look up"New value: +"MeSH descriptor name or free-text term to look up. Must carry a term: a blank or whitespace-only value is rejected rather than searched." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). `blank_query`: The query holds no search term once whitespace, and any markup the tool strips first, are removed — so NCBI would receive a blank term. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "queue_full", - "ncbi_unreachable", - "ncbi_deadline_exceeded", - "ncbi_invalid_response", - "ncbi_resource_not_found" -]New value: +[ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found", + "blank_query" +]
- Changed
pubmed_search_articles9 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"PubMed search query (supports full NCBI syntax)"New value: +"PubMed search query (supports full NCBI syntax). Must carry a search term: a value that is blank once markup is stripped is rejected rather than sent to PubMed as an empty term." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). `blank_query`: The query holds no search term once whitespace, and any markup the tool strips first, are removed — so NCBI would receive a blank term. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "queue_full", - "ncbi_unreachable", - "ncbi_deadline_exceeded", - "ncbi_invalid_response", - "ncbi_resource_not_found" -]New value: +[ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found", + "blank_query" +] - changed
Output schema / properties / summaries / items / properties / authors / descriptionPrevious value: -"Formatted author string"New value: +"Formatted author string — the first three of the record's own authors, then \"et al.\". On an NCBI Bookshelf chapter these are the chapter's authors; the book's editors are reported separately in `editors`." - added
Output schema / properties / summaries / items / properties / bookTitleAdded value: +{ + "description": "Title of the book an NCBI Bookshelf record belongs to, e.g. \"GeneReviews(®)\". Present instead of `source` on a book record; absent on a journal article.", + "type": "string" +} - added
Output schema / properties / summaries / items / properties / docTypeAdded value: +{ + "description": "What PubMed classifies this record as: \"chapter\" or \"book\" for an NCBI Bookshelf record, \"citation\" for an ordinary journal article. Absent when PubMed supplies none.", + "type": "string" +} - added
Output schema / properties / summaries / items / properties / editorsAdded value: +{ + "description": "Editors of the containing book, kept out of `authors` so they cannot displace the record's own authors. Absent on a journal article and on a book that credits no editors.", + "items": { + "description": "One editor, \"Surname Initials\" as ESummary renders it", + "type": "string" + }, + "type": "array" +} - added
Output schema / properties / summaries / items / properties / publisherNameAdded value: +{ + "description": "Publisher of the book an NCBI Bookshelf record belongs to. Present only on a book record; absent on a journal article.", + "type": "string" +} - changed
Output schema / properties / summaries / items / properties / source / descriptionPrevious value: -"Journal source"New value: +"Journal the article appeared in. Absent on an NCBI Bookshelf record, which has no journal — its venue is in `bookTitle` and `publisherName` instead, and `docType` says which kind of record it is."
- Changed
pubmed_spell_check3 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"PubMed search query to spell-check"New value: +"PubMed search query to spell-check. Must carry a term: a blank or whitespace-only value is rejected rather than sent to ESpell." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). `blank_query`: The query holds no search term once whitespace, and any markup the tool strips first, are removed — so NCBI would receive a blank term. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "queue_full", - "ncbi_unreachable", - "ncbi_deadline_exceeded", - "ncbi_invalid_response", - "ncbi_resource_not_found" -]New value: +[ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found", + "blank_query" +]
5 tool updates
v2.10.8- Changed
pubmed_europepmc_fetch3 fields changed- changed
Output schema / properties / records / items / properties / authors / descriptionPrevious value: -"Formatted author string"New value: +"Formatted author string as display-ready plain text — JATS/HTML markup stripped and HTML entities decoded." - changed
Output schema / properties / records / items / properties / journal / descriptionPrevious value: -"Journal title"New value: +"Journal title as display-ready plain text — JATS/HTML markup stripped and HTML entities decoded." - changed
Output schema / properties / records / items / properties / title / descriptionPrevious value: -"Record title"New value: +"Record title as display-ready plain text — JATS/HTML markup stripped and HTML entities decoded."
- Changed
pubmed_europepmc_search3 fields changed- changed
Output schema / properties / hits / items / properties / authors / descriptionPrevious value: -"Formatted author string"New value: +"Formatted author string as display-ready plain text — JATS/HTML markup stripped and HTML entities decoded." - changed
Output schema / properties / hits / items / properties / journal / descriptionPrevious value: -"Journal title"New value: +"Journal title as display-ready plain text — JATS/HTML markup stripped and HTML entities decoded." - changed
Output schema / properties / hits / items / properties / title / descriptionPrevious value: -"Article title"New value: +"Article title as display-ready plain text — JATS/HTML markup stripped and HTML entities decoded."
- Changed
pubmed_fetch_articles6 fields changed- added
Input schema / properties / maxResponseCharactersAdded value: +{ + "description": "Opt-in ceiling for the whole response, in characters. Each article is measured as the JSON record it is returned as — title, abstract, authors, journal, MeSH terms, grants, identifiers, every field it carries. Articles are kept in response order until the next one would cross the ceiling; that article and the rest are deferred whole (never partially populated) and listed in `deferred.ids`. Response envelope fields — counts, `unavailablePmids`, `deferred` itself — are not counted. Omit to return every resolved article.", + "maximum": 1000000, + "minimum": 1, + "type": "integer" +} - added
Output schema / properties / deferredAdded value: +{ + "additionalProperties": false, + "description": "Continuation state for articles the whole-response budget withheld. Present only when `maxResponseCharacters` deferred at least one article.", + "properties": { + "deferredCount": { + "description": "Articles that resolved but were withheld to stay under the ceiling", + "type": "number" + }, + "ids": { + "description": "PMIDs of the deferred articles, in response order. Re-call `pubmed_fetch_articles` with these as `pmids` and the same other inputs to retrieve them. Never contains a PMID from `unavailablePmids`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "maxResponseCharacters": { + "description": "The `maxResponseCharacters` ceiling this response was budgeted against", + "type": "number" + }, + "nextDeferredCharacters": { + "description": "Serialized size of the next deferred article — the first entry in `ids`, where the response stopped. Raise `maxResponseCharacters` to at least this to make progress; a smaller article further down `ids` cannot be reached until this one fits.", + "type": "number" + }, + "returnedCharacters": { + "description": "Serialized characters the returned article records account for", + "type": "number" + } + }, + "required": [ + "maxResponseCharacters", + "returnedCharacters", + "deferredCount", + "ids", + "nextDeferredCharacters" + ], + "type": "object" +} - changed
Output schema / properties / notice / descriptionPrevious value: -"Optional guidance when no articles were returned — points to discovery tools. Absent on successful fetches."New value: +"Optional guidance when no articles were returned — points to discovery tools — or when `maxResponseCharacters` deferred articles, naming how to retrieve them. Absent on successful unbudgeted fetches." - changed
Output schema / properties / totalReturned / descriptionPrevious value: -"Number of articles returned"New value: +"Number of articles in this response. Under a `maxResponseCharacters` budget this counts the kept articles only; `deferred.deferredCount` covers the rest." - added
Output schema / properties / truncatedAdded value: +{ + "description": "True when `maxResponseCharacters` withheld at least one resolved article. Absent when the response carries every article that resolved. The continuation state is in `deferred`.", + "type": "boolean" +} - changed
Output schema / properties / unavailablePmids / descriptionPrevious value: -"PMIDs that returned no article data"New value: +"PMIDs that returned no article data. Reported in full regardless of where a `maxResponseCharacters` cutoff lands — these are misses, not deferrals, and re-requesting them returns nothing."
- Changed
pubmed_fetch_fulltext10 fields changed- changed
Input schema / properties / maxCharacters / descriptionPrevious value: -"Per-article budget for body text, in characters. Counts `source=pmc` section and subsection text, or the `source=unpaywall` `content` body; titles, abstracts, identifiers, and references are never counted or shortened. Applied after `sections`, `maxSections`, and `includeReferences`, so semantic filtering is unaffected. The response-wide ceiling is this value times the number of articles returned. Omit for the full body."New value: +"Per-article budget for body text, in characters. Counts `source=pmc` section and subsection text, or the `source=unpaywall` `content` body; titles, abstracts, identifiers, and references are never counted or shortened. Applied after `sections`, `maxSections`, and `includeReferences`, so semantic filtering is unaffected. This knob alone bounds only bodies: the response-wide ceiling it implies is this value times the number of articles returned, plus every uncounted field. Use `maxResponseCharacters` for a true whole-response ceiling. Omit for the full body." - added
Input schema / properties / maxResponseCharactersAdded value: +{ + "description": "Opt-in ceiling for the whole response, in characters — the true response-wide counterpart to the per-article `maxCharacters`. Each article is measured as the JSON record it is returned as, after every filter and the per-article body budget: title, abstract, body sections, references, identifiers, license and source metadata — every field it carries. One ledger covers all tiers, so PMC-, Europe PMC-, and Unpaywall-served articles spend the same budget. Articles are kept in response order until the next one would cross the ceiling; that article and the rest are deferred whole (never partially populated) and listed in `deferred.ids`. Response envelope fields — counts, `unavailable`, `truncation`, `deferred` itself — are not counted. Omit to return every resolved article.", + "maximum": 1000000, + "minimum": 1, + "type": "integer" +} - changed
Output schema / properties / articles / items / oneOfPrevious value: -[ - { - "additionalProperties": false, - "description": "Structured JATS full-text article. `viaSource` records whether the JATS came from NCBI PMC or Europe PMC.", - "properties": { - "abstract": { - "description": "Abstract", - "type": "string" - }, - "affiliations": { - "description": "Author affiliations", - "items": { - "type": "string" - }, - "type": "array" - }, - "articleType": { - "description": "Article type", - "type": "string" - }, - "authors": { - "description": "Authors", - "items": { - "additionalProperties": false, - "description": "Author entry", - "properties": { - "collectiveName": { - "description": "Group name", - "type": "string" - }, - "givenNames": { - "description": "Given names", - "type": "string" - }, - "lastName": { - "description": "Last name", - "type": "string" - } - }, - "type": "object" - }, - "type": "array" - }, - "doi": { - "description": "DOI, cased as the tier that served this record reports it (NCBI PMC, Europe PMC, or Unpaywall). DOIs are case-insensitive by spec and no case normalization is applied here, so casing can differ between tiers and from other tools — compare case-insensitively.", - "type": "string" - }, - "epmcId": { - "description": "Europe PMC record id — present when `viaSource` is `europepmc`", - "type": "string" - }, - "epmcSource": { - "description": "Europe PMC source code when `viaSource` is `europepmc`. Common values: `MED` (PubMed-derived), `PMC` (PMC counterpart), `PPR` (preprint), `PAT` (patent), `AGR` (Agricola), plus less common codes (`CTX`, `CBA`, `ETH`, `HIR`). Treat as opaque — EPMC may introduce new codes.", - "type": "string" - }, - "journal": { - "additionalProperties": false, - "description": "Journal information", - "properties": { - "issn": { - "description": "ISSN", - "type": "string" - }, - "issue": { - "description": "Issue number", - "type": "string" - }, - "pages": { - "description": "Page range", - "type": "string" - }, - "title": { - "description": "Journal title", - "type": "string" - }, - "volume": { - "description": "Volume number", - "type": "string" - } - }, - "type": "object" - }, - "keywords": { - "description": "Keywords", - "items": { - "type": "string" - }, - "type": "array" - }, - "pmcId": { - "description": "PMC ID — present for NCBI PMC records and Europe PMC entries that have a PMC counterpart. Absent for EPMC-only records like preprints; use `epmcId` in that case.", - "type": "string" - }, - "pmcUrl": { - "description": "PMC URL — derived from `pmcId` when present", - "type": "string" - }, - "pmid": { - "description": "PubMed ID", - "type": "string" - }, - "publicationDate": { - "additionalProperties": false, - "description": "Publication date", - "properties": { - "day": { - "description": "Publication day", - "type": "string" - }, - "month": { - "description": "Publication month", - "type": "string" - }, - "year": { - "description": "Publication year", - "type": "string" - } - }, - "type": "object" - }, - "pubmedUrl": { - "description": "PubMed URL", - "type": "string" - }, - "references": { - "description": "Reference list", - "items": { - "additionalProperties": false, - "description": "Reference entry", - "properties": { - "citation": { - "description": "Citation text", - "type": "string" - }, - "id": { - "description": "Reference ID", - "type": "string" - }, - "label": { - "description": "Reference label", - "type": "string" - } - }, - "required": [ - "citation" - ], - "type": "object" - }, - "type": "array" - }, - "sections": { - "description": "Article body sections", - "items": { - "additionalProperties": false, - "description": "Article body section", - "properties": { - "label": { - "description": "Section label", - "type": "string" - }, - "subsections": { - "description": "Nested subsections", - "items": { - "additionalProperties": false, - "description": "Article subsection", - "properties": { - "label": { - "description": "Subsection label", - "type": "string" - }, - "text": { - "description": "Subsection body text", - "type": "string" - }, - "title": { - "description": "Subsection heading", - "type": "string" - } - }, - "required": [ - "text" - ], - "type": "object" - }, - "type": "array" - }, - "text": { - "description": "Section body text", - "type": "string" - }, - "title": { - "description": "Section heading", - "type": "string" - } - }, - "required": [ - "text" - ], - "type": "object" - }, - "type": "array" - }, - "source": { - "const": "pmc", - "description": "Structured JATS — same DTD whether sourced from NCBI PMC or Europe PMC", - "type": "string" - }, - "title": { - "description": "Article title", - "type": "string" - }, - "viaSource": { - "description": "Which layer produced the JATS: `pmc` for NCBI PMC EFetch (db=pmc), `europepmc` for Europe PMC `fullTextXML`. Both paths return the same JATS shape; the discriminator records origin for observability and license attribution.", - "enum": [ - "pmc", - "europepmc" - ], - "type": "string" - } - }, - "required": [ - "source", - "viaSource", - "sections" - ], - "type": "object" - }, - { - "additionalProperties": false, - "description": "Best-effort full text from an open-access copy", - "properties": { - "content": { - "description": "Full article text — Markdown or plain text per `contentFormat`", - "type": "string" - }, - "contentFormat": { - "description": "How `content` was extracted. html-markdown: Defuddle extracted Markdown from an HTML landing page; light section structure may survive but is not guaranteed. pdf-text: unpdf extracted plain text from a PDF; no section, reference, or heading structure.", - "enum": [ - "html-markdown", - "pdf-text" - ], - "type": "string" - }, - "doi": { - "description": "DOI used to locate the open-access copy", - "type": "string" - }, - "hostType": { - "description": "`publisher` or `repository` — where the OA copy is hosted", - "type": "string" - }, - "license": { - "description": "License identifier from Unpaywall (e.g. cc-by, cc0)", - "type": "string" - }, - "pmcId": { - "description": "PMC ID this article was requested under, in `PMC<digits>` form — present for `pmcids` input, absent for `pmids` and `dois` input. Ties the article back to the requested identifier, which `unavailable[]` keys on for the ids that found nothing.", - "type": "string" - }, - "pmid": { - "description": "PubMed ID when input was `pmids`; absent for `pmcids` and `dois` input", - "type": "string" - }, - "pubmedUrl": { - "description": "PubMed URL — present when `pmid` is set", - "type": "string" - }, - "source": { - "const": "unpaywall", - "description": "Content fetched from an open-access copy indexed by Unpaywall. Best-effort — structural fidelity depends on `contentFormat`.", - "type": "string" - }, - "sourceUrl": { - "description": "URL the content was fetched from", - "type": "string" - }, - "title": { - "description": "Detected article title when present", - "type": "string" - }, - "totalPages": { - "description": "Page count reported by the PDF extractor; absent for HTML", - "type": "number" - }, - "version": { - "description": "OA version: submittedVersion | acceptedVersion | publishedVersion", - "type": "string" - }, - "viaSource": { - "const": "unpaywall", - "description": "Layer that produced this article. Constant `unpaywall` for this branch.", - "type": "string" - }, - "wordCount": { - "description": "Approximate word count reported by the HTML extractor; absent for PDFs", - "type": "number" - } - }, - "required": [ - "source", - "viaSource", - "contentFormat", - "doi", - "sourceUrl", - "content" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "description": "Structured JATS full-text article. `viaSource` records whether the JATS came from NCBI PMC or Europe PMC.", + "properties": { + "abstract": { + "description": "Abstract", + "type": "string" + }, + "affiliations": { + "description": "Author affiliations", + "items": { + "type": "string" + }, + "type": "array" + }, + "articleType": { + "description": "Article type", + "type": "string" + }, + "authors": { + "description": "Authors", + "items": { + "additionalProperties": false, + "description": "Author entry", + "properties": { + "collectiveName": { + "description": "Group name", + "type": "string" + }, + "givenNames": { + "description": "Given names", + "type": "string" + }, + "lastName": { + "description": "Last name", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "doi": { + "description": "DOI, cased as the tier that served this record reports it (NCBI PMC, Europe PMC, or Unpaywall). DOIs are case-insensitive by spec and no case normalization is applied here, so casing can differ between tiers and from other tools — compare case-insensitively.", + "type": "string" + }, + "epmcId": { + "description": "Europe PMC record id — present when `viaSource` is `europepmc`", + "type": "string" + }, + "epmcSource": { + "description": "Europe PMC source code when `viaSource` is `europepmc`. Common values: `MED` (PubMed-derived), `PMC` (PMC counterpart), `PPR` (preprint), `PAT` (patent), `AGR` (Agricola), plus less common codes (`CTX`, `CBA`, `ETH`, `HIR`). Treat as opaque — EPMC may introduce new codes.", + "type": "string" + }, + "journal": { + "additionalProperties": false, + "description": "Journal information", + "properties": { + "issn": { + "description": "ISSN", + "type": "string" + }, + "issue": { + "description": "Issue number", + "type": "string" + }, + "pages": { + "description": "Page range", + "type": "string" + }, + "title": { + "description": "Journal title", + "type": "string" + }, + "volume": { + "description": "Volume number", + "type": "string" + } + }, + "type": "object" + }, + "keywords": { + "description": "Keywords", + "items": { + "type": "string" + }, + "type": "array" + }, + "pmcId": { + "description": "PMC ID — present for NCBI PMC records and Europe PMC entries that have a PMC counterpart. Absent for EPMC-only records like preprints; use `epmcId` in that case.", + "type": "string" + }, + "pmcUrl": { + "description": "PMC URL — derived from `pmcId` when present", + "type": "string" + }, + "pmid": { + "description": "PubMed ID", + "type": "string" + }, + "publicationDate": { + "additionalProperties": false, + "description": "Publication date", + "properties": { + "day": { + "description": "Publication day", + "type": "string" + }, + "month": { + "description": "Publication month", + "type": "string" + }, + "year": { + "description": "Publication year", + "type": "string" + } + }, + "type": "object" + }, + "pubmedUrl": { + "description": "PubMed URL", + "type": "string" + }, + "references": { + "description": "Reference list", + "items": { + "additionalProperties": false, + "description": "Reference entry", + "properties": { + "citation": { + "description": "Citation text", + "type": "string" + }, + "id": { + "description": "Reference ID", + "type": "string" + }, + "label": { + "description": "Reference label", + "type": "string" + } + }, + "required": [ + "citation" + ], + "type": "object" + }, + "type": "array" + }, + "sections": { + "description": "Article body sections", + "items": { + "additionalProperties": false, + "description": "Article body section", + "properties": { + "label": { + "description": "Section label", + "type": "string" + }, + "subsections": { + "description": "Nested subsections", + "items": { + "additionalProperties": false, + "description": "Article subsection", + "properties": { + "label": { + "description": "Subsection label", + "type": "string" + }, + "text": { + "description": "Subsection body text. Sections nested deeper than this level are folded in here in document order, each heading rendered on its own line above its text.", + "type": "string" + }, + "title": { + "description": "Subsection heading", + "type": "string" + } + }, + "required": [ + "text" + ], + "type": "object" + }, + "type": "array" + }, + "text": { + "description": "Section body text", + "type": "string" + }, + "title": { + "description": "Section heading", + "type": "string" + } + }, + "required": [ + "text" + ], + "type": "object" + }, + "type": "array" + }, + "source": { + "const": "pmc", + "description": "Structured JATS — same DTD whether sourced from NCBI PMC or Europe PMC", + "type": "string" + }, + "title": { + "description": "Article title", + "type": "string" + }, + "viaSource": { + "description": "Which layer produced the JATS: `pmc` for NCBI PMC EFetch (db=pmc), `europepmc` for Europe PMC `fullTextXML`. Both paths return the same JATS shape; the discriminator records origin for observability and license attribution.", + "enum": [ + "pmc", + "europepmc" + ], + "type": "string" + } + }, + "required": [ + "source", + "viaSource", + "sections" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "Best-effort full text from an open-access copy", + "properties": { + "content": { + "description": "Full article text — Markdown or plain text per `contentFormat`", + "type": "string" + }, + "contentFormat": { + "description": "How `content` was extracted. html-markdown: Defuddle extracted Markdown from an HTML landing page; light section structure may survive but is not guaranteed. pdf-text: unpdf extracted plain text from a PDF; no section, reference, or heading structure.", + "enum": [ + "html-markdown", + "pdf-text" + ], + "type": "string" + }, + "doi": { + "description": "DOI used to locate the open-access copy", + "type": "string" + }, + "hostType": { + "description": "`publisher` or `repository` — where the OA copy is hosted", + "type": "string" + }, + "license": { + "description": "License identifier from Unpaywall (e.g. cc-by, cc0)", + "type": "string" + }, + "pmcId": { + "description": "PMC ID this article was requested under, in `PMC<digits>` form — present for `pmcids` input, absent for `pmids` and `dois` input. Ties the article back to the requested identifier, which `unavailable[]` keys on for the ids that found nothing.", + "type": "string" + }, + "pmid": { + "description": "PubMed ID when input was `pmids`; absent for `pmcids` and `dois` input", + "type": "string" + }, + "pubmedUrl": { + "description": "PubMed URL — present when `pmid` is set", + "type": "string" + }, + "source": { + "const": "unpaywall", + "description": "Content fetched from an open-access copy indexed by Unpaywall. Best-effort — structural fidelity depends on `contentFormat`.", + "type": "string" + }, + "sourceUrl": { + "description": "URL the content was fetched from", + "type": "string" + }, + "title": { + "description": "Detected article title when present", + "type": "string" + }, + "totalPages": { + "description": "Page count reported by the PDF extractor; absent for HTML", + "type": "number" + }, + "version": { + "description": "OA version: submittedVersion | acceptedVersion | publishedVersion", + "type": "string" + }, + "viaSource": { + "const": "unpaywall", + "description": "Layer that produced this article. Constant `unpaywall` for this branch.", + "type": "string" + }, + "wordCount": { + "description": "Approximate word count reported by the HTML extractor; absent for PDFs", + "type": "number" + } + }, + "required": [ + "source", + "viaSource", + "contentFormat", + "doi", + "sourceUrl", + "content" + ], + "type": "object" + } +] - added
Output schema / properties / deferredAdded value: +{ + "additionalProperties": false, + "description": "Continuation state for articles the whole-response budget withheld. Present only when `maxResponseCharacters` deferred at least one article.", + "properties": { + "deferredCount": { + "description": "Articles the chain resolved but withheld to stay under the ceiling", + "type": "number" + }, + "idType": { + "description": "Which input branch the deferred ids belong to — re-submit them as `pmids`, `pmcids`, or `dois` respectively. Matches the `idType` on `unavailable` entries.", + "enum": [ + "pmid", + "pmcid", + "doi" + ], + "type": "string" + }, + "ids": { + "description": "Identifiers of the deferred articles, in response order, keyed as they were requested (PMC IDs in `PMC<digits>` form). Re-call `pubmed_fetch_fulltext` with these under the `idType` branch and the same other inputs. Never contains an id from `unavailable`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "maxResponseCharacters": { + "description": "The `maxResponseCharacters` ceiling this response was budgeted against", + "type": "number" + }, + "nextDeferredCharacters": { + "description": "Serialized size of the next deferred article — the first entry in `ids`, where the response stopped. Raise `maxResponseCharacters` to at least this to make progress; a smaller article further down `ids` cannot be reached until this one fits.", + "type": "number" + }, + "returnedCharacters": { + "description": "Serialized characters the returned article records account for", + "type": "number" + } + }, + "required": [ + "maxResponseCharacters", + "returnedCharacters", + "deferredCount", + "idType", + "ids", + "nextDeferredCharacters" + ], + "type": "object" +} - changed
Output schema / properties / notice / descriptionPrevious value: -"Optional guidance for a partial or empty body. A `sections`-filter miss names the requested terms and affected article id(s) and suggests retrying without `sections` or using broader headings. A metadata-only record names the id(s) the chain could retrieve as front matter only and points at `pubmed_fetch_articles` for the abstract. A budgeted response names the characters returned versus carried and points at `truncation`. Absent when none of those applies."New value: +"Optional guidance for a partial or empty body. A `sections`-filter miss names the requested terms and affected article id(s) and suggests retrying without `sections` or using broader headings. A metadata-only record names the id(s) the chain could retrieve as front matter only and points at `pubmed_fetch_articles` for the abstract. A budgeted response names the characters returned versus carried and points at `truncation`. A response-wide budget that deferred articles names the ids to re-request. Absent when none of those applies." - changed
Output schema / properties / totalReturned / descriptionPrevious value: -"Number of articles returned"New value: +"Number of articles in this response. Under a `maxResponseCharacters` budget this counts the kept articles only; `deferred.deferredCount` covers the rest." - changed
Output schema / properties / truncated / descriptionPrevious value: -"True when a character budget shortened at least one returned body. Absent when every returned article carries its full post-filter body. The per-article accounting is in `truncation`."New value: +"True when a character budget shortened at least one returned body, or withheld a whole article. Absent when every resolved article is present with its full post-filter body. The per-article body accounting is in `truncation`; the withheld ids are in `deferred`." - changed
Output schema / properties / unavailable / descriptionPrevious value: -"Per-identifier explanations for any requested PMIDs, PMCIDs, or DOIs with no returnable full text. `idType` discriminates which branch the id came from."New value: +"Per-identifier explanations for any requested PMIDs, PMCIDs, or DOIs with no returnable full text. `idType` discriminates which branch the id came from. Distinct from `deferred`: nothing here is retrievable by re-calling, and an id never appears in both." - changed
Output schema / properties / unavailable / items / properties / reason / descriptionPrevious value: -"Why no full text was returned. not-found: upstream returned no record for this ID. no-pmc-fallback-disabled: every tier was skipped (`triedTiers` is all `not-attempted`) — typically because EPMC (`EUROPEPMC_ENABLED`) and Unpaywall (`UNPAYWALL_EMAIL`) are not configured. no-epmc-fulltext: EPMC indexed the record but publishes no fullTextXML. no-body: the record was retrieved but carries front matter and abstract only, with no body sections — use `pubmed_fetch_articles` for the metadata. no-doi: no DOI to query Unpaywall. no-oa: Unpaywall has no OA copy. fetch-failed: download failed. parse-failed: extraction empty. service-error: upstream server failure (threw, timed out, or returned malformed data)."New value: +"Why no full text was returned — the most specific signal any tier that answered reported. not-found: upstream returned no record for this ID. no-pmc-fallback-disabled: every tier was skipped (`triedTiers` is all `not-attempted`) — typically because EPMC (`EUROPEPMC_ENABLED`) and Unpaywall (`UNPAYWALL_EMAIL`) are not configured. no-epmc-fulltext: EPMC indexed the record but publishes no fullTextXML. no-body: the record was retrieved but carries front matter and abstract only, with no body sections — use `pubmed_fetch_articles` for the metadata. no-doi: no DOI to query Unpaywall. no-oa: Unpaywall has no OA copy. fetch-failed: download failed. parse-failed: extraction empty. service-error: upstream server failure (threw, timed out, or returned malformed data). A reason never means the chain ran to completion — read `unqueriedTiers` for that." - added
Output schema / properties / unavailable / items / properties / unqueriedTiersAdded value: +{ + "description": "Tiers the chain skipped because this deployment has not configured them, and that could have served this id — the search was incomplete, and a deployment with these tiers configured may still resolve the id. `triedTiers` carries which environment variable each one is waiting on. Absent when every tier that could have served the id was actually queried; a tier skipped because it was inapplicable to this id (no DOI for Unpaywall) is never listed.", + "items": { + "description": "A fallback tier this deployment has not configured", + "enum": [ + "europepmc", + "unpaywall" + ], + "type": "string" + }, + "type": "array" +}
- Changed
pubmed_find_related4 fields changed- changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). `europepmc_unreachable`: Europe PMC was unreachable after all retry attempts. `europepmc_invalid_response`: Europe PMC returned a body that could not be parsed (invalid JSON or XML). `europepmc_invalid_input`: Europe PMC rejected the request input (empty query, unknown sort field, malformed parameter). `openalex_unreachable`: OpenAlex was unreachable after all retry attempts. `openalex_invalid_response`: OpenAlex returned a body that could not be parsed (invalid JSON). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). `europepmc_unreachable`: Europe PMC was unreachable after all retry attempts. `europepmc_invalid_response`: Europe PMC returned a body that could not be parsed (invalid JSON or XML). `europepmc_invalid_input`: Europe PMC rejected the request input (empty query, unknown sort field, malformed parameter). `openalex_unreachable`: OpenAlex was unreachable after all retry attempts. `openalex_invalid_response`: OpenAlex returned a body that could not be parsed (invalid JSON). `all_providers_failed`: Every provider eligible for the requested relationship failed; none answered. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "queue_full", - "ncbi_unreachable", - "ncbi_deadline_exceeded", - "ncbi_invalid_response", - "ncbi_resource_not_found", - "europepmc_unreachable", - "europepmc_invalid_response", - "europepmc_invalid_input", - "openalex_unreachable", - "openalex_invalid_response" -]New value: +[ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found", + "europepmc_unreachable", + "europepmc_invalid_response", + "europepmc_invalid_input", + "openalex_unreachable", + "openalex_invalid_response", + "all_providers_failed" +] - changed
Output schema / properties / notice / descriptionPrevious value: -"Guidance when results are empty, a fallback provider answered, or offset overshot. Absent on a clean NCBI result page."New value: +"Guidance when results are empty, a fallback provider answered, offset overshot, or Europe PMC rows were excluded for carrying no PubMed PMID. Absent on a clean NCBI result page." - changed
Output schema / properties / totalCount / descriptionPrevious value: -"Total related articles found before windowing"New value: +"Total related articles found before windowing. A Europe PMC total may shrink to the PubMed-addressable count once a request window covers the whole upstream set, since rows without a PubMed PMID cannot be returned."
11 tool updates
v2.10.4- Changed
pubmed_convert_ids6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "records", + "totalConverted", + "totalSubmitted" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). Other values are possible when a failure originates below the handler.", + "examples": [ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "records", - "totalConverted", - "totalSubmitted" -]
- Changed
pubmed_europepmc_fetch6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "records" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `europepmc_unreachable`: Europe PMC was unreachable after all retry attempts. `europepmc_invalid_response`: Europe PMC returned a body that could not be parsed (invalid JSON or XML). `europepmc_invalid_input`: Europe PMC rejected the request input (empty query, unknown sort field, malformed parameter). `europepmc_disabled`: Europe PMC service is disabled via EUROPEPMC_ENABLED=false. Other values are possible when a failure originates below the handler.", + "examples": [ + "europepmc_unreachable", + "europepmc_invalid_response", + "europepmc_invalid_input", + "europepmc_disabled" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "records" -]
- Changed
pubmed_europepmc_search6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "hits", + "cursorMark", + "searchUrl", + "query", + "totalCount", + "appliedSources" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `europepmc_unreachable`: Europe PMC was unreachable after all retry attempts. `europepmc_invalid_response`: Europe PMC returned a body that could not be parsed (invalid JSON or XML). `europepmc_invalid_input`: Europe PMC rejected the request input (empty query, unknown sort field, malformed parameter). `europepmc_disabled`: Europe PMC service is disabled via EUROPEPMC_ENABLED=false. Other values are possible when a failure originates below the handler.", + "examples": [ + "europepmc_unreachable", + "europepmc_invalid_response", + "europepmc_invalid_input", + "europepmc_disabled" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "hits", - "cursorMark", - "searchUrl", - "query", - "totalCount", - "appliedSources" -]
- Changed
pubmed_fetch_articles6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "articles", + "totalReturned" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). `invalid_efetch_response`: NCBI EFetch returned a payload missing the PubmedArticleSet wrapper. Other values are possible when a failure originates below the handler.", + "examples": [ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found", + "invalid_efetch_response" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "articles", - "totalReturned" -]
- Changed
pubmed_fetch_fulltext7 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "articles", + "totalReturned" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). `unpaywall_unreachable`: Unpaywall was unreachable when resolving a DOI or fetching content. `europepmc_unreachable`: Europe PMC was unreachable after all retry attempts. `europepmc_invalid_response`: Europe PMC returned a body that could not be parsed (invalid JSON or XML). `europepmc_invalid_input`: Europe PMC rejected the request input (empty query, unknown sort field, malformed parameter). Other values are possible when a failure originates below the handler.", + "examples": [ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found", + "unpaywall_unreachable", + "europepmc_unreachable", + "europepmc_invalid_response", + "europepmc_invalid_input" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - added
Output schema / properties / truncatedAdded value: +{ + "description": "True when a character budget shortened at least one returned body. Absent when every returned article carries its full post-filter body. The per-article accounting is in `truncation`.", + "type": "boolean" +} - removed
Output schema / requiredRemoved value: -[ - "articles", - "totalReturned" -]
- Changed
pubmed_find_related6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "sourcePmid", + "relationship", + "offset", + "articles", + "totalCount", + "source" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). `europepmc_unreachable`: Europe PMC was unreachable after all retry attempts. `europepmc_invalid_response`: Europe PMC returned a body that could not be parsed (invalid JSON or XML). `europepmc_invalid_input`: Europe PMC rejected the request input (empty query, unknown sort field, malformed parameter). `openalex_unreachable`: OpenAlex was unreachable after all retry attempts. `openalex_invalid_response`: OpenAlex returned a body that could not be parsed (invalid JSON). Other values are possible when a failure originates below the handler.", + "examples": [ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found", + "europepmc_unreachable", + "europepmc_invalid_response", + "europepmc_invalid_input", + "openalex_unreachable", + "openalex_invalid_response" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "sourcePmid", - "relationship", - "offset", - "articles", - "totalCount", - "source" -]
- Changed
pubmed_format_citations6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "citations", + "totalSubmitted", + "totalFormatted" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). Other values are possible when a failure originates below the handler.", + "examples": [ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "citations", - "totalSubmitted", - "totalFormatted" -]
- Changed
pubmed_lookup_citation6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "results", + "totalMatched", + "totalSubmitted", + "totalWarnings" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). Other values are possible when a failure originates below the handler.", + "examples": [ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "results", - "totalMatched", - "totalSubmitted", - "totalWarnings" -]
- Changed
pubmed_lookup_mesh6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "query", + "offset", + "results", + "totalCount" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). Other values are possible when a failure originates below the handler.", + "examples": [ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "query", - "offset", - "results", - "totalCount" -]
- Changed
pubmed_search_articles6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "query", + "offset", + "pmids", + "summaries", + "searchUrl", + "effectiveQuery", + "totalCount", + "appliedFilters" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). Other values are possible when a failure originates below the handler.", + "examples": [ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "query", - "offset", - "pmids", - "summaries", - "searchUrl", - "effectiveQuery", - "totalCount", - "appliedFilters" -]
- Changed
pubmed_spell_check6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "original", + "corrected", + "hasSuggestion" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `queue_full`: Local NCBI request queue is at capacity. `ncbi_unreachable`: NCBI E-utilities is unreachable after all retry attempts. `ncbi_deadline_exceeded`: Total request deadline expired before NCBI returned a response. `ncbi_invalid_response`: NCBI returned a body that could not be parsed (invalid XML/JSON). `ncbi_resource_not_found`: NCBI returned a structured \"not found\" error for the requested ID(s). Other values are possible when a failure originates below the handler.", + "examples": [ + "queue_full", + "ncbi_unreachable", + "ncbi_deadline_exceeded", + "ncbi_invalid_response", + "ncbi_resource_not_found" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "original", - "corrected", - "hasSuggestion" -]
7 tool updates
v2.10.2- Changed
pubmed_convert_ids1 field changed- changed
Output schema / properties / records / items / properties / doi / descriptionPrevious value: -"Digital Object Identifier; absent if no DOI is on record"New value: +"Digital Object Identifier, cased as the PMC ID Converter reports it; absent if no DOI is on record. DOIs are case-insensitive by spec and no case normalization is applied here, so casing can differ from a Europe PMC-sourced `doi` — compare the two case-insensitively."
- Added
pubmed_europepmc_fetch - Changed
pubmed_europepmc_search5 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"Europe PMC search query. Supports field tokens like `AUTH:\"<name>\"`, `JOURNAL:\"<title>\"`, `TITLE:\"<words>\"`, `PUB_YEAR:[2020 TO 2024]`, `DOI:\"...\"`, `EXT_ID:\"<pmid>\" AND SRC:MED`. Free text is matched broadly across abstract/title/keywords."New value: +"Europe PMC search query. Supports field tokens like `AUTH:\"<name>\"`, `JOURNAL:\"<title>\"`, `TITLE:\"<words>\"`, `PUB_YEAR:[2020 TO 2024]`, `DOI:\"...\"`, `EXT_ID:<pmid> AND SRC:MED`, `PMCID:PMC<digits>`. Identifier tokens combined with `AND SRC:` must be unquoted — the quoted form matches nothing. Free text is matched broadly across abstract/title/keywords." - changed
Output schema / properties / hits / items / properties / abstractSnippet / descriptionPrevious value: -"First few hundred characters of the abstract as display-ready plain text — JATS/HTML markup stripped and HTML entities decoded — when `resultType: \"core\"` is requested"New value: +"First 400 characters of the abstract as display-ready plain text — JATS/HTML markup stripped and HTML entities decoded — when `resultType: \"core\"` is requested, with a trailing … appended when the abstract was cut. Check `abstractTruncated` before treating it as the whole abstract." - added
Output schema / properties / hits / items / properties / abstractTruncatedAdded value: +{ + "description": "Whether `abstractSnippet` was cut short of the full abstract. Retrieve the complete text with `pubmed_europepmc_fetch` using this record’s `source` and `epmcId`. Present whenever `abstractSnippet` is; omitted when Europe PMC carries no abstract.", + "type": "boolean" +} - changed
Output schema / properties / hits / items / properties / doi / descriptionPrevious value: -"DOI when present"New value: +"DOI when present, cased as Europe PMC reports it. DOIs are case-insensitive by spec and no case normalization is applied here, so the same DOI can arrive in a different case from `pubmed_fetch_articles` (Europe PMC `10.1056/nejmoa2212948`, NCBI `10.1056/NEJMoa2212948`) — a byte-for-byte comparison across the two reports a false mismatch." - changed
Output schema / properties / hits / items / properties / epmcId / descriptionPrevious value: -"Europe PMC's internal record id; key for `fullTextXML` lookup"New value: +"Europe PMC's internal record id. Pass it with this hit's `source` to `pubmed_europepmc_fetch` for the complete record. Europe PMC's `fullTextXML` is keyed on `pmcId`, not on this id, so records without a PMC counterpart have no full text to fetch."
- Changed
pubmed_fetch_articles1 field changed- changed
Output schema / properties / articles / items / properties / doi / descriptionPrevious value: -"DOI"New value: +"DOI, cased as NCBI reports it (usually the publisher's mixed case). DOIs are case-insensitive by spec and no case normalization is applied here, so the same DOI can arrive in a different case from `pubmed_europepmc_search` and `pubmed_europepmc_fetch` (NCBI `10.1056/NEJMoa2212948`, Europe PMC `10.1056/nejmoa2212948`) — a byte-for-byte comparison across the two reports a false mismatch."
- Changed
pubmed_fetch_fulltext11 fields changed- added
Input schema / properties / maxCharactersAdded value: +{ + "description": "Per-article budget for body text, in characters. Counts `source=pmc` section and subsection text, or the `source=unpaywall` `content` body; titles, abstracts, identifiers, and references are never counted or shortened. Applied after `sections`, `maxSections`, and `includeReferences`, so semantic filtering is unaffected. The response-wide ceiling is this value times the number of articles returned. Omit for the full body.", + "maximum": 1000000, + "minimum": 1, + "type": "integer" +} - added
Input schema / properties / maxCharactersPerSectionAdded value: +{ + "description": "Budget for a single top-level body section, in characters, counting the section text plus its subsections. Combine with `maxCharacters` to cap both one section and the article; the tighter of the two wins. Applies to `source=pmc` results only.", + "maximum": 1000000, + "minimum": 1, + "type": "integer" +} - added
Input schema / properties / overflowModeAdded value: +{ + "default": "truncate", + "description": "How to spend `maxCharacters` across an article that exceeds it. truncate: fill sections in document order, so early sections stay whole and sections past the budget are dropped (counted in `truncation.omittedSections`). outline: split the budget evenly so every section keeps its heading, and an excerpt as far as the budget reaches — use it to survey what an article contains before requesting specific `sections`. Ignored when no budget is set, and identical for `source=unpaywall` bodies, which have no headings to preserve.", + "enum": [ + "truncate", + "outline" + ], + "type": "string" +} - changed
Input schema / properties / pmcids / descriptionPrevious value: -"PMC IDs to fetch (e.g. [\"PMC9575052\"]). Provide exactly one of `pmcids`, `pmids`, or `dois`."New value: +"PMC IDs to fetch (e.g. [\"PMC9575052\"]). Provide exactly one of `pmcids`, `pmids`, or `dois`. PMC IDs with no retrievable full text fall through to Europe PMC, then to Unpaywall on the DOI the chain resolves for them." - changed
Output schema / properties / articles / items / oneOfPrevious value: -[ - { - "additionalProperties": false, - "description": "Structured JATS full-text article. `viaSource` records whether the JATS came from NCBI PMC or Europe PMC.", - "properties": { - "abstract": { - "description": "Abstract", - "type": "string" - }, - "affiliations": { - "description": "Author affiliations", - "items": { - "type": "string" - }, - "type": "array" - }, - "articleType": { - "description": "Article type", - "type": "string" - }, - "authors": { - "description": "Authors", - "items": { - "additionalProperties": false, - "description": "Author entry", - "properties": { - "collectiveName": { - "description": "Group name", - "type": "string" - }, - "givenNames": { - "description": "Given names", - "type": "string" - }, - "lastName": { - "description": "Last name", - "type": "string" - } - }, - "type": "object" - }, - "type": "array" - }, - "doi": { - "description": "DOI", - "type": "string" - }, - "epmcId": { - "description": "Europe PMC record id — present when `viaSource` is `europepmc`", - "type": "string" - }, - "epmcSource": { - "description": "Europe PMC source code when `viaSource` is `europepmc`. Common values: `MED` (PubMed-derived), `PMC` (PMC counterpart), `PPR` (preprint), `PAT` (patent), `AGR` (Agricola), plus less common codes (`CTX`, `CBA`, `ETH`, `HIR`). Treat as opaque — EPMC may introduce new codes.", - "type": "string" - }, - "journal": { - "additionalProperties": false, - "description": "Journal information", - "properties": { - "issn": { - "description": "ISSN", - "type": "string" - }, - "issue": { - "description": "Issue number", - "type": "string" - }, - "pages": { - "description": "Page range", - "type": "string" - }, - "title": { - "description": "Journal title", - "type": "string" - }, - "volume": { - "description": "Volume number", - "type": "string" - } - }, - "type": "object" - }, - "keywords": { - "description": "Keywords", - "items": { - "type": "string" - }, - "type": "array" - }, - "pmcId": { - "description": "PMC ID — present for NCBI PMC records and Europe PMC entries that have a PMC counterpart. Absent for EPMC-only records like preprints; use `epmcId` in that case.", - "type": "string" - }, - "pmcUrl": { - "description": "PMC URL — derived from `pmcId` when present", - "type": "string" - }, - "pmid": { - "description": "PubMed ID", - "type": "string" - }, - "publicationDate": { - "additionalProperties": false, - "description": "Publication date", - "properties": { - "day": { - "description": "Publication day", - "type": "string" - }, - "month": { - "description": "Publication month", - "type": "string" - }, - "year": { - "description": "Publication year", - "type": "string" - } - }, - "type": "object" - }, - "pubmedUrl": { - "description": "PubMed URL", - "type": "string" - }, - "references": { - "description": "Reference list", - "items": { - "additionalProperties": false, - "description": "Reference entry", - "properties": { - "citation": { - "description": "Citation text", - "type": "string" - }, - "id": { - "description": "Reference ID", - "type": "string" - }, - "label": { - "description": "Reference label", - "type": "string" - } - }, - "required": [ - "citation" - ], - "type": "object" - }, - "type": "array" - }, - "sections": { - "description": "Article body sections", - "items": { - "additionalProperties": false, - "description": "Article body section", - "properties": { - "label": { - "description": "Section label", - "type": "string" - }, - "subsections": { - "description": "Nested subsections", - "items": { - "additionalProperties": false, - "description": "Article subsection", - "properties": { - "label": { - "description": "Subsection label", - "type": "string" - }, - "text": { - "description": "Subsection body text", - "type": "string" - }, - "title": { - "description": "Subsection heading", - "type": "string" - } - }, - "required": [ - "text" - ], - "type": "object" - }, - "type": "array" - }, - "text": { - "description": "Section body text", - "type": "string" - }, - "title": { - "description": "Section heading", - "type": "string" - } - }, - "required": [ - "text" - ], - "type": "object" - }, - "type": "array" - }, - "source": { - "const": "pmc", - "description": "Structured JATS — same DTD whether sourced from NCBI PMC or Europe PMC", - "type": "string" - }, - "title": { - "description": "Article title", - "type": "string" - }, - "viaSource": { - "description": "Which layer produced the JATS: `pmc` for NCBI PMC EFetch (db=pmc), `europepmc` for Europe PMC `fullTextXML`. Both paths return the same JATS shape; the discriminator records origin for observability and license attribution.", - "enum": [ - "pmc", - "europepmc" - ], - "type": "string" - } - }, - "required": [ - "source", - "viaSource", - "sections" - ], - "type": "object" - }, - { - "additionalProperties": false, - "description": "Best-effort full text from an open-access copy", - "properties": { - "content": { - "description": "Full article text — Markdown or plain text per `contentFormat`", - "type": "string" - }, - "contentFormat": { - "description": "How `content` was extracted. html-markdown: Defuddle extracted Markdown from an HTML landing page; light section structure may survive but is not guaranteed. pdf-text: unpdf extracted plain text from a PDF; no section, reference, or heading structure.", - "enum": [ - "html-markdown", - "pdf-text" - ], - "type": "string" - }, - "doi": { - "description": "DOI used to locate the open-access copy", - "type": "string" - }, - "hostType": { - "description": "`publisher` or `repository` — where the OA copy is hosted", - "type": "string" - }, - "license": { - "description": "License identifier from Unpaywall (e.g. cc-by, cc0)", - "type": "string" - }, - "pmid": { - "description": "PubMed ID when input was `pmids`; absent for `dois` input", - "type": "string" - }, - "pubmedUrl": { - "description": "PubMed URL — present when `pmid` is set", - "type": "string" - }, - "source": { - "const": "unpaywall", - "description": "Content fetched from an open-access copy indexed by Unpaywall. Best-effort — structural fidelity depends on `contentFormat`.", - "type": "string" - }, - "sourceUrl": { - "description": "URL the content was fetched from", - "type": "string" - }, - "title": { - "description": "Detected article title when present", - "type": "string" - }, - "totalPages": { - "description": "Page count reported by the PDF extractor; absent for HTML", - "type": "number" - }, - "version": { - "description": "OA version: submittedVersion | acceptedVersion | publishedVersion", - "type": "string" - }, - "viaSource": { - "const": "unpaywall", - "description": "Layer that produced this article. Constant `unpaywall` for this branch.", - "type": "string" - }, - "wordCount": { - "description": "Approximate word count reported by the HTML extractor; absent for PDFs", - "type": "number" - } - }, - "required": [ - "source", - "viaSource", - "contentFormat", - "doi", - "sourceUrl", - "content" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "description": "Structured JATS full-text article. `viaSource` records whether the JATS came from NCBI PMC or Europe PMC.", + "properties": { + "abstract": { + "description": "Abstract", + "type": "string" + }, + "affiliations": { + "description": "Author affiliations", + "items": { + "type": "string" + }, + "type": "array" + }, + "articleType": { + "description": "Article type", + "type": "string" + }, + "authors": { + "description": "Authors", + "items": { + "additionalProperties": false, + "description": "Author entry", + "properties": { + "collectiveName": { + "description": "Group name", + "type": "string" + }, + "givenNames": { + "description": "Given names", + "type": "string" + }, + "lastName": { + "description": "Last name", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "doi": { + "description": "DOI, cased as the tier that served this record reports it (NCBI PMC, Europe PMC, or Unpaywall). DOIs are case-insensitive by spec and no case normalization is applied here, so casing can differ between tiers and from other tools — compare case-insensitively.", + "type": "string" + }, + "epmcId": { + "description": "Europe PMC record id — present when `viaSource` is `europepmc`", + "type": "string" + }, + "epmcSource": { + "description": "Europe PMC source code when `viaSource` is `europepmc`. Common values: `MED` (PubMed-derived), `PMC` (PMC counterpart), `PPR` (preprint), `PAT` (patent), `AGR` (Agricola), plus less common codes (`CTX`, `CBA`, `ETH`, `HIR`). Treat as opaque — EPMC may introduce new codes.", + "type": "string" + }, + "journal": { + "additionalProperties": false, + "description": "Journal information", + "properties": { + "issn": { + "description": "ISSN", + "type": "string" + }, + "issue": { + "description": "Issue number", + "type": "string" + }, + "pages": { + "description": "Page range", + "type": "string" + }, + "title": { + "description": "Journal title", + "type": "string" + }, + "volume": { + "description": "Volume number", + "type": "string" + } + }, + "type": "object" + }, + "keywords": { + "description": "Keywords", + "items": { + "type": "string" + }, + "type": "array" + }, + "pmcId": { + "description": "PMC ID — present for NCBI PMC records and Europe PMC entries that have a PMC counterpart. Absent for EPMC-only records like preprints; use `epmcId` in that case.", + "type": "string" + }, + "pmcUrl": { + "description": "PMC URL — derived from `pmcId` when present", + "type": "string" + }, + "pmid": { + "description": "PubMed ID", + "type": "string" + }, + "publicationDate": { + "additionalProperties": false, + "description": "Publication date", + "properties": { + "day": { + "description": "Publication day", + "type": "string" + }, + "month": { + "description": "Publication month", + "type": "string" + }, + "year": { + "description": "Publication year", + "type": "string" + } + }, + "type": "object" + }, + "pubmedUrl": { + "description": "PubMed URL", + "type": "string" + }, + "references": { + "description": "Reference list", + "items": { + "additionalProperties": false, + "description": "Reference entry", + "properties": { + "citation": { + "description": "Citation text", + "type": "string" + }, + "id": { + "description": "Reference ID", + "type": "string" + }, + "label": { + "description": "Reference label", + "type": "string" + } + }, + "required": [ + "citation" + ], + "type": "object" + }, + "type": "array" + }, + "sections": { + "description": "Article body sections", + "items": { + "additionalProperties": false, + "description": "Article body section", + "properties": { + "label": { + "description": "Section label", + "type": "string" + }, + "subsections": { + "description": "Nested subsections", + "items": { + "additionalProperties": false, + "description": "Article subsection", + "properties": { + "label": { + "description": "Subsection label", + "type": "string" + }, + "text": { + "description": "Subsection body text", + "type": "string" + }, + "title": { + "description": "Subsection heading", + "type": "string" + } + }, + "required": [ + "text" + ], + "type": "object" + }, + "type": "array" + }, + "text": { + "description": "Section body text", + "type": "string" + }, + "title": { + "description": "Section heading", + "type": "string" + } + }, + "required": [ + "text" + ], + "type": "object" + }, + "type": "array" + }, + "source": { + "const": "pmc", + "description": "Structured JATS — same DTD whether sourced from NCBI PMC or Europe PMC", + "type": "string" + }, + "title": { + "description": "Article title", + "type": "string" + }, + "viaSource": { + "description": "Which layer produced the JATS: `pmc` for NCBI PMC EFetch (db=pmc), `europepmc` for Europe PMC `fullTextXML`. Both paths return the same JATS shape; the discriminator records origin for observability and license attribution.", + "enum": [ + "pmc", + "europepmc" + ], + "type": "string" + } + }, + "required": [ + "source", + "viaSource", + "sections" + ], + "type": "object" + }, + { + "additionalProperties": false, + "description": "Best-effort full text from an open-access copy", + "properties": { + "content": { + "description": "Full article text — Markdown or plain text per `contentFormat`", + "type": "string" + }, + "contentFormat": { + "description": "How `content` was extracted. html-markdown: Defuddle extracted Markdown from an HTML landing page; light section structure may survive but is not guaranteed. pdf-text: unpdf extracted plain text from a PDF; no section, reference, or heading structure.", + "enum": [ + "html-markdown", + "pdf-text" + ], + "type": "string" + }, + "doi": { + "description": "DOI used to locate the open-access copy", + "type": "string" + }, + "hostType": { + "description": "`publisher` or `repository` — where the OA copy is hosted", + "type": "string" + }, + "license": { + "description": "License identifier from Unpaywall (e.g. cc-by, cc0)", + "type": "string" + }, + "pmcId": { + "description": "PMC ID this article was requested under, in `PMC<digits>` form — present for `pmcids` input, absent for `pmids` and `dois` input. Ties the article back to the requested identifier, which `unavailable[]` keys on for the ids that found nothing.", + "type": "string" + }, + "pmid": { + "description": "PubMed ID when input was `pmids`; absent for `pmcids` and `dois` input", + "type": "string" + }, + "pubmedUrl": { + "description": "PubMed URL — present when `pmid` is set", + "type": "string" + }, + "source": { + "const": "unpaywall", + "description": "Content fetched from an open-access copy indexed by Unpaywall. Best-effort — structural fidelity depends on `contentFormat`.", + "type": "string" + }, + "sourceUrl": { + "description": "URL the content was fetched from", + "type": "string" + }, + "title": { + "description": "Detected article title when present", + "type": "string" + }, + "totalPages": { + "description": "Page count reported by the PDF extractor; absent for HTML", + "type": "number" + }, + "version": { + "description": "OA version: submittedVersion | acceptedVersion | publishedVersion", + "type": "string" + }, + "viaSource": { + "const": "unpaywall", + "description": "Layer that produced this article. Constant `unpaywall` for this branch.", + "type": "string" + }, + "wordCount": { + "description": "Approximate word count reported by the HTML extractor; absent for PDFs", + "type": "number" + } + }, + "required": [ + "source", + "viaSource", + "contentFormat", + "doi", + "sourceUrl", + "content" + ], + "type": "object" + } +] - changed
Output schema / properties / notice / descriptionPrevious value: -"Optional guidance when a `sections` filter removed every body section — names the requested section terms and the affected article id(s), and suggests retrying without `sections` or using broader headings. Absent when no section filter was applied or sections matched."New value: +"Optional guidance for a partial or empty body. A `sections`-filter miss names the requested terms and affected article id(s) and suggests retrying without `sections` or using broader headings. A metadata-only record names the id(s) the chain could retrieve as front matter only and points at `pubmed_fetch_articles` for the abstract. A budgeted response names the characters returned versus carried and points at `truncation`. Absent when none of those applies." - added
Output schema / properties / truncationAdded value: +{ + "additionalProperties": false, + "description": "Character accounting for full text the budget shortened. Present only when a budget actually removed characters — its absence means every returned article carries its full post-filter body.", + "properties": { + "articles": { + "description": "Per-article accounting, covering only the articles the budget shortened", + "items": { + "additionalProperties": false, + "description": "Character accounting for one article the budget shortened", + "properties": { + "id": { + "description": "Identifier for the article — PMCID, PMID, DOI, or Europe PMC id, whichever the article carries first", + "type": "string" + }, + "originalCharacters": { + "description": "Body characters this article carried before the budget pass", + "type": "number" + }, + "returnedCharacters": { + "description": "Body characters this article carries in the response", + "type": "number" + }, + "sections": { + "description": "Per-section accounting for `source: pmc` articles, in document order, including sections dropped for budget. Absent for `source: unpaywall`, whose body has no section structure.", + "items": { + "additionalProperties": false, + "description": "Character accounting for one body section of a budgeted article", + "properties": { + "originalCharacters": { + "description": "Body characters this section carried before the budget pass", + "type": "number" + }, + "returnedCharacters": { + "description": "Body characters this section carries in the response. Zero means the section was dropped in `truncate` mode, or kept as a heading-only entry in `outline` mode.", + "type": "number" + }, + "title": { + "description": "Section heading, when the section carries one", + "type": "string" + }, + "truncated": { + "description": "True when the section returned fewer characters than it originally carried", + "type": "boolean" + } + }, + "required": [ + "originalCharacters", + "returnedCharacters", + "truncated" + ], + "type": "object" + }, + "type": "array" + }, + "source": { + "description": "Which output shape was budgeted: `pmc` budgets body sections and subsections, `unpaywall` budgets the single `content` body", + "enum": [ + "pmc", + "unpaywall" + ], + "type": "string" + } + }, + "required": [ + "id", + "source", + "originalCharacters", + "returnedCharacters" + ], + "type": "object" + }, + "type": "array" + }, + "maxCharacters": { + "description": "The `maxCharacters` budget applied, when set", + "type": "number" + }, + "maxCharactersPerSection": { + "description": "The `maxCharactersPerSection` budget applied, when set", + "type": "number" + }, + "mode": { + "description": "The `overflowMode` that produced these results", + "enum": [ + "truncate", + "outline" + ], + "type": "string" + }, + "omittedSections": { + "description": "Body sections dropped entirely because an article budget was exhausted before reaching them. Always 0 in `outline` mode, which keeps every heading.", + "type": "number" + }, + "originalCharacters": { + "description": "Body characters the shortened articles carried before the budget pass", + "type": "number" + }, + "returnedCharacters": { + "description": "Body characters the shortened articles carry in this response", + "type": "number" + } + }, + "required": [ + "mode", + "originalCharacters", + "returnedCharacters", + "omittedSections", + "articles" + ], + "type": "object" +} - changed
Output schema / properties / unavailable / items / properties / reason / descriptionPrevious value: -"Why no full text was returned. not-found: upstream returned no record for this ID. no-pmc-fallback-disabled: every tier was skipped (`triedTiers` is all `not-attempted`) — typically because EPMC (`EUROPEPMC_ENABLED`) and Unpaywall (`UNPAYWALL_EMAIL`) are not configured. no-epmc-fulltext: EPMC indexed the record but publishes no fullTextXML. no-doi: no DOI to query Unpaywall. no-oa: Unpaywall has no OA copy. fetch-failed: download failed. parse-failed: extraction empty. service-error: upstream server failure (threw, timed out, or returned malformed data)."New value: +"Why no full text was returned. not-found: upstream returned no record for this ID. no-pmc-fallback-disabled: every tier was skipped (`triedTiers` is all `not-attempted`) — typically because EPMC (`EUROPEPMC_ENABLED`) and Unpaywall (`UNPAYWALL_EMAIL`) are not configured. no-epmc-fulltext: EPMC indexed the record but publishes no fullTextXML. no-body: the record was retrieved but carries front matter and abstract only, with no body sections — use `pubmed_fetch_articles` for the metadata. no-doi: no DOI to query Unpaywall. no-oa: Unpaywall has no OA copy. fetch-failed: download failed. parse-failed: extraction empty. service-error: upstream server failure (threw, timed out, or returned malformed data)." - changed
Output schema / properties / unavailable / items / properties / reason / enumPrevious value: -[ - "not-found", - "no-pmc-fallback-disabled", - "no-epmc-fulltext", - "no-doi", - "no-oa", - "fetch-failed", - "parse-failed", - "service-error" -]New value: +[ + "not-found", + "no-pmc-fallback-disabled", + "no-epmc-fulltext", + "no-body", + "no-doi", + "no-oa", + "fetch-failed", + "parse-failed", + "service-error" +] - changed
Output schema / properties / unavailable / items / properties / triedTiers / items / properties / outcome / descriptionPrevious value: -"Per-tier outcome. not-attempted: tier was skipped. miss: tier returned no record. no-fulltext: EPMC indexed the record but publishes no fullTextXML. no-doi: no DOI to query Unpaywall. no-oa: Unpaywall reports no open-access copy. fetch-failed: OA copy download failed. parse-failed: extraction produced empty content. service-error: tier service threw."New value: +"Per-tier outcome. not-attempted: tier was skipped. miss: tier returned no record. no-fulltext: EPMC indexed the record but publishes no fullTextXML. no-body: the tier returned a record with front matter and abstract but no body sections, so the chain continued. no-doi: no DOI to query Unpaywall. no-oa: Unpaywall reports no open-access copy. fetch-failed: OA copy download failed. parse-failed: extraction produced empty content. service-error: tier service threw." - changed
Output schema / properties / unavailable / items / properties / triedTiers / items / properties / outcome / enumPrevious value: -[ - "not-attempted", - "miss", - "no-fulltext", - "no-doi", - "no-oa", - "fetch-failed", - "parse-failed", - "service-error" -]New value: +[ + "not-attempted", + "miss", + "no-fulltext", + "no-body", + "no-doi", + "no-oa", + "fetch-failed", + "parse-failed", + "service-error" +]
- Changed
pubmed_lookup_mesh6 fields changed- added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "Result offset for pagination (0-based). Pass the `nextOffset` from the previous response to get the following page; the exact-descriptor match is pinned to the first page only.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" +} - added
Output schema / properties / nextOffsetAdded value: +{ + "description": "Offset to request for the next page. Omitted when this is the last page, so its absence is the end-of-results signal.", + "type": "number" +} - changed
Output schema / properties / notice / descriptionPrevious value: -"Optional guidance when no descriptors matched — suggests spell-check or free-text search. Absent on successful results."New value: +"Optional guidance when no descriptors matched or the offset overshot the result set — suggests spell-check, free-text search, or resetting the offset. Absent on successful result pages." - added
Output schema / properties / offsetAdded value: +{ + "description": "Result offset this page was read from", + "type": "number" +} - changed
Output schema / properties / totalCount / descriptionPrevious value: -"Total matching MeSH descriptors"New value: +"Total MeSH descriptors matching the query upstream, before the maxResults cap" - changed
Output schema / requiredPrevious value: -[ - "query", - "results", - "totalCount" -]New value: +[ + "query", + "offset", + "results", + "totalCount" +]
- Changed
pubmed_search_articles5 fields changed- changed
Input schema / properties / offset / descriptionPrevious value: -"Result offset for pagination (0-based)"New value: +"Result offset for pagination (0-based). PubMed serves at most the first 9999 records of a result set, so this caps at 9998; narrow the query or add filters to reach anything beyond it." - changed
Input schema / properties / offset / maximumPrevious value: -9007199254740991New value: +9998 - changed
Input schema / properties / summaryCount / descriptionPrevious value: -"Fetch brief summaries for top N results (0 = PMIDs only)"New value: +"Fetch brief summaries for top N results (0 = PMIDs only). Above the 50 cap, pass the remaining PMIDs to pubmed_fetch_articles." - changed
Output schema / properties / notice / descriptionPrevious value: -"Optional guidance when results are empty or paging overshot — e.g. how to broaden filters or reset offset. Absent on successful result pages."New value: +"Optional guidance when the result set does not reflect what was asked for — a field tag PubMed ignored, a phrase it matched nothing for, a dateRange dropped for having one bound, no matches at all, or paging past the end. Absent when nothing applies." - changed
Output schema / properties / summaries / items / properties / doi / descriptionPrevious value: -"DOI"New value: +"DOI, cased as NCBI reports it. DOIs are case-insensitive by spec and no case normalization is applied here, so casing can differ from a Europe PMC-sourced `doi` — compare the two case-insensitively."
1 tool update
v2.9.8- Changed
pubmed_fetch_fulltext1 field changed- added
Output schema / properties / noticeAdded value: +{ + "description": "Optional guidance when a `sections` filter removed every body section — names the requested section terms and the affected article id(s), and suggests retrying without `sections` or using broader headings. Absent when no section filter was applied or sections matched.", + "type": "string" +}
3 tool updates
v2.9.6- Changed
pubmed_convert_ids1 field changed- changed
Input schema / properties / ids / descriptionPrevious value: -"Article identifiers to convert. All IDs must be the same type. DOIs: \"10.1093/nar/gks1195\", PMIDs: \"23193287\", PMCIDs: \"PMC3531190\"."New value: +"Article identifiers to convert. All IDs must be the same type. DOIs: \"10.1093/nar/gks1195\", PMIDs: \"23193287\", PMCIDs: \"PMC3531190\" (the \"PMC\" prefix is optional — bare digits like \"3531190\" are also accepted)."
- Changed
pubmed_europepmc_search1 field changed- changed
Output schema / properties / hits / items / properties / abstractSnippet / descriptionPrevious value: -"First few hundred characters of the abstract when `resultType: \"core\"` is requested"New value: +"First few hundred characters of the abstract as display-ready plain text — JATS/HTML markup stripped and HTML entities decoded — when `resultType: \"core\"` is requested"
- Changed
pubmed_lookup_mesh4 fields changed- added
Output schema / properties / results / items / properties / entrezUidAdded value: +{ + "description": "NCBI Entrez UID for this record — the join key for E-utilities (eSummary/eFetch db=mesh).", + "type": "string" +} - changed
Output schema / properties / results / items / properties / meshId / descriptionPrevious value: -"MeSH descriptor unique identifier"New value: +"Canonical MeSH DescriptorUI (e.g. \"D003924\") — resolves at the MeSH Browser and NLM linked data. Falls back to the raw Entrez UID when a record is not decodable." - changed
Output schema / properties / results / items / properties / treeNumbers / descriptionPrevious value: -"MeSH tree numbers"New value: +"Navigable MeSH tree numbers (e.g. \"D02.078.370.141.450\"). Omitted for supplementary concept records (SCRs), which map to a heading rather than occupying a tree position." - changed
Output schema / properties / results / items / requiredPrevious value: -[ - "meshId", - "name" -]New value: +[ + "meshId", + "entrezUid", + "name" +]
4 tool updates
v2.9.4- Changed
pubmed_europepmc_search3 fields changed- removed
Output schema / properties / hitCountRemoved value: -{ - "description": "Total matching records across all pages", - "type": "number" -} - added
Output schema / properties / totalCountAdded value: +{ + "description": "Total matching records across all pages", + "type": "number" +} - changed
Output schema / requiredPrevious value: -[ - "hits", - "cursorMark", - "searchUrl", - "query", - "hitCount", - "appliedSources" -]New value: +[ + "hits", + "cursorMark", + "searchUrl", + "query", + "totalCount", + "appliedSources" +]
- Changed
pubmed_find_related3 fields changed- added
Output schema / properties / totalCountAdded value: +{ + "description": "Total related articles found before windowing", + "type": "number" +} - removed
Output schema / properties / totalFoundRemoved value: -{ - "description": "Total related articles found before windowing", - "type": "number" -} - changed
Output schema / requiredPrevious value: -[ - "sourcePmid", - "relationship", - "offset", - "articles", - "totalFound", - "source" -]New value: +[ + "sourcePmid", + "relationship", + "offset", + "articles", + "totalCount", + "source" +]
- Changed
pubmed_lookup_mesh2 fields changed- added
Output schema / properties / totalCountAdded value: +{ + "description": "Total matching MeSH descriptors", + "type": "number" +} - changed
Output schema / requiredPrevious value: -[ - "query", - "results" -]New value: +[ + "query", + "results", + "totalCount" +]
- Changed
pubmed_search_articles3 fields changed- added
Output schema / properties / totalCountAdded value: +{ + "description": "Total matching articles", + "type": "number" +} - removed
Output schema / properties / totalFoundRemoved value: -{ - "description": "Total matching articles", - "type": "number" -} - changed
Output schema / requiredPrevious value: -[ - "query", - "offset", - "pmids", - "summaries", - "searchUrl", - "effectiveQuery", - "totalFound", - "appliedFilters" -]New value: +[ + "query", + "offset", + "pmids", + "summaries", + "searchUrl", + "effectiveQuery", + "totalCount", + "appliedFilters" +]
6 tool updates
v2.9.1- Changed
pubmed_europepmc_search1 field changed- changed
Input schema / properties / sort / descriptionPrevious value: -"Optional EPMC sort: `<field> asc|desc`. Documented sortable fields: `P_PDATE_D` (publication date), `CITED` (citation count), `AUTH_FIRST` (first author surname), `PUB_YEAR` (publication year). Examples: `P_PDATE_D desc` (newest first), `CITED desc` (most cited). Omit for relevance ranking. Fields outside the documented set are rejected by EPMC."New value: +"Optional EPMC sort: `<field> asc|desc`. Documented sortable fields: `P_PDATE_D` (publication date), `CITED` (citation count), `AUTH_FIRST` (first author surname), `PUB_YEAR` (publication year). Examples: `P_PDATE_D desc` (newest first), `CITED desc` (most cited). Omit for relevance ranking. Fields outside the documented set are rejected by EPMC. Note: `P_PDATE_D` is ignored for preprint-only (`sources: [\"PPR\"]`) result sets — preprints have no populated publication date, so use `PUB_YEAR` to order preprints by date."
- Changed
pubmed_fetch_articles1 field changed- added
Output schema / properties / noticeAdded value: +{ + "description": "Optional guidance when no articles were returned — points to discovery tools. Absent on successful fetches.", + "type": "string" +}
- Changed
pubmed_fetch_fulltext1 field changed- changed
Input schema / properties / dois / descriptionPrevious value: -"DOIs to resolve (e.g. [\"10.21203/rs.3.rs-9010375/v1\"]). Provide exactly one of `pmcids`, `pmids`, or `dois`. Covers preprints and EPMC-only OA records that lack PMID/PMCID. Chain: Europe PMC search-by-DOI → fullTextXML → Unpaywall."New value: +"DOIs to resolve (e.g. [\"10.21203/rs.3.rs-9010375/v1\"]). Provide exactly one of `pmcids`, `pmids`, or `dois`. Resolved to a PMCID via the PMC ID Converter and returned as structured JATS when the article is in PMC; DOIs with no PMC counterpart (preprints, EPMC-only OA) fall through to Europe PMC, then Unpaywall, when those layers are enabled."
- Changed
pubmed_find_related6 fields changed- added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "Result offset for pagination (0-based); page through results by incrementing by maxResults", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" +} - changed
Output schema / properties / notice / descriptionPrevious value: -"Optional guidance when results are empty — e.g. invalid source PMID, or references requested for a non-PMC source. Absent on successful result pages."New value: +"Guidance when results are empty, a fallback provider answered, or offset overshot. Absent on a clean NCBI result page." - added
Output schema / properties / offsetAdded value: +{ + "description": "Result offset used", + "type": "number" +} - added
Output schema / properties / sourceAdded value: +{ + "description": "Provider that answered this request", + "enum": [ + "ncbi", + "europepmc", + "openalex" + ], + "type": "string" +} - changed
Output schema / properties / totalFound / descriptionPrevious value: -"Total related articles found before truncation"New value: +"Total related articles found before windowing" - changed
Output schema / requiredPrevious value: -[ - "sourcePmid", - "relationship", - "articles", - "totalFound" -]New value: +[ + "sourcePmid", + "relationship", + "offset", + "articles", + "totalFound", + "source" +]
- Changed
pubmed_format_citations3 fields changed- changed
Input schema / properties / format / anyOfPrevious value: -[ - { - "description": "Single citation style. One of: apa, mla, bibtex, ris.", - "enum": [ - "apa", - "mla", - "bibtex", - "ris" - ], - "type": "string" - }, - { - "description": "Multiple citation styles to generate. Each entry: apa, mla, bibtex, or ris.", - "items": { - "enum": [ - "apa", - "mla", - "bibtex", - "ris" - ], - "type": "string" - }, - "minItems": 1, - "type": "array" - } -]New value: +[ + { + "description": "Single citation style. One of: apa, mla, bibtex, ris, vancouver.", + "enum": [ + "apa", + "mla", + "bibtex", + "ris", + "vancouver" + ], + "type": "string" + }, + { + "description": "Multiple citation styles to generate. Each entry: apa, mla, bibtex, ris, or vancouver.", + "items": { + "enum": [ + "apa", + "mla", + "bibtex", + "ris", + "vancouver" + ], + "type": "string" + }, + "minItems": 1, + "type": "array" + } +] - changed
Input schema / properties / format / descriptionPrevious value: -"Citation format(s) to generate — single style as a string or multiple as an array. Allowed values: apa, mla, bibtex, ris."New value: +"Citation format(s) to generate — single style as a string or multiple as an array. Allowed values: apa, mla, bibtex, ris, vancouver." - added
Output schema / properties / noticeAdded value: +{ + "description": "Optional guidance when no citations were produced — points to discovery tools. Absent when at least one citation was produced.", + "type": "string" +}
- Changed
pubmed_lookup_citation1 field changed- changed
Input schema / properties / citations / items / descriptionPrevious value: -"Citation to match against PubMed. Must include at least one bibliographic field (journal, year, volume, firstPage, or authorName)."New value: +"Citation to match against PubMed. Must include at least journal or year — ECitMatch primary-keys on journal+volume+page, so author-only or volume-only inputs guarantee no match."
2 tool updates
v2.7.8- Changed
pubmed_europepmc_search1 field changed- changed
Output schema / requiredPrevious value: -[ - "query", - "hits", - "hitCount", - "cursorMark", - "appliedSources", - "searchUrl" -]New value: +[ + "hits", + "cursorMark", + "searchUrl", + "query", + "hitCount", + "appliedSources" +]
- Changed
pubmed_search_articles1 field changed- changed
Output schema / requiredPrevious value: -[ - "query", - "effectiveQuery", - "appliedFilters", - "totalFound", - "offset", - "pmids", - "summaries", - "searchUrl" -]New value: +[ + "query", + "offset", + "pmids", + "summaries", + "searchUrl", + "effectiveQuery", + "totalFound", + "appliedFilters" +]
10 tool updates
v2.7.6- Added
pubmed_convert_ids - Added
pubmed_europepmc_search - Added
pubmed_fetch_articles - Added
pubmed_fetch_fulltext - Added
pubmed_find_related - Added
pubmed_format_citations - Added
pubmed_lookup_citation - Added
pubmed_lookup_mesh - Added
pubmed_search_articles - Added
pubmed_spell_check
9 tool updates
v2.7.4- Removed
pubmed_convert_ids - Removed
pubmed_fetch_articles - Removed
pubmed_fetch_fulltext - Removed
pubmed_find_related - Removed
pubmed_format_citations - Removed
pubmed_lookup_citation - Removed
pubmed_lookup_mesh - Removed
pubmed_search_articles - Removed
pubmed_spell_check
13 tool updates
v2.3.2- Removed
pubmed_article_connections - Added
pubmed_convert_ids - Added
pubmed_fetch_articles - Removed
pubmed_fetch_contents - Added
pubmed_fetch_fulltext - Added
pubmed_find_related - Added
pubmed_format_citations - Removed
pubmed_generate_chart - Added
pubmed_lookup_citation - Added
pubmed_lookup_mesh - Removed
pubmed_research_agent - Changed
pubmed_search_articles30 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / authorAdded value: +{ + "description": "Filter by author name (e.g. \"Smith J\")", + "type": "string" +} - removed
Input schema / properties / dateRange / additionalPropertiesRemoved value: -false - changed
Input schema / properties / dateRange / descriptionPrevious value: -"Defines an optional date range for the search."New value: +"Filter by date range" - changed
Input schema / properties / dateRange / properties / dateType / descriptionPrevious value: -"The type of date to filter by: 'pdat' (Publication Date), 'mdat' (Modification Date), 'edat' (Entrez Date). Default is 'pdat'."New value: +"Date type: pdat (publication), mdat (modification), edat (entrez)" - changed
Input schema / properties / dateRange / properties / maxDate / descriptionPrevious value: -"The end date for the search range (YYYY, YYYY/MM, or YYYY/MM/DD)."New value: +"End date (YYYY/MM/DD, YYYY/MM, or YYYY)" - removed
Input schema / properties / dateRange / properties / maxDate / patternRemoved value: -"^\\d{4}(\\/\\d{2}(\\/\\d{2})?)?$" - changed
Input schema / properties / dateRange / properties / minDate / descriptionPrevious value: -"The start date for the search range (YYYY, YYYY/MM, or YYYY/MM/DD)."New value: +"Start date (YYYY/MM/DD, YYYY/MM, or YYYY)" - removed
Input schema / properties / dateRange / properties / minDate / patternRemoved value: -"^\\d{4}(\\/\\d{2}(\\/\\d{2})?)?$" - added
Input schema / properties / dateRange / requiredAdded value: +[ + "minDate", + "maxDate" +] - removed
Input schema / properties / fetchBriefSummariesRemoved value: -{ - "default": 0, - "description": "Number of top PMIDs for which to fetch brief summaries using ESummary. Set to 0 to disable. Max 50. Default 0.", - "maximum": 50, - "minimum": 0, - "type": "integer" -} - removed
Input schema / properties / filterByPublicationTypesRemoved value: -{ - "description": "An array of publication types to filter by (e.g., [\"Review\", \"Clinical Trial\"]).", - "items": { - "type": "string" - }, - "type": "array" -} - added
Input schema / properties / freeFullTextAdded value: +{ + "description": "Only include free full text articles", + "type": "boolean" +} - added
Input schema / properties / hasAbstractAdded value: +{ + "description": "Only include articles with abstracts", + "type": "boolean" +} - added
Input schema / properties / journalAdded value: +{ + "description": "Filter by journal name", + "type": "string" +} - added
Input schema / properties / languageAdded value: +{ + "description": "Filter by language (e.g. \"english\")", + "type": "string" +} - changed
Input schema / properties / maxResults / descriptionPrevious value: -"Maximum number of articles to retrieve. Corresponds to ESearch's 'retmax' parameter. Default is 20, max is 1000."New value: +"Maximum results to return" - removed
Input schema / properties / maxResults / exclusiveMinimumRemoved value: -0 - added
Input schema / properties / maxResults / minimumAdded value: +1 - added
Input schema / properties / meshTermsAdded value: +{ + "description": "Filter by MeSH terms", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / offsetAdded value: +{ + "default": 0, + "description": "Result offset for pagination (0-based)", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" +} - added
Input schema / properties / publicationTypesAdded value: +{ + "description": "Filter by publication type (e.g. \"Review\", \"Clinical Trial\", \"Meta-Analysis\")", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / queryAdded value: +{ + "description": "PubMed search query (supports full NCBI syntax)", + "minLength": 1, + "type": "string" +} - removed
Input schema / properties / queryTermRemoved value: -{ - "description": "The primary keyword or phrase to search for in PubMed. Must be at least 3 characters long.", - "minLength": 3, - "type": "string" -} - added
Input schema / properties / sortAdded value: +{ + "default": "relevance", + "description": "Sort order: relevance (default), pub_date (newest first), author, or journal", + "enum": [ + "relevance", + "pub_date", + "author", + "journal" + ], + "type": "string" +} - removed
Input schema / properties / sortByRemoved value: -{ - "default": "relevance", - "description": "Sorting criteria for results. Options: 'relevance' (default), 'pub_date', 'author', 'journal_name'.", - "enum": [ - "relevance", - "pub_date", - "author", - "journal_name" - ], - "type": "string" -} - added
Input schema / properties / speciesAdded value: +{ + "description": "Filter by species", + "enum": [ + "humans", + "animals" + ], + "type": "string" +} - added
Input schema / properties / summaryCountAdded value: +{ + "default": 0, + "description": "Fetch brief summaries for top N results (0 = PMIDs only)", + "maximum": 50, + "minimum": 0, + "type": "integer" +} - changed
Input schema / requiredPrevious value: -[ - "queryTerm" -]New value: +[ + "query" +] - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "offset": { + "description": "Result offset used", + "type": "number" + }, + "pmids": { + "description": "PubMed IDs", + "items": { + "type": "string" + }, + "type": "array" + }, + "query": { + "description": "Original query", + "type": "string" + }, + "searchUrl": { + "description": "PubMed search URL", + "type": "string" + }, + "summaries": { + "description": "Brief summaries (empty array when summaryCount is 0)", + "items": { + "additionalProperties": false, + "properties": { + "authors": { + "description": "Formatted author string", + "type": "string" + }, + "doi": { + "description": "DOI", + "type": "string" + }, + "pmcId": { + "description": "PMC ID", + "type": "string" + }, + "pmcUrl": { + "description": "PMC URL", + "type": "string" + }, + "pmid": { + "description": "PubMed ID", + "type": "string" + }, + "pubDate": { + "description": "Publication date", + "type": "string" + }, + "pubmedUrl": { + "description": "PubMed URL", + "type": "string" + }, + "source": { + "description": "Journal source", + "type": "string" + }, + "title": { + "description": "Article title", + "type": "string" + } + }, + "required": [ + "pmid" + ], + "type": "object" + }, + "type": "array" + }, + "totalFound": { + "description": "Total matching articles", + "type": "number" + } + }, + "required": [ + "query", + "totalFound", + "offset", + "pmids", + "summaries", + "searchUrl" + ], + "type": "object" +}
- Added
pubmed_spell_check
5 tool updates
v1.0.0- First observed
pubmed_article_connections - First observed
pubmed_fetch_contents - First observed
pubmed_generate_chart - First observed
pubmed_research_agent - First observed
pubmed_search_articles
TDQS
Scored across 11 tools
Each tool targets a distinct resource or action, but there is a cluster of retrieval tools (pubmed_fetch_articles, pubmed_fetch_fulltext, pubmed_europepmc_fetch) whose boundaries are subtle and rely on dense descriptions to separate. Similarly pubmed_search_articles vs pubmed_europepmc_search overlap conceptually across corpora. Descriptions do resolve these, keeping confusion to one or two pairs.
Names are uniformly snake_case with a consistent pubmed_ prefix, and most follow a predictable verb_noun pattern (search_articles, fetch_articles, lookup_mesh, convert_ids). The two Europe PMC tools invert the order (europepmc_fetch, europepmc_search), a minor but noticeable deviation.
Eleven tools is well-scoped for a biomedical literature server, covering search, retrieval, citation, vocabulary, and ID operations without bloat. Each tool clearly earns its place.
The surface covers the full retrieval lifecycle: search, metadata fetch, full-text, related/citing, MeSH, citation formatting and lookup, ID conversion, and Europe PMC fallback paths. Minor gaps exist (e.g. no explicit bulk export or saved-set management), but core workflows are complete with graceful fallbacks.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Connect AI clients to biomedical data and tools.
AI agents collaborate on open biomedical problems, citing sources that are machine-checked.
PubMed biomedical papers: new research daily. $0.01/query. Register in-session — free testnet funds.
Open scientific and engineering knowledge for AI agents: search, evidence, document publishing.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenance🔍 Enable AI assistants to search, access, and analyze PubMed articles through a simple MCP interface.129MIT
- AlicenseBqualityDmaintenanceEnables AI assistants to search and retrieve biomedical research articles from PubMed's database of over 35 million citations, including metadata, abstracts, MeSH terms, and full-text PDFs when available.11MIT
- AlicenseAqualityDmaintenanceAn MCP server that provides direct access to PubMed and PubMed Central via the NCBI E-utilities API. It enables AI models to search biomedical literature, retrieve detailed article metadata, and download open-access full texts.5MIT
- AlicenseAqualityCmaintenanceProvides structured PubMed literature data for LLM agents, supporting search, caching, and open-access full-text downloads via the MCP protocol.56111Apache 2.0