mgbam commited on
Commit
d3ef28f
·
verified ·
1 Parent(s): 6523621

Create pubchem_ext.py

Browse files
Files changed (1) hide show
  1. mcp/pubchem_ext.py +46 -0
mcp/pubchem_ext.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ pubchem_ext.py · PubChem PUG-REST helper
3
+ Docs: https://pubchem.ncbi.nlm.nih.gov/docs/pug-rest-tutorial 📄
4
+
5
+ • No API-key is required for the public endpoint.
6
+ • If you set PUBCHEM_KEY (token), we include it as X-Pubchem-ApiKey
7
+ which lifts burst limits. Otherwise header is omitted.
8
+ • One retry on 5xx / ReadTimeout, then returns {}.
9
+ """
10
+
11
+ from __future__ import annotations
12
+ import os, asyncio, httpx
13
+ from urllib.parse import quote_plus
14
+ from functools import lru_cache
15
+ from typing import Dict
16
+
17
+ _TOKEN = os.getenv("PUBCHEM_KEY") # optional
18
+ _BASE = "https://pubchem.ncbi.nlm.nih.gov/rest/pug"
19
+ _HDR = {"Accept": "application/json"}
20
+ if _TOKEN:
21
+ _HDR["X-Pubchem-ApiKey"] = _TOKEN
22
+
23
+ @lru_cache(maxsize=256)
24
+ async def fetch_compound(name: str) -> Dict:
25
+ """
26
+ Return compound data as dict or {} on failure.
27
+ Uses /compound/name/<drug>/JSON endpoint.
28
+ """
29
+ url = f"{_BASE}/compound/name/{quote_plus(name)}/JSON"
30
+
31
+ async def _hit() -> Dict:
32
+ async with httpx.AsyncClient(timeout=10, headers=_HDR) as cli:
33
+ r = await cli.get(url)
34
+ if r.status_code == 404:
35
+ return {} # no such compound
36
+ r.raise_for_status()
37
+ return r.json()
38
+
39
+ try:
40
+ return await _hit()
41
+ except (httpx.HTTPStatusError, httpx.ReadTimeout):
42
+ await asyncio.sleep(0.5) # quick back-off
43
+ try:
44
+ return await _hit()
45
+ except Exception:
46
+ return {} # graceful fallback