Every full-text failure comes back as a typed reason with the tiers it tried in order, so a gap in the results is something you can act on rather than something you have to re-run to understand. The Europe PMC layer matters for the same reason: preprints, patents and Agricola records simply are not in PubMed, and this is the tool that admits it and goes elsewhere.
Eleven tools over NCBI's E-utilities, the PMC ID Converter, Europe PMC and Unpaywall, plus a pubmed://database/info resource and a research_plan prompt. It runs over stdio, as a Streamable HTTP server, or on Cloudflare Workers from the same codebase.
- pubmed_search_articles takes PubMed's own boolean and field-tag syntax — author, journal, MeSH, language, species, publication type, date ranges by publication, modification or Entrez date — and echoes back the query it actually ran
- pubmed_fetch_articles pulls up to 200 records at once, with authors and their affiliations deduplicated, and switches to POST on its own once a batch reaches 100
- pubmed_fetch_fulltext walks a three-stage chain — NCBI PMC EFetch, then Europe PMC fullTextXML, then Unpaywall — and every record says which stage it came from in viaSource
- When full text is not there, you get a reason rather than an empty result: not-found, no-oa, no-epmc-fulltext, fetch-failed and the rest, each with a triedTiers list showing what was attempted in order
- Character budgets keep a full-text pull from swamping the context: maxCharacters per article, maxCharactersPerSection per section, and overflowMode set to truncate or outline depending on whether you would rather have whole sections or every heading
- Section filtering by title, so you can ask for methods and results and skip the introduction
- pubmed_europepmc_search reaches what PubMed cannot — preprints (PPR), patents (PAT), Agricola (AGR) — with cursor-based paging through cursorMark, and pubmed_europepmc_fetch returns the untruncated abstract for the hits worth reading whole
- pubmed_find_related follows a paper three ways: similar content, cited_by, and references
- pubmed_lookup_citation resolves a half-remembered reference — journal, year, volume, first page, author — to a PMID through ECitMatch, and says matched, not_found or ambiguous rather than guessing
- pubmed_lookup_mesh returns MeSH descriptors with tree numbers, scope notes and entry terms, which is how you build a query that is precise instead of merely long
- pubmed_format_citations writes APA 7th, MLA 9th, BibTeX, RIS or Vancouver, several styles at once, up to 50 articles per request
- pubmed_convert_ids maps between DOI, PMID and PMCID up to 50 at a time, reporting per-ID errors instead of failing the whole batch
Nothing to sign up for — PubMed and Europe PMC are public, and MCP_AUTH_MODE defaults to none. An NCBI_API_KEY is optional and raises the rate limit from 3 req/s to 10 req/s; NCBI_ADMIN_EMAIL is the contact address NCBI asks you to send along. Setting UNPAYWALL_EMAIL is what turns on the Unpaywall stage of the full-text chain. Run it with npx from @cyanheads/pubmed-mcp-server, from the ghcr.io/cyanheads/pubmed-mcp-server image, or against the author's public instance at https://pubmed.caseyjhand.com/mcp; building from the repository wants Bun v1.3.2 or higher.
One command — npx -y @cyanheads/pubmed-mcp-server@latest
