tooluniverse 1.0.7__py3-none-any.whl → 1.0.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tooluniverse might be problematic. Click here for more details.
- tooluniverse/__init__.py +37 -14
- tooluniverse/admetai_tool.py +16 -5
- tooluniverse/base_tool.py +36 -0
- tooluniverse/biogrid_tool.py +118 -0
- tooluniverse/build_optimizer.py +87 -0
- tooluniverse/cache/__init__.py +3 -0
- tooluniverse/cache/memory_cache.py +99 -0
- tooluniverse/cache/result_cache_manager.py +235 -0
- tooluniverse/cache/sqlite_backend.py +257 -0
- tooluniverse/clinvar_tool.py +90 -0
- tooluniverse/compose_scripts/output_summarizer.py +87 -33
- tooluniverse/compose_tool.py +2 -2
- tooluniverse/custom_tool.py +28 -0
- tooluniverse/data/adverse_event_tools.json +97 -98
- tooluniverse/data/agentic_tools.json +81 -162
- tooluniverse/data/arxiv_tools.json +1 -4
- tooluniverse/data/compose_tools.json +0 -54
- tooluniverse/data/core_tools.json +1 -4
- tooluniverse/data/dataset_tools.json +7 -7
- tooluniverse/data/doaj_tools.json +1 -3
- tooluniverse/data/drug_discovery_agents.json +282 -0
- tooluniverse/data/europe_pmc_tools.json +1 -2
- tooluniverse/data/genomics_tools.json +174 -0
- tooluniverse/data/geo_tools.json +86 -0
- tooluniverse/data/literature_search_tools.json +15 -35
- tooluniverse/data/markitdown_tools.json +51 -0
- tooluniverse/data/monarch_tools.json +1 -2
- tooluniverse/data/openalex_tools.json +1 -5
- tooluniverse/data/opentarget_tools.json +8 -16
- tooluniverse/data/output_summarization_tools.json +23 -20
- tooluniverse/data/packages/bioinformatics_core_tools.json +2 -2
- tooluniverse/data/packages/cheminformatics_tools.json +1 -1
- tooluniverse/data/packages/genomics_tools.json +1 -1
- tooluniverse/data/packages/single_cell_tools.json +1 -1
- tooluniverse/data/packages/structural_biology_tools.json +1 -1
- tooluniverse/data/pmc_tools.json +1 -4
- tooluniverse/data/ppi_tools.json +139 -0
- tooluniverse/data/pubmed_tools.json +1 -3
- tooluniverse/data/semantic_scholar_tools.json +1 -2
- tooluniverse/data/tool_composition_tools.json +2 -4
- tooluniverse/data/unified_guideline_tools.json +206 -4
- tooluniverse/data/xml_tools.json +15 -15
- tooluniverse/data/zenodo_tools.json +1 -2
- tooluniverse/dbsnp_tool.py +71 -0
- tooluniverse/default_config.py +6 -0
- tooluniverse/ensembl_tool.py +61 -0
- tooluniverse/execute_function.py +235 -76
- tooluniverse/generate_tools.py +303 -20
- tooluniverse/genomics_gene_search_tool.py +56 -0
- tooluniverse/geo_tool.py +116 -0
- tooluniverse/gnomad_tool.py +63 -0
- tooluniverse/logging_config.py +64 -2
- tooluniverse/markitdown_tool.py +159 -0
- tooluniverse/mcp_client_tool.py +10 -5
- tooluniverse/molecule_2d_tool.py +9 -3
- tooluniverse/molecule_3d_tool.py +9 -3
- tooluniverse/output_hook.py +217 -150
- tooluniverse/smcp.py +18 -10
- tooluniverse/smcp_server.py +89 -199
- tooluniverse/string_tool.py +112 -0
- tooluniverse/tools/{MultiAgentLiteratureSearch.py → ADMETAnalyzerAgent.py} +18 -18
- tooluniverse/tools/ArXiv_search_papers.py +3 -3
- tooluniverse/tools/CMA_Guidelines_Search.py +52 -0
- tooluniverse/tools/CORE_search_papers.py +3 -3
- tooluniverse/tools/ClinVar_search_variants.py +52 -0
- tooluniverse/tools/ClinicalTrialDesignAgent.py +63 -0
- tooluniverse/tools/CompoundDiscoveryAgent.py +59 -0
- tooluniverse/tools/DOAJ_search_articles.py +2 -2
- tooluniverse/tools/DiseaseAnalyzerAgent.py +52 -0
- tooluniverse/tools/DrugInteractionAnalyzerAgent.py +52 -0
- tooluniverse/tools/DrugOptimizationAgent.py +63 -0
- tooluniverse/tools/Ensembl_lookup_gene_by_symbol.py +52 -0
- tooluniverse/tools/EuropePMC_search_articles.py +1 -1
- tooluniverse/tools/GIN_Guidelines_Search.py +52 -0
- tooluniverse/tools/GWAS_search_associations_by_gene.py +52 -0
- tooluniverse/tools/LiteratureSynthesisAgent.py +59 -0
- tooluniverse/tools/PMC_search_papers.py +3 -3
- tooluniverse/tools/PubMed_search_articles.py +2 -2
- tooluniverse/tools/SemanticScholar_search_papers.py +1 -1
- tooluniverse/tools/UCSC_get_genes_by_region.py +67 -0
- tooluniverse/tools/Zenodo_search_records.py +1 -1
- tooluniverse/tools/__init__.py +33 -3
- tooluniverse/tools/convert_to_markdown.py +59 -0
- tooluniverse/tools/dbSNP_get_variant_by_rsid.py +46 -0
- tooluniverse/tools/gnomAD_query_variant.py +52 -0
- tooluniverse/tools/openalex_literature_search.py +4 -4
- tooluniverse/ucsc_tool.py +60 -0
- tooluniverse/unified_guideline_tools.py +1175 -57
- tooluniverse/utils.py +51 -4
- tooluniverse/zenodo_tool.py +2 -1
- {tooluniverse-1.0.7.dist-info → tooluniverse-1.0.9.dist-info}/METADATA +10 -3
- {tooluniverse-1.0.7.dist-info → tooluniverse-1.0.9.dist-info}/RECORD +96 -61
- {tooluniverse-1.0.7.dist-info → tooluniverse-1.0.9.dist-info}/entry_points.txt +0 -3
- {tooluniverse-1.0.7.dist-info → tooluniverse-1.0.9.dist-info}/WHEEL +0 -0
- {tooluniverse-1.0.7.dist-info → tooluniverse-1.0.9.dist-info}/licenses/LICENSE +0 -0
- {tooluniverse-1.0.7.dist-info → tooluniverse-1.0.9.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MarkItDown Tool for ToolUniverse
|
|
3
|
+
|
|
4
|
+
Simple implementation following Microsoft's official MCP pattern.
|
|
5
|
+
Supports http:, https:, file:, data: URIs.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
import urllib.parse
|
|
12
|
+
import urllib.request
|
|
13
|
+
import tempfile
|
|
14
|
+
from typing import Dict, Any
|
|
15
|
+
from .base_tool import BaseTool
|
|
16
|
+
from .tool_registry import register_tool
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@register_tool("MarkItDownTool")
|
|
20
|
+
class MarkItDownTool(BaseTool):
|
|
21
|
+
"""MarkItDown tool for converting files to Markdown."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, tool_config):
|
|
24
|
+
super().__init__(tool_config)
|
|
25
|
+
self.tool_name = tool_config.get("name", "MarkItDownTool")
|
|
26
|
+
|
|
27
|
+
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
28
|
+
"""Execute MarkItDown tool."""
|
|
29
|
+
try:
|
|
30
|
+
return self._convert_to_markdown(arguments)
|
|
31
|
+
except Exception as e:
|
|
32
|
+
return {"error": str(e)}
|
|
33
|
+
|
|
34
|
+
def _convert_to_markdown(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
35
|
+
"""Convert a resource described by URI to Markdown using markitdown CLI."""
|
|
36
|
+
uri = arguments.get("uri")
|
|
37
|
+
output_path = arguments.get("output_path")
|
|
38
|
+
enable_plugins = arguments.get("enable_plugins", False)
|
|
39
|
+
|
|
40
|
+
if not uri:
|
|
41
|
+
return {"error": "URI is required"}
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
# Parse URI
|
|
45
|
+
parsed_uri = urllib.parse.urlparse(uri)
|
|
46
|
+
scheme = parsed_uri.scheme.lower()
|
|
47
|
+
|
|
48
|
+
# Handle different URI schemes
|
|
49
|
+
if scheme in ["http", "https"]:
|
|
50
|
+
# Download from URL
|
|
51
|
+
temp_file = self._download_from_url(uri)
|
|
52
|
+
if not temp_file:
|
|
53
|
+
return {"error": f"Failed to download from URL: {uri}"}
|
|
54
|
+
input_path = temp_file
|
|
55
|
+
cleanup_temp = True
|
|
56
|
+
|
|
57
|
+
elif scheme == "file":
|
|
58
|
+
# Local file
|
|
59
|
+
file_path = urllib.request.url2pathname(parsed_uri.path)
|
|
60
|
+
if not os.path.exists(file_path):
|
|
61
|
+
return {"error": f"File not found: {file_path}"}
|
|
62
|
+
input_path = file_path
|
|
63
|
+
cleanup_temp = False
|
|
64
|
+
|
|
65
|
+
elif scheme == "data":
|
|
66
|
+
# Data URI
|
|
67
|
+
temp_file = self._handle_data_uri(uri)
|
|
68
|
+
if not temp_file:
|
|
69
|
+
return {"error": f"Failed to process data URI: {uri}"}
|
|
70
|
+
input_path = temp_file
|
|
71
|
+
cleanup_temp = True
|
|
72
|
+
|
|
73
|
+
else:
|
|
74
|
+
return {
|
|
75
|
+
"error": f"Unsupported URI scheme: {scheme}. Supported schemes: http, https, file, data"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Build markitdown command
|
|
79
|
+
cmd = [sys.executable, "-m", "markitdown", input_path]
|
|
80
|
+
if enable_plugins:
|
|
81
|
+
cmd.append("--use-plugins")
|
|
82
|
+
if output_path:
|
|
83
|
+
cmd.extend(["-o", output_path])
|
|
84
|
+
|
|
85
|
+
# Execute command
|
|
86
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
|
87
|
+
|
|
88
|
+
if result.returncode != 0:
|
|
89
|
+
error_msg = f"MarkItDown failed: {result.stderr}"
|
|
90
|
+
if cleanup_temp and os.path.exists(input_path):
|
|
91
|
+
os.unlink(input_path)
|
|
92
|
+
return {"error": error_msg}
|
|
93
|
+
|
|
94
|
+
# Get markdown content
|
|
95
|
+
if output_path and os.path.exists(output_path):
|
|
96
|
+
with open(output_path, "r", encoding="utf-8") as f:
|
|
97
|
+
markdown_content = f.read()
|
|
98
|
+
else:
|
|
99
|
+
markdown_content = result.stdout
|
|
100
|
+
|
|
101
|
+
# Clean up temporary file if needed
|
|
102
|
+
if cleanup_temp and os.path.exists(input_path):
|
|
103
|
+
os.unlink(input_path)
|
|
104
|
+
|
|
105
|
+
# Prepare response
|
|
106
|
+
response = {
|
|
107
|
+
"markdown_content": markdown_content,
|
|
108
|
+
"file_info": {
|
|
109
|
+
"original_uri": uri,
|
|
110
|
+
"uri_scheme": scheme,
|
|
111
|
+
"output_file": output_path if output_path else None,
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# If no output_path specified, also return the content as a string for convenience
|
|
116
|
+
if not output_path:
|
|
117
|
+
response["content"] = markdown_content
|
|
118
|
+
|
|
119
|
+
return response
|
|
120
|
+
|
|
121
|
+
except Exception as e:
|
|
122
|
+
return {"error": f"URI processing failed: {str(e)}"}
|
|
123
|
+
|
|
124
|
+
def _download_from_url(self, url: str) -> str:
|
|
125
|
+
"""Download content from URL to temporary file."""
|
|
126
|
+
try:
|
|
127
|
+
with urllib.request.urlopen(url, timeout=30) as response:
|
|
128
|
+
content = response.read()
|
|
129
|
+
|
|
130
|
+
# Create temporary file
|
|
131
|
+
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
|
132
|
+
temp_file.write(content)
|
|
133
|
+
return temp_file.name
|
|
134
|
+
except Exception:
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
def _handle_data_uri(self, data_uri: str) -> str:
|
|
138
|
+
"""Handle data URI and save to temporary file."""
|
|
139
|
+
try:
|
|
140
|
+
# Parse data URI: data:[<mediatype>][;base64],<data>
|
|
141
|
+
if "," not in data_uri:
|
|
142
|
+
return None
|
|
143
|
+
|
|
144
|
+
header, data = data_uri.split(",", 1)
|
|
145
|
+
|
|
146
|
+
# Check if base64 encoded
|
|
147
|
+
if ";base64" in header:
|
|
148
|
+
import base64
|
|
149
|
+
|
|
150
|
+
content = base64.b64decode(data)
|
|
151
|
+
else:
|
|
152
|
+
content = data.encode("utf-8")
|
|
153
|
+
|
|
154
|
+
# Create temporary file
|
|
155
|
+
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
|
156
|
+
temp_file.write(content)
|
|
157
|
+
return temp_file.name
|
|
158
|
+
except Exception:
|
|
159
|
+
return None
|
tooluniverse/mcp_client_tool.py
CHANGED
|
@@ -26,18 +26,23 @@ class BaseMCPClient:
|
|
|
26
26
|
|
|
27
27
|
def __init__(self, server_url: str, transport: str = "http", timeout: int = 30):
|
|
28
28
|
self.server_url = os.path.expandvars(server_url)
|
|
29
|
-
|
|
29
|
+
# Normalize transport for backward compatibility: treat 'stdio' as HTTP
|
|
30
|
+
normalized_transport = (
|
|
31
|
+
transport.lower() if isinstance(transport, str) else "http"
|
|
32
|
+
)
|
|
33
|
+
if normalized_transport == "stdio":
|
|
34
|
+
normalized_transport = "http"
|
|
35
|
+
self.transport = normalized_transport
|
|
30
36
|
self.timeout = timeout
|
|
31
37
|
self.session = None
|
|
32
38
|
self.mcp_session_id = None
|
|
33
39
|
self._initialized = False
|
|
34
40
|
|
|
35
|
-
# Validate transport
|
|
41
|
+
# Validate transport (accept 'stdio' via normalization above)
|
|
36
42
|
supported_transports = ["http", "websocket"]
|
|
37
43
|
if self.transport not in supported_transports:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
)
|
|
44
|
+
# Keep message concise to satisfy line length rules
|
|
45
|
+
raise ValueError("Invalid transport")
|
|
41
46
|
|
|
42
47
|
async def _ensure_session(self):
|
|
43
48
|
"""Ensure HTTP session is available for HTTP transport"""
|
tooluniverse/molecule_2d_tool.py
CHANGED
|
@@ -9,6 +9,7 @@ Supports SMILES, InChI, molecule names, and various output formats.
|
|
|
9
9
|
import base64
|
|
10
10
|
import requests
|
|
11
11
|
import io
|
|
12
|
+
import warnings
|
|
12
13
|
from typing import Any, Dict, Optional
|
|
13
14
|
from .visualization_tool import VisualizationTool
|
|
14
15
|
from .tool_registry import register_tool
|
|
@@ -21,9 +22,14 @@ class Molecule2DTool(VisualizationTool):
|
|
|
21
22
|
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
22
23
|
"""Generate 2D molecular structure visualization."""
|
|
23
24
|
try:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
# Suppress RDKit RuntimeWarnings about converter registration
|
|
26
|
+
with warnings.catch_warnings():
|
|
27
|
+
warnings.filterwarnings(
|
|
28
|
+
"ignore", category=RuntimeWarning, module="importlib._bootstrap"
|
|
29
|
+
)
|
|
30
|
+
from rdkit import Chem
|
|
31
|
+
from rdkit.Chem import Draw
|
|
32
|
+
from rdkit.Chem import rdDepictor
|
|
27
33
|
|
|
28
34
|
# Extract parameters
|
|
29
35
|
smiles = arguments.get("smiles")
|
tooluniverse/molecule_3d_tool.py
CHANGED
|
@@ -6,6 +6,7 @@ Tool for visualizing 3D molecular structures using RDKit and py3Dmol.
|
|
|
6
6
|
Supports SMILES, MOL files, SDF content, and various visualization styles.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
+
import warnings
|
|
9
10
|
from typing import Any, Dict
|
|
10
11
|
from .visualization_tool import VisualizationTool
|
|
11
12
|
from .tool_registry import register_tool
|
|
@@ -18,9 +19,14 @@ class Molecule3DTool(VisualizationTool):
|
|
|
18
19
|
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
19
20
|
"""Generate 3D molecular structure visualization."""
|
|
20
21
|
try:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
# Suppress RDKit RuntimeWarnings about converter registration
|
|
23
|
+
with warnings.catch_warnings():
|
|
24
|
+
warnings.filterwarnings(
|
|
25
|
+
"ignore", category=RuntimeWarning, module="importlib._bootstrap"
|
|
26
|
+
)
|
|
27
|
+
import py3Dmol
|
|
28
|
+
from rdkit import Chem
|
|
29
|
+
from rdkit.Chem import AllChem
|
|
24
30
|
|
|
25
31
|
# Extract parameters
|
|
26
32
|
smiles = arguments.get("smiles")
|