Source code for tooluniverse.monarch_v3_tool

# monarch_v3_tool.py
"""
Monarch Initiative V3 API tool for ToolUniverse.

The Monarch Initiative integrates gene, disease, and phenotype data
from multiple organisms to support biomedical discovery. The V3 API
provides access to a knowledge graph linking genes, diseases, phenotypes,
and variants across species.

API: https://api.monarchinitiative.org/v3/api/
No authentication required. Free public access.
"""

import requests
from typing import Dict, Any
from .base_tool import BaseTool
from .tool_registry import register_tool

MONARCH_BASE_URL = "https://api.monarchinitiative.org/v3/api"


[docs] @register_tool("MonarchV3Tool") class MonarchV3Tool(BaseTool): """ Tool for querying the Monarch Initiative V3 knowledge graph. Monarch provides integrated data linking genes, diseases, phenotypes, and model organisms. The V3 API supports entity lookup, association queries, and cross-species phenotype comparisons. Data sources include OMIM, ClinVar, HPO, MGI, ZFIN, FlyBase, WormBase, and others. Supports: entity lookup, phenotype associations, disease-gene associations. No authentication required. """
[docs] def __init__(self, tool_config: Dict[str, Any]): super().__init__(tool_config) self.timeout = tool_config.get("timeout", 30) fields = tool_config.get("fields", {}) self.endpoint = fields.get("endpoint", "entity")
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Execute the Monarch V3 API call.""" try: return self._query(arguments) except requests.exceptions.Timeout: return {"error": f"Monarch API timed out after {self.timeout}s"} except requests.exceptions.ConnectionError: return {"error": "Failed to connect to Monarch Initiative API"} except requests.exceptions.HTTPError as e: return {"error": f"Monarch API HTTP error: {e.response.status_code}"} except Exception as e: return {"error": f"Unexpected error querying Monarch: {str(e)}"}
[docs] def _query(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Route to appropriate Monarch V3 endpoint.""" if self.endpoint == "entity": return self._get_entity(arguments) elif self.endpoint == "associations": return self._get_associations(arguments) elif self.endpoint == "search": return self._search(arguments) else: return {"error": f"Unknown endpoint: {self.endpoint}"}
[docs] def _get_entity(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Get detailed entity information by CURIE identifier.""" entity_id = arguments.get("entity_id", "") if not entity_id: return { "error": "entity_id parameter is required (e.g., HGNC:11998, MONDO:0005148, HP:0001250)" } url = f"{MONARCH_BASE_URL}/entity/{entity_id}" response = requests.get(url, timeout=self.timeout) response.raise_for_status() data = response.json() return { "data": { "id": data.get("id"), "name": data.get("name"), "full_name": data.get("full_name"), "category": data.get("category"), "description": data.get("description"), "symbol": data.get("symbol"), "synonyms": data.get("synonym", []), "xrefs": data.get("xref", []), "taxon": data.get("in_taxon"), "taxon_label": data.get("in_taxon_label"), "provided_by": data.get("provided_by"), }, "metadata": { "source": "Monarch Initiative V3", }, }
[docs] def _get_associations(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Get associations for an entity with filtering by category.""" subject = arguments.get("subject", "") if not subject: return { "error": "subject parameter is required (e.g., HGNC:11998 or MONDO:0005148)" } category = arguments.get("category", "") if not category: return { "error": "category parameter is required. Options: biolink:GeneToPhenotypicFeatureAssociation, biolink:DiseaseToPhenotypicFeatureAssociation, biolink:CorrelatedGeneToDiseaseAssociation, biolink:CausalGeneToDiseaseAssociation, biolink:VariantToDiseaseAssociation, biolink:GeneToPathwayAssociation" } limit = arguments.get("limit") or 20 url = f"{MONARCH_BASE_URL}/association" params = { "subject": subject, "category": category, "limit": min(limit, 200), } response = requests.get(url, params=params, timeout=self.timeout) response.raise_for_status() data = response.json() associations = [] for item in data.get("items", []): associations.append( { "subject": item.get("subject"), "subject_label": item.get("subject_label"), "object": item.get("object"), "object_label": item.get("object_label"), "category": item.get("category"), "predicate": item.get("predicate"), "negated": item.get("negated"), "provided_by": item.get("provided_by"), "primary_knowledge_source": item.get("primary_knowledge_source"), } ) return { "data": associations, "metadata": { "source": "Monarch Initiative V3", "subject": subject, "category": category, "total_results": data.get("total", len(associations)), }, }