tooluniverse 1.0.9__py3-none-any.whl → 1.0.10__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/admetai_tool.py +1 -1
- tooluniverse/agentic_tool.py +65 -17
- tooluniverse/base_tool.py +19 -8
- tooluniverse/boltz_tool.py +1 -1
- tooluniverse/cache/result_cache_manager.py +167 -12
- tooluniverse/compose_scripts/drug_safety_analyzer.py +1 -1
- tooluniverse/compose_scripts/multi_agent_literature_search.py +1 -1
- tooluniverse/compose_scripts/output_summarizer.py +4 -4
- tooluniverse/compose_scripts/tool_graph_composer.py +1 -1
- tooluniverse/compose_scripts/tool_metadata_generator.py +1 -1
- tooluniverse/compose_tool.py +9 -9
- tooluniverse/core_tool.py +2 -2
- tooluniverse/ctg_tool.py +4 -4
- tooluniverse/custom_tool.py +1 -1
- tooluniverse/dataset_tool.py +2 -2
- tooluniverse/default_config.py +1 -1
- tooluniverse/enrichr_tool.py +14 -14
- tooluniverse/execute_function.py +520 -15
- tooluniverse/extended_hooks.py +4 -4
- tooluniverse/gene_ontology_tool.py +1 -1
- tooluniverse/generate_tools.py +3 -3
- tooluniverse/humanbase_tool.py +10 -10
- tooluniverse/logging_config.py +2 -2
- tooluniverse/mcp_client_tool.py +57 -129
- tooluniverse/mcp_integration.py +52 -49
- tooluniverse/mcp_tool_registry.py +147 -528
- tooluniverse/openalex_tool.py +8 -8
- tooluniverse/openfda_tool.py +2 -2
- tooluniverse/output_hook.py +15 -15
- tooluniverse/package_tool.py +1 -1
- tooluniverse/pmc_tool.py +2 -2
- tooluniverse/remote/boltz/boltz_mcp_server.py +1 -1
- tooluniverse/remote/depmap_24q2/depmap_24q2_mcp_tool.py +2 -2
- tooluniverse/remote/immune_compass/compass_tool.py +3 -3
- tooluniverse/remote/pinnacle/pinnacle_tool.py +2 -2
- tooluniverse/remote/transcriptformer/transcriptformer_tool.py +3 -3
- tooluniverse/remote/uspto_downloader/uspto_downloader_mcp_server.py +3 -3
- tooluniverse/remote_tool.py +4 -4
- tooluniverse/scripts/filter_tool_files.py +2 -2
- tooluniverse/smcp.py +93 -12
- tooluniverse/smcp_server.py +100 -20
- tooluniverse/space/__init__.py +46 -0
- tooluniverse/space/loader.py +133 -0
- tooluniverse/space/validator.py +353 -0
- tooluniverse/tool_finder_embedding.py +2 -2
- tooluniverse/tool_finder_keyword.py +9 -9
- tooluniverse/tool_finder_llm.py +6 -6
- tooluniverse/tools/_shared_client.py +3 -3
- tooluniverse/url_tool.py +1 -1
- tooluniverse/uspto_tool.py +1 -1
- tooluniverse/utils.py +10 -10
- {tooluniverse-1.0.9.dist-info → tooluniverse-1.0.10.dist-info}/METADATA +7 -3
- {tooluniverse-1.0.9.dist-info → tooluniverse-1.0.10.dist-info}/RECORD +57 -54
- {tooluniverse-1.0.9.dist-info → tooluniverse-1.0.10.dist-info}/WHEEL +0 -0
- {tooluniverse-1.0.9.dist-info → tooluniverse-1.0.10.dist-info}/entry_points.txt +0 -0
- {tooluniverse-1.0.9.dist-info → tooluniverse-1.0.10.dist-info}/licenses/LICENSE +0 -0
- {tooluniverse-1.0.9.dist-info → tooluniverse-1.0.10.dist-info}/top_level.txt +0 -0
tooluniverse/openalex_tool.py
CHANGED
|
@@ -37,14 +37,14 @@ class OpenAlexTool(BaseTool):
|
|
|
37
37
|
"""
|
|
38
38
|
Search for literature using OpenAlex API.
|
|
39
39
|
|
|
40
|
-
Parameters
|
|
40
|
+
Parameters
|
|
41
41
|
search_keywords (str): Keywords to search for in title, abstract, and content.
|
|
42
42
|
max_results (int): Maximum number of results to return (default: 10).
|
|
43
43
|
year_from (int): Start year for publication date filter (optional).
|
|
44
44
|
year_to (int): End year for publication date filter (optional).
|
|
45
45
|
open_access (bool): Filter for open access papers only (optional).
|
|
46
46
|
|
|
47
|
-
Returns
|
|
47
|
+
Returns
|
|
48
48
|
list: List of dictionaries containing paper information.
|
|
49
49
|
"""
|
|
50
50
|
# Encode search keywords for URL
|
|
@@ -98,10 +98,10 @@ class OpenAlexTool(BaseTool):
|
|
|
98
98
|
"""
|
|
99
99
|
Extract relevant information from a work object returned by OpenAlex API.
|
|
100
100
|
|
|
101
|
-
Parameters
|
|
101
|
+
Parameters
|
|
102
102
|
work (dict): Work object from OpenAlex API response.
|
|
103
103
|
|
|
104
|
-
Returns
|
|
104
|
+
Returns
|
|
105
105
|
dict: Formatted paper information.
|
|
106
106
|
"""
|
|
107
107
|
# Extract title
|
|
@@ -204,10 +204,10 @@ class OpenAlexTool(BaseTool):
|
|
|
204
204
|
"""
|
|
205
205
|
Retrieve a specific paper by its DOI.
|
|
206
206
|
|
|
207
|
-
Parameters
|
|
207
|
+
Parameters
|
|
208
208
|
doi (str): DOI of the paper to retrieve.
|
|
209
209
|
|
|
210
|
-
Returns
|
|
210
|
+
Returns
|
|
211
211
|
dict: Paper information or None if not found.
|
|
212
212
|
"""
|
|
213
213
|
try:
|
|
@@ -229,11 +229,11 @@ class OpenAlexTool(BaseTool):
|
|
|
229
229
|
"""
|
|
230
230
|
Retrieve papers by a specific author.
|
|
231
231
|
|
|
232
|
-
Parameters
|
|
232
|
+
Parameters
|
|
233
233
|
author_name (str): Name of the author to search for.
|
|
234
234
|
max_results (int): Maximum number of results to return.
|
|
235
235
|
|
|
236
|
-
Returns
|
|
236
|
+
Returns
|
|
237
237
|
list: List of papers by the author.
|
|
238
238
|
"""
|
|
239
239
|
try:
|
tooluniverse/openfda_tool.py
CHANGED
|
@@ -85,11 +85,11 @@ def extract_sentences_with_keywords(text_list, keywords):
|
|
|
85
85
|
"""
|
|
86
86
|
Extracts sentences containing any of the specified keywords from the text.
|
|
87
87
|
|
|
88
|
-
Parameters
|
|
88
|
+
Parameters
|
|
89
89
|
- text (str): The input text from which to extract sentences.
|
|
90
90
|
- keywords (list): A list of keywords to search for in the text.
|
|
91
91
|
|
|
92
|
-
Returns
|
|
92
|
+
Returns
|
|
93
93
|
- list: A list of sentences containing any of the keywords.
|
|
94
94
|
"""
|
|
95
95
|
sentences_with_keywords = []
|
tooluniverse/output_hook.py
CHANGED
|
@@ -65,7 +65,7 @@ class HookRule:
|
|
|
65
65
|
arguments (Dict[str, Any]): Arguments passed to the tool
|
|
66
66
|
context (Dict[str, Any]): Additional context information
|
|
67
67
|
|
|
68
|
-
Returns
|
|
68
|
+
Returns
|
|
69
69
|
bool: True if conditions are met, False otherwise
|
|
70
70
|
"""
|
|
71
71
|
# Evaluate output length conditions
|
|
@@ -158,7 +158,7 @@ class OutputHook:
|
|
|
158
158
|
arguments (Dict[str, Any]): Arguments passed to the tool
|
|
159
159
|
context (Dict[str, Any]): Additional context information
|
|
160
160
|
|
|
161
|
-
Returns
|
|
161
|
+
Returns
|
|
162
162
|
bool: True if hook should trigger, False otherwise
|
|
163
163
|
"""
|
|
164
164
|
if not self.enabled:
|
|
@@ -184,7 +184,7 @@ class OutputHook:
|
|
|
184
184
|
arguments (Dict[str, Any]): Arguments passed to the tool
|
|
185
185
|
context (Dict[str, Any]): Additional context information
|
|
186
186
|
|
|
187
|
-
Returns
|
|
187
|
+
Returns
|
|
188
188
|
Any: The processed output
|
|
189
189
|
|
|
190
190
|
Raises:
|
|
@@ -290,7 +290,7 @@ class SummarizationHook(OutputHook):
|
|
|
290
290
|
arguments (Dict[str, Any]): Arguments passed to the tool
|
|
291
291
|
context (Dict[str, Any]): Additional context information
|
|
292
292
|
|
|
293
|
-
Returns
|
|
293
|
+
Returns
|
|
294
294
|
Any: The summarized output, or original output if summarization fails
|
|
295
295
|
"""
|
|
296
296
|
try:
|
|
@@ -408,7 +408,7 @@ class SummarizationHook(OutputHook):
|
|
|
408
408
|
Args:
|
|
409
409
|
context (Dict[str, Any]): Execution context containing arguments and metadata
|
|
410
410
|
|
|
411
|
-
Returns
|
|
411
|
+
Returns
|
|
412
412
|
str: Extracted query context or fallback description
|
|
413
413
|
"""
|
|
414
414
|
arguments = context.get("arguments", {})
|
|
@@ -519,7 +519,7 @@ class HookManager:
|
|
|
519
519
|
arguments (Dict[str, Any]): Arguments passed to the tool
|
|
520
520
|
context (Dict[str, Any]): Additional context information
|
|
521
521
|
|
|
522
|
-
Returns
|
|
522
|
+
Returns
|
|
523
523
|
Any: The processed output after applying all applicable hooks
|
|
524
524
|
"""
|
|
525
525
|
if not self.enabled:
|
|
@@ -553,7 +553,7 @@ class HookManager:
|
|
|
553
553
|
"""
|
|
554
554
|
Validate that LLM API keys are available for hook tools.
|
|
555
555
|
|
|
556
|
-
Returns
|
|
556
|
+
Returns
|
|
557
557
|
bool: True if API keys are available, False otherwise
|
|
558
558
|
"""
|
|
559
559
|
from .agentic_tool import AgenticTool
|
|
@@ -641,7 +641,7 @@ class HookManager:
|
|
|
641
641
|
Args:
|
|
642
642
|
hook_name (str): Name of the hook to retrieve
|
|
643
643
|
|
|
644
|
-
Returns
|
|
644
|
+
Returns
|
|
645
645
|
Optional[OutputHook]: Hook instance if found, None otherwise
|
|
646
646
|
"""
|
|
647
647
|
for hook in self.hooks:
|
|
@@ -684,7 +684,7 @@ class HookManager:
|
|
|
684
684
|
"""
|
|
685
685
|
Get the path to the hook configuration file.
|
|
686
686
|
|
|
687
|
-
Returns
|
|
687
|
+
Returns
|
|
688
688
|
Path: Path to the configuration file
|
|
689
689
|
"""
|
|
690
690
|
try:
|
|
@@ -934,7 +934,7 @@ class HookManager:
|
|
|
934
934
|
Args:
|
|
935
935
|
tool_name (str): Name of the tool to check
|
|
936
936
|
|
|
937
|
-
Returns
|
|
937
|
+
Returns
|
|
938
938
|
bool: True if the tool is a hook tool and should be excluded from hook processing
|
|
939
939
|
"""
|
|
940
940
|
hook_tool_names = [
|
|
@@ -956,7 +956,7 @@ class HookManager:
|
|
|
956
956
|
Args:
|
|
957
957
|
hook_config (Dict[str, Any]): Hook configuration
|
|
958
958
|
|
|
959
|
-
Returns
|
|
959
|
+
Returns
|
|
960
960
|
Optional[OutputHook]: Created hook instance or None if type not supported
|
|
961
961
|
"""
|
|
962
962
|
hook_type = hook_config.get("type", "SummarizationHook")
|
|
@@ -985,7 +985,7 @@ class HookManager:
|
|
|
985
985
|
Args:
|
|
986
986
|
hook_config (Dict[str, Any]): Original hook configuration
|
|
987
987
|
|
|
988
|
-
Returns
|
|
988
|
+
Returns
|
|
989
989
|
Dict[str, Any]: Enhanced configuration with defaults applied
|
|
990
990
|
"""
|
|
991
991
|
hook_type = hook_config.get("type", "SummarizationHook")
|
|
@@ -1052,7 +1052,7 @@ class HookManager:
|
|
|
1052
1052
|
tool_name (str): Name of the current tool
|
|
1053
1053
|
context (Dict[str, Any]): Execution context
|
|
1054
1054
|
|
|
1055
|
-
Returns
|
|
1055
|
+
Returns
|
|
1056
1056
|
bool: True if hook is applicable, False otherwise
|
|
1057
1057
|
"""
|
|
1058
1058
|
# Check tool-specific hooks
|
|
@@ -1138,7 +1138,7 @@ class FileSaveHook(OutputHook):
|
|
|
1138
1138
|
arguments (Dict[str, Any]): Arguments passed to the tool
|
|
1139
1139
|
context (Dict[str, Any]): Execution context
|
|
1140
1140
|
|
|
1141
|
-
Returns
|
|
1141
|
+
Returns
|
|
1142
1142
|
Dict[str, Any]: Dictionary containing file information:
|
|
1143
1143
|
- file_path: Path to the saved file
|
|
1144
1144
|
- data_format: Format of the data (json, text, binary, etc.)
|
|
@@ -1213,7 +1213,7 @@ class FileSaveHook(OutputHook):
|
|
|
1213
1213
|
Args:
|
|
1214
1214
|
data (Any): The data to analyze
|
|
1215
1215
|
|
|
1216
|
-
Returns
|
|
1216
|
+
Returns
|
|
1217
1217
|
tuple[str, str]: (data_format, data_structure)
|
|
1218
1218
|
"""
|
|
1219
1219
|
if isinstance(data, dict):
|
tooluniverse/package_tool.py
CHANGED
|
@@ -27,7 +27,7 @@ class PackageTool(BaseTool):
|
|
|
27
27
|
Args:
|
|
28
28
|
arguments (dict): Optional parameters for customization
|
|
29
29
|
|
|
30
|
-
Returns
|
|
30
|
+
Returns
|
|
31
31
|
dict: Package information including name, description, installation, docs, usage
|
|
32
32
|
"""
|
|
33
33
|
include_examples = arguments.get("include_examples", True)
|
tooluniverse/pmc_tool.py
CHANGED
|
@@ -43,7 +43,7 @@ class PMCTool(BaseTool):
|
|
|
43
43
|
date_to: End date filter (YYYY/MM/DD)
|
|
44
44
|
article_type: Article type filter (e.g., 'research-article', 'review')
|
|
45
45
|
|
|
46
|
-
Returns
|
|
46
|
+
Returns
|
|
47
47
|
List of paper dictionaries
|
|
48
48
|
"""
|
|
49
49
|
try:
|
|
@@ -158,7 +158,7 @@ class PMCTool(BaseTool):
|
|
|
158
158
|
Args:
|
|
159
159
|
tool_arguments: Dictionary containing search parameters
|
|
160
160
|
|
|
161
|
-
Returns
|
|
161
|
+
Returns
|
|
162
162
|
List of paper dictionaries
|
|
163
163
|
"""
|
|
164
164
|
query = tool_arguments.get("query", "")
|
|
@@ -35,7 +35,7 @@ def run_boltz2(query: dict):
|
|
|
35
35
|
- without_potentials (bool): Whether to run without potentials (default: False)
|
|
36
36
|
- diffusion_samples (int): Number of diffusion samples to generate (default: 1)
|
|
37
37
|
- Additional constraint keys may be included as needed
|
|
38
|
-
Returns
|
|
38
|
+
Returns
|
|
39
39
|
dict: A dictionary containing the docking results with the following structure:
|
|
40
40
|
- predicted_structure (str): The predicted protein-ligand complex structure in CIF format
|
|
41
41
|
- structure_format (str): Format of the structure file (typically 'cif')
|
|
@@ -163,7 +163,7 @@ class DepmapCorrelationTool:
|
|
|
163
163
|
gene_a (str): First gene symbol (e.g., 'BRAF', 'TP53'). Must be present in dataset.
|
|
164
164
|
gene_b (str): Second gene symbol (e.g., 'MAPK1', 'MDM2'). Must be present in dataset.
|
|
165
165
|
|
|
166
|
-
Returns
|
|
166
|
+
Returns
|
|
167
167
|
Dict[str, float]: Dictionary containing correlation analysis results:
|
|
168
168
|
- 'correlation': Pearson correlation coefficient (-1.0 to 1.0)
|
|
169
169
|
- 'p_value': Statistical significance of correlation
|
|
@@ -272,7 +272,7 @@ async def compute_depmap24q2_gene_correlations(
|
|
|
272
272
|
gene_b (str): Second gene symbol for correlation analysis (e.g., 'MAPK1', 'MDM2').
|
|
273
273
|
Must use standard HUGO gene nomenclature.
|
|
274
274
|
|
|
275
|
-
Returns
|
|
275
|
+
Returns
|
|
276
276
|
dict: Comprehensive correlation analysis results containing:
|
|
277
277
|
- 'correlation_data' (dict): Statistical measures including:
|
|
278
278
|
* 'correlation': Pearson correlation coefficient (-1.0 to 1.0)
|
|
@@ -118,7 +118,7 @@ class CompassTool:
|
|
|
118
118
|
exclude (List[str]): List of column names to exclude from results.
|
|
119
119
|
Defaults to ['CANCER', 'Reference'].
|
|
120
120
|
|
|
121
|
-
Returns
|
|
121
|
+
Returns
|
|
122
122
|
List[List[Tuple[str, float]]]: For each sample, a list of tuples containing
|
|
123
123
|
(concept_name, concept_score) sorted by score descending.
|
|
124
124
|
"""
|
|
@@ -161,7 +161,7 @@ class CompassTool:
|
|
|
161
161
|
batch_size (int): Batch size for model inference. Larger values may improve speed
|
|
162
162
|
but require more memory. Defaults to 128.
|
|
163
163
|
|
|
164
|
-
Returns
|
|
164
|
+
Returns
|
|
165
165
|
Tuple[bool, List[Tuple[str, float]]]: A tuple containing:
|
|
166
166
|
- bool: True if predicted as responder (probability ≥ threshold), False otherwise
|
|
167
167
|
- List[Tuple[str, float]]: Top immune cell concepts ranked by importance,
|
|
@@ -222,7 +222,7 @@ async def run_compass_prediction(
|
|
|
222
222
|
Default 0.5 provides balanced sensitivity/specificity.
|
|
223
223
|
Consider lower thresholds (~0.3) for higher sensitivity.
|
|
224
224
|
|
|
225
|
-
Returns
|
|
225
|
+
Returns
|
|
226
226
|
dict: Structured prediction results containing:
|
|
227
227
|
- 'prediction' (dict): Core prediction results with:
|
|
228
228
|
* 'is_responder' (bool): True if predicted responder (probability ≥ threshold)
|
|
@@ -101,7 +101,7 @@ class PinnaclePPITool:
|
|
|
101
101
|
The method handles various naming conventions including spaces,
|
|
102
102
|
hyphens, underscores, and capitalization differences.
|
|
103
103
|
|
|
104
|
-
Returns
|
|
104
|
+
Returns
|
|
105
105
|
Tuple[Dict[str, torch.Tensor], str]: A tuple containing:
|
|
106
106
|
- Dict mapping protein/gene names to their embedding tensors (empty if no match)
|
|
107
107
|
- Status message indicating match quality and selected cell type
|
|
@@ -198,7 +198,7 @@ async def run_pinnacle_ppi_retrieval(cell_type: str, embed_path: Optional[str] =
|
|
|
198
198
|
- Tissue types: 'liver', 'heart', 'brain', 'immune'
|
|
199
199
|
The tool performs intelligent matching to find the best available match.
|
|
200
200
|
|
|
201
|
-
Returns
|
|
201
|
+
Returns
|
|
202
202
|
dict: Comprehensive embedding retrieval results containing:
|
|
203
203
|
- 'embeddings' (dict, optional): Protein-to-embedding mapping where:
|
|
204
204
|
* Keys: Gene/protein symbols (e.g., 'TP53', 'EGFR', 'BRCA1')
|
|
@@ -105,7 +105,7 @@ class TranscriptformerEmbeddingTool:
|
|
|
105
105
|
Args:
|
|
106
106
|
disease (str): Disease identifier (normalized to lowercase with underscores).
|
|
107
107
|
|
|
108
|
-
Returns
|
|
108
|
+
Returns
|
|
109
109
|
Dict: Cached metadata dictionary containing:
|
|
110
110
|
- store_path: Path to disease-specific embedding store
|
|
111
111
|
- ensembl_ids_ordered: Ordered list of Ensembl gene IDs
|
|
@@ -213,7 +213,7 @@ class TranscriptformerEmbeddingTool:
|
|
|
213
213
|
disease (str): Disease context identifier (e.g., 'breast_cancer', 'diabetes').
|
|
214
214
|
Must match available disease stores.
|
|
215
215
|
|
|
216
|
-
Returns
|
|
216
|
+
Returns
|
|
217
217
|
Tuple[Optional[Dict[str, np.ndarray]], List[str]]: A tuple containing:
|
|
218
218
|
- Dictionary mapping gene names to embedding vectors (None if failed)
|
|
219
219
|
- List of context information and error messages
|
|
@@ -416,7 +416,7 @@ async def run_transcriptformer_embedding_retrieval(
|
|
|
416
416
|
- 'alzheimer': Alzheimer's disease contexts
|
|
417
417
|
Must match available disease stores.
|
|
418
418
|
|
|
419
|
-
Returns
|
|
419
|
+
Returns
|
|
420
420
|
dict: Comprehensive embedding retrieval results containing:
|
|
421
421
|
- 'embeddings' (dict, optional): Gene-to-embedding mapping where:
|
|
422
422
|
* Keys: Gene identifiers (symbols or Ensembl IDs as provided)
|
|
@@ -29,7 +29,7 @@ def download_abst(query: dict):
|
|
|
29
29
|
"""Retrieve the abstract of a patent application by its application number.
|
|
30
30
|
Args:
|
|
31
31
|
"query" dict: A dictionary containing the application number under the key "applicationNumberText".
|
|
32
|
-
Returns
|
|
32
|
+
Returns
|
|
33
33
|
dict: A dictionary containing the abstract text under the 'result' key or an error message under the 'error' key if the document could not be retrieved.
|
|
34
34
|
"""
|
|
35
35
|
return agents["get_abstract_from_patent_app_number"].run(query)
|
|
@@ -40,7 +40,7 @@ def download_claims(query: dict):
|
|
|
40
40
|
"""Retrieve the claims of a patent application by its application number.
|
|
41
41
|
Args:
|
|
42
42
|
"query" dict: A dictionary containing the application number under the key "applicationNumberText".
|
|
43
|
-
Returns
|
|
43
|
+
Returns
|
|
44
44
|
dict: A dictionary containing the claims text under the 'result' key or an error message under the 'error' key if the document could not be retrieved.
|
|
45
45
|
"""
|
|
46
46
|
return agents["get_claims_from_patent_app_number"].run(query)
|
|
@@ -51,7 +51,7 @@ def download_full_text(query: dict):
|
|
|
51
51
|
"""Retrieve the full text of a patent application by its application number.
|
|
52
52
|
Args:
|
|
53
53
|
"query" dict: A dictionary containing the application number under the key "applicationNumberText".
|
|
54
|
-
Returns
|
|
54
|
+
Returns
|
|
55
55
|
dict: A dictionary containing the full text under the 'result' key or an error message under the 'error' key if the document could not be retrieved.
|
|
56
56
|
"""
|
|
57
57
|
return agents["get_full_text_from_patent_app_number"].run(query)
|
tooluniverse/remote_tool.py
CHANGED
|
@@ -45,7 +45,7 @@ class RemoteTool(BaseTool):
|
|
|
45
45
|
Args:
|
|
46
46
|
arguments (dict, optional): Tool arguments (ignored)
|
|
47
47
|
|
|
48
|
-
Returns
|
|
48
|
+
Returns
|
|
49
49
|
dict: Error message indicating the tool is not available locally
|
|
50
50
|
"""
|
|
51
51
|
server_type = self.remote_info.get("server_type", "Unknown")
|
|
@@ -69,7 +69,7 @@ class RemoteTool(BaseTool):
|
|
|
69
69
|
"""
|
|
70
70
|
Get information about the remote server hosting this tool.
|
|
71
71
|
|
|
72
|
-
Returns
|
|
72
|
+
Returns
|
|
73
73
|
dict: Remote server information including server type, URL, and original tool type
|
|
74
74
|
"""
|
|
75
75
|
return self.remote_info.copy()
|
|
@@ -78,7 +78,7 @@ class RemoteTool(BaseTool):
|
|
|
78
78
|
"""
|
|
79
79
|
Check if this tool is available for local execution.
|
|
80
80
|
|
|
81
|
-
Returns
|
|
81
|
+
Returns
|
|
82
82
|
bool: Always False for RemoteTool instances
|
|
83
83
|
"""
|
|
84
84
|
return False
|
|
@@ -87,7 +87,7 @@ class RemoteTool(BaseTool):
|
|
|
87
87
|
"""
|
|
88
88
|
Get server connection information for this remote tool.
|
|
89
89
|
|
|
90
|
-
Returns
|
|
90
|
+
Returns
|
|
91
91
|
dict: Server connection details
|
|
92
92
|
"""
|
|
93
93
|
return {
|
|
@@ -46,7 +46,7 @@ def filter_tool_relationship_graph(data, valid_tool_names):
|
|
|
46
46
|
data: The loaded JSON data
|
|
47
47
|
valid_tool_names: Set of valid tool names
|
|
48
48
|
|
|
49
|
-
Returns
|
|
49
|
+
Returns
|
|
50
50
|
Filtered data
|
|
51
51
|
"""
|
|
52
52
|
if not isinstance(data, dict):
|
|
@@ -111,7 +111,7 @@ def filter_v4_all_tools(data, valid_tool_names):
|
|
|
111
111
|
data: The loaded JSON data
|
|
112
112
|
valid_tool_names: Set of valid tool names
|
|
113
113
|
|
|
114
|
-
Returns
|
|
114
|
+
Returns
|
|
115
115
|
Filtered data
|
|
116
116
|
"""
|
|
117
117
|
if not isinstance(data, list):
|
tooluniverse/smcp.py
CHANGED
|
@@ -10,8 +10,8 @@ The SMCP module provides a complete solution for exposing scientific computation
|
|
|
10
10
|
resources through the standardized MCP protocol, making it easy for AI agents to
|
|
11
11
|
discover, understand, and execute scientific tools in a unified manner.
|
|
12
12
|
|
|
13
|
-
Usage Patterns
|
|
14
|
-
|
|
13
|
+
Usage Patterns
|
|
14
|
+
--------------
|
|
15
15
|
|
|
16
16
|
Quick Start:
|
|
17
17
|
|
|
@@ -47,8 +47,8 @@ result = await client.call_tool("UniProt_get_entry_by_accession", {
|
|
|
47
47
|
})
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
Architecture
|
|
51
|
-
|
|
50
|
+
Architecture
|
|
51
|
+
------------
|
|
52
52
|
|
|
53
53
|
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
|
54
54
|
│ MCP Client │◄──►│ SMCP │◄──►│ ToolUniverse │
|
|
@@ -69,8 +69,8 @@ The SMCP server acts as an intelligent middleware layer that:
|
|
|
69
69
|
4. Returns formatted results via MCP protocol
|
|
70
70
|
5. Provides intelligent tool discovery and recommendation
|
|
71
71
|
|
|
72
|
-
Integration Points
|
|
73
|
-
|
|
72
|
+
Integration Points
|
|
73
|
+
------------------
|
|
74
74
|
|
|
75
75
|
MCP Protocol Layer:
|
|
76
76
|
- Standard MCP methods (tools/list, tools/call, etc.)
|
|
@@ -219,6 +219,21 @@ class SMCP(FastMCP):
|
|
|
219
219
|
during tool loading. Useful for excluding entire categories of tools
|
|
220
220
|
(e.g., all ToolFinder types or all OpenTarget tools).
|
|
221
221
|
|
|
222
|
+
space : str or list of str, optional
|
|
223
|
+
Space configuration URI(s) to load. Can be a single URI string or a list
|
|
224
|
+
of URIs for loading multiple Space configurations. Supported formats:
|
|
225
|
+
- Local file: "./config.yaml" or "/path/to/config.yaml"
|
|
226
|
+
- HuggingFace: "hf:username/repo" or "hf:username/repo/file.yaml"
|
|
227
|
+
- HTTP URL: "https://example.com/config.yaml"
|
|
228
|
+
|
|
229
|
+
When provided, Space configurations are loaded after tool initialization,
|
|
230
|
+
applying LLM settings, hooks, and tool selections from the configuration files.
|
|
231
|
+
Multiple spaces can be loaded sequentially, with later configurations
|
|
232
|
+
potentially overriding earlier ones.
|
|
233
|
+
|
|
234
|
+
Example: space="./my-workspace.yaml"
|
|
235
|
+
Example: space=["hf:community/bio-tools", "./custom-tools.yaml"]
|
|
236
|
+
|
|
222
237
|
auto_expose_tools : bool, default True
|
|
223
238
|
Whether to automatically expose ToolUniverse tools as MCP tools.
|
|
224
239
|
When True, all loaded tools become available via the MCP interface
|
|
@@ -281,6 +296,7 @@ class SMCP(FastMCP):
|
|
|
281
296
|
tool_config_files: Optional[Dict[str, str]] = None,
|
|
282
297
|
include_tool_types: Optional[List[str]] = None,
|
|
283
298
|
exclude_tool_types: Optional[List[str]] = None,
|
|
299
|
+
space: Optional[Union[str, List[str]]] = None,
|
|
284
300
|
auto_expose_tools: bool = True,
|
|
285
301
|
search_enabled: bool = True,
|
|
286
302
|
max_workers: int = 5,
|
|
@@ -325,6 +341,7 @@ class SMCP(FastMCP):
|
|
|
325
341
|
self.tool_config_files = tool_config_files or {}
|
|
326
342
|
self.include_tool_types = include_tool_types or []
|
|
327
343
|
self.exclude_tool_types = exclude_tool_types or []
|
|
344
|
+
self.space = space
|
|
328
345
|
self.auto_expose_tools = auto_expose_tools
|
|
329
346
|
self.search_enabled = search_enabled
|
|
330
347
|
self.max_workers = max_workers
|
|
@@ -332,18 +349,61 @@ class SMCP(FastMCP):
|
|
|
332
349
|
self.hook_config = hook_config
|
|
333
350
|
self.hook_type = hook_type
|
|
334
351
|
|
|
352
|
+
# Space configuration storage
|
|
353
|
+
self.space_llm_config = None
|
|
354
|
+
self.space_metadata = None
|
|
355
|
+
|
|
335
356
|
# Thread pool for concurrent tool execution
|
|
336
357
|
self.executor = ThreadPoolExecutor(max_workers=max_workers)
|
|
337
358
|
|
|
338
359
|
# Track exposed tools to avoid duplicates
|
|
339
360
|
self._exposed_tools = set()
|
|
340
361
|
|
|
341
|
-
#
|
|
362
|
+
# Load Space configurations first if provided
|
|
363
|
+
if space:
|
|
364
|
+
self._load_space_configs(space)
|
|
365
|
+
|
|
366
|
+
# Initialize SMCP-specific features (after Space is loaded)
|
|
342
367
|
self._setup_smcp_tools()
|
|
343
368
|
|
|
344
369
|
# Register custom MCP methods
|
|
345
370
|
self._register_custom_mcp_methods()
|
|
346
371
|
|
|
372
|
+
def _load_space_configs(self, space: Union[str, List[str]]):
|
|
373
|
+
"""
|
|
374
|
+
Load Space configurations.
|
|
375
|
+
|
|
376
|
+
This method loads Space configuration(s) and retrieves the LLM config
|
|
377
|
+
and metadata from ToolUniverse. It completely reuses ToolUniverse's
|
|
378
|
+
load_space functionality without reimplementing any logic.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
space: Space URI or list of URIs (e.g., "./config.yaml",
|
|
382
|
+
"hf:user/repo", or ["config1.yaml", "config2.yaml"])
|
|
383
|
+
"""
|
|
384
|
+
space_list = [space] if isinstance(space, str) else space
|
|
385
|
+
|
|
386
|
+
for uri in space_list:
|
|
387
|
+
print(f"📦 Loading Space: {uri}")
|
|
388
|
+
|
|
389
|
+
# Directly call ToolUniverse's method (complete reuse)
|
|
390
|
+
config = self.tooluniverse.load_space(uri)
|
|
391
|
+
|
|
392
|
+
# Get configurations from ToolUniverse (complete reuse)
|
|
393
|
+
self.space_metadata = self.tooluniverse.get_space_metadata()
|
|
394
|
+
self.space_llm_config = self.tooluniverse.get_space_llm_config()
|
|
395
|
+
|
|
396
|
+
print(f"✅ Space loaded: {config.get('name', 'Unknown')}")
|
|
397
|
+
|
|
398
|
+
def get_llm_config(self) -> Optional[Dict[str, Any]]:
|
|
399
|
+
"""
|
|
400
|
+
Get the current Space LLM configuration.
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
LLM configuration dictionary or None if not set
|
|
404
|
+
"""
|
|
405
|
+
return self.space_llm_config
|
|
406
|
+
|
|
347
407
|
def _register_custom_mcp_methods(self):
|
|
348
408
|
"""
|
|
349
409
|
Register custom MCP protocol methods for enhanced functionality.
|
|
@@ -857,9 +917,28 @@ class SMCP(FastMCP):
|
|
|
857
917
|
- All setup phases include comprehensive error handling
|
|
858
918
|
- Performance scales with the number of tools being loaded and exposed
|
|
859
919
|
"""
|
|
860
|
-
#
|
|
861
|
-
|
|
862
|
-
|
|
920
|
+
# Determine if ToolUniverse already has tools loaded (e.g., provided pre-configured instance)
|
|
921
|
+
preloaded_tools = getattr(self.tooluniverse, "all_tools", [])
|
|
922
|
+
preloaded_count = (
|
|
923
|
+
len(preloaded_tools) if isinstance(preloaded_tools, list) else 0
|
|
924
|
+
)
|
|
925
|
+
|
|
926
|
+
if preloaded_count > 0:
|
|
927
|
+
self.logger.info(
|
|
928
|
+
f"ToolUniverse already pre-configured with {preloaded_count} tool(s); skipping automatic loading."
|
|
929
|
+
)
|
|
930
|
+
|
|
931
|
+
# Check if Space has already loaded specific tools
|
|
932
|
+
if (
|
|
933
|
+
self.space
|
|
934
|
+
and hasattr(self.tooluniverse, "_current_space_config")
|
|
935
|
+
and preloaded_count > 0
|
|
936
|
+
):
|
|
937
|
+
# Space has already loaded specific tools, don't reload all tools
|
|
938
|
+
self.logger.info(
|
|
939
|
+
f"Space configuration loaded {preloaded_count} tool(s), skipping additional loading"
|
|
940
|
+
)
|
|
941
|
+
elif preloaded_count == 0 and self.tool_categories:
|
|
863
942
|
try:
|
|
864
943
|
# Validate categories first
|
|
865
944
|
valid_categories = self._get_valid_categories()
|
|
@@ -924,8 +1003,10 @@ class SMCP(FastMCP):
|
|
|
924
1003
|
include_tool_types=self.include_tool_types,
|
|
925
1004
|
exclude_tool_types=self.exclude_tool_types,
|
|
926
1005
|
)
|
|
927
|
-
elif self.auto_expose_tools
|
|
928
|
-
|
|
1006
|
+
elif self.auto_expose_tools and not (
|
|
1007
|
+
self.space and hasattr(self.tooluniverse, "_current_space_config")
|
|
1008
|
+
):
|
|
1009
|
+
# Load all tools by default (unless Space already handled tool loading)
|
|
929
1010
|
self.tooluniverse.load_tools(
|
|
930
1011
|
exclude_tools=self.exclude_tools,
|
|
931
1012
|
exclude_categories=self.exclude_categories,
|