Skip to main content
Glama
cyanheads

pubmed-mcp-server

by cyanheads

Pubmed Fetch Articles

pubmed_fetch_articles
Read-only

Fetch detailed PubMed article metadata by PMID, including abstract, authors, journal, and MeSH terms. Use maxResponseCharacters to cap response size and defer excess articles.

Instructions

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.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pmidsYesPubMed IDs to fetch
includeMeshNoInclude MeSH terms
includeGrantsNoInclude grant information
maxResponseCharactersNoOpt-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

TableJSON Schema
NameRequiredDescriptionDefault
errorNoPresent when the call failed. Absent on success.
noticeNoOptional 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.
articlesNoParsed articles
deferredNoContinuation state for articles the whole-response budget withheld. Present only when `maxResponseCharacters` deferred at least one article.
truncatedNoTrue when `maxResponseCharacters` withheld at least one resolved article. Absent when the response carries every article that resolved. The continuation state is in `deferred`.
totalReturnedNoNumber of articles in this response. Under a `maxResponseCharacters` budget this counts the kept articles only; `deferred.deferredCount` covers the rest.
unavailablePmidsNoPMIDs 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.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed9 schema fields changedv2.10.12
    • changedOutput schema / properties / articles / items / properties / authors / description
      Previous 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."
    • addedOutput schema / properties / articles / items / properties / book
      Added 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"
      +}
    • changedOutput schema / properties / articles / items / properties / journalInfo / description
      Previous 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)"
    • addedOutput schema / properties / articles / items / properties / journalInfo / properties / elocationId
      Added 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"
      +}
    • addedOutput schema / properties / articles / items / properties / journalInfo / properties / elocationIdType
      Added 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"
      +}
    • addedOutput schema / properties / articles / items / properties / recordType
      Added 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"
      +}
    • changedOutput schema / properties / articles / items / properties / title / description
      Previous 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`."
    • addedOutput schema / properties / articles / items / required
      Added value: +[
      +  "recordType"
      +]
    • changedOutput schema / properties / unavailablePmids / description
      Previous 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."
  2. Changed6 schema fields changedv2.10.8
    • addedInput schema / properties / maxResponseCharacters
      Added 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"
      +}
    • addedOutput schema / properties / deferred
      Added 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"
      +}
    • changedOutput schema / properties / notice / description
      Previous 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."
    • changedOutput schema / properties / totalReturned / description
      Previous 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."
    • addedOutput schema / properties / truncated
      Added 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"
      +}
    • changedOutput schema / properties / unavailablePmids / description
      Previous 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."
  3. Changed6 schema fields changedv2.10.4
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / additionalProperties
      Added value: +false
    • changedOutput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedOutput schema / anyOf
      Added value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "articles",
      +      "totalReturned"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • addedOutput schema / properties / error
      Added 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"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "articles",
      -  "totalReturned"
      -]
  4. Changed1 schema field changedv2.10.2
    • changedOutput schema / properties / articles / items / properties / doi / description
      Previous 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."
  5. Changed1 schema field changedv2.9.1
    • addedOutput schema / properties / notice
      Added value: +{
      +  "description": "Optional guidance when no articles were returned — points to discovery tools. Absent on successful fetches.",
      +  "type": "string"
      +}
  6. Addedv2.7.6
  7. Removedv2.7.4
  8. Addedv2.3.2

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.