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/humanbase_tool.py
CHANGED
|
@@ -35,19 +35,19 @@ class HumanBaseTool(BaseTool):
|
|
|
35
35
|
"""
|
|
36
36
|
Retrieve the official gene symbol (same as EnrichrTool method)
|
|
37
37
|
|
|
38
|
-
Parameters
|
|
38
|
+
Parameters
|
|
39
39
|
gene_name (str): The gene name or synonym to query.
|
|
40
40
|
|
|
41
|
-
Returns
|
|
41
|
+
Returns
|
|
42
42
|
str: The official gene symbol.
|
|
43
43
|
"""
|
|
44
44
|
"""
|
|
45
45
|
Retrieve the official gene symbol for a given gene name or synonym using the MyGene.info API.
|
|
46
46
|
|
|
47
|
-
Parameters
|
|
47
|
+
Parameters
|
|
48
48
|
gene_name (str): The gene name or synonym to query.
|
|
49
49
|
|
|
50
|
-
Returns
|
|
50
|
+
Returns
|
|
51
51
|
str: The official gene symbol if found; otherwise, raises an Exception.
|
|
52
52
|
"""
|
|
53
53
|
# URL-encode the gene_name to handle special characters
|
|
@@ -96,10 +96,10 @@ class HumanBaseTool(BaseTool):
|
|
|
96
96
|
"""
|
|
97
97
|
Convert gene names to Entrez IDs using NCBI Entrez API.
|
|
98
98
|
|
|
99
|
-
Parameters
|
|
99
|
+
Parameters
|
|
100
100
|
gene_names (list): List of gene names to convert.
|
|
101
101
|
|
|
102
|
-
Returns
|
|
102
|
+
Returns
|
|
103
103
|
list: List of Entrez IDs corresponding to the gene names.
|
|
104
104
|
"""
|
|
105
105
|
# Define the NCBI Entrez API URL for querying gene information
|
|
@@ -149,13 +149,13 @@ class HumanBaseTool(BaseTool):
|
|
|
149
149
|
"""
|
|
150
150
|
Retrieve protein-protein interactions and biological processes from HumanBase.
|
|
151
151
|
|
|
152
|
-
Parameters
|
|
152
|
+
Parameters
|
|
153
153
|
genes (list): List of gene names to analyze.
|
|
154
154
|
tissue (str): Tissue type for tissue-specific interactions.
|
|
155
155
|
max_node (int): Maximum number of nodes to retrieve.
|
|
156
156
|
interaction (str): Specific interaction type to filter by.
|
|
157
157
|
|
|
158
|
-
Returns
|
|
158
|
+
Returns
|
|
159
159
|
tuple: (NetworkX Graph of interactions, list of biological processes)
|
|
160
160
|
"""
|
|
161
161
|
genes = self.get_entrez_ids(genes)
|
|
@@ -243,13 +243,13 @@ class HumanBaseTool(BaseTool):
|
|
|
243
243
|
"""
|
|
244
244
|
Convert NetworkX graph and biological processes to string representation.
|
|
245
245
|
|
|
246
|
-
Parameters
|
|
246
|
+
Parameters
|
|
247
247
|
graph (networkx.Graph): The network graph.
|
|
248
248
|
bp_collection (list): List of biological processes.
|
|
249
249
|
original_genes (list): Original gene list provided by user.
|
|
250
250
|
tissue (str): Tissue type used for analysis.
|
|
251
251
|
|
|
252
|
-
Returns
|
|
252
|
+
Returns
|
|
253
253
|
str: Comprehensive string representation of the network data.
|
|
254
254
|
"""
|
|
255
255
|
output = []
|
tooluniverse/logging_config.py
CHANGED
|
@@ -232,7 +232,7 @@ def get_logger(name: Optional[str] = None) -> logging.Logger:
|
|
|
232
232
|
Args:
|
|
233
233
|
name (str, optional): Logger name (usually __name__)
|
|
234
234
|
|
|
235
|
-
Returns
|
|
235
|
+
Returns
|
|
236
236
|
logging.Logger: Logger instance
|
|
237
237
|
"""
|
|
238
238
|
return _logger_manager.get_logger(name)
|
|
@@ -291,7 +291,7 @@ def get_hook_logger(name: str = "HookManager") -> logging.Logger:
|
|
|
291
291
|
Args:
|
|
292
292
|
name (str): Name of the logger. Defaults to 'HookManager'
|
|
293
293
|
|
|
294
|
-
Returns
|
|
294
|
+
Returns
|
|
295
295
|
logging.Logger: Configured logger for hook operations
|
|
296
296
|
"""
|
|
297
297
|
return get_logger(name)
|
tooluniverse/mcp_client_tool.py
CHANGED
|
@@ -8,11 +8,11 @@ supporting all MCP functionality including tools, resources, and prompts.
|
|
|
8
8
|
import json
|
|
9
9
|
import asyncio
|
|
10
10
|
import websockets
|
|
11
|
-
import aiohttp
|
|
12
|
-
import uuid
|
|
13
11
|
from typing import Dict, List, Any, Optional
|
|
14
12
|
from urllib.parse import urljoin
|
|
15
13
|
import warnings
|
|
14
|
+
from mcp.client.session import ClientSession
|
|
15
|
+
from mcp.client.streamable_http import streamablehttp_client
|
|
16
16
|
from .base_tool import BaseTool
|
|
17
17
|
from .tool_registry import register_tool
|
|
18
18
|
import os
|
|
@@ -35,8 +35,6 @@ class BaseMCPClient:
|
|
|
35
35
|
self.transport = normalized_transport
|
|
36
36
|
self.timeout = timeout
|
|
37
37
|
self.session = None
|
|
38
|
-
self.mcp_session_id = None
|
|
39
|
-
self._initialized = False
|
|
40
38
|
|
|
41
39
|
# Validate transport (accept 'stdio' via normalization above)
|
|
42
40
|
supported_transports = ["http", "websocket"]
|
|
@@ -44,24 +42,9 @@ class BaseMCPClient:
|
|
|
44
42
|
# Keep message concise to satisfy line length rules
|
|
45
43
|
raise ValueError("Invalid transport")
|
|
46
44
|
|
|
47
|
-
async def _ensure_session(self):
|
|
48
|
-
"""Ensure HTTP session is available for HTTP transport"""
|
|
49
|
-
if self.transport == "http" and self.session is None:
|
|
50
|
-
connector = aiohttp.TCPConnector()
|
|
51
|
-
timeout = aiohttp.ClientTimeout(total=self.timeout)
|
|
52
|
-
self.session = aiohttp.ClientSession(connector=connector, timeout=timeout)
|
|
53
|
-
|
|
54
45
|
async def _close_session(self):
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
try:
|
|
58
|
-
await self.session.close()
|
|
59
|
-
except Exception:
|
|
60
|
-
pass # Ignore errors during cleanup
|
|
61
|
-
finally:
|
|
62
|
-
self.session = None
|
|
63
|
-
self.mcp_session_id = None
|
|
64
|
-
self._initialized = False
|
|
46
|
+
"""Placeholder for compatibility; HTTP client calls are scoped per request."""
|
|
47
|
+
return
|
|
65
48
|
|
|
66
49
|
def _get_mcp_endpoint(self, path: str) -> str:
|
|
67
50
|
"""Get the full MCP endpoint URL"""
|
|
@@ -72,115 +55,55 @@ class BaseMCPClient:
|
|
|
72
55
|
return urljoin(base_url + "/", path)
|
|
73
56
|
return self.server_url
|
|
74
57
|
|
|
75
|
-
async def _initialize_mcp_session(self):
|
|
76
|
-
"""Initialize MCP session if needed (for compatibility with different MCP servers)"""
|
|
77
|
-
if self._initialized:
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
await self._ensure_session()
|
|
81
|
-
|
|
82
|
-
# Try to get session ID from server
|
|
83
|
-
try:
|
|
84
|
-
url = f"{self.server_url.rstrip('/')}/mcp"
|
|
85
|
-
test_payload = {"jsonrpc": "2.0", "id": 1, "method": "tools/list"}
|
|
86
|
-
|
|
87
|
-
headers = {
|
|
88
|
-
"Content-Type": "application/json",
|
|
89
|
-
"Accept": "application/json, text/event-stream",
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async with self.session.post(
|
|
93
|
-
url, json=test_payload, headers=headers
|
|
94
|
-
) as response:
|
|
95
|
-
session_id = response.headers.get("mcp-session-id")
|
|
96
|
-
if session_id:
|
|
97
|
-
self.mcp_session_id = session_id
|
|
98
|
-
|
|
99
|
-
if response.status in [200, 400, 406, 500]:
|
|
100
|
-
self._initialized = True
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
except Exception:
|
|
104
|
-
pass
|
|
105
|
-
|
|
106
|
-
# Fallback: generate session ID
|
|
107
|
-
if not self.mcp_session_id:
|
|
108
|
-
self.mcp_session_id = str(uuid.uuid4()).replace("-", "")
|
|
109
|
-
|
|
110
|
-
self._initialized = True
|
|
111
|
-
|
|
112
58
|
async def _make_mcp_request(
|
|
113
59
|
self, method: str, params: Optional[Dict] = None
|
|
114
60
|
) -> Dict[str, Any]:
|
|
115
61
|
"""Make an MCP JSON-RPC request"""
|
|
116
|
-
request_id = "1"
|
|
117
|
-
|
|
118
|
-
payload = {"jsonrpc": "2.0", "id": request_id, "method": method}
|
|
119
|
-
|
|
120
|
-
if params:
|
|
121
|
-
payload["params"] = params
|
|
122
|
-
|
|
123
62
|
if self.transport == "http":
|
|
124
|
-
await self._ensure_session()
|
|
125
|
-
await self._initialize_mcp_session() # Ensure session is initialized
|
|
126
|
-
|
|
127
|
-
headers = {
|
|
128
|
-
"Content-Type": "application/json",
|
|
129
|
-
"Accept": "application/json, text/event-stream",
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
# Add session ID if available
|
|
133
|
-
if self.mcp_session_id:
|
|
134
|
-
headers["mcp-session-id"] = self.mcp_session_id
|
|
135
|
-
|
|
136
63
|
endpoint = self._get_mcp_endpoint("")
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
for line in response_text.split("\n"):
|
|
153
|
-
line = line.strip()
|
|
154
|
-
if line.startswith("data: "):
|
|
155
|
-
json_data = line[6:]
|
|
156
|
-
try:
|
|
157
|
-
result = json.loads(json_data)
|
|
158
|
-
break
|
|
159
|
-
except json.JSONDecodeError:
|
|
160
|
-
continue
|
|
161
|
-
else:
|
|
162
|
-
raise Exception(
|
|
163
|
-
f"Failed to parse SSE response: {response_text}"
|
|
64
|
+
async with streamablehttp_client(endpoint, timeout=self.timeout) as (
|
|
65
|
+
read_stream,
|
|
66
|
+
write_stream,
|
|
67
|
+
_,
|
|
68
|
+
):
|
|
69
|
+
async with ClientSession(read_stream, write_stream) as session:
|
|
70
|
+
await session.initialize()
|
|
71
|
+
|
|
72
|
+
if method == "tools/list":
|
|
73
|
+
result = await session.list_tools()
|
|
74
|
+
elif method == "tools/call":
|
|
75
|
+
if not params or "name" not in params:
|
|
76
|
+
raise ValueError("Missing tool name for tools/call")
|
|
77
|
+
result = await session.call_tool(
|
|
78
|
+
params["name"], params.get("arguments") or {}
|
|
164
79
|
)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
result = await
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
80
|
+
elif method == "resources/list":
|
|
81
|
+
result = await session.list_resources()
|
|
82
|
+
elif method == "resources/read":
|
|
83
|
+
if not params or "uri" not in params:
|
|
84
|
+
raise ValueError("Missing uri for resources/read")
|
|
85
|
+
result = await session.read_resource(params["uri"])
|
|
86
|
+
elif method == "prompts/list":
|
|
87
|
+
result = await session.list_prompts()
|
|
88
|
+
elif method == "prompts/get":
|
|
89
|
+
if not params or "name" not in params:
|
|
90
|
+
raise ValueError("Missing prompt name for prompts/get")
|
|
91
|
+
result = await session.get_prompt(
|
|
92
|
+
params["name"], params.get("arguments")
|
|
175
93
|
)
|
|
94
|
+
else:
|
|
95
|
+
raise ValueError(f"Unsupported MCP method: {method}")
|
|
176
96
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return result.get("result", {})
|
|
97
|
+
if hasattr(result, "model_dump"):
|
|
98
|
+
return result.model_dump(mode="json")
|
|
99
|
+
return result
|
|
181
100
|
|
|
182
101
|
elif self.transport == "websocket":
|
|
183
102
|
async with websockets.connect(self.server_url) as websocket:
|
|
103
|
+
request_id = "1"
|
|
104
|
+
payload = {"jsonrpc": "2.0", "id": request_id, "method": method}
|
|
105
|
+
if params:
|
|
106
|
+
payload["params"] = params
|
|
184
107
|
await websocket.send(json.dumps(payload))
|
|
185
108
|
response = await websocket.recv()
|
|
186
109
|
result = json.loads(response)
|
|
@@ -575,7 +498,6 @@ class MCPAutoLoaderTool(BaseTool, BaseMCPClient):
|
|
|
575
498
|
async def discover_tools(self) -> Dict[str, Any]:
|
|
576
499
|
"""Discover all available tools from the MCP server"""
|
|
577
500
|
try:
|
|
578
|
-
await self._initialize_mcp_session()
|
|
579
501
|
tools_response = await self._make_mcp_request("tools/list")
|
|
580
502
|
tools = tools_response.get("tools", [])
|
|
581
503
|
|
|
@@ -631,22 +553,28 @@ class MCPAutoLoaderTool(BaseTool, BaseMCPClient):
|
|
|
631
553
|
return configs
|
|
632
554
|
|
|
633
555
|
def register_tools_in_engine(self, engine):
|
|
634
|
-
"""Register discovered tools
|
|
556
|
+
"""Register discovered tools using ToolUniverse public API"""
|
|
635
557
|
try:
|
|
636
558
|
configs = self.generate_proxy_tool_configs()
|
|
637
559
|
|
|
638
560
|
for config in configs:
|
|
639
|
-
|
|
640
|
-
|
|
561
|
+
config["type"]
|
|
562
|
+
tool_name = config["name"]
|
|
641
563
|
|
|
642
|
-
#
|
|
643
|
-
|
|
564
|
+
# Use public API to register tool
|
|
565
|
+
engine.register_custom_tool(
|
|
566
|
+
tool_class=MCPProxyTool,
|
|
567
|
+
tool_name=tool_name,
|
|
568
|
+
tool_config=config,
|
|
569
|
+
instantiate=True, # Immediately instantiate and cache
|
|
570
|
+
)
|
|
644
571
|
|
|
645
|
-
#
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
572
|
+
# Keep reference for tracking
|
|
573
|
+
# Use the actual key that register_custom_tool uses
|
|
574
|
+
actual_key = config.get("name", tool_name)
|
|
575
|
+
self._registered_tools[tool_name] = engine.callable_functions[
|
|
576
|
+
actual_key
|
|
577
|
+
]
|
|
650
578
|
|
|
651
579
|
return len(configs)
|
|
652
580
|
except Exception as e:
|
tooluniverse/mcp_integration.py
CHANGED
|
@@ -16,8 +16,8 @@ def load_mcp_tools(self, server_urls: List[str] = None, **kwargs):
|
|
|
16
16
|
This method automatically discovers tools from MCP servers and registers them
|
|
17
17
|
as ToolUniverse tools, enabling seamless usage of remote capabilities.
|
|
18
18
|
|
|
19
|
-
Parameters
|
|
20
|
-
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
21
|
server_urls : list of str, optional
|
|
22
22
|
List of MCP server URLs to load tools from. Examples:
|
|
23
23
|
|
|
@@ -35,31 +35,34 @@ def load_mcp_tools(self, server_urls: List[str] = None, **kwargs):
|
|
|
35
35
|
- selected_tools (list): Specific tools to load from each server
|
|
36
36
|
- categories (list): Tool categories to filter by
|
|
37
37
|
|
|
38
|
-
Returns
|
|
39
|
-
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
40
|
dict
|
|
41
41
|
Summary of loaded tools with counts and any errors encountered.
|
|
42
42
|
|
|
43
|
-
Examples
|
|
44
|
-
|
|
43
|
+
Examples
|
|
44
|
+
--------
|
|
45
45
|
|
|
46
46
|
Load from specific servers:
|
|
47
|
-
```python
|
|
48
|
-
tu = ToolUniverse()
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
result = tu.load_mcp_tools([
|
|
52
|
-
"http://localhost:8001", # Local analysis server
|
|
53
|
-
"http://ml-server:8002", # Remote ML server
|
|
54
|
-
"ws://realtime:9000" # WebSocket server
|
|
55
|
-
])
|
|
48
|
+
.. code-block:: python
|
|
56
49
|
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
tu = ToolUniverse()
|
|
51
|
+
|
|
52
|
+
# Load tools from multiple MCP servers
|
|
53
|
+
result = tu.load_mcp_tools([
|
|
54
|
+
"http://localhost:8001", # Local analysis server
|
|
55
|
+
"http://ml-server:8002", # Remote ML server
|
|
56
|
+
"ws://realtime:9000" # WebSocket server
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
print(f"Loaded {result['total_tools']} tools from {result['servers_connected']} servers")
|
|
59
60
|
|
|
60
61
|
Load with custom configuration:
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
|
|
63
|
+
.. code-block:: python
|
|
64
|
+
|
|
65
|
+
tu.load_mcp_tools(
|
|
63
66
|
server_urls=["http://localhost:8001"],
|
|
64
67
|
tool_prefix="analysis\\_",
|
|
65
68
|
timeout=60,
|
|
@@ -223,8 +226,8 @@ def discover_mcp_tools(self, server_urls: List[str] = None, **kwargs) -> Dict[st
|
|
|
223
226
|
without actually registering them in ToolUniverse. Useful for exploration
|
|
224
227
|
and selective tool loading.
|
|
225
228
|
|
|
226
|
-
Parameters
|
|
227
|
-
|
|
229
|
+
Parameters
|
|
230
|
+
----------
|
|
228
231
|
server_urls : list of str, optional
|
|
229
232
|
List of MCP server URLs to discover from
|
|
230
233
|
**kwargs
|
|
@@ -232,28 +235,28 @@ def discover_mcp_tools(self, server_urls: List[str] = None, **kwargs) -> Dict[st
|
|
|
232
235
|
- timeout (int): Connection timeout (default: 30)
|
|
233
236
|
- include_schemas (bool): Include tool parameter schemas (default: True)
|
|
234
237
|
|
|
235
|
-
Returns
|
|
236
|
-
|
|
238
|
+
Returns
|
|
239
|
+
-------
|
|
237
240
|
dict
|
|
238
241
|
Discovery results with tools organized by server
|
|
239
242
|
|
|
240
|
-
Examples
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
243
|
+
Examples
|
|
244
|
+
--------
|
|
245
|
+
.. code-block:: python
|
|
246
|
+
|
|
247
|
+
tu = ToolUniverse()
|
|
248
|
+
|
|
249
|
+
# Discover what's available
|
|
250
|
+
discovery = tu.discover_mcp_tools([
|
|
251
|
+
"http://localhost:8001",
|
|
252
|
+
"http://ml-server:8002"
|
|
253
|
+
])
|
|
254
|
+
|
|
255
|
+
# Show available tools
|
|
256
|
+
for server, info in discovery["servers"].items():
|
|
257
|
+
print(f"\\n{server}:")
|
|
258
|
+
for tool in info.get("tools", []):
|
|
259
|
+
print(f" - {tool['name']}: {tool['description']}")
|
|
257
260
|
"""
|
|
258
261
|
if server_urls is None:
|
|
259
262
|
try:
|
|
@@ -334,20 +337,20 @@ def list_mcp_connections(self) -> Dict[str, Any]:
|
|
|
334
337
|
"""
|
|
335
338
|
List all active MCP connections and loaded tools.
|
|
336
339
|
|
|
337
|
-
Returns
|
|
338
|
-
|
|
340
|
+
Returns
|
|
341
|
+
-------
|
|
339
342
|
dict
|
|
340
343
|
Information about MCP connections, auto-loaders, and loaded tools
|
|
341
344
|
|
|
342
|
-
Examples
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
tu = ToolUniverse()
|
|
346
|
-
tu.load_mcp_tools(["http://localhost:8001"])
|
|
345
|
+
Examples
|
|
346
|
+
--------
|
|
347
|
+
.. code-block:: python
|
|
347
348
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
349
|
+
tu = ToolUniverse()
|
|
350
|
+
tu.load_mcp_tools(["http://localhost:8001"])
|
|
351
|
+
|
|
352
|
+
connections = tu.list_mcp_connections()
|
|
353
|
+
print(f"Active MCP connections: {len(connections['connections'])}")
|
|
351
354
|
"""
|
|
352
355
|
mcp_tools = {}
|
|
353
356
|
mcp_loaders = {}
|