Download mcp/drugcentral.py from mgbam/MCP_Res: direct link, hf CLI and curl.
- Browser
- Download file 4.29 kB
-
https://huggingface.co/spaces/mgbam/MCP_Res/resolve/d3ef28f09426c4c4300a38bc46fb3ffa674e48c8/mcp/drugcentral.py
- Command line
-
hf download hf://spaces/mgbam/MCP_Res@d3ef28f09426c4c4300a38bc46fb3ffa674e48c8/mcp/drugcentral.py
-
curl -L -o drugcentral.py https://huggingface.co/spaces/mgbam/MCP_Res/resolve/d3ef28f09426c4c4300a38bc46fb3ffa674e48c8/mcp/drugcentral.py
4.29 kB
| #!/usr/bin/env python3 | |
| """ | |
| MedGenesis β DrugCentral async wrapper | |
| Docs & schema: https://drugcentral.org/OpenAPI β SMART API spec :contentReference[oaicite:0]{index=0} | |
| Key upgrades | |
| ------------ | |
| * Exponential back-off retry (2 s β 4 s β 8 s) for transient 5xx / 429 errors :contentReference[oaicite:1]{index=1} | |
| * 12-hour LRU cache (256 drugs) β fair-use & faster UI refreshes :contentReference[oaicite:2]{index=2} | |
| * Optional `fields` param so callers can ask only for e.g. MoA or approvals :contentReference[oaicite:3]{index=3} | |
| * Graceful `None` on 404 (βdrug not foundβ) :contentReference[oaicite:4]{index=4} | |
| """ | |
| from __future__ import annotations | |
| import asyncio, httpx | |
| from functools import lru_cache | |
| from typing import Dict, Optional | |
| _BASE = "https://drugcentral.org/api/v1/drug" # public SMART endpoint :contentReference[oaicite:5]{index=5} | |
| _TIMEOUT = 15 # seconds | |
| _MAX_RETRIES = 3 | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # internal helper with back-off | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def _get(params: Dict, retries: int = _MAX_RETRIES) -> Optional[Dict]: | |
| delay = 2 | |
| last: Optional[httpx.Response] = None | |
| for _ in range(retries): | |
| async with httpx.AsyncClient(timeout=_TIMEOUT) as cli: | |
| last = await cli.get(_BASE, params=params) | |
| if last.status_code == 200: | |
| return last.json() # full drug record (incl. MoA, ATC, etc.) :contentReference[oaicite:6]{index=6} | |
| if last.status_code == 404: # not found β exit early | |
| return None | |
| await asyncio.sleep(delay) | |
| delay *= 2 # back-off | |
| # raise on persistent non-404 errors | |
| last.raise_for_status() # type: ignore | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # public cached wrapper | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 12 h cache at default HF runtime | |
| async def fetch_drugcentral( | |
| drug_name: str, | |
| *, | |
| fields: str | None = None, # comma-sep field filter | |
| ) -> Optional[Dict]: | |
| """ | |
| Retrieve DrugCentral record for *drug_name* or ``None``. | |
| Parameters | |
| ---------- | |
| drug_name : str | |
| Common / generic name queried against DrugCentral βnameβ param. | |
| fields : str | None | |
| Comma-separated list (e.g. ``'id,name,moa,indications'``) to limit payload | |
| size β useful for bandwidth-sensitive environments. Full list in docs :contentReference[oaicite:7]{index=7} | |
| """ | |
| params: Dict[str, str] = {"name": drug_name} | |
| if fields: | |
| params["fields"] = fields # narrow response (undocumented but supported) :contentReference[oaicite:8]{index=8} | |
| return await _get(params) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # quick CLI demo | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| if __name__ == "__main__": | |
| async def _demo(): | |
| rec = await fetch_drugcentral("temozolomide", fields="id,name,moa,indications") | |
| if rec: | |
| print(rec["name"], "β MoA:", rec.get("moa")) | |
| else: | |
| print("Drug not found") | |
| asyncio.run(_demo()) | |