mcp-use 1.3.7__py3-none-any.whl → 1.3.9__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.

@@ -7,7 +7,7 @@ through HTTP APIs with SSE or Streamable HTTP for transport.
7
7
 
8
8
  import httpx
9
9
  from mcp import ClientSession
10
- from mcp.client.session import ElicitationFnT, SamplingFnT
10
+ from mcp.client.session import ElicitationFnT, LoggingFnT, MessageHandlerFnT, SamplingFnT
11
11
 
12
12
  from ..logging import logger
13
13
  from ..task_managers import SseConnectionManager, StreamableHttpConnectionManager
@@ -30,6 +30,8 @@ class HttpConnector(BaseConnector):
30
30
  sse_read_timeout: float = 60 * 5,
31
31
  sampling_callback: SamplingFnT | None = None,
32
32
  elicitation_callback: ElicitationFnT | None = None,
33
+ message_handler: MessageHandlerFnT | None = None,
34
+ logging_callback: LoggingFnT | None = None,
33
35
  ):
34
36
  """Initialize a new HTTP connector.
35
37
 
@@ -42,7 +44,12 @@ class HttpConnector(BaseConnector):
42
44
  sampling_callback: Optional sampling callback.
43
45
  elicitation_callback: Optional elicitation callback.
44
46
  """
45
- super().__init__(sampling_callback=sampling_callback, elicitation_callback=elicitation_callback)
47
+ super().__init__(
48
+ sampling_callback=sampling_callback,
49
+ elicitation_callback=elicitation_callback,
50
+ message_handler=message_handler,
51
+ logging_callback=logging_callback,
52
+ )
46
53
  self.base_url = base_url.rstrip("/")
47
54
  self.auth_token = auth_token
48
55
  self.headers = headers or {}
@@ -78,6 +85,8 @@ class HttpConnector(BaseConnector):
78
85
  write_stream,
79
86
  sampling_callback=self.sampling_callback,
80
87
  elicitation_callback=self.elicitation_callback,
88
+ message_handler=self._internal_message_handler,
89
+ logging_callback=self.logging_callback,
81
90
  client_info=self.client_info,
82
91
  )
83
92
  await test_client.__aenter__()
@@ -162,6 +171,8 @@ class HttpConnector(BaseConnector):
162
171
  write_stream,
163
172
  sampling_callback=self.sampling_callback,
164
173
  elicitation_callback=self.elicitation_callback,
174
+ message_handler=self._internal_message_handler,
175
+ logging_callback=self.logging_callback,
165
176
  client_info=self.client_info,
166
177
  )
167
178
  await self.client_session.__aenter__()
@@ -12,7 +12,7 @@ import time
12
12
 
13
13
  import aiohttp
14
14
  from mcp import ClientSession
15
- from mcp.client.session import ElicitationFnT, SamplingFnT
15
+ from mcp.client.session import ElicitationFnT, LoggingFnT, MessageHandlerFnT, SamplingFnT
16
16
 
17
17
  from ..logging import logger
18
18
  from ..task_managers import SseConnectionManager
@@ -20,10 +20,7 @@ from ..task_managers import SseConnectionManager
20
20
  # Import E2B SDK components (optional dependency)
21
21
  try:
22
22
  logger.debug("Attempting to import e2b_code_interpreter...")
23
- from e2b_code_interpreter import (
24
- CommandHandle,
25
- Sandbox,
26
- )
23
+ from e2b_code_interpreter import CommandHandle, Sandbox
27
24
 
28
25
  logger.debug("Successfully imported e2b_code_interpreter")
29
26
  except ImportError as e:
@@ -53,6 +50,8 @@ class SandboxConnector(BaseConnector):
53
50
  sse_read_timeout: float = 60 * 5,
54
51
  sampling_callback: SamplingFnT | None = None,
55
52
  elicitation_callback: ElicitationFnT | None = None,
53
+ message_handler: MessageHandlerFnT | None = None,
54
+ logging_callback: LoggingFnT | None = None,
56
55
  ):
57
56
  """Initialize a new sandbox connector.
58
57
 
@@ -67,7 +66,12 @@ class SandboxConnector(BaseConnector):
67
66
  sampling_callback: Optional sampling callback.
68
67
  elicitation_callback: Optional elicitation callback.
69
68
  """
70
- super().__init__(sampling_callback=sampling_callback, elicitation_callback=elicitation_callback)
69
+ super().__init__(
70
+ sampling_callback=sampling_callback,
71
+ elicitation_callback=elicitation_callback,
72
+ message_handler=message_handler,
73
+ logging_callback=logging_callback,
74
+ )
71
75
  if Sandbox is None:
72
76
  raise ImportError(
73
77
  "E2B SDK (e2b-code-interpreter) not found. Please install it with "
@@ -227,6 +231,8 @@ class SandboxConnector(BaseConnector):
227
231
  write_stream,
228
232
  sampling_callback=self.sampling_callback,
229
233
  elicitation_callback=self.elicitation_callback,
234
+ message_handler=self._internal_message_handler,
235
+ logging_callback=self.logging_callback,
230
236
  client_info=self.client_info,
231
237
  )
232
238
  await self.client_session.__aenter__()
@@ -8,7 +8,7 @@ through the standard input/output streams.
8
8
  import sys
9
9
 
10
10
  from mcp import ClientSession, StdioServerParameters
11
- from mcp.client.session import ElicitationFnT, SamplingFnT
11
+ from mcp.client.session import ElicitationFnT, LoggingFnT, MessageHandlerFnT, SamplingFnT
12
12
 
13
13
  from ..logging import logger
14
14
  from ..task_managers import StdioConnectionManager
@@ -31,6 +31,8 @@ class StdioConnector(BaseConnector):
31
31
  errlog=sys.stderr,
32
32
  sampling_callback: SamplingFnT | None = None,
33
33
  elicitation_callback: ElicitationFnT | None = None,
34
+ message_handler: MessageHandlerFnT | None = None,
35
+ logging_callback: LoggingFnT | None = None,
34
36
  ):
35
37
  """Initialize a new stdio connector.
36
38
 
@@ -42,7 +44,12 @@ class StdioConnector(BaseConnector):
42
44
  sampling_callback: Optional callback to sample the client.
43
45
  elicitation_callback: Optional callback to elicit the client.
44
46
  """
45
- super().__init__(sampling_callback=sampling_callback, elicitation_callback=elicitation_callback)
47
+ super().__init__(
48
+ sampling_callback=sampling_callback,
49
+ elicitation_callback=elicitation_callback,
50
+ message_handler=message_handler,
51
+ logging_callback=logging_callback,
52
+ )
46
53
  self.command = command
47
54
  self.args = args or [] # Ensure args is never None
48
55
  self.env = env
@@ -69,6 +76,8 @@ class StdioConnector(BaseConnector):
69
76
  write_stream,
70
77
  sampling_callback=self.sampling_callback,
71
78
  elicitation_callback=self.elicitation_callback,
79
+ message_handler=self._internal_message_handler,
80
+ logging_callback=self.logging_callback,
72
81
  client_info=self.client_info,
73
82
  )
74
83
  await self.client_session.__aenter__()
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,29 @@
1
+ import traceback
2
+
3
+ from ..logging import logger
4
+
5
+ retryable_exceptions = (TimeoutError, ConnectionError) # We can add more exceptions here
6
+
7
+
8
+ def format_error(error: Exception, **context) -> dict:
9
+ """
10
+ Formats an exception into a structured format that can be understood by LLMs.
11
+
12
+ Args:
13
+ error: The exception to format.
14
+ **context: Additional context to include in the formatted error.
15
+
16
+ Returns:
17
+ A dictionary containing the formatted error.
18
+ """
19
+ formatted_context = {
20
+ "error": type(error).__name__,
21
+ "details": str(error),
22
+ "isRetryable": isinstance(error, retryable_exceptions),
23
+ "stack": traceback.format_exc(),
24
+ "code": getattr(error, "code", "UNKNOWN"),
25
+ }
26
+ formatted_context.update(context)
27
+
28
+ logger.error(f"Structured error: {formatted_context}") # For observability (maybe remove later)
29
+ return formatted_context
@@ -6,16 +6,14 @@ from .tools import (
6
6
  ListServersTool,
7
7
  MCPServerTool,
8
8
  SearchToolsTool,
9
- UseToolFromServerTool,
10
9
  )
11
10
 
12
11
  __all__ = [
13
12
  "ServerManager",
14
- "ListServersTool",
13
+ "MCPServerTool",
15
14
  "ConnectServerTool",
16
- "GetActiveServerTool",
17
15
  "DisconnectServerTool",
16
+ "GetActiveServerTool",
17
+ "ListServersTool",
18
18
  "SearchToolsTool",
19
- "MCPServerTool",
20
- "UseToolFromServerTool",
21
19
  ]
@@ -4,14 +4,7 @@ from mcp_use.client import MCPClient
4
4
  from mcp_use.logging import logger
5
5
 
6
6
  from ..adapters.base import BaseAdapter
7
- from .tools import (
8
- ConnectServerTool,
9
- DisconnectServerTool,
10
- GetActiveServerTool,
11
- ListServersTool,
12
- SearchToolsTool,
13
- UseToolFromServerTool,
14
- )
7
+ from .tools import ConnectServerTool, DisconnectServerTool, GetActiveServerTool, ListServersTool, SearchToolsTool
15
8
 
16
9
 
17
10
  class ServerManager:
@@ -73,12 +66,21 @@ class ServerManager:
73
66
  except Exception as e:
74
67
  logger.error(f"Error prefetching tools for server '{server_name}': {e}")
75
68
 
76
- @property
77
- def tools(self) -> list[BaseTool]:
78
- """Get all server management tools.
69
+ def get_active_server_tools(self) -> list[BaseTool]:
70
+ """Get tools from the currently active server.
71
+
72
+ Returns:
73
+ List of tools from the active server, or empty list if no server is active
74
+ """
75
+ if self.active_server and self.active_server in self._server_tools:
76
+ return self._server_tools[self.active_server]
77
+ return []
78
+
79
+ def get_management_tools(self) -> list[BaseTool]:
80
+ """Get the server management tools.
79
81
 
80
82
  Returns:
81
- list of LangChain tools for server management
83
+ List of server management tools
82
84
  """
83
85
  return [
84
86
  ListServersTool(self),
@@ -86,5 +88,36 @@ class ServerManager:
86
88
  GetActiveServerTool(self),
87
89
  DisconnectServerTool(self),
88
90
  SearchToolsTool(self),
89
- UseToolFromServerTool(self),
90
91
  ]
92
+
93
+ def has_tool_changes(self, current_tool_names: set[str]) -> bool:
94
+ """Check if the available tools have changed.
95
+
96
+ Args:
97
+ current_tool_names: Set of currently known tool names
98
+
99
+ Returns:
100
+ True if tools have changed, False otherwise
101
+ """
102
+ new_tool_names = {tool.name for tool in self.tools}
103
+ return new_tool_names != current_tool_names
104
+
105
+ @property
106
+ def tools(self) -> list[BaseTool]:
107
+ """Get all server management tools and tools from the active server.
108
+
109
+ Returns:
110
+ list of LangChain tools for server management plus tools from active server
111
+ """
112
+ management_tools = self.get_management_tools()
113
+
114
+ # Add tools from the active server if available
115
+ if self.active_server and self.active_server in self._server_tools:
116
+ server_tools = self._server_tools[self.active_server]
117
+ logger.debug(f"Including {len(server_tools)} tools from active server '{self.active_server}'")
118
+ logger.debug(f"Server tools: {[tool.name for tool in server_tools]}")
119
+ return management_tools + server_tools
120
+ else:
121
+ logger.debug("No active server - returning only management tools")
122
+
123
+ return management_tools
@@ -4,14 +4,12 @@ from .disconnect_server import DisconnectServerTool
4
4
  from .get_active_server import GetActiveServerTool
5
5
  from .list_servers_tool import ListServersTool
6
6
  from .search_tools import SearchToolsTool
7
- from .use_tool import UseToolFromServerTool
8
7
 
9
8
  __all__ = [
10
9
  "MCPServerTool",
11
- "ListServersTool",
12
10
  "ConnectServerTool",
13
- "GetActiveServerTool",
14
11
  "DisconnectServerTool",
12
+ "GetActiveServerTool",
13
+ "ListServersTool",
15
14
  "SearchToolsTool",
16
- "UseToolFromServerTool",
17
15
  ]
@@ -2,6 +2,7 @@ from typing import ClassVar
2
2
 
3
3
  from pydantic import BaseModel, Field
4
4
 
5
+ from mcp_use.errors.error_formatting import format_error
5
6
  from mcp_use.logging import logger
6
7
 
7
8
  from .base_tool import MCPServerTool
@@ -62,7 +63,7 @@ class ConnectServerTool(MCPServerTool):
62
63
 
63
64
  except Exception as e:
64
65
  logger.error(f"Error connecting to server '{server_name}': {e}")
65
- return f"Failed to connect to server '{server_name}': {str(e)}"
66
+ return format_error(e, server_name=server_name)
66
67
 
67
68
  def _run(self, server_name: str) -> str:
68
69
  """Synchronous version that raises a NotImplementedError - use _arun instead."""
@@ -2,6 +2,7 @@ from typing import ClassVar
2
2
 
3
3
  from pydantic import BaseModel
4
4
 
5
+ from mcp_use.errors.error_formatting import format_error
5
6
  from mcp_use.logging import logger
6
7
 
7
8
  from .base_tool import MCPServerTool
@@ -36,7 +37,7 @@ class DisconnectServerTool(MCPServerTool):
36
37
  return f"Successfully disconnected from MCP server '{server_name}'."
37
38
  except Exception as e:
38
39
  logger.error(f"Error disconnecting from server '{server_name}': {e}")
39
- return f"Failed to disconnect from server '{server_name}': {str(e)}"
40
+ return format_error(e, server_name=server_name)
40
41
 
41
42
  async def _arun(self, **kwargs) -> str:
42
43
  """Async implementation of _run."""
@@ -2,6 +2,7 @@ from typing import ClassVar
2
2
 
3
3
  from pydantic import BaseModel
4
4
 
5
+ from mcp_use.errors.error_formatting import format_error
5
6
  from mcp_use.logging import logger
6
7
 
7
8
  from .base_tool import MCPServerTool
@@ -44,6 +45,7 @@ class ListServersTool(MCPServerTool):
44
45
  result += f" {tool_count} tools available for this server\n"
45
46
  except Exception as e:
46
47
  logger.error(f"Unexpected error listing tools for server '{server_name}': {e}")
48
+ return format_error(e, server=server_name, operation="list_tools")
47
49
 
48
50
  return result
49
51
 
mcp_use/session.py CHANGED
@@ -5,8 +5,12 @@ This module provides a session manager for MCP connections,
5
5
  which handles authentication, initialization, and tool discovery.
6
6
  """
7
7
 
8
+ from datetime import timedelta
8
9
  from typing import Any
9
10
 
11
+ from mcp.types import CallToolResult, GetPromptResult, Prompt, ReadResourceResult, Resource, Tool
12
+ from pydantic import AnyUrl
13
+
10
14
  from .connectors.base import BaseConnector
11
15
 
12
16
 
@@ -82,3 +86,69 @@ class MCPSession:
82
86
  True if the connector is connected, False otherwise.
83
87
  """
84
88
  return self.connector.is_connected
89
+
90
+ # Convenience methods for MCP operations
91
+ async def call_tool(
92
+ self, name: str, arguments: dict[str, Any], read_timeout_seconds: timedelta | None = None
93
+ ) -> CallToolResult:
94
+ """Call an MCP tool.
95
+
96
+ Args:
97
+ name: The name of the tool to call.
98
+ arguments: The arguments to pass to the tool.
99
+ read_timeout_seconds: Optional timeout for the tool call.
100
+
101
+ Returns:
102
+ The result of the tool call.
103
+
104
+ Raises:
105
+ RuntimeError: If the connection is lost and cannot be reestablished.
106
+ """
107
+ return await self.connector.call_tool(name, arguments, read_timeout_seconds)
108
+
109
+ async def list_tools(self) -> list[Tool]:
110
+ """List all available tools from the MCP server.
111
+
112
+ Returns:
113
+ List of available tools.
114
+ """
115
+ return await self.connector.list_tools()
116
+
117
+ async def list_resources(self) -> list[Resource]:
118
+ """List all available resources from the MCP server.
119
+
120
+ Returns:
121
+ List of available resources.
122
+ """
123
+ return await self.connector.list_resources()
124
+
125
+ async def read_resource(self, uri: AnyUrl) -> ReadResourceResult:
126
+ """Read a resource by URI.
127
+
128
+ Args:
129
+ uri: The URI of the resource to read.
130
+
131
+ Returns:
132
+ The resource content.
133
+ """
134
+ return await self.connector.read_resource(uri)
135
+
136
+ async def list_prompts(self) -> list[Prompt]:
137
+ """List all available prompts from the MCP server.
138
+
139
+ Returns:
140
+ List of available prompts.
141
+ """
142
+ return await self.connector.list_prompts()
143
+
144
+ async def get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> GetPromptResult:
145
+ """Get a prompt by name.
146
+
147
+ Args:
148
+ name: The name of the prompt to get.
149
+ arguments: Optional arguments for the prompt.
150
+
151
+ Returns:
152
+ The prompt result with messages.
153
+ """
154
+ return await self.connector.get_prompt(name, arguments)
@@ -11,10 +11,7 @@ from posthog import Posthog
11
11
  from scarf import ScarfEventLogger
12
12
 
13
13
  from mcp_use.logging import MCP_USE_DEBUG
14
- from mcp_use.telemetry.events import (
15
- BaseTelemetryEvent,
16
- MCPAgentExecutionEvent,
17
- )
14
+ from mcp_use.telemetry.events import BaseTelemetryEvent, MCPAgentExecutionEvent
18
15
  from mcp_use.telemetry.utils import get_package_version
19
16
  from mcp_use.utils import singleton
20
17