tooluniverse 1.0.9.1__py3-none-any.whl → 1.0.11__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.

Files changed (191) hide show
  1. tooluniverse/__init__.py +57 -1
  2. tooluniverse/admetai_tool.py +1 -1
  3. tooluniverse/agentic_tool.py +65 -17
  4. tooluniverse/base_tool.py +19 -8
  5. tooluniverse/blast_tool.py +132 -0
  6. tooluniverse/boltz_tool.py +3 -3
  7. tooluniverse/cache/result_cache_manager.py +167 -12
  8. tooluniverse/cbioportal_tool.py +42 -0
  9. tooluniverse/clinvar_tool.py +268 -74
  10. tooluniverse/compose_scripts/drug_safety_analyzer.py +1 -1
  11. tooluniverse/compose_scripts/multi_agent_literature_search.py +1 -1
  12. tooluniverse/compose_scripts/output_summarizer.py +4 -4
  13. tooluniverse/compose_scripts/tool_discover.py +1941 -443
  14. tooluniverse/compose_scripts/tool_graph_composer.py +1 -1
  15. tooluniverse/compose_scripts/tool_metadata_generator.py +1 -1
  16. tooluniverse/compose_tool.py +9 -9
  17. tooluniverse/core_tool.py +2 -2
  18. tooluniverse/ctg_tool.py +4 -4
  19. tooluniverse/custom_tool.py +1 -1
  20. tooluniverse/data/agentic_tools.json +0 -370
  21. tooluniverse/data/alphafold_tools.json +6 -6
  22. tooluniverse/data/blast_tools.json +112 -0
  23. tooluniverse/data/cbioportal_tools.json +87 -0
  24. tooluniverse/data/clinvar_tools.json +235 -0
  25. tooluniverse/data/compose_tools.json +0 -89
  26. tooluniverse/data/dbsnp_tools.json +275 -0
  27. tooluniverse/data/emdb_tools.json +61 -0
  28. tooluniverse/data/ensembl_tools.json +259 -0
  29. tooluniverse/data/file_download_tools.json +275 -0
  30. tooluniverse/data/geo_tools.json +200 -48
  31. tooluniverse/data/gnomad_tools.json +109 -0
  32. tooluniverse/data/gtopdb_tools.json +68 -0
  33. tooluniverse/data/gwas_tools.json +32 -0
  34. tooluniverse/data/interpro_tools.json +199 -0
  35. tooluniverse/data/jaspar_tools.json +70 -0
  36. tooluniverse/data/kegg_tools.json +356 -0
  37. tooluniverse/data/mpd_tools.json +87 -0
  38. tooluniverse/data/ols_tools.json +314 -0
  39. tooluniverse/data/package_discovery_tools.json +64 -0
  40. tooluniverse/data/packages/categorized_tools.txt +0 -1
  41. tooluniverse/data/packages/machine_learning_tools.json +0 -47
  42. tooluniverse/data/paleobiology_tools.json +91 -0
  43. tooluniverse/data/pride_tools.json +62 -0
  44. tooluniverse/data/pypi_package_inspector_tools.json +158 -0
  45. tooluniverse/data/python_executor_tools.json +341 -0
  46. tooluniverse/data/regulomedb_tools.json +50 -0
  47. tooluniverse/data/remap_tools.json +89 -0
  48. tooluniverse/data/screen_tools.json +89 -0
  49. tooluniverse/data/tool_discovery_agents.json +428 -0
  50. tooluniverse/data/tool_discovery_agents.json.backup +1343 -0
  51. tooluniverse/data/uniprot_tools.json +77 -0
  52. tooluniverse/data/web_search_tools.json +250 -0
  53. tooluniverse/data/worms_tools.json +55 -0
  54. tooluniverse/dataset_tool.py +2 -2
  55. tooluniverse/dbsnp_tool.py +196 -58
  56. tooluniverse/default_config.py +36 -3
  57. tooluniverse/emdb_tool.py +30 -0
  58. tooluniverse/enrichr_tool.py +14 -14
  59. tooluniverse/ensembl_tool.py +140 -47
  60. tooluniverse/execute_function.py +594 -29
  61. tooluniverse/extended_hooks.py +4 -4
  62. tooluniverse/file_download_tool.py +269 -0
  63. tooluniverse/gene_ontology_tool.py +1 -1
  64. tooluniverse/generate_tools.py +3 -3
  65. tooluniverse/geo_tool.py +81 -28
  66. tooluniverse/gnomad_tool.py +100 -52
  67. tooluniverse/gtopdb_tool.py +41 -0
  68. tooluniverse/humanbase_tool.py +10 -10
  69. tooluniverse/interpro_tool.py +72 -0
  70. tooluniverse/jaspar_tool.py +30 -0
  71. tooluniverse/kegg_tool.py +230 -0
  72. tooluniverse/logging_config.py +2 -2
  73. tooluniverse/mcp_client_tool.py +57 -129
  74. tooluniverse/mcp_integration.py +52 -49
  75. tooluniverse/mcp_tool_registry.py +147 -528
  76. tooluniverse/mpd_tool.py +42 -0
  77. tooluniverse/ncbi_eutils_tool.py +96 -0
  78. tooluniverse/ols_tool.py +435 -0
  79. tooluniverse/openalex_tool.py +8 -8
  80. tooluniverse/openfda_tool.py +2 -2
  81. tooluniverse/output_hook.py +15 -15
  82. tooluniverse/package_discovery_tool.py +217 -0
  83. tooluniverse/package_tool.py +1 -1
  84. tooluniverse/paleobiology_tool.py +30 -0
  85. tooluniverse/pmc_tool.py +2 -2
  86. tooluniverse/pride_tool.py +30 -0
  87. tooluniverse/pypi_package_inspector_tool.py +593 -0
  88. tooluniverse/python_executor_tool.py +711 -0
  89. tooluniverse/regulomedb_tool.py +30 -0
  90. tooluniverse/remap_tool.py +44 -0
  91. tooluniverse/remote/boltz/boltz_mcp_server.py +1 -1
  92. tooluniverse/remote/depmap_24q2/depmap_24q2_mcp_tool.py +3 -3
  93. tooluniverse/remote/immune_compass/compass_tool.py +3 -3
  94. tooluniverse/remote/pinnacle/pinnacle_tool.py +2 -2
  95. tooluniverse/remote/transcriptformer/transcriptformer_tool.py +3 -3
  96. tooluniverse/remote/uspto_downloader/uspto_downloader_mcp_server.py +3 -3
  97. tooluniverse/remote_tool.py +4 -4
  98. tooluniverse/screen_tool.py +44 -0
  99. tooluniverse/scripts/filter_tool_files.py +2 -2
  100. tooluniverse/smcp.py +93 -12
  101. tooluniverse/smcp_server.py +100 -21
  102. tooluniverse/space/__init__.py +46 -0
  103. tooluniverse/space/loader.py +133 -0
  104. tooluniverse/space/validator.py +353 -0
  105. tooluniverse/tool_finder_embedding.py +5 -3
  106. tooluniverse/tool_finder_keyword.py +12 -10
  107. tooluniverse/tool_finder_llm.py +12 -8
  108. tooluniverse/tools/{UCSC_get_genes_by_region.py → BLAST_nucleotide_search.py} +22 -26
  109. tooluniverse/tools/BLAST_protein_search.py +63 -0
  110. tooluniverse/tools/ClinVar_search_variants.py +26 -15
  111. tooluniverse/tools/CodeQualityAnalyzer.py +3 -3
  112. tooluniverse/tools/EMDB_get_structure.py +46 -0
  113. tooluniverse/tools/GtoPdb_get_targets.py +52 -0
  114. tooluniverse/tools/InterPro_get_domain_details.py +46 -0
  115. tooluniverse/tools/InterPro_get_protein_domains.py +49 -0
  116. tooluniverse/tools/InterPro_search_domains.py +52 -0
  117. tooluniverse/tools/JASPAR_get_transcription_factors.py +52 -0
  118. tooluniverse/tools/MPD_get_phenotype_data.py +59 -0
  119. tooluniverse/tools/PRIDE_search_proteomics.py +52 -0
  120. tooluniverse/tools/PackageAnalyzer.py +55 -0
  121. tooluniverse/tools/Paleobiology_get_fossils.py +52 -0
  122. tooluniverse/tools/PyPIPackageInspector.py +59 -0
  123. tooluniverse/tools/ReMap_get_transcription_factor_binding.py +59 -0
  124. tooluniverse/tools/ReferenceInfoAnalyzer.py +55 -0
  125. tooluniverse/tools/RegulomeDB_query_variant.py +46 -0
  126. tooluniverse/tools/SCREEN_get_regulatory_elements.py +59 -0
  127. tooluniverse/tools/{ArgumentDescriptionOptimizer.py → TestResultsAnalyzer.py} +13 -13
  128. tooluniverse/tools/ToolDiscover.py +11 -11
  129. tooluniverse/tools/UniProt_id_mapping.py +63 -0
  130. tooluniverse/tools/UniProt_search.py +63 -0
  131. tooluniverse/tools/UnifiedToolGenerator.py +59 -0
  132. tooluniverse/tools/WoRMS_search_species.py +49 -0
  133. tooluniverse/tools/XMLToolOptimizer.py +55 -0
  134. tooluniverse/tools/__init__.py +119 -29
  135. tooluniverse/tools/_shared_client.py +3 -3
  136. tooluniverse/tools/alphafold_get_annotations.py +3 -3
  137. tooluniverse/tools/alphafold_get_prediction.py +3 -3
  138. tooluniverse/tools/alphafold_get_summary.py +3 -3
  139. tooluniverse/tools/cBioPortal_get_cancer_studies.py +46 -0
  140. tooluniverse/tools/cBioPortal_get_mutations.py +52 -0
  141. tooluniverse/tools/{gnomAD_query_variant.py → clinvar_get_clinical_significance.py} +8 -11
  142. tooluniverse/tools/clinvar_get_variant_details.py +49 -0
  143. tooluniverse/tools/dbSNP_get_variant_by_rsid.py +7 -7
  144. tooluniverse/tools/dbsnp_get_frequencies.py +46 -0
  145. tooluniverse/tools/dbsnp_search_by_gene.py +52 -0
  146. tooluniverse/tools/download_binary_file.py +66 -0
  147. tooluniverse/tools/download_file.py +71 -0
  148. tooluniverse/tools/download_text_content.py +55 -0
  149. tooluniverse/tools/dynamic_package_discovery.py +59 -0
  150. tooluniverse/tools/ensembl_get_sequence.py +52 -0
  151. tooluniverse/tools/{Ensembl_lookup_gene_by_symbol.py → ensembl_get_variants.py} +11 -11
  152. tooluniverse/tools/ensembl_lookup_gene.py +46 -0
  153. tooluniverse/tools/geo_get_dataset_info.py +46 -0
  154. tooluniverse/tools/geo_get_sample_info.py +46 -0
  155. tooluniverse/tools/geo_search_datasets.py +67 -0
  156. tooluniverse/tools/gnomad_get_gene_constraints.py +49 -0
  157. tooluniverse/tools/kegg_find_genes.py +52 -0
  158. tooluniverse/tools/kegg_get_gene_info.py +46 -0
  159. tooluniverse/tools/kegg_get_pathway_info.py +46 -0
  160. tooluniverse/tools/kegg_list_organisms.py +44 -0
  161. tooluniverse/tools/kegg_search_pathway.py +46 -0
  162. tooluniverse/tools/ols_find_similar_terms.py +63 -0
  163. tooluniverse/tools/{get_hyperopt_info.py → ols_get_ontology_info.py} +13 -10
  164. tooluniverse/tools/ols_get_term_ancestors.py +67 -0
  165. tooluniverse/tools/ols_get_term_children.py +67 -0
  166. tooluniverse/tools/{TestCaseGenerator.py → ols_get_term_info.py} +12 -9
  167. tooluniverse/tools/{CodeOptimizer.py → ols_search_ontologies.py} +22 -14
  168. tooluniverse/tools/ols_search_terms.py +71 -0
  169. tooluniverse/tools/python_code_executor.py +79 -0
  170. tooluniverse/tools/python_script_runner.py +79 -0
  171. tooluniverse/tools/web_api_documentation_search.py +63 -0
  172. tooluniverse/tools/web_search.py +71 -0
  173. tooluniverse/uniprot_tool.py +219 -16
  174. tooluniverse/url_tool.py +19 -1
  175. tooluniverse/uspto_tool.py +1 -1
  176. tooluniverse/utils.py +12 -12
  177. tooluniverse/web_search_tool.py +229 -0
  178. tooluniverse/worms_tool.py +64 -0
  179. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/METADATA +8 -3
  180. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/RECORD +184 -92
  181. tooluniverse/data/genomics_tools.json +0 -174
  182. tooluniverse/tools/ToolDescriptionOptimizer.py +0 -67
  183. tooluniverse/tools/ToolImplementationGenerator.py +0 -67
  184. tooluniverse/tools/ToolOptimizer.py +0 -59
  185. tooluniverse/tools/ToolSpecificationGenerator.py +0 -67
  186. tooluniverse/tools/ToolSpecificationOptimizer.py +0 -63
  187. tooluniverse/ucsc_tool.py +0 -60
  188. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/WHEEL +0 -0
  189. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/entry_points.txt +0 -0
  190. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/licenses/LICENSE +0 -0
  191. {tooluniverse-1.0.9.1.dist-info → tooluniverse-1.0.11.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,30 @@
1
+ import requests
2
+ from typing import Any, Dict
3
+ from .base_tool import BaseTool
4
+ from .tool_registry import register_tool
5
+
6
+
7
+ @register_tool("RegulomeDBRESTTool")
8
+ class RegulomeDBRESTTool(BaseTool):
9
+ def __init__(self, tool_config: Dict):
10
+ super().__init__(tool_config)
11
+ self.base_url = "https://regulomedb.org"
12
+ self.session = requests.Session()
13
+ self.session.headers.update({"Accept": "application/json"})
14
+ self.timeout = 30
15
+
16
+ def _build_url(self, args: Dict[str, Any]) -> str:
17
+ url = self.tool_config["fields"]["endpoint"]
18
+ for k, v in args.items():
19
+ url = url.replace(f"{{{k}}}", str(v))
20
+ return url
21
+
22
+ def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
23
+ try:
24
+ url = self._build_url(arguments)
25
+ response = self.session.get(url, timeout=self.timeout)
26
+ response.raise_for_status()
27
+ data = response.json()
28
+ return {"status": "success", "data": data, "url": url}
29
+ except Exception as e:
30
+ return {"status": "error", "error": f"RegulomeDB API error: {str(e)}"}
@@ -0,0 +1,44 @@
1
+ import requests
2
+ from typing import Any, Dict
3
+ from .base_tool import BaseTool
4
+ from .tool_registry import register_tool
5
+
6
+
7
+ @register_tool("ReMapRESTTool")
8
+ class ReMapRESTTool(BaseTool):
9
+ def __init__(self, tool_config: Dict):
10
+ super().__init__(tool_config)
11
+ self.session = requests.Session()
12
+ self.session.headers.update({"Accept": "application/json"})
13
+ self.timeout = 30
14
+
15
+ def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
16
+ try:
17
+ # Use ENCODE as alternative data source for ChIP-seq data
18
+ chromosome = arguments.get("chromosome", "chr1")
19
+ start = arguments.get("start", 1000000)
20
+ end = arguments.get("end", 2000000)
21
+
22
+ # Build ENCODE API URL for experiments
23
+ # Query for general experiments as ReMap alternative
24
+ url = "https://www.encodeproject.org/search/?type=Experiment&format=json&limit=10"
25
+
26
+ response = self.session.get(url, timeout=self.timeout)
27
+ response.raise_for_status()
28
+
29
+ # Parse JSON response
30
+ data = response.json()
31
+
32
+ return {
33
+ "status": "success",
34
+ "data": data,
35
+ "url": url,
36
+ "query_info": {
37
+ "chromosome": chromosome,
38
+ "start": start,
39
+ "end": end,
40
+ "data_source": "ENCODE (ReMap alternative)",
41
+ },
42
+ }
43
+ except Exception as e:
44
+ return {"status": "error", "error": f"ReMap API error: {str(e)}"}
@@ -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')
@@ -96,7 +96,7 @@ class DepmapCorrelationTool:
96
96
  else:
97
97
  # Fallback to text file format
98
98
  gene_names_path = os.path.join(self.data_dir, "gene_names.txt")
99
- with open(gene_names_path, "r") as f:
99
+ with open(gene_names_path, "r", encoding="utf-8") as f:
100
100
  self.gene_names = np.array([line.strip() for line in f])
101
101
 
102
102
  # Create bidirectional mapping for efficient gene symbol lookups
@@ -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)
@@ -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 {
@@ -0,0 +1,44 @@
1
+ import requests
2
+ from typing import Any, Dict
3
+ from .base_tool import BaseTool
4
+ from .tool_registry import register_tool
5
+
6
+
7
+ @register_tool("SCREENRESTTool")
8
+ class SCREENRESTTool(BaseTool):
9
+ def __init__(self, tool_config: Dict):
10
+ super().__init__(tool_config)
11
+ self.session = requests.Session()
12
+ self.session.headers.update({"Accept": "application/json"})
13
+ self.timeout = 30
14
+
15
+ def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
16
+ try:
17
+ # Use ENCODE as alternative data source for regulatory elements
18
+ chromosome = arguments.get("chromosome", "chr1")
19
+ start = arguments.get("start", 1000000)
20
+ end = arguments.get("end", 2000000)
21
+
22
+ # Build ENCODE API URL for experiments
23
+ # Query for general experiments as SCREEN alternative
24
+ url = "https://www.encodeproject.org/search/?type=Experiment&format=json&limit=10"
25
+
26
+ response = self.session.get(url, timeout=self.timeout)
27
+ response.raise_for_status()
28
+
29
+ # Parse JSON response
30
+ data = response.json()
31
+
32
+ return {
33
+ "status": "success",
34
+ "data": data,
35
+ "url": url,
36
+ "query_info": {
37
+ "chromosome": chromosome,
38
+ "start": start,
39
+ "end": end,
40
+ "data_source": "ENCODE (SCREEN alternative)",
41
+ },
42
+ }
43
+ except Exception as e:
44
+ return {"status": "error", "error": f"SCREEN API error: {str(e)}"}
@@ -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
- # Initialize SMCP-specific features
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
- # Always ensure full tool set is loaded (hooks may have preloaded a minimal set)
861
- # Deduplication in ToolUniverse.load_tools prevents duplicates, so reloading is safe
862
- if self.tool_categories:
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
- # Load all tools by default
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,