Searches and fetches PubMed and PMC via NCBI E-utilities (ESearch then EFetch/ESummary) to gather biomedical evidence and build text corpora. Use when the user wants citations for a condition or drug, abstracts to summarize, MeSH-based searches, or a corpus of literature to run NER over. Trigger keywords: PubMed, PMC, NCBI, E-utilities, ESearch, EFetch, ESummary, MeSH, PMID, literature search, abstracts, evidence. Pairs adjacent to OpenMed: fetched abstracts feed openmed.analyze_text for biomedical NER, and OpenMed-extracted diagnoses/drugs/genes become the search terms. E-utilities are public; an optional free API key raises rate limits from 3 to 10 requests/second.
74
91%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Search PubMed (citations/abstracts) and PMC (full text) programmatically
with NCBI E-utilities — the stable HTTP interface to Entrez. The core pattern
is two steps: ESearch returns matching record IDs (PMIDs), then EFetch (or
ESummary) downloads the records. The Entrez History server (usehistory=y)
lets you chain the two without re-sending thousands of IDs.
E-utilities are public. No key is required, but a free API key raises your limit from 3 to 10 requests/second and is strongly recommended for batch work.
For ClinicalTrials.gov use searching-clinicaltrials; this skill is for the
published literature.
Base URL: https://eutils.ncbi.nlm.nih.gov/entrez/eutils/. JSON for ESearch/
ESummary via retmode=json; EFetch returns text or XML (no JSON for PubMed).
import requests, time
BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"
API_KEY = None # set to your free NCBI key to get 10 req/s instead of 3
def _params(**kw):
if API_KEY:
kw["api_key"] = API_KEY
return kw
def esearch(term: str, retmax: int = 50) -> dict:
"""Find PMIDs; usehistory=y stores them on the Entrez History server."""
r = requests.get(f"{BASE}/esearch.fcgi", params=_params(
db="pubmed", term=term, retmax=retmax,
usehistory="y", retmode="json"), timeout=30)
r.raise_for_status()
res = r.json()["esearchresult"]
return {"count": int(res["count"]), "ids": res["idlist"],
"webenv": res["webenv"], "query_key": res["querykey"]}
def efetch_abstracts(webenv: str, query_key: str, retmax: int = 50) -> str:
"""Pull abstracts by reference to the stored result set (no ID list needed)."""
r = requests.get(f"{BASE}/efetch.fcgi", params=_params(
db="pubmed", WebEnv=webenv, query_key=query_key,
retmax=retmax, rettype="abstract", retmode="text"), timeout=60)
r.raise_for_status()
return r.text
hits = esearch('("type 2 diabetes"[MeSH]) AND metformin AND 2023:2025[pdat]')
print(hits["count"], "papers")
abstracts = efetch_abstracts(hits["webenv"], hits["query_key"])Equivalent cURL (search then fetch one PMID's abstract):
curl "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=metformin&retmode=json"
curl "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=38000000&rettype=abstract&retmode=text"When you need titles/authors/journal/date as JSON (not the full abstract), use ESummary — it returns one record per ID:
def esummary(ids: list[str]) -> dict:
r = requests.get(f"{BASE}/esummary.fcgi", params=_params(
db="pubmed", id=",".join(ids), retmode="json"), timeout=30)
r.raise_for_status()
return r.json()["result"] # keyed by PMID: title, pubdate, source, authors…For PMC full text, repeat with db=pmc and EFetch rettype=""/retmode=xml
(JATS XML). Respect each article's license before redistributing full text.
"<disease>"[MeSH] AND <drug>[tiab] AND 2020:2025[pdat]. Use
[tiab] (title/abstract), [au] (author), [pdat] (publication date).usehistory=y to capture WebEnv + query_key and the count.openmed.analyze_text to extract diseases, drugs,
genes, and oncology entities for downstream synthesis.openmed.analyze_text(note) yields Disease,
Pharmaceutical, Genomics, and Oncology entities. Turn the top spans into the
ESearch term (optionally grounded: ICD-10 label, RxNorm ingredient, gene
symbol) to retrieve targeted evidence.openmed.analyze_text(abstract, model_name="disease_detection_superclinical")
(or a Genomics/Oncology model) to structure the literature into entities for
evidence tables or knowledge-graph edges.api_key, throttle, and retry with backoff. NCBI also requests a
tool= and email= parameter identifying your application.retmode=text (human-readable) or
retmode=xml (PubMedArticle XML) and parse XML for structured fields.WebEnv/query_key are session-scoped — fetch promptly
after searching, or re-run ESearch.retstart/retmax (or history) rather than
pulling everything at once; cap total fetches.[tiab]
term variants so you do not miss them.80da98c
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.