Source code for tooluniverse.gpcrdb_tool
"""
GPCRdb API tool for ToolUniverse.
GPCRdb is a comprehensive database for G protein-coupled receptors (GPCRs),
which are the targets of ~35% of all approved drugs.
API Documentation: https://docs.gpcrdb.org/web_services.html
No authentication required.
"""
import requests
from typing import Dict, Any, Optional, List
from .base_tool import BaseTool
from .tool_registry import register_tool
# Base URL for GPCRdb API
GPCRDB_API_URL = "https://gpcrdb.org/services"
[docs]
@register_tool("GPCRdbTool")
class GPCRdbTool(BaseTool):
"""
Tool for querying GPCRdb GPCR database.
GPCRdb provides:
- GPCR protein information and classification
- Structure data for GPCR crystal/cryo-EM structures
- Ligand binding data
- Mutation data and effects
- Sequence alignments
No authentication required. Free public access.
"""
[docs]
def __init__(self, tool_config: Dict[str, Any]):
super().__init__(tool_config)
self.timeout: int = tool_config.get("timeout", 30)
self.parameter = tool_config.get("parameter", {})
[docs]
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Execute GPCRdb API call based on operation type."""
operation = arguments.get("operation", "")
if operation == "get_protein":
return self._get_protein(arguments)
elif operation == "list_proteins":
return self._list_proteins(arguments)
elif operation == "get_structures":
return self._get_structures(arguments)
elif operation == "get_ligands":
return self._get_ligands(arguments)
elif operation == "get_mutations":
return self._get_mutations(arguments)
else:
return {
"status": "error",
"error": f"Unknown operation: {operation}. Supported: get_protein, list_proteins, get_structures, get_ligands, get_mutations",
}
[docs]
def _get_protein(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Get detailed protein information for a GPCR.
Args:
arguments: Dict containing:
- protein: Protein entry name (e.g., adrb2_human) or UniProt accession
"""
protein = arguments.get("protein", "")
if not protein:
return {"status": "error", "error": "Missing required parameter: protein"}
try:
response = requests.get(
f"{GPCRDB_API_URL}/protein/{protein}/",
timeout=self.timeout,
headers={
"Accept": "application/json",
"User-Agent": "ToolUniverse/GPCRdb",
},
)
response.raise_for_status()
data = response.json()
return {
"status": "success",
"data": data,
"metadata": {
"source": "GPCRdb",
"protein": protein,
},
}
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
return {"status": "error", "error": f"Protein not found: {protein}"}
return {"status": "error", "error": f"HTTP error: {e.response.status_code}"}
except requests.exceptions.RequestException as e:
return {"status": "error", "error": f"Request failed: {str(e)}"}
except Exception as e:
return {"status": "error", "error": f"Unexpected error: {str(e)}"}
[docs]
def _list_proteins(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
List GPCR protein families from GPCRdb.
Args:
arguments: Dict containing:
- family: GPCR family (e.g., "001" for Class A). If provided, returns proteins in that family.
- species: Species (ignored if no family specified)
Note: GPCRdb API does not support listing all proteins by species alone.
Without family, returns list of protein families.
"""
family = arguments.get("family", "")
arguments.get("species", "human")
try:
if family:
# List proteins in specific family
url = f"{GPCRDB_API_URL}/proteinfamily/proteins/{family}/"
else:
# List protein families (no endpoint for all proteins by species)
url = f"{GPCRDB_API_URL}/proteinfamily/"
response = requests.get(
url,
timeout=self.timeout,
headers={
"Accept": "application/json",
"User-Agent": "ToolUniverse/GPCRdb",
},
)
response.raise_for_status()
data = response.json()
proteins = data if isinstance(data, list) else [data]
return {
"status": "success",
"data": {
"proteins": proteins,
"count": len(proteins),
"family": family if family else "all families",
"note": "Specify 'family' parameter to list proteins in a specific family. Without family, returns list of protein families.",
},
"metadata": {
"source": "GPCRdb",
},
}
except requests.exceptions.RequestException as e:
return {"status": "error", "error": f"Request failed: {str(e)}"}
except Exception as e:
return {"status": "error", "error": f"Unexpected error: {str(e)}"}
[docs]
def _get_structures(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Get GPCR structure information.
Args:
arguments: Dict containing:
- protein: Protein entry name (optional - if not provided, returns all structures)
- state: Receptor state filter (active, inactive, intermediate)
"""
protein = arguments.get("protein", "")
state = arguments.get("state", "")
try:
if protein:
url = f"{GPCRDB_API_URL}/structure/protein/{protein}/"
else:
url = f"{GPCRDB_API_URL}/structure/"
response = requests.get(
url,
timeout=self.timeout,
headers={
"Accept": "application/json",
"User-Agent": "ToolUniverse/GPCRdb",
},
)
response.raise_for_status()
data = response.json()
structures = data if isinstance(data, list) else [data]
# Filter by state if specified
if state:
structures = [
s for s in structures if s.get("state", "").lower() == state.lower()
]
return {
"status": "success",
"data": {
"structures": structures,
"count": len(structures),
"protein": protein if protein else "all",
"state_filter": state if state else "all",
},
"metadata": {
"source": "GPCRdb",
},
}
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
return {
"status": "success",
"data": {"structures": [], "count": 0},
"metadata": {"note": "No structures found"},
}
return {"status": "error", "error": f"HTTP error: {e.response.status_code}"}
except requests.exceptions.RequestException as e:
return {"status": "error", "error": f"Request failed: {str(e)}"}
except Exception as e:
return {"status": "error", "error": f"Unexpected error: {str(e)}"}
[docs]
def _get_ligands(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Get ligands associated with a GPCR.
Args:
arguments: Dict containing:
- protein: Protein entry name (e.g., adrb2_human)
"""
protein = arguments.get("protein", "")
if not protein:
return {"status": "error", "error": "Missing required parameter: protein"}
try:
response = requests.get(
f"{GPCRDB_API_URL}/ligands/protein/{protein}/",
timeout=self.timeout,
headers={
"Accept": "application/json",
"User-Agent": "ToolUniverse/GPCRdb",
},
)
response.raise_for_status()
data = response.json()
ligands = data if isinstance(data, list) else data.get("ligands", [])
return {
"status": "success",
"data": {
"protein": protein,
"ligands": ligands,
"count": len(ligands),
},
"metadata": {
"source": "GPCRdb",
"protein": protein,
},
}
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
return {
"status": "success",
"data": {"protein": protein, "ligands": [], "count": 0},
"metadata": {"note": "No ligands found for this protein"},
}
return {"status": "error", "error": f"HTTP error: {e.response.status_code}"}
except requests.exceptions.RequestException as e:
return {"status": "error", "error": f"Request failed: {str(e)}"}
except Exception as e:
return {"status": "error", "error": f"Unexpected error: {str(e)}"}
[docs]
def _get_mutations(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Get mutation data for a GPCR.
Args:
arguments: Dict containing:
- protein: Protein entry name (e.g., adrb2_human)
"""
protein = arguments.get("protein", "")
if not protein:
return {"status": "error", "error": "Missing required parameter: protein"}
try:
response = requests.get(
f"{GPCRDB_API_URL}/mutants/protein/{protein}/",
timeout=self.timeout,
headers={
"Accept": "application/json",
"User-Agent": "ToolUniverse/GPCRdb",
},
)
response.raise_for_status()
data = response.json()
mutations = data if isinstance(data, list) else data.get("mutations", [])
return {
"status": "success",
"data": {
"protein": protein,
"mutations": mutations,
"count": len(mutations),
},
"metadata": {
"source": "GPCRdb",
"protein": protein,
},
}
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
return {
"status": "success",
"data": {"protein": protein, "mutations": [], "count": 0},
"metadata": {"note": "No mutation data found"},
}
return {"status": "error", "error": f"HTTP error: {e.response.status_code}"}
except requests.exceptions.RequestException as e:
return {"status": "error", "error": f"Request failed: {str(e)}"}
except Exception as e:
return {"status": "error", "error": f"Unexpected error: {str(e)}"}