Source code for tooluniverse.marrvel_tool

"""
MARRVEL tools for ToolUniverse — aggregated human gene & disease data.

MARRVEL (Model organism Aggregated Resources for Rare Variant ExpLoration, BCM)
aggregates human gene/disease annotation from many sources (OMIM, HGNC, Ensembl,
Entrez, UniProt, Pharos) behind one API. These tools expose the human gene-level
endpoints used in rare-disease / Mendelian variant triage.

API: http://api.marrvel.org/data  (public, no authentication, JSON)
"""

from typing import Any, Dict

import requests

from .base_tool import BaseTool
from .tool_registry import register_tool

MARRVEL_BASE = "http://api.marrvel.org/data"
HUMAN_TAXON = "9606"


[docs] @register_tool("MARRVELGeneTool") class MARRVELGeneTool(BaseTool): """Aggregated identity/annotation for a human gene by symbol."""
[docs] def __init__(self, tool_config: Dict[str, Any]): super().__init__(tool_config) self.timeout = tool_config.get("fields", {}).get("timeout", 30)
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: symbol = (arguments.get("symbol") or "").strip() if not symbol: return {"status": "error", "error": "'symbol' (e.g. 'CFTR') is required"} url = f"{MARRVEL_BASE}/gene/taxonId/{HUMAN_TAXON}/symbol/{symbol}" try: resp = requests.get( url, headers={"Accept": "application/json"}, timeout=self.timeout ) if resp.status_code == 404: return { "status": "success", "data": {}, "metadata": { "total_results": 0, "query_symbol": symbol, "note": f"No MARRVEL gene record for '{symbol}'.", }, } resp.raise_for_status() rec = resp.json() except requests.exceptions.Timeout: return { "status": "error", "error": f"MARRVEL request timed out after {self.timeout}s", } except requests.exceptions.RequestException as e: return {"status": "error", "error": f"MARRVEL request failed: {e}"} except ValueError: return {"status": "error", "error": "MARRVEL returned a non-JSON response"} if not isinstance(rec, dict) or not rec: return { "status": "success", "data": {}, "metadata": {"total_results": 0, "query_symbol": symbol}, } xref = rec.get("xref", {}) or {} return { "status": "success", "data": { "symbol": rec.get("symbol"), "name": rec.get("name"), "entrez_id": rec.get("entrezId"), "hgnc_id": xref.get("hgncId"), "omim_id": xref.get("omimId"), "ensembl_id": xref.get("ensemblId"), "uniprot_id": rec.get("uniprotKBId"), "chromosome": rec.get("chr"), "location": rec.get("location"), "type": rec.get("type"), "aliases": rec.get("alias", []), "prev_symbols": rec.get("prevSymbols", []), "summary": rec.get("entrezSummary"), }, "metadata": { "total_results": 1, "query_symbol": symbol, "source": "MARRVEL (aggregated)", }, }
[docs] @register_tool("MARRVELOmimTool") class MARRVELOmimTool(BaseTool): """OMIM phenotype/disease associations for a human gene by symbol."""
[docs] def __init__(self, tool_config: Dict[str, Any]): super().__init__(tool_config) self.timeout = tool_config.get("fields", {}).get("timeout", 30)
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: symbol = (arguments.get("symbol") or "").strip() if not symbol: return {"status": "error", "error": "'symbol' (e.g. 'CFTR') is required"} url = f"{MARRVEL_BASE}/omim/gene/symbol/{symbol}" try: resp = requests.get( url, headers={"Accept": "application/json"}, timeout=self.timeout ) if resp.status_code == 404: return { "status": "success", "data": [], "metadata": {"total_results": 0, "query_symbol": symbol}, } resp.raise_for_status() payload = resp.json() except requests.exceptions.Timeout: return { "status": "error", "error": f"MARRVEL request timed out after {self.timeout}s", } except requests.exceptions.RequestException as e: return {"status": "error", "error": f"MARRVEL request failed: {e}"} except ValueError: return {"status": "error", "error": "MARRVEL returned a non-JSON response"} phenos = [] if isinstance(payload, dict): phenos = payload.get("phenotypes", []) or [] elif isinstance(payload, list): phenos = payload results = [ { "gene_mim_number": p.get("mimNumber"), "phenotype": p.get("phenotype"), "phenotype_mim_number": p.get("phenotypeMimNumber"), "inheritance": p.get("phenotypeInheritance"), "phenotypic_series": p.get("phenotypicSeriesNumber"), } for p in phenos if isinstance(p, dict) ] return { "status": "success", "data": results, "metadata": { "total_results": len(results), "query_symbol": symbol, "source": "MARRVEL / OMIM", }, }