mcp-use 1.2.13__py3-none-any.whl → 1.3.0__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 mcp-use might be problematic. Click here for more details.

@@ -9,6 +9,7 @@ import logging
9
9
  from collections.abc import AsyncIterator
10
10
 
11
11
  from langchain.agents import AgentExecutor, create_tool_calling_agent
12
+ from langchain.agents.output_parsers.tools import ToolAgentAction
12
13
  from langchain.globals import set_debug
13
14
  from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
14
15
  from langchain.schema import AIMessage, BaseMessage, HumanMessage, SystemMessage
@@ -21,7 +22,6 @@ from langchain_core.utils.input import get_color_mapping
21
22
 
22
23
  from mcp_use.client import MCPClient
23
24
  from mcp_use.connectors.base import BaseConnector
24
- from mcp_use.session import MCPSession
25
25
 
26
26
  from ..adapters.langchain_adapter import LangChainAdapter
27
27
  from ..logging import logger
@@ -102,9 +102,7 @@ class MCPAgent:
102
102
 
103
103
  # State tracking
104
104
  self._agent_executor: AgentExecutor | None = None
105
- self._sessions: dict[str, MCPSession] = {}
106
105
  self._system_message: SystemMessage | None = None
107
- self._tools: list[BaseTool] = []
108
106
 
109
107
  async def initialize(self) -> None:
110
108
  """Initialize the MCP client and agent."""
@@ -346,20 +344,18 @@ class MCPAgent:
346
344
  history_to_use = (
347
345
  external_history if external_history is not None else self._conversation_history
348
346
  )
349
- langchain_history: list[BaseMessage] = [
350
- m for m in history_to_use if isinstance(m, HumanMessage | AIMessage)
351
- ]
352
- inputs = {"input": query, "chat_history": langchain_history}
347
+ inputs = {"input": query, "chat_history": history_to_use}
353
348
 
354
349
  # 3. Stream & diff -------------------------------------------------------
355
- accumulated = ""
356
350
  async for event in self._agent_executor.astream_events(inputs):
351
+ if event.get("event") == "on_chain_end":
352
+ output = event["data"]["output"]
353
+ if isinstance(output, list):
354
+ for message in output:
355
+ if not isinstance(message, ToolAgentAction):
356
+ self.add_to_history(message)
357
357
  yield event
358
358
 
359
- # 4. Persist assistant message ------------------------------------------
360
- if self.memory_enabled and accumulated:
361
- self.add_to_history(AIMessage(content=accumulated))
362
-
363
359
  # 5. House-keeping -------------------------------------------------------
364
360
  if initialised_here and manage_connector:
365
361
  await self.close()
mcp_use/client.py CHANGED
@@ -12,6 +12,7 @@ from typing import Any
12
12
  from .config import create_connector_from_config, load_config_file
13
13
  from .logging import logger
14
14
  from .session import MCPSession
15
+ from .types.clientoptions import ClientOptions
15
16
 
16
17
 
17
18
  class MCPClient:
@@ -24,14 +25,17 @@ class MCPClient:
24
25
  def __init__(
25
26
  self,
26
27
  config: str | dict[str, Any] | None = None,
28
+ options: ClientOptions | None = None,
27
29
  ) -> None:
28
30
  """Initialize a new MCP client.
29
31
 
30
32
  Args:
31
33
  config: Either a dict containing configuration or a path to a JSON config file.
32
34
  If None, an empty configuration is used.
35
+ options: Configuration options for the client.
33
36
  """
34
37
  self.config: dict[str, Any] = {}
38
+ self.options = options or {}
35
39
  self.sessions: dict[str, MCPSession] = {}
36
40
  self.active_sessions: list[str] = []
37
41
 
@@ -43,22 +47,24 @@ class MCPClient:
43
47
  self.config = config
44
48
 
45
49
  @classmethod
46
- def from_dict(cls, config: dict[str, Any]) -> "MCPClient":
50
+ def from_dict(cls, config: dict[str, Any], options: ClientOptions | None = None) -> "MCPClient":
47
51
  """Create a MCPClient from a dictionary.
48
52
 
49
53
  Args:
50
54
  config: The configuration dictionary.
55
+ options: Optional client configuration options.
51
56
  """
52
- return cls(config=config)
57
+ return cls(config=config, options=options)
53
58
 
54
59
  @classmethod
55
- def from_config_file(cls, filepath: str) -> "MCPClient":
60
+ def from_config_file(cls, filepath: str, options: ClientOptions | None = None) -> "MCPClient":
56
61
  """Create a MCPClient from a configuration file.
57
62
 
58
63
  Args:
59
64
  filepath: The path to the configuration file.
65
+ options: Optional client configuration options.
60
66
  """
61
- return cls(config=load_config_file(filepath))
67
+ return cls(config=load_config_file(filepath), options=options)
62
68
 
63
69
  def add_server(
64
70
  self,
@@ -111,6 +117,7 @@ class MCPClient:
111
117
 
112
118
  Args:
113
119
  server_name: The name of the server to create a session for.
120
+ auto_initialize: Whether to automatically initialize the session.
114
121
 
115
122
  Returns:
116
123
  The created MCPSession.
@@ -128,7 +135,9 @@ class MCPClient:
128
135
  raise ValueError(f"Server '{server_name}' not found in config")
129
136
 
130
137
  server_config = servers[server_name]
131
- connector = create_connector_from_config(server_config)
138
+
139
+ # Create connector with options
140
+ connector = create_connector_from_config(server_config, options=self.options)
132
141
 
133
142
  # Create the session
134
143
  session = MCPSession(connector)
@@ -146,16 +155,16 @@ class MCPClient:
146
155
  self,
147
156
  auto_initialize: bool = True,
148
157
  ) -> dict[str, MCPSession]:
149
- """Create a session for the specified server.
158
+ """Create sessions for all configured servers.
150
159
 
151
160
  Args:
152
- auto_initialize: Whether to automatically initialize the session.
161
+ auto_initialize: Whether to automatically initialize the sessions.
153
162
 
154
163
  Returns:
155
- The created MCPSession. If server_name is None, returns the first created session.
164
+ Dictionary mapping server names to their MCPSession instances.
156
165
 
157
166
  Warns:
158
- Warning: If no servers are configured.
167
+ UserWarning: If no servers are configured.
159
168
  """
160
169
  # Get server config
161
170
  servers = self.config.get("mcpServers", {})
mcp_use/config.py CHANGED
@@ -7,7 +7,15 @@ This module provides functionality to load MCP configuration from JSON files.
7
7
  import json
8
8
  from typing import Any
9
9
 
10
- from .connectors import BaseConnector, HttpConnector, StdioConnector, WebSocketConnector
10
+ from .connectors import (
11
+ BaseConnector,
12
+ HttpConnector,
13
+ SandboxConnector,
14
+ StdioConnector,
15
+ WebSocketConnector,
16
+ )
17
+ from .connectors.utils import is_stdio_server
18
+ from .types.clientoptions import ClientOptions
11
19
 
12
20
 
13
21
  def load_config_file(filepath: str) -> dict[str, Any]:
@@ -23,23 +31,41 @@ def load_config_file(filepath: str) -> dict[str, Any]:
23
31
  return json.load(f)
24
32
 
25
33
 
26
- def create_connector_from_config(server_config: dict[str, Any]) -> BaseConnector:
34
+ def create_connector_from_config(
35
+ server_config: dict[str, Any],
36
+ options: ClientOptions | None = None,
37
+ ) -> BaseConnector:
27
38
  """Create a connector based on server configuration.
28
-
39
+ This function can be called with just the server_config parameter:
40
+ create_connector_from_config(server_config)
29
41
  Args:
30
42
  server_config: The server configuration section
43
+ options: Optional client configuration options including sandboxing preferences.
44
+ If None, default client options will be used.
31
45
 
32
46
  Returns:
33
47
  A configured connector instance
34
48
  """
49
+ # Use default options if none provided
50
+ options = options or {"is_sandboxed": False}
51
+
35
52
  # Stdio connector (command-based)
36
- if "command" in server_config and "args" in server_config:
53
+ if is_stdio_server(server_config) and not options.get("is_sandboxed", False):
37
54
  return StdioConnector(
38
55
  command=server_config["command"],
39
56
  args=server_config["args"],
40
57
  env=server_config.get("env", None),
41
58
  )
42
59
 
60
+ # Sandboxed connector
61
+ elif is_stdio_server(server_config) and options.get("is_sandboxed", False):
62
+ return SandboxConnector(
63
+ command=server_config["command"],
64
+ args=server_config["args"],
65
+ env=server_config.get("env", None),
66
+ e2b_options=options.get("sandbox_options", {}),
67
+ )
68
+
43
69
  # HTTP connector
44
70
  elif "url" in server_config:
45
71
  return HttpConnector(
@@ -5,9 +5,16 @@ This module provides interfaces for connecting to MCP implementations
5
5
  through different transport mechanisms.
6
6
  """
7
7
 
8
- from .base import BaseConnector
9
- from .http import HttpConnector
10
- from .stdio import StdioConnector
11
- from .websocket import WebSocketConnector
8
+ from .base import BaseConnector # noqa: F401
9
+ from .http import HttpConnector # noqa: F401
10
+ from .sandbox import SandboxConnector # noqa: F401
11
+ from .stdio import StdioConnector # noqa: F401
12
+ from .websocket import WebSocketConnector # noqa: F401
12
13
 
13
- __all__ = ["BaseConnector", "StdioConnector", "WebSocketConnector", "HttpConnector"]
14
+ __all__ = [
15
+ "BaseConnector",
16
+ "StdioConnector",
17
+ "HttpConnector",
18
+ "WebSocketConnector",
19
+ "SandboxConnector",
20
+ ]
@@ -0,0 +1,291 @@
1
+ """
2
+ Sandbox connector for MCP implementations.
3
+
4
+ This module provides a connector for communicating with MCP implementations
5
+ that are executed inside a sandbox environment (currently using E2B).
6
+ """
7
+
8
+ import asyncio
9
+ import os
10
+ import sys
11
+ import time
12
+
13
+ import aiohttp
14
+ from mcp import ClientSession
15
+
16
+ from ..logging import logger
17
+ from ..task_managers import SseConnectionManager
18
+
19
+ # Import E2B SDK components (optional dependency)
20
+ try:
21
+ logger.debug("Attempting to import e2b_code_interpreter...")
22
+ from e2b_code_interpreter import (
23
+ CommandHandle,
24
+ Sandbox,
25
+ )
26
+
27
+ logger.debug("Successfully imported e2b_code_interpreter")
28
+ except ImportError as e:
29
+ logger.debug(f"Failed to import e2b_code_interpreter: {e}")
30
+ CommandHandle = None
31
+ Sandbox = None
32
+
33
+ from ..types.sandbox import SandboxOptions
34
+ from .base import BaseConnector
35
+
36
+
37
+ class SandboxConnector(BaseConnector):
38
+ """Connector for MCP implementations running in a sandbox environment.
39
+
40
+ This connector runs a user-defined stdio command within a sandbox environment,
41
+ currently implemented using E2B, potentially wrapped by a utility like 'supergateway'
42
+ to expose its stdio.
43
+ """
44
+
45
+ def __init__(
46
+ self,
47
+ command: str,
48
+ args: list[str],
49
+ env: dict[str, str] | None = None,
50
+ e2b_options: SandboxOptions | None = None,
51
+ timeout: float = 5,
52
+ sse_read_timeout: float = 60 * 5,
53
+ ):
54
+ """Initialize a new sandbox connector.
55
+
56
+ Args:
57
+ command: The user's MCP server command to execute in the sandbox.
58
+ args: Command line arguments for the user's MCP server command.
59
+ env: Environment variables for the user's MCP server command.
60
+ e2b_options: Configuration options for the E2B sandbox environment.
61
+ See SandboxOptions for available options and defaults.
62
+ timeout: Timeout for the sandbox process in seconds.
63
+ sse_read_timeout: Timeout for the SSE connection in seconds.
64
+ """
65
+ super().__init__()
66
+ if Sandbox is None:
67
+ raise ImportError(
68
+ "E2B SDK (e2b-code-interpreter) not found. "
69
+ "Please install it with 'pip install mcp-use[e2b]' "
70
+ "(or 'pip install e2b-code-interpreter')."
71
+ )
72
+
73
+ self.user_command = command
74
+ self.user_args = args or []
75
+ self.user_env = env or {}
76
+
77
+ _e2b_options = e2b_options or {}
78
+
79
+ self.api_key = _e2b_options.get("api_key") or os.environ.get("E2B_API_KEY")
80
+ if not self.api_key:
81
+ raise ValueError(
82
+ "E2B API key is required. Provide it via 'e2b_options.api_key' "
83
+ "or the E2B_API_KEY environment variable."
84
+ )
85
+
86
+ self.sandbox_template_id = _e2b_options.get("sandbox_template_id", "base")
87
+ self.supergateway_cmd_parts = _e2b_options.get(
88
+ "supergateway_command", "npx -y supergateway"
89
+ )
90
+
91
+ self.sandbox: Sandbox | None = None
92
+ self.process: CommandHandle | None = None
93
+ self.client: ClientSession | None = None
94
+ self.errlog = sys.stderr
95
+ self.base_url: str | None = None
96
+ self._connected = False
97
+ self._connection_manager: SseConnectionManager | None = None
98
+
99
+ # SSE connection parameters
100
+ self.headers = {}
101
+ self.timeout = timeout
102
+ self.sse_read_timeout = sse_read_timeout
103
+
104
+ self.stdout_lines: list[str] = []
105
+ self.stderr_lines: list[str] = []
106
+ self._server_ready = asyncio.Event()
107
+
108
+ def _handle_stdout(self, data: str) -> None:
109
+ """Handle stdout data from the sandbox process."""
110
+ self.stdout_lines.append(data)
111
+ logger.debug(f"[SANDBOX STDOUT] {data}", end="", flush=True)
112
+
113
+ def _handle_stderr(self, data: str) -> None:
114
+ """Handle stderr data from the sandbox process."""
115
+ self.stderr_lines.append(data)
116
+ logger.debug(f"[SANDBOX STDERR] {data}", file=self.errlog, end="", flush=True)
117
+
118
+ async def wait_for_server_response(self, base_url: str, timeout: int = 30) -> bool:
119
+ """Wait for the server to respond to HTTP requests.
120
+ Args:
121
+ base_url: The base URL to check for server readiness
122
+ timeout: Maximum time to wait in seconds
123
+ Returns:
124
+ True if server is responding, raises TimeoutError otherwise
125
+ """
126
+ logger.info(f"Waiting for server at {base_url} to respond...")
127
+ sys.stdout.flush()
128
+
129
+ start_time = time.time()
130
+ ping_url = f"{base_url}/sse"
131
+
132
+ # Try to connect to the server
133
+ while time.time() - start_time < timeout:
134
+ try:
135
+ async with aiohttp.ClientSession() as session:
136
+ try:
137
+ # First try the endpoint
138
+ async with session.get(ping_url, timeout=2) as response:
139
+ if response.status == 200:
140
+ elapsed = time.time() - start_time
141
+ logger.info(
142
+ f"Server is ready! "
143
+ f"SSE endpoint responded with 200 after {elapsed:.1f}s"
144
+ )
145
+ return True
146
+ except Exception:
147
+ # If sse endpoint doesn't work, try the base URL
148
+ async with session.get(base_url, timeout=2) as response:
149
+ if response.status < 500: # Accept any non-server error
150
+ elapsed = time.time() - start_time
151
+ logger.info(
152
+ f"Server is ready! Base URL responded with "
153
+ f"{response.status} after {elapsed:.1f}s"
154
+ )
155
+ return True
156
+ except Exception:
157
+ # Wait a bit before trying again
158
+ await asyncio.sleep(0.5)
159
+ continue
160
+
161
+ # If we get here, the request failed
162
+ await asyncio.sleep(0.5)
163
+
164
+ # Log status every 5 seconds
165
+ elapsed = time.time() - start_time
166
+ if int(elapsed) % 5 == 0:
167
+ logger.info(f"Still waiting for server to respond... ({elapsed:.1f}s elapsed)")
168
+ sys.stdout.flush()
169
+
170
+ # If we get here, we timed out
171
+ raise TimeoutError(f"Timeout waiting for server to respond (waited {timeout} seconds)")
172
+
173
+ async def connect(self):
174
+ """Connect to the sandbox and start the MCP server."""
175
+
176
+ if self._connected:
177
+ logger.debug("Already connected to MCP implementation")
178
+ return
179
+
180
+ logger.debug("Connecting to MCP implementation in sandbox")
181
+
182
+ try:
183
+ # Create and start the sandbox
184
+ self.sandbox = Sandbox(
185
+ template=self.sandbox_template_id,
186
+ api_key=self.api_key,
187
+ )
188
+
189
+ # Get the host for the sandbox
190
+ host = self.sandbox.get_host(3000)
191
+ self.base_url = f"https://{host}".rstrip("/")
192
+
193
+ # Append command with args
194
+ command = f"{self.user_command} {' '.join(self.user_args)}"
195
+
196
+ # Construct the full command with supergateway
197
+ full_command = f'{self.supergateway_cmd_parts} \
198
+ --base-url {self.base_url} \
199
+ --port 3000 \
200
+ --cors \
201
+ --stdio "{command}"'
202
+
203
+ logger.debug(f"Full command: {full_command}")
204
+
205
+ # Start the process in the sandbox with our stdout/stderr handlers
206
+ self.process: CommandHandle = self.sandbox.commands.run(
207
+ full_command,
208
+ envs=self.user_env,
209
+ timeout=1000 * 60 * 10, # 10 minutes timeout
210
+ background=True,
211
+ on_stdout=self._handle_stdout,
212
+ on_stderr=self._handle_stderr,
213
+ )
214
+
215
+ # Wait for the server to be ready
216
+ await self.wait_for_server_response(self.base_url, timeout=30)
217
+ logger.debug("Initializing connection manager...")
218
+
219
+ # Create the SSE connection URL
220
+ sse_url = f"{self.base_url}/sse"
221
+
222
+ # Create and start the connection manager
223
+ self._connection_manager = SseConnectionManager(
224
+ sse_url, self.headers, self.timeout, self.sse_read_timeout
225
+ )
226
+ read_stream, write_stream = await self._connection_manager.start()
227
+
228
+ # Create the client session
229
+ self.client = ClientSession(read_stream, write_stream, sampling_callback=None)
230
+ await self.client.__aenter__()
231
+
232
+ # Mark as connected
233
+ self._connected = True
234
+ logger.debug(
235
+ f"Successfully connected to MCP implementation via HTTP/SSE: {self.base_url}"
236
+ )
237
+
238
+ except Exception as e:
239
+ logger.error(f"Failed to connect to MCP implementation: {e}")
240
+
241
+ # Clean up any resources if connection failed
242
+ await self._cleanup_resources()
243
+
244
+ raise e
245
+
246
+ async def _cleanup_resources(self) -> None:
247
+ """Clean up all resources associated with this connector, including the sandbox.
248
+ This method extends the base implementation to also terminate the sandbox instance
249
+ and clean up any processes running in the sandbox.
250
+ """
251
+ logger.debug("Cleaning up sandbox resources")
252
+
253
+ # Terminate any running process
254
+ if self.process:
255
+ try:
256
+ logger.debug("Terminating sandbox process")
257
+ self.process.kill()
258
+ except Exception as e:
259
+ logger.warning(f"Error terminating sandbox process: {e}")
260
+ finally:
261
+ self.process = None
262
+
263
+ # Close the sandbox
264
+ if self.sandbox:
265
+ try:
266
+ logger.debug("Closing sandbox instance")
267
+ self.sandbox.kill()
268
+ logger.debug("Sandbox instance closed successfully")
269
+ except Exception as e:
270
+ logger.warning(f"Error closing sandbox: {e}")
271
+ finally:
272
+ self.sandbox = None
273
+
274
+ # Then call the parent method to clean up the rest
275
+ await super()._cleanup_resources()
276
+
277
+ # Clear any collected output
278
+ self.stdout_lines = []
279
+ self.stderr_lines = []
280
+ self.base_url = None
281
+
282
+ async def disconnect(self) -> None:
283
+ """Close the connection to the MCP implementation."""
284
+ if not self._connected:
285
+ logger.debug("Not connected to MCP implementation")
286
+ return
287
+
288
+ logger.debug("Disconnecting from MCP implementation")
289
+ await self._cleanup_resources()
290
+ self._connected = False
291
+ logger.debug("Disconnected from MCP implementation")
@@ -0,0 +1,13 @@
1
+ from typing import Any
2
+
3
+
4
+ def is_stdio_server(server_config: dict[str, Any]) -> bool:
5
+ """Check if the server configuration is for a stdio server.
6
+
7
+ Args:
8
+ server_config: The server configuration section
9
+
10
+ Returns:
11
+ True if the server is a stdio server, False otherwise
12
+ """
13
+ return "command" in server_config and "args" in server_config
@@ -0,0 +1,23 @@
1
+ """
2
+ Options for MCP client configuration.
3
+
4
+ This module provides data classes and type definitions for configuring the MCP client.
5
+ """
6
+
7
+ from typing import NotRequired, TypedDict
8
+
9
+ from .sandbox import SandboxOptions
10
+
11
+
12
+ class ClientOptions(TypedDict):
13
+ """Options for configuring the MCP client.
14
+
15
+ This class encapsulates all configuration options for the MCPClient,
16
+ making it easier to extend the API without breaking backward compatibility.
17
+ """
18
+
19
+ is_sandboxed: NotRequired[bool]
20
+ """Whether to use sandboxed execution mode for running MCP servers."""
21
+
22
+ sandbox_options: NotRequired[SandboxOptions]
23
+ """Options for sandbox configuration when is_sandboxed=True."""
@@ -0,0 +1,23 @@
1
+ """Type definitions for sandbox-related configurations."""
2
+
3
+ from typing import NotRequired, TypedDict
4
+
5
+
6
+ class SandboxOptions(TypedDict):
7
+ """Configuration options for sandbox execution.
8
+
9
+ This type defines the configuration options available when running
10
+ MCP servers in a sandboxed environment (e.g., using E2B).
11
+ """
12
+
13
+ api_key: str
14
+ """Direct API key for sandbox provider (e.g., E2B API key).
15
+ If not provided, will use E2B_API_KEY environment variable."""
16
+
17
+ sandbox_template_id: NotRequired[str]
18
+ """Template ID for the sandbox environment.
19
+ Default: 'base'"""
20
+
21
+ supergateway_command: NotRequired[str]
22
+ """Command to run supergateway.
23
+ Default: 'npx -y supergateway'"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-use
3
- Version: 1.2.13
3
+ Version: 1.3.0
4
4
  Summary: MCP Library for LLMs
5
5
  Author-email: Pietro Zullo <pietro.zullo@gmail.com>
6
6
  License: MIT
@@ -33,6 +33,8 @@ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
33
33
  Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
34
34
  Requires-Dist: pytest>=7.4.0; extra == 'dev'
35
35
  Requires-Dist: ruff>=0.1.0; extra == 'dev'
36
+ Provides-Extra: e2b
37
+ Requires-Dist: e2b-code-interpreter>=1.5.0; extra == 'e2b'
36
38
  Provides-Extra: openai
37
39
  Requires-Dist: openai>=1.10.0; extra == 'openai'
38
40
  Provides-Extra: search
@@ -67,30 +69,64 @@ Description-Content-Type: text/markdown
67
69
  <img src="https://img.shields.io/github/stars/pietrozullo/mcp-use?style=social" /></a>
68
70
  </p>
69
71
  <p align="center">
70
- <a href="https://x.com/pietrozullo" alt="Twitter Follow">
72
+ <a href="https://x.com/pietrozullo" alt="Twitter Follow - Pietro">
71
73
  <img src="https://img.shields.io/twitter/follow/Pietro?style=social" /></a>
74
+ <a href="https://x.com/pederzh" alt="Twitter Follow - Luigi">
75
+ <img src="https://img.shields.io/twitter/follow/Luigi?style=social" /></a>
72
76
  <a href="https://discord.gg/XkNkSkMz3V" alt="Discord">
73
77
  <img src="https://dcbadge.limes.pink/api/server/https://discord.gg/XkNkSkMz3V?style=flat" /></a>
74
78
  </p>
75
79
  🌐 MCP-Use is the open source way to connect **any LLM to any MCP server** and build custom agents that have tool access, without using closed source or application clients.
76
80
 
81
+ 💬 Get started quickly - chat with your servers on our <b>hosted version</b>! <b>[Try mcp-use chat *(beta)* ](https://chat.mcp-use.io)</b>.
82
+
77
83
  💡 Let developers easily connect any LLM to tools like web browsing, file operations, and more.
78
84
 
79
85
  # Features
80
86
 
81
87
  ## ✨ Key Features
82
-
83
- | Feature | Description |
84
- |---------|-------------|
85
- | 🔄 [**Ease of use**](#quick-start) | Create your first MCP capable agent you need only 6 lines of code |
86
- | 🤖 [**LLM Flexibility**](#installing-langchain-providers) | Works with any langchain supported LLM that supports tool calling (OpenAI, Anthropic, Groq, LLama etc.) |
87
- | 🌐 [**Code Builder**](https://mcp-use.io/builder) | Explore MCP capabilities and generate starter code with the interactive [code builder](https://mcp-use.io/builder). |
88
- | 🔗 [**HTTP Support**](#http-connection-example) | Direct connection to MCP servers running on specific HTTP ports |
89
- | ⚙️ [**Dynamic Server Selection**](#dynamic-server-selection-server-manager) | Agents can dynamically choose the most appropriate MCP server for a given task from the available pool |
90
- | 🧩 [**Multi-Server Support**](#multi-server-support) | Use multiple MCP servers simultaneously in a single agent |
91
- | 🛡️ [**Tool Restrictions**](#tool-access-control) | Restrict potentially dangerous tools like file system or network access |
92
- | 🔧 [**Custom Agents**](#build-a-custom-agent) | Build your own agents with any framework using the LangChain adapter or create new adapters |
93
-
88
+ <table>
89
+ <tr>
90
+ <th width="400">Feature</th>
91
+ <th>Description</th>
92
+ </tr>
93
+ <tr>
94
+ <td>🔄 <a href="#quick-start"><strong>Ease of use</strong></a></td>
95
+ <td>Create your first MCP capable agent you need only 6 lines of code</td>
96
+ </tr>
97
+ <tr>
98
+ <td>🤖 <a href="#installing-langchain-providers"><strong>LLM Flexibility</strong></a></td>
99
+ <td>Works with any langchain supported LLM that supports tool calling (OpenAI, Anthropic, Groq, LLama etc.)</td>
100
+ </tr>
101
+ <tr>
102
+ <td>🌐 <a href="https://mcp-use.io/builder"><strong>Code Builder</strong></a></td>
103
+ <td>Explore MCP capabilities and generate starter code with the interactive <a href="https://mcp-use.io/builder">code builder</a>.</td>
104
+ </tr>
105
+ <tr>
106
+ <td>🔗 <a href="#http-connection-example"><strong>HTTP Support</strong></a></td>
107
+ <td>Direct connection to MCP servers running on specific HTTP ports</td>
108
+ </tr>
109
+ <tr>
110
+ <td>⚙️ <a href="#dynamic-server-selection-server-manager"><strong>Dynamic Server Selection</strong></a></td>
111
+ <td>Agents can dynamically choose the most appropriate MCP server for a given task from the available pool</td>
112
+ </tr>
113
+ <tr>
114
+ <td>🧩 <a href="#multi-server-support"><strong>Multi-Server Support</strong></a></td>
115
+ <td>Use multiple MCP servers simultaneously in a single agent</td>
116
+ </tr>
117
+ <tr>
118
+ <td>🛡️ <a href="#tool-access-control"><strong>Tool Restrictions</strong></a></td>
119
+ <td>Restrict potentially dangerous tools like file system or network access</td>
120
+ </tr>
121
+ <tr>
122
+ <td>🔧 <a href="#build-a-custom-agent"><strong>Custom Agents</strong></a></td>
123
+ <td>Build your own agents with any framework using the LangChain adapter or create new adapters</td>
124
+ </tr>
125
+ <tr>
126
+ <td>❓ <a href="https://mcp-use.io/what-should-we-build-next"><strong>What should we build next</strong></a></td>
127
+ <td>Let us know what you'd like us to build next</td>
128
+ </tr>
129
+ </table>
94
130
 
95
131
  # Quick start
96
132
 
@@ -118,11 +154,8 @@ pip install langchain-openai
118
154
 
119
155
  # For Anthropic
120
156
  pip install langchain-anthropic
121
-
122
- # For other providers, check the [LangChain chat models documentation](https://python.langchain.com/docs/integrations/chat/)
123
157
  ```
124
-
125
- and add your API keys for the provider you want to use to your `.env` file.
158
+ For other providers, check the [LangChain chat models documentation](https://python.langchain.com/docs/integrations/chat/) and add your API keys for the provider you want to use to your `.env` file.
126
159
 
127
160
  ```bash
128
161
  OPENAI_API_KEY=
@@ -561,6 +594,101 @@ if __name__ == "__main__":
561
594
  asyncio.run(main())
562
595
  ```
563
596
 
597
+ # Sandboxed Execution
598
+
599
+ MCP-Use supports running MCP servers in a sandboxed environment using E2B's cloud infrastructure. This allows you to run MCP servers without having to install dependencies locally, making it easier to use tools that might have complex setups or system requirements.
600
+
601
+ ## Installation
602
+
603
+ To use sandboxed execution, you need to install the E2B dependency:
604
+
605
+ ```bash
606
+ # Install mcp-use with E2B support
607
+ pip install "mcp-use[e2b]"
608
+
609
+ # Or install the dependency directly
610
+ pip install e2b-code-interpreter
611
+ ```
612
+
613
+ You'll also need an E2B API key. You can sign up at [e2b.dev](https://e2b.dev) to get your API key.
614
+
615
+ ## Configuration
616
+
617
+ To enable sandboxed execution, use the `ClientOptions` parameter when creating your `MCPClient`:
618
+
619
+ ```python
620
+ import asyncio
621
+ import os
622
+ from dotenv import load_dotenv
623
+ from langchain_openai import ChatOpenAI
624
+ from mcp_use import MCPAgent, MCPClient
625
+ from mcp_use.types.sandbox import SandboxOptions
626
+ from mcp_use.types.clientoptions import ClientOptions
627
+
628
+ async def main():
629
+ # Load environment variables (needs E2B_API_KEY)
630
+ load_dotenv()
631
+
632
+ # Define MCP server configuration
633
+ server_config = {
634
+ "mcpServers": {
635
+ "everything": {
636
+ "command": "npx",
637
+ "args": ["-y", "@modelcontextprotocol/server-everything"],
638
+ }
639
+ }
640
+ }
641
+
642
+ # Define sandbox options
643
+ sandbox_options: SandboxOptions = {
644
+ "api_key": os.getenv("E2B_API_KEY"), # API key can also be provided directly
645
+ "sandbox_template_id": "base", # Use base template
646
+ }
647
+
648
+ # Create client options for sandboxed mode
649
+ client_options: ClientOptions = {
650
+ "is_sandboxed": True,
651
+ "sandbox_options": sandbox_options
652
+ }
653
+
654
+ # Create client with sandboxed mode enabled
655
+ client = MCPClient(
656
+ config=server_config,
657
+ options=client_options
658
+ )
659
+
660
+ # Create agent with the sandboxed client
661
+ llm = ChatOpenAI(model="gpt-4o")
662
+ agent = MCPAgent(llm=llm, client=client)
663
+
664
+ # Run your agent
665
+ result = await agent.run("Use the command line tools to help me add 1+1")
666
+ print(result)
667
+
668
+ # Clean up
669
+ await client.close_all_sessions()
670
+
671
+ if __name__ == "__main__":
672
+ asyncio.run(main())
673
+ ```
674
+
675
+ ## Sandbox Options
676
+
677
+ The `SandboxOptions` type provides configuration for the sandbox environment:
678
+
679
+ | Option | Description | Default |
680
+ | ---------------------- | ---------------------------------------------------------------------------------------- | --------------------- |
681
+ | `api_key` | E2B API key. Required - can be provided directly or via E2B_API_KEY environment variable | None |
682
+ | `sandbox_template_id` | Template ID for the sandbox environment | "base" |
683
+ | `supergateway_command` | Command to run supergateway | "npx -y supergateway" |
684
+
685
+ ## Benefits of Sandboxed Execution
686
+
687
+ - **No local dependencies**: Run MCP servers without installing dependencies locally
688
+ - **Isolation**: Execute code in a secure, isolated environment
689
+ - **Consistent environment**: Ensure consistent behavior across different systems
690
+ - **Resource efficiency**: Offload resource-intensive tasks to cloud infrastructure
691
+
564
692
  # Build a Custom Agent:
565
693
 
566
694
  You can also build your own custom agent using the LangChain adapter:
@@ -652,7 +780,6 @@ agent = MCPAgent(
652
780
 
653
781
  This is useful when you only need to see the agent's steps and decision-making process without all the low-level debug information from other components.
654
782
 
655
-
656
783
  # Roadmap
657
784
 
658
785
  <ul>
@@ -1,6 +1,6 @@
1
1
  mcp_use/__init__.py,sha256=FikKagS6u8mugJOeslN3xfSA-tBLhjOywZSEcQ-y23g,1006
2
- mcp_use/client.py,sha256=3mEiAtGlC28iv0zeEtQcMI6cfTlllyjSvS0dwuoVBrw,8317
3
- mcp_use/config.py,sha256=O9V4pa-shZ2mPokRTrd7KZQ2GpuTcYBGUslefl1fosw,1653
2
+ mcp_use/client.py,sha256=n0sJtRmntJtsVnmI1qCSTY8iuY9xYFybmA7V8rn09bE,8863
3
+ mcp_use/config.py,sha256=ks-aX1Kzk_iUBbUAA2_-BRGN4oltYU3CN5CKanMfPUs,2564
4
4
  mcp_use/logging.py,sha256=UhQdMx0H0q08-ZPjY_hAJVErkEUAkU1oahHqwdfdK_U,4274
5
5
  mcp_use/session.py,sha256=IPVzYASFMZx7-xpK4X_MR5chcsIwGvcs6vYXiO1hutM,2604
6
6
  mcp_use/adapters/__init__.py,sha256=-xCrgPThuX7x0PHGFDdjb7M-mgw6QV3sKu5PM7ShnRg,275
@@ -8,13 +8,15 @@ mcp_use/adapters/base.py,sha256=bPVjHERySX6Vw16mEmgFaJuy4Yc_sM8JPtOAqJrP6Rg,7164
8
8
  mcp_use/adapters/langchain_adapter.py,sha256=nrsOYDQu-nlLw14f2uNHM-pH8l-yQfZelWXZLhBSMeQ,11008
9
9
  mcp_use/agents/__init__.py,sha256=N3eVYP2PxqNO2KcQv5fY8UMUX2W3eLTNkkzuFIJ1DUA,261
10
10
  mcp_use/agents/base.py,sha256=bfuldi_89AbSbNc8KeTiCArRT9V62CNxHOWYkLHWjyA,1605
11
- mcp_use/agents/mcpagent.py,sha256=xZr-ihW5CW2wKAi0Gi-9GIXlJE0MGu-18xR8vi-Fu6Q,27025
11
+ mcp_use/agents/mcpagent.py,sha256=1T6ZJkuMvXdR9dP-59V-m40wJ0dgO0Hxoz14jaTYPCE,26913
12
12
  mcp_use/agents/prompts/system_prompt_builder.py,sha256=GH5Pvl49IBpKpZA9YTI83xMsdYSkRN_hw4LFHkKtxbg,4122
13
13
  mcp_use/agents/prompts/templates.py,sha256=AZKrGWuI516C-PmyOPvxDBibNdqJtN24sOHTGR06bi4,1933
14
- mcp_use/connectors/__init__.py,sha256=jnd-7pPPJMb0UNJ6aD9lInj5Tlamc8lA_mFyG8RWJpo,385
14
+ mcp_use/connectors/__init__.py,sha256=cUF4yT0bNr8qeLkSzg28SHueiV5qDaHEB1l1GZ2K0dc,536
15
15
  mcp_use/connectors/base.py,sha256=uJFU80kIpr0bVRAHDXTWRziIwdb_5Yjf2HsDNokZw-M,7731
16
16
  mcp_use/connectors/http.py,sha256=2ZG5JxcK1WZ4jkTfTir6bEQLMxXBTPHyi0s42RHGeFs,2837
17
+ mcp_use/connectors/sandbox.py,sha256=SxSOOLOCDPtlVTCxxZSRbVfvva6rzDWfBLa56ne7esc,10902
17
18
  mcp_use/connectors/stdio.py,sha256=MTzsqmVVihACUKngE-g5BignK3jAFds2CFv3aSzbJfs,2608
19
+ mcp_use/connectors/utils.py,sha256=zQ8GdNQx0Twz3by90BoU1RsWPf9wODGof4K3-NxPXeA,366
18
20
  mcp_use/connectors/websocket.py,sha256=LeU53YI3zjbwKq5GzFRziqA_z9Dn5qACiNyxWDrn2ns,9540
19
21
  mcp_use/managers/__init__.py,sha256=rzsJbOhtlmxNQLGcdmtmHaiExEXmiQiUuzPrAgKhAJw,439
20
22
  mcp_use/managers/server_manager.py,sha256=YVl5ciNIQfVzP-BR9hA0ac6YSwq0WChpA_Lxvh2e9HE,3984
@@ -31,7 +33,9 @@ mcp_use/task_managers/base.py,sha256=xBrS9_GdlR0tr6sKN5pyMGUrQVGKRD6Qlk6hhOFcxRE
31
33
  mcp_use/task_managers/sse.py,sha256=nLKt99OiqoJxFT62zCeNwSZUmdPPg4SD7M1pCEPOa3c,2391
32
34
  mcp_use/task_managers/stdio.py,sha256=MJcW03lUZUs_HEUxwFPaqy7m8QLbmdn6LagpcfZdjc8,2130
33
35
  mcp_use/task_managers/websocket.py,sha256=POB4YwCff6IJ0vj4eGpYqfDwLiqA0_fEUS4hbborGa4,1848
34
- mcp_use-1.2.13.dist-info/METADATA,sha256=Jhij8qlF_RqgiiRlVSVZYIlP6TgGYjcr3j_2LLSe0bo,20966
35
- mcp_use-1.2.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
36
- mcp_use-1.2.13.dist-info/licenses/LICENSE,sha256=7Pw7dbwJSBw8zH-WE03JnR5uXvitRtaGTP9QWPcexcs,1068
37
- mcp_use-1.2.13.dist-info/RECORD,,
36
+ mcp_use/types/clientoptions.py,sha256=COzZPg19OlVm5F5ou6RhgzDVkPRs88Jz4c4uBanq5Ko,687
37
+ mcp_use/types/sandbox.py,sha256=opJ9r56F1FvaqVvPovfAj5jZbsOexgwYx5wLgSlN8_U,712
38
+ mcp_use-1.3.0.dist-info/METADATA,sha256=45e-TFXg17LD7sE8kyBgUqCYaeDVebgn63fED2vEznI,25427
39
+ mcp_use-1.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
40
+ mcp_use-1.3.0.dist-info/licenses/LICENSE,sha256=7Pw7dbwJSBw8zH-WE03JnR5uXvitRtaGTP9QWPcexcs,1068
41
+ mcp_use-1.3.0.dist-info/RECORD,,