swarms 7.7.9__py3-none-any.whl → 7.8.1__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.
- swarms/agents/self_agent_builder.py +40 -0
- swarms/prompts/agent_self_builder_prompt.py +103 -0
- swarms/schemas/__init__.py +6 -1
- swarms/schemas/agent_class_schema.py +91 -0
- swarms/schemas/agent_mcp_errors.py +18 -0
- swarms/schemas/agent_tool_schema.py +13 -0
- swarms/schemas/llm_agent_schema.py +92 -0
- swarms/schemas/mcp_schemas.py +43 -0
- swarms/structs/__init__.py +4 -0
- swarms/structs/agent.py +305 -262
- swarms/structs/aop.py +3 -1
- swarms/structs/batch_agent_execution.py +64 -0
- swarms/structs/conversation.py +33 -19
- swarms/structs/council_judge.py +179 -93
- swarms/structs/long_agent.py +424 -0
- swarms/structs/ma_utils.py +11 -8
- swarms/structs/malt.py +1 -1
- swarms/structs/swarm_router.py +71 -15
- swarms/tools/__init__.py +12 -0
- swarms/tools/base_tool.py +2840 -264
- swarms/tools/create_agent_tool.py +104 -0
- swarms/tools/mcp_client_call.py +504 -0
- swarms/tools/py_func_to_openai_func_str.py +43 -5
- swarms/tools/pydantic_to_json.py +10 -27
- swarms/utils/audio_processing.py +343 -0
- swarms/utils/index.py +226 -0
- swarms/utils/litellm_tokenizer.py +97 -11
- swarms/utils/litellm_wrapper.py +65 -67
- {swarms-7.7.9.dist-info → swarms-7.8.1.dist-info}/METADATA +2 -2
- {swarms-7.7.9.dist-info → swarms-7.8.1.dist-info}/RECORD +33 -22
- swarms/tools/mcp_client.py +0 -246
- swarms/tools/mcp_integration.py +0 -340
- {swarms-7.7.9.dist-info → swarms-7.8.1.dist-info}/LICENSE +0 -0
- {swarms-7.7.9.dist-info → swarms-7.8.1.dist-info}/WHEEL +0 -0
- {swarms-7.7.9.dist-info → swarms-7.8.1.dist-info}/entry_points.txt +0 -0
swarms/tools/mcp_client.py
DELETED
@@ -1,246 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
import json
|
3
|
-
from typing import List, Literal, Dict, Any, Union
|
4
|
-
from fastmcp import Client
|
5
|
-
from swarms.utils.str_to_dict import str_to_dict
|
6
|
-
from loguru import logger
|
7
|
-
|
8
|
-
|
9
|
-
def parse_agent_output(
|
10
|
-
dictionary: Union[str, Dict[Any, Any]],
|
11
|
-
) -> tuple[str, Dict[Any, Any]]:
|
12
|
-
"""
|
13
|
-
Parse agent output into tool name and parameters.
|
14
|
-
|
15
|
-
Args:
|
16
|
-
dictionary: Either a string or dictionary containing tool information.
|
17
|
-
If string, it will be converted to a dictionary.
|
18
|
-
Must contain a 'name' key for the tool name.
|
19
|
-
|
20
|
-
Returns:
|
21
|
-
tuple[str, Dict[Any, Any]]: A tuple containing the tool name and its parameters.
|
22
|
-
|
23
|
-
Raises:
|
24
|
-
ValueError: If the input is invalid or missing required 'name' key.
|
25
|
-
"""
|
26
|
-
try:
|
27
|
-
if isinstance(dictionary, str):
|
28
|
-
dictionary = str_to_dict(dictionary)
|
29
|
-
|
30
|
-
elif not isinstance(dictionary, dict):
|
31
|
-
raise ValueError("Invalid dictionary")
|
32
|
-
|
33
|
-
# Handle regular dictionary format
|
34
|
-
if "name" in dictionary:
|
35
|
-
name = dictionary["name"]
|
36
|
-
# Remove the name key and use remaining key-value pairs as parameters
|
37
|
-
params = dict(dictionary)
|
38
|
-
params.pop("name")
|
39
|
-
return name, params
|
40
|
-
|
41
|
-
raise ValueError("Invalid function call format")
|
42
|
-
except Exception as e:
|
43
|
-
raise ValueError(f"Error parsing agent output: {str(e)}")
|
44
|
-
|
45
|
-
|
46
|
-
async def _list_all(url: str):
|
47
|
-
"""
|
48
|
-
Asynchronously list all tools available on a given MCP server.
|
49
|
-
|
50
|
-
Args:
|
51
|
-
url: The URL of the MCP server to query.
|
52
|
-
|
53
|
-
Returns:
|
54
|
-
List of available tools.
|
55
|
-
|
56
|
-
Raises:
|
57
|
-
ValueError: If there's an error connecting to or querying the server.
|
58
|
-
"""
|
59
|
-
try:
|
60
|
-
async with Client(url) as client:
|
61
|
-
return await client.list_tools()
|
62
|
-
except Exception as e:
|
63
|
-
raise ValueError(f"Error listing tools: {str(e)}")
|
64
|
-
|
65
|
-
|
66
|
-
def list_all(url: str, output_type: Literal["str", "json"] = "json"):
|
67
|
-
"""
|
68
|
-
Synchronously list all tools available on a given MCP server.
|
69
|
-
|
70
|
-
Args:
|
71
|
-
url: The URL of the MCP server to query.
|
72
|
-
|
73
|
-
Returns:
|
74
|
-
List of dictionaries containing tool information.
|
75
|
-
|
76
|
-
Raises:
|
77
|
-
ValueError: If there's an error connecting to or querying the server.
|
78
|
-
"""
|
79
|
-
try:
|
80
|
-
out = asyncio.run(_list_all(url))
|
81
|
-
|
82
|
-
outputs = []
|
83
|
-
for tool in out:
|
84
|
-
outputs.append(tool.model_dump())
|
85
|
-
|
86
|
-
if output_type == "json":
|
87
|
-
return json.dumps(outputs, indent=4)
|
88
|
-
else:
|
89
|
-
return outputs
|
90
|
-
except Exception as e:
|
91
|
-
raise ValueError(f"Error in list_all: {str(e)}")
|
92
|
-
|
93
|
-
|
94
|
-
def list_tools_for_multiple_urls(
|
95
|
-
urls: List[str], output_type: Literal["str", "json"] = "json"
|
96
|
-
):
|
97
|
-
"""
|
98
|
-
List tools available across multiple MCP servers.
|
99
|
-
|
100
|
-
Args:
|
101
|
-
urls: List of MCP server URLs to query.
|
102
|
-
output_type: Format of the output, either "json" (string) or "str" (list).
|
103
|
-
|
104
|
-
Returns:
|
105
|
-
If output_type is "json": JSON string containing all tools with server URLs.
|
106
|
-
If output_type is "str": List of tools with server URLs.
|
107
|
-
|
108
|
-
Raises:
|
109
|
-
ValueError: If there's an error querying any of the servers.
|
110
|
-
"""
|
111
|
-
try:
|
112
|
-
out = []
|
113
|
-
for url in urls:
|
114
|
-
tools = list_all(url)
|
115
|
-
# Add server URL to each tool's data
|
116
|
-
for tool in tools:
|
117
|
-
tool["server_url"] = url
|
118
|
-
out.append(tools)
|
119
|
-
|
120
|
-
if output_type == "json":
|
121
|
-
return json.dumps(out, indent=4)
|
122
|
-
else:
|
123
|
-
return out
|
124
|
-
except Exception as e:
|
125
|
-
raise ValueError(
|
126
|
-
f"Error listing tools for multiple URLs: {str(e)}"
|
127
|
-
)
|
128
|
-
|
129
|
-
|
130
|
-
async def _execute_mcp_tool(
|
131
|
-
url: str,
|
132
|
-
parameters: Dict[Any, Any] = None,
|
133
|
-
*args,
|
134
|
-
**kwargs,
|
135
|
-
) -> Dict[Any, Any]:
|
136
|
-
"""
|
137
|
-
Asynchronously execute a tool on an MCP server.
|
138
|
-
|
139
|
-
Args:
|
140
|
-
url: The URL of the MCP server.
|
141
|
-
parameters: Dictionary containing tool name and parameters.
|
142
|
-
*args: Additional positional arguments for the Client.
|
143
|
-
**kwargs: Additional keyword arguments for the Client.
|
144
|
-
|
145
|
-
Returns:
|
146
|
-
Dictionary containing the tool execution results.
|
147
|
-
|
148
|
-
Raises:
|
149
|
-
ValueError: If the URL is invalid or tool execution fails.
|
150
|
-
"""
|
151
|
-
try:
|
152
|
-
|
153
|
-
name, params = parse_agent_output(parameters)
|
154
|
-
|
155
|
-
outputs = []
|
156
|
-
|
157
|
-
async with Client(url, *args, **kwargs) as client:
|
158
|
-
out = await client.call_tool(
|
159
|
-
name=name,
|
160
|
-
arguments=params,
|
161
|
-
)
|
162
|
-
|
163
|
-
for output in out:
|
164
|
-
outputs.append(output.model_dump())
|
165
|
-
|
166
|
-
# convert outputs to string
|
167
|
-
return json.dumps(outputs, indent=4)
|
168
|
-
except Exception as e:
|
169
|
-
raise ValueError(f"Error executing MCP tool: {str(e)}")
|
170
|
-
|
171
|
-
|
172
|
-
def execute_mcp_tool(
|
173
|
-
url: str,
|
174
|
-
parameters: Dict[Any, Any] = None,
|
175
|
-
) -> Dict[Any, Any]:
|
176
|
-
"""
|
177
|
-
Synchronously execute a tool on an MCP server.
|
178
|
-
|
179
|
-
Args:
|
180
|
-
url: The URL of the MCP server.
|
181
|
-
parameters: Dictionary containing tool name and parameters.
|
182
|
-
|
183
|
-
Returns:
|
184
|
-
Dictionary containing the tool execution results.
|
185
|
-
|
186
|
-
Raises:
|
187
|
-
ValueError: If tool execution fails.
|
188
|
-
"""
|
189
|
-
try:
|
190
|
-
logger.info(f"Executing MCP tool with URL: {url}")
|
191
|
-
logger.debug(f"Tool parameters: {parameters}")
|
192
|
-
|
193
|
-
result = asyncio.run(
|
194
|
-
_execute_mcp_tool(
|
195
|
-
url=url,
|
196
|
-
parameters=parameters,
|
197
|
-
)
|
198
|
-
)
|
199
|
-
|
200
|
-
logger.info("MCP tool execution completed successfully")
|
201
|
-
logger.debug(f"Tool execution result: {result}")
|
202
|
-
return result
|
203
|
-
except Exception as e:
|
204
|
-
logger.error(f"Error in execute_mcp_tool: {str(e)}")
|
205
|
-
raise ValueError(f"Error in execute_mcp_tool: {str(e)}")
|
206
|
-
|
207
|
-
|
208
|
-
def find_and_execute_tool(
|
209
|
-
urls: List[str], tool_name: str, parameters: Dict[Any, Any]
|
210
|
-
) -> Dict[Any, Any]:
|
211
|
-
"""
|
212
|
-
Find a tool across multiple servers and execute it with the given parameters.
|
213
|
-
|
214
|
-
Args:
|
215
|
-
urls: List of server URLs to search through.
|
216
|
-
tool_name: Name of the tool to find and execute.
|
217
|
-
parameters: Parameters to pass to the tool.
|
218
|
-
|
219
|
-
Returns:
|
220
|
-
Dict containing the tool execution results.
|
221
|
-
|
222
|
-
Raises:
|
223
|
-
ValueError: If tool is not found on any server or execution fails.
|
224
|
-
"""
|
225
|
-
try:
|
226
|
-
# Search for tool across all servers
|
227
|
-
for url in urls:
|
228
|
-
try:
|
229
|
-
tools = list_all(url)
|
230
|
-
# Check if tool exists on this server
|
231
|
-
if any(tool["name"] == tool_name for tool in tools):
|
232
|
-
# Prepare parameters in correct format
|
233
|
-
tool_params = {"name": tool_name, **parameters}
|
234
|
-
# Execute tool on this server
|
235
|
-
return execute_mcp_tool(
|
236
|
-
url=url, parameters=tool_params
|
237
|
-
)
|
238
|
-
except Exception:
|
239
|
-
# Skip servers that fail and continue searching
|
240
|
-
continue
|
241
|
-
|
242
|
-
raise ValueError(
|
243
|
-
f"Tool '{tool_name}' not found on any provided servers"
|
244
|
-
)
|
245
|
-
except Exception as e:
|
246
|
-
raise ValueError(f"Error in find_and_execute_tool: {str(e)}")
|
swarms/tools/mcp_integration.py
DELETED
@@ -1,340 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from typing import Any
|
4
|
-
|
5
|
-
|
6
|
-
from loguru import logger
|
7
|
-
|
8
|
-
import abc
|
9
|
-
import asyncio
|
10
|
-
from contextlib import AbstractAsyncContextManager, AsyncExitStack
|
11
|
-
from pathlib import Path
|
12
|
-
from typing import Literal
|
13
|
-
|
14
|
-
from anyio.streams.memory import (
|
15
|
-
MemoryObjectReceiveStream,
|
16
|
-
MemoryObjectSendStream,
|
17
|
-
)
|
18
|
-
from mcp import (
|
19
|
-
ClientSession,
|
20
|
-
StdioServerParameters,
|
21
|
-
Tool as MCPTool,
|
22
|
-
stdio_client,
|
23
|
-
)
|
24
|
-
from mcp.client.sse import sse_client
|
25
|
-
from mcp.types import CallToolResult, JSONRPCMessage
|
26
|
-
from typing_extensions import NotRequired, TypedDict
|
27
|
-
|
28
|
-
|
29
|
-
class MCPServer(abc.ABC):
|
30
|
-
"""Base class for Model Context Protocol servers."""
|
31
|
-
|
32
|
-
@abc.abstractmethod
|
33
|
-
async def connect(self):
|
34
|
-
"""Connect to the server. For example, this might mean spawning a subprocess or
|
35
|
-
opening a network connection. The server is expected to remain connected until
|
36
|
-
`cleanup()` is called.
|
37
|
-
"""
|
38
|
-
pass
|
39
|
-
|
40
|
-
@property
|
41
|
-
@abc.abstractmethod
|
42
|
-
def name(self) -> str:
|
43
|
-
"""A readable name for the server."""
|
44
|
-
pass
|
45
|
-
|
46
|
-
@abc.abstractmethod
|
47
|
-
async def cleanup(self):
|
48
|
-
"""Cleanup the server. For example, this might mean closing a subprocess or
|
49
|
-
closing a network connection.
|
50
|
-
"""
|
51
|
-
pass
|
52
|
-
|
53
|
-
@abc.abstractmethod
|
54
|
-
async def list_tools(self) -> list[MCPTool]:
|
55
|
-
"""List the tools available on the server."""
|
56
|
-
pass
|
57
|
-
|
58
|
-
@abc.abstractmethod
|
59
|
-
async def call_tool(
|
60
|
-
self, tool_name: str, arguments: dict[str, Any] | None
|
61
|
-
) -> CallToolResult:
|
62
|
-
"""Invoke a tool on the server."""
|
63
|
-
pass
|
64
|
-
|
65
|
-
|
66
|
-
class _MCPServerWithClientSession(MCPServer, abc.ABC):
|
67
|
-
"""Base class for MCP servers that use a `ClientSession` to communicate with the server."""
|
68
|
-
|
69
|
-
def __init__(self, cache_tools_list: bool):
|
70
|
-
"""
|
71
|
-
Args:
|
72
|
-
cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
|
73
|
-
cached and only fetched from the server once. If `False`, the tools list will be
|
74
|
-
fetched from the server on each call to `list_tools()`. The cache can be invalidated
|
75
|
-
by calling `invalidate_tools_cache()`. You should set this to `True` if you know the
|
76
|
-
server will not change its tools list, because it can drastically improve latency
|
77
|
-
(by avoiding a round-trip to the server every time).
|
78
|
-
"""
|
79
|
-
self.session: ClientSession | None = None
|
80
|
-
self.exit_stack: AsyncExitStack = AsyncExitStack()
|
81
|
-
self._cleanup_lock: asyncio.Lock = asyncio.Lock()
|
82
|
-
self.cache_tools_list = cache_tools_list
|
83
|
-
|
84
|
-
# The cache is always dirty at startup, so that we fetch tools at least once
|
85
|
-
self._cache_dirty = True
|
86
|
-
self._tools_list: list[MCPTool] | None = None
|
87
|
-
|
88
|
-
@abc.abstractmethod
|
89
|
-
def create_streams(
|
90
|
-
self,
|
91
|
-
) -> AbstractAsyncContextManager[
|
92
|
-
tuple[
|
93
|
-
MemoryObjectReceiveStream[JSONRPCMessage | Exception],
|
94
|
-
MemoryObjectSendStream[JSONRPCMessage],
|
95
|
-
]
|
96
|
-
]:
|
97
|
-
"""Create the streams for the server."""
|
98
|
-
pass
|
99
|
-
|
100
|
-
async def __aenter__(self):
|
101
|
-
await self.connect()
|
102
|
-
return self
|
103
|
-
|
104
|
-
async def __aexit__(self, exc_type, exc_value, traceback):
|
105
|
-
await self.cleanup()
|
106
|
-
|
107
|
-
def invalidate_tools_cache(self):
|
108
|
-
"""Invalidate the tools cache."""
|
109
|
-
self._cache_dirty = True
|
110
|
-
|
111
|
-
async def connect(self):
|
112
|
-
"""Connect to the server."""
|
113
|
-
try:
|
114
|
-
transport = await self.exit_stack.enter_async_context(
|
115
|
-
self.create_streams()
|
116
|
-
)
|
117
|
-
read, write = transport
|
118
|
-
session = await self.exit_stack.enter_async_context(
|
119
|
-
ClientSession(read, write)
|
120
|
-
)
|
121
|
-
await session.initialize()
|
122
|
-
self.session = session
|
123
|
-
except Exception as e:
|
124
|
-
logger.error(f"Error initializing MCP server: {e}")
|
125
|
-
await self.cleanup()
|
126
|
-
raise
|
127
|
-
|
128
|
-
async def list_tools(self) -> list[MCPTool]:
|
129
|
-
"""List the tools available on the server."""
|
130
|
-
if not self.session:
|
131
|
-
raise Exception(
|
132
|
-
"Server not initialized. Make sure you call `connect()` first."
|
133
|
-
)
|
134
|
-
|
135
|
-
# Return from cache if caching is enabled, we have tools, and the cache is not dirty
|
136
|
-
if (
|
137
|
-
self.cache_tools_list
|
138
|
-
and not self._cache_dirty
|
139
|
-
and self._tools_list
|
140
|
-
):
|
141
|
-
return self._tools_list
|
142
|
-
|
143
|
-
# Reset the cache dirty to False
|
144
|
-
self._cache_dirty = False
|
145
|
-
|
146
|
-
# Fetch the tools from the server
|
147
|
-
self._tools_list = (await self.session.list_tools()).tools
|
148
|
-
return self._tools_list
|
149
|
-
|
150
|
-
async def call_tool(
|
151
|
-
self, arguments: dict[str, Any] | None
|
152
|
-
) -> CallToolResult:
|
153
|
-
"""Invoke a tool on the server."""
|
154
|
-
tool_name = arguments.get("tool_name") or arguments.get(
|
155
|
-
"name"
|
156
|
-
)
|
157
|
-
|
158
|
-
if not tool_name:
|
159
|
-
raise Exception("No tool name found in arguments")
|
160
|
-
|
161
|
-
if not self.session:
|
162
|
-
raise Exception(
|
163
|
-
"Server not initialized. Make sure you call `connect()` first."
|
164
|
-
)
|
165
|
-
|
166
|
-
return await self.session.call_tool(tool_name, arguments)
|
167
|
-
|
168
|
-
async def cleanup(self):
|
169
|
-
"""Cleanup the server."""
|
170
|
-
async with self._cleanup_lock:
|
171
|
-
try:
|
172
|
-
await self.exit_stack.aclose()
|
173
|
-
self.session = None
|
174
|
-
except Exception as e:
|
175
|
-
logger.error(f"Error cleaning up server: {e}")
|
176
|
-
|
177
|
-
|
178
|
-
class MCPServerStdioParams(TypedDict):
|
179
|
-
"""Mirrors `mcp.client.stdio.StdioServerParameters`, but lets you pass params without another
|
180
|
-
import.
|
181
|
-
"""
|
182
|
-
|
183
|
-
command: str
|
184
|
-
"""The executable to run to start the server. For example, `python` or `node`."""
|
185
|
-
|
186
|
-
args: NotRequired[list[str]]
|
187
|
-
"""Command line args to pass to the `command` executable. For example, `['foo.py']` or
|
188
|
-
`['server.js', '--port', '8080']`."""
|
189
|
-
|
190
|
-
env: NotRequired[dict[str, str]]
|
191
|
-
"""The environment variables to set for the server. ."""
|
192
|
-
|
193
|
-
cwd: NotRequired[str | Path]
|
194
|
-
"""The working directory to use when spawning the process."""
|
195
|
-
|
196
|
-
encoding: NotRequired[str]
|
197
|
-
"""The text encoding used when sending/receiving messages to the server. Defaults to `utf-8`."""
|
198
|
-
|
199
|
-
encoding_error_handler: NotRequired[
|
200
|
-
Literal["strict", "ignore", "replace"]
|
201
|
-
]
|
202
|
-
"""The text encoding error handler. Defaults to `strict`.
|
203
|
-
|
204
|
-
See https://docs.python.org/3/library/codecs.html#codec-base-classes for
|
205
|
-
explanations of possible values.
|
206
|
-
"""
|
207
|
-
|
208
|
-
|
209
|
-
class MCPServerStdio(_MCPServerWithClientSession):
|
210
|
-
"""MCP server implementation that uses the stdio transport. See the [spec]
|
211
|
-
(https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) for
|
212
|
-
details.
|
213
|
-
"""
|
214
|
-
|
215
|
-
def __init__(
|
216
|
-
self,
|
217
|
-
params: MCPServerStdioParams,
|
218
|
-
cache_tools_list: bool = False,
|
219
|
-
name: str | None = None,
|
220
|
-
):
|
221
|
-
"""Create a new MCP server based on the stdio transport.
|
222
|
-
|
223
|
-
Args:
|
224
|
-
params: The params that configure the server. This includes the command to run to
|
225
|
-
start the server, the args to pass to the command, the environment variables to
|
226
|
-
set for the server, the working directory to use when spawning the process, and
|
227
|
-
the text encoding used when sending/receiving messages to the server.
|
228
|
-
cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
|
229
|
-
cached and only fetched from the server once. If `False`, the tools list will be
|
230
|
-
fetched from the server on each call to `list_tools()`. The cache can be
|
231
|
-
invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
|
232
|
-
if you know the server will not change its tools list, because it can drastically
|
233
|
-
improve latency (by avoiding a round-trip to the server every time).
|
234
|
-
name: A readable name for the server. If not provided, we'll create one from the
|
235
|
-
command.
|
236
|
-
"""
|
237
|
-
super().__init__(cache_tools_list)
|
238
|
-
|
239
|
-
self.params = StdioServerParameters(
|
240
|
-
command=params["command"],
|
241
|
-
args=params.get("args", []),
|
242
|
-
env=params.get("env"),
|
243
|
-
cwd=params.get("cwd"),
|
244
|
-
encoding=params.get("encoding", "utf-8"),
|
245
|
-
encoding_error_handler=params.get(
|
246
|
-
"encoding_error_handler", "strict"
|
247
|
-
),
|
248
|
-
)
|
249
|
-
|
250
|
-
self._name = name or f"stdio: {self.params.command}"
|
251
|
-
|
252
|
-
def create_streams(
|
253
|
-
self,
|
254
|
-
) -> AbstractAsyncContextManager[
|
255
|
-
tuple[
|
256
|
-
MemoryObjectReceiveStream[JSONRPCMessage | Exception],
|
257
|
-
MemoryObjectSendStream[JSONRPCMessage],
|
258
|
-
]
|
259
|
-
]:
|
260
|
-
"""Create the streams for the server."""
|
261
|
-
return stdio_client(self.params)
|
262
|
-
|
263
|
-
@property
|
264
|
-
def name(self) -> str:
|
265
|
-
"""A readable name for the server."""
|
266
|
-
return self._name
|
267
|
-
|
268
|
-
|
269
|
-
class MCPServerSseParams(TypedDict):
|
270
|
-
"""Mirrors the params in`mcp.client.sse.sse_client`."""
|
271
|
-
|
272
|
-
url: str
|
273
|
-
"""The URL of the server."""
|
274
|
-
|
275
|
-
headers: NotRequired[dict[str, str]]
|
276
|
-
"""The headers to send to the server."""
|
277
|
-
|
278
|
-
timeout: NotRequired[float]
|
279
|
-
"""The timeout for the HTTP request. Defaults to 5 seconds."""
|
280
|
-
|
281
|
-
sse_read_timeout: NotRequired[float]
|
282
|
-
"""The timeout for the SSE connection, in seconds. Defaults to 5 minutes."""
|
283
|
-
|
284
|
-
|
285
|
-
class MCPServerSse(_MCPServerWithClientSession):
|
286
|
-
"""MCP server implementation that uses the HTTP with SSE transport. See the [spec]
|
287
|
-
(https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse)
|
288
|
-
for details.
|
289
|
-
"""
|
290
|
-
|
291
|
-
def __init__(
|
292
|
-
self,
|
293
|
-
params: MCPServerSseParams,
|
294
|
-
cache_tools_list: bool = False,
|
295
|
-
name: str | None = None,
|
296
|
-
):
|
297
|
-
"""Create a new MCP server based on the HTTP with SSE transport.
|
298
|
-
|
299
|
-
Args:
|
300
|
-
params: The params that configure the server. This includes the URL of the server,
|
301
|
-
the headers to send to the server, the timeout for the HTTP request, and the
|
302
|
-
timeout for the SSE connection.
|
303
|
-
|
304
|
-
cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
|
305
|
-
cached and only fetched from the server once. If `False`, the tools list will be
|
306
|
-
fetched from the server on each call to `list_tools()`. The cache can be
|
307
|
-
invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
|
308
|
-
if you know the server will not change its tools list, because it can drastically
|
309
|
-
improve latency (by avoiding a round-trip to the server every time).
|
310
|
-
|
311
|
-
name: A readable name for the server. If not provided, we'll create one from the
|
312
|
-
URL.
|
313
|
-
"""
|
314
|
-
super().__init__(cache_tools_list)
|
315
|
-
|
316
|
-
self.params = params
|
317
|
-
self._name = name or f"sse: {self.params['url']}"
|
318
|
-
|
319
|
-
def create_streams(
|
320
|
-
self,
|
321
|
-
) -> AbstractAsyncContextManager[
|
322
|
-
tuple[
|
323
|
-
MemoryObjectReceiveStream[JSONRPCMessage | Exception],
|
324
|
-
MemoryObjectSendStream[JSONRPCMessage],
|
325
|
-
]
|
326
|
-
]:
|
327
|
-
"""Create the streams for the server."""
|
328
|
-
return sse_client(
|
329
|
-
url=self.params["url"],
|
330
|
-
headers=self.params.get("headers", None),
|
331
|
-
timeout=self.params.get("timeout", 5),
|
332
|
-
sse_read_timeout=self.params.get(
|
333
|
-
"sse_read_timeout", 60 * 5
|
334
|
-
),
|
335
|
-
)
|
336
|
-
|
337
|
-
@property
|
338
|
-
def name(self) -> str:
|
339
|
-
"""A readable name for the server."""
|
340
|
-
return self._name
|
File without changes
|
File without changes
|
File without changes
|