Apache License 2.0

技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

深度技术分析:cyanheads/pubmed-mcp-server

项目背景与痛点

在生物医学领域,及时有效地检索关键文献对于研究发展至关重要。然而,由于文献数量庞大且分散在PubMed、Europe PMC等多个权威数据库中,如何高效地获取论文全文、引文和MeSH术语,成为科研人员面临的一大挑战。pubmed-mcp-server项目应运而生,它提供了一个通过MCP(Meta Clinical Portal)标准接口,可以搜索PubMed和Europe PMC,获取文章全文、引文及MeSH术语的服务。

核心技术揭秘

pubmed-mcp-server采用标准化的MCP协议,通过HTTP接口或STDIO形式提供数据。其技术实现覆盖了请求解析、数据获取与整合多个核心环节。首先是请求解析,解析用户的查询条件,将其转化为符合各数据库标准的搜索请求;其次是数据获取,通过相关API接口获取原始数据;最后,将处理过的数据整合成MCP协议规定的格式返回。

graph TD A[用户请求] --> B{"参数校验"} B -->|"通过"| C[执行业务] C --> D[解析请求] D --> E[数据获取] E --> F[数据整合] F --> H[返回数据] B -->|"失败"| G[返回错误]

在请求解析阶段,还需根据用户需求选择数据源PubMed或Europe PMC,并转换成相应数据库支持的查询语言。数据获取阶段,除了按需从数据库中抓取数据,还需考虑异常情况的处理和性能优化。于此同时,系统必须保证数据的及时性和鲜活性,以提供可靠的论文内容和相关引用信息。

功能亮点与差异

相比同类竞品,pubmed-mcp-server最为独特的设计在于支持多种输入输出方式:既可通过STDIO直接接收并反馈数据,也可采用流式HTTP接口,这样极大方便了不同开发背景下的接入使用。此外,它还集成了Unpaywall等额外数据源来补充全文获取的功能,使得获取数据的范围和种类更为广泛,显著提高了数据的利用价值。

应用场景与落地建议

在生产环境中使用该服务,需特别关注其对API请求错误、数据接收延迟的处理能力。确保服务的高可用性和稳定性。此外,针对大规模文献检索需求,应评估系统的性能扩展性,合理规划资源分配。适合的场景包括生物医学研究机构、医疗信息数据库、学术会议数据支撑服务等,能显著提高文献整合分析的效率与质量。

综合评价

pubmed-mcp-server通过科学的数据整合和优化的设计,解决了多数据库文献检索和获取的难题。其灵活的接口使用方式和全面的数据支持是其显著优势,但同时也需要注重服务的性能优化和技术细节,确保在大规模应用中的高可用性和稳定性。对于生物医学研究领域而言,它无疑是一种强有力的工具。

关于

GitHub 原始描述(英文)

Search PubMed/Europe PMC, fetch articles and full text (PMC/EPMC/Unpaywall), citations, MeSH terms via MCP. STDIO or Streamable HTTP.

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

语言占比

Dockerfile
TypeScript

贡献者

README

@cyanheads/pubmed-mcp-server

Search PubMed/Europe PMC, fetch articles and full text (PMC/EPMC/Unpaywall), citations, MeSH terms via MCP. STDIO or Streamable HTTP.

12 Tools • 1 Resource • 1 Prompt

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework

Public Hosted Server: https://pubmed.caseyjhand.com/mcp


Overview

Biomedical literature from PubMed, PubMed Central, and Europe PMC. Search it, fetch metadata and full text, resolve identifiers and partial citations, format references, and ground queries in MeSH vocabulary. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above. Ships the pubmed-guide agent skill (skill://pubmed-guide/SKILL.md), which MCP clients read for PubMed query syntax, DOI-to-PMID routes outside PMC, reference-list resolution, citation counts, and full-text misses.

Tools

Tool Description
pubmed_search_articles Search PubMed with full query syntax, structured filters, date ranges, and optional summaries
pubmed_fetch_articles Fetch article metadata by PMID: abstract, authors, journal, MeSH terms, databank accessions such as trial registration IDs, grants, a collective author’s investigators on request, linked retraction and correction notices
pubmed_fetch_fulltext Fetch full text by PMID, PMCID, or DOI, falling back from PMC to Europe PMC to Unpaywall
pubmed_europepmc_search Search Europe PMC for preprints, patents, Agricola, and open-access records PubMed doesn’t carry
pubmed_europepmc_fetch Fetch complete Europe PMC records, including the untruncated abstract, as records: [{ source, epmcId }]
pubmed_fetch_citation_metrics Fetch NIH iCite citation metrics by PMID: Relative Citation Ratio, NIH percentile, citation counts and rates
pubmed_format_citations Format citations in APA 7th, MLA 9th, BibTeX, RIS, or Vancouver (ICMJE/NLM), with linked retraction and correction notices
pubmed_find_related Find similar articles, citing articles, or references for a PMID
pubmed_spell_check Correct a misspelled PubMed query via NCBI ESpell
pubmed_lookup_mesh Look up MeSH headings with tree numbers, scope notes, and entry terms
pubmed_lookup_citation Resolve partial references, up to 25 at a time, to PMIDs via ECitMatch
pubmed_convert_ids Convert between DOI, PMID, and PMCID via the PMC ID Converter

Resources

Resource Description
pubmed://database/info PubMed database metadata via EInfo (field list, record count, last update)

Prompts

Prompt Description
research_plan Generate a structured four-phase biomedical research plan

Capability reference

pubmed_search_articles tool

  • Full PubMed query syntax plus filters (author, journal, MeSH, publication type, language, species, abstract, free full text) and publication/modification/Entrez date ranges
  • query is optional: with an author, journal, MeSH, or publication-type filter, the filters alone make the search (a journal’s output over a date range, for example)
  • Up to 1,000 results per page and offsets up to 9,998, or maxResults: 0 for the match count alone; summaryCount adds briefs for up to 50 hits. A larger page size is served at the cap with a notice naming where to continue
  • Reports totalCount, the effectiveQuery PubMed ran, and the appliedFilters
  • Rejects blank filter values, impossible dates, and reversed date ranges before PubMed is called

pubmed_fetch_articles tool

  • Up to 200 PMIDs per call; misses are listed in unavailablePmids
  • Abstract, authors, journal, DOI, publication types, linked retraction/erratum/comment notices, and links; MeSH terms on by default, grants via includeGrants, and the members of a collective author (its InvestigatorList, thousands on some consortium trials) via includeInvestigators
  • A retracted, corrected, or questioned article opens with the same notice block as pubmed_format_citations, directly under its title
  • dataBanks lists the record’s trial registrations and data deposits (ClinicalTrials.gov NCT IDs, GenBank and PDB accessions, Dryad DOIs) verbatim; search pubmed_search_articles for <accession>[si] to find other records citing one
  • recordType separates journal articles from Bookshelf chapters and books; opt-in maxResponseCharacters defers overflow to deferred.ids

pubmed_fetch_fulltext tool

  • pmcids, pmids, and dois in any mix, up to 50 distinct identifiers per call: the first 10 are fetched and the rest returned in overLimit for a follow-up call. Each is tried against PMC, then Europe PMC, then Unpaywall (needs UNPAYWALL_EMAIL); an article several of them name is fetched and returned once, and viaSource names the tier that answered
  • source: "pmc" returns sections (the body, then back matter such as acknowledgments, declarations, and appendices), tables, and figures; source: "unpaywall" returns a best-effort HTML or PDF text body
  • Europe PMC full text is fetched for records Europe PMC marks open access, preprints included; articles carry the licenses their PMC JATS states
  • Misses carry a typed reason and triedTiers; sections, maxSections, maxCharacters, overflowMode, and maxResponseCharacters bound the response, truncation reports what was cut, and sectionCap names the sections maxSections cut

pubmed_europepmc_search tool

  • Adds preprints (PPR), patents (PAT), and Agricola (AGR) to MED and PMC; defaults to MED, PMC, PPR
  • Cursor pagination via cursorMark / nextCursorMark, up to 100 per page; a larger page size is served at the cap with a notice naming where to continue. Abstracts arrive as 400-character snippets
  • Optional sort of comma-separated <field> asc|desc keys; relevance is the default order, and a sort Europe PMC cannot use fails as europepmc_invalid_input
  • Hits carry license and hasFullTextXml
  • Not registered when EUROPEPMC_ENABLED=false

pubmed_europepmc_fetch tool

  • Up to 25 records per call as records: [{ source, epmcId }], each pair copied from a search hit, with the full abstract, license, and hasFullTextXml; unresolved ids land in notFound; opt-in maxResponseCharacters defers overflow to deferred.records
  • Not registered when EUROPEPMC_ENABLED=false

pubmed_fetch_citation_metrics tool

  • Up to 1,000 PMIDs per call; the first 200 distinct are fetched and the rest returned in overLimit, PMIDs NIH iCite has no record for in unavailablePmids
  • Relative Citation Ratio (with a provisional flag), NIH percentile, citation count and rates, Approximate Potential to Translate, MeSH category shares, and clinical citations
  • iCite does not flag retractions; check pubmed_fetch_articles for notices
  • Source: NIH iCite

pubmed_format_citations tool

  • Up to 50 PMIDs per call, in any mix of apa, mla, bibtex, ris, and vancouver
  • Bookshelf records cite as edited books, each chapter dated by its own last revision or contribution date; PMIDs that can’t be fetched are reported as unavailable
  • Vancouver writes page ranges in elided Citing Medicine form (1637-1645 → 1637-45); BibTeX issn and RIS SN carry the journal’s linking ISSN, and RIS TI drops its trailing period
  • Retractions, errata, and expressions of concern NCBI links to an article come back as notices and are shown ahead of its citations; Vancouver adds a Retraction in: / Erratum in: note and APA a retraction parenthetical

pubmed_find_related tool

  • similar, cited_by, or references, up to 50 per page with offset pagination. A larger page size is served at the cap with a notice naming where to continue
  • Falls back to Europe PMC, then OpenAlex, and names the provider that answered; fails as all_providers_failed if none can

pubmed_spell_check tool

  • Returns original, corrected, and hasSuggestion; corrections land in place, so field tags, operators, spacing, and gene symbols stay as written, and a single letter such as an author initial is never swapped for another
  • Values of indexed field tags (aged[mh], zhang y[au], free full text[sb]) are kept as written; free-text fields ([tiab], [ti], [tw]) are still corrected
  • Run it after a zero-hit or thin search, then retry pubmed_search_articles with corrected

pubmed_lookup_mesh tool

  • Descriptors by name or free-text term, with an exact heading match pinned first (the descriptor, for a drug-class heading); up to 50 per page, continued via nextOffset. A larger page size is served at the cap with a notice naming where to continue
  • Records carry their MeSH unique ID (meshId, e.g. D000072657) beside the Entrez UID; includeDetails (default on) adds tree numbers, scope notes, and entry terms

pubmed_lookup_citation tool

  • Up to 25 partial citations per call; a journal or a four-digit year is required, and volume, first page, and author sharpen the match
  • Each is matched independently and comes back matched, not_found, or ambiguous, with recovery detail

pubmed_convert_ids tool

  • Up to 50 ids per call, all of one declared idType (doi, pmid, pmcid); only PMC-indexed articles resolve
  • One success or error row per id, in order, so a partial batch never fails

pubmed://database/info resource

  • Live EInfo call for the pubmed database, returned as application/json
  • count, lastUpdate, and fields[], whose names are the search tags pubmed_search_articles accepts

research_plan prompt

  • Arguments: title, goal, and keywords required; organism and includeAgentPrompts optional
  • Returns a four-phase research plan; includeAgentPrompts: "true" adds an agent-guidance block under each of its nine sub-steps, two of which point at tools: the literature review names pubmed_search_articles and pubmed_lookup_mesh, and the interpretation step names pubmed_search_articles

Features

Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.

PubMed-specific:

  • NCBI E-utilities (ESearch, EFetch, ESummary, ELink, ESpell, EInfo, ECitMatch) and the PMC ID Converter, with Europe PMC, OpenAlex, and Unpaywall filling the gaps
  • Shared NCBI request queue: paced request starts, capped concurrency, a cooldown that holds every caller after an NCBI 429, and one deadline covering queue wait and retries
  • XML parsing built for PubMed’s inconsistent records: structured abstracts, missing fields, varying date formats
  • Forgiving identifiers: a zero-padded PMID resolves as the PMID it spells in every tool that takes one; pubmed_fetch_fulltext also matches DOIs case-insensitively and PMC IDs with or without the PMC prefix
  • Hand-rolled citation formatters (APA, MLA, BibTeX, RIS, Vancouver) with no dependencies

Agent-friendly output:

  • Provenance in responses: source labels, license fields on full-text and Europe PMC results, best-effort warnings on Unpaywall results, and effective-query echo on searches, so agents can judge what to 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", typed unavailable reasons, viaSource and triedTiers fields, so callers branch on data, not string parsing

Getting started

Connect to the hosted instance, no install:

claude mcp add --transport http pubmed-mcp-server https://pubmed.caseyjhand.com/mcp

Or run it locally:

claude mcp add pubmed-mcp-server -- npx -y @cyanheads/pubmed-mcp-server

For other clients, add this to the MCP config file:

{
  "mcpServers": {
    "pubmed-mcp-server": {
      "command": "npx",
      "args": ["-y", "@cyanheads/pubmed-mcp-server"]
    }
  }
}

An NCBI API key in NCBI_API_KEY raises the rate limit from 3 to 10 requests per second (-e NCBI_API_KEY=your-key, or an env entry). For Docker or a source build, see Running the server.

Configuration

Variable Description Default
NCBI_API_KEY NCBI API key; raises the rate limit from 3 to 10 req/s. NCBI counts the limit per key (per IP address without one), so processes sharing a key or an address share it. none
NCBI_ADMIN_EMAIL Contact email sent with NCBI requests, as NCBI recommends. none
NCBI_REQUEST_DELAY_MS Minimum gap between NCBI request starts, in ms. 400 (120 with a key)
NCBI_MAX_CONCURRENT Max concurrent in-flight NCBI requests. 8
NCBI_MAX_RETRIES Retry attempts for failed NCBI requests. 6
NCBI_TIMEOUT_MS Per-request HTTP timeout, in ms. 30000
NCBI_TOTAL_DEADLINE_MS Deadline for one NCBI call across queue wait, retries, and backoff, in ms. A call that can’t start in time is rejected at once. 60000
UNPAYWALL_EMAIL Contact email for Unpaywall. Setting it enables the Unpaywall tier of pubmed_fetch_fulltext for non-PMC DOIs. none
UNPAYWALL_TIMEOUT_MS Per-request timeout for Unpaywall lookups and content fetches, in ms. 20000
EUROPEPMC_ENABLED Set false to disable every Europe PMC call: both Europe PMC tools go unregistered, pubmed_fetch_fulltext skips that tier, and pubmed_find_related skips that fallback. true
EUROPEPMC_EMAIL Optional contact email sent with Europe PMC requests. none
EUROPEPMC_REQUEST_DELAY_MS Minimum gap between Europe PMC request starts, in ms. 200
EUROPEPMC_MAX_RETRIES Retry attempts for failed Europe PMC requests. 3
EUROPEPMC_TIMEOUT_MS Per-request timeout for Europe PMC calls, in ms. 20000
MCP_TRANSPORT_TYPE Transport: stdio or http. stdio
MCP_HTTP_PORT HTTP server port. 3010
MCP_SESSION_MODE HTTP session mode: stateless, stateful, or auto. stateless
MCP_AUTH_MODE Authentication: none, jwt, or oauth. none
MCP_LOG_LEVEL Log level (debug, info, warning, error, etc.). info
LOGS_DIR Directory for log files (Node.js only). <app-root>/logs
STORAGE_PROVIDER_TYPE Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. in-memory
OTEL_ENABLED Enable OpenTelemetry. false

See .env.example for every server setting and the common framework overrides.

Running the server

Local development

Requires Bun v1.4.0 or higher (or Node.js v24+).

  • Clone and install:

    git clone https://github.com/cyanheads/pubmed-mcp-server.git
    cd pubmed-mcp-server && bun install
    cp .env.example .env   # set NCBI_API_KEY, NCBI_ADMIN_EMAIL, and UNPAYWALL_EMAIL as needed
    
  • Build and run the production version:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:http
    # or
    bun run start:stdio
    
  • Run checks and tests:

    bun run devcheck  # Lints, formats, type-checks, and more
    bun run test      # Runs the test suite
    

Docker

docker run --rm -p 3010:3010 ghcr.io/cyanheads/pubmed-mcp-server:latest

The image defaults to HTTP transport, stateless session mode, and logs to /var/log/pubmed-mcp-server. To run it over stdio from an MCP client, use "command": "docker" with "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/pubmed-mcp-server:latest"]. To build locally, docker build -t pubmed-mcp-server .; OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.

Project structure

Directory Purpose
src/mcp-server/tools Tool definitions (*.tool.ts). Twelve tools across PubMed, PMC, Europe PMC, and NIH iCite.
src/mcp-server/resources Resource definitions. Database info resource.
src/mcp-server/prompts Prompt definitions. Research plan prompt.
src/services/ncbi NCBI E-utilities service layer — API client, queue, parser, formatter.
src/services/europe-pmc Europe PMC service — search + fullTextXML JATS retrieval. Reuses the NCBI JATS parser.
src/services/unpaywall Unpaywall service — DOI → OA location resolution and content fetch (HTML/PDF).
src/services/openalex OpenAlex service — last-resort provider for pubmed_find_related.
src/config Server-specific environment variable parsing and validation with Zod.
tests/ Unit and integration tests, mirroring the src/ structure.
skills/ The published pubmed-guide agent skill, served over MCP and shipped in the package, the .mcpb bundle, and the Docker image.

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic
  • Use ctx.log for logging, ctx.state for storage
  • Register new tools and resources in the createApp() arrays in src/index.ts
  • Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields

Contributing

Issues are welcome. Run checks and tests before submitting:

bun run devcheck
bun run test

License

This project is licensed under the Apache 2.0 License. See the LICENSE file for details.

评论

暂无评论