# mcp/ncbi.py """ NCBI E-utilities helpers – Gene, Protein, ClinVar, MeSH. """ import os import httpx from typing import List, Dict NCBI_KEY = os.getenv("BIO_KEY") # optional but increases rate limits BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/" async def _get(endpoint: str, params: Dict) -> Dict: if NCBI_KEY: params["api_key"] = NCBI_KEY async with httpx.AsyncClient(timeout=20) as client: r = await client.get(f"{BASE}{endpoint}", params=params) r.raise_for_status() return r.json() if r.headers["Content-Type"].startswith("application/json") else r.text # ---------- Public helpers ---------- async def search_gene(term: str, retmax: int = 5) -> List[Dict]: """Return basic gene info (ID + name/symbol) by search term.""" data = await _get("esearch.fcgi", {"db": "gene", "term": term, "retmode": "json", "retmax": retmax}) ids = data["esearchresult"]["idlist"] if not ids: return [] summary = await _get("esummary.fcgi", {"db": "gene", "id": ",".join(ids), "retmode": "json"}) return list(summary["result"].values())[1:] # first key is 'uids' async def get_mesh_definition(term: str) -> str: """Return MeSH term definition (first record).""" text = await _get("esummary.fcgi", {"db": "mesh", "term": term, "retmode": "json", "retmax": 1}) recs = list(text["result"].values())[1:] return recs[0].get("ds_meshterms", [""])[0] if recs else ""