mcp-use 1.1.5__py3-none-any.whl → 1.2.5__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.
- mcp_use/__init__.py +14 -1
- mcp_use/adapters/__init__.py +5 -0
- mcp_use/adapters/langchain_adapter.py +212 -0
- mcp_use/agents/__init__.py +6 -2
- mcp_use/agents/mcpagent.py +290 -114
- mcp_use/agents/prompts/system_prompt_builder.py +105 -0
- mcp_use/agents/prompts/templates.py +43 -0
- mcp_use/agents/server_manager.py +280 -0
- mcp_use/logging.py +51 -4
- {mcp_use-1.1.5.dist-info → mcp_use-1.2.5.dist-info}/METADATA +92 -7
- {mcp_use-1.1.5.dist-info → mcp_use-1.2.5.dist-info}/RECORD +13 -10
- mcp_use/agents/langchain_agent.py +0 -267
- mcp_use/agents/prompts/default.py +0 -22
- {mcp_use-1.1.5.dist-info → mcp_use-1.2.5.dist-info}/WHEEL +0 -0
- {mcp_use-1.1.5.dist-info → mcp_use-1.2.5.dist-info}/licenses/LICENSE +0 -0
mcp_use/__init__.py
CHANGED
|
@@ -11,7 +11,7 @@ from .agents.mcpagent import MCPAgent
|
|
|
11
11
|
from .client import MCPClient
|
|
12
12
|
from .config import load_config_file
|
|
13
13
|
from .connectors import BaseConnector, HttpConnector, StdioConnector, WebSocketConnector
|
|
14
|
-
from .logging import logger
|
|
14
|
+
from .logging import MCP_USE_DEBUG, Logger, logger
|
|
15
15
|
from .session import MCPSession
|
|
16
16
|
|
|
17
17
|
__version__ = version("mcp-use")
|
|
@@ -27,4 +27,17 @@ __all__ = [
|
|
|
27
27
|
"create_session_from_config",
|
|
28
28
|
"load_config_file",
|
|
29
29
|
"logger",
|
|
30
|
+
"MCP_USE_DEBUG",
|
|
31
|
+
"Logger",
|
|
32
|
+
"set_debug",
|
|
30
33
|
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Helper function to set debug mode
|
|
37
|
+
def set_debug(debug=2):
|
|
38
|
+
"""Set the debug mode for mcp_use.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
debug: Whether to enable debug mode (default: True)
|
|
42
|
+
"""
|
|
43
|
+
Logger.set_debug(debug)
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LangChain adapter for MCP tools.
|
|
3
|
+
|
|
4
|
+
This module provides utilities to convert MCP tools to LangChain tools.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, NoReturn
|
|
8
|
+
|
|
9
|
+
from jsonschema_pydantic import jsonschema_to_pydantic
|
|
10
|
+
from langchain_core.tools import BaseTool, ToolException
|
|
11
|
+
from mcp.types import CallToolResult, EmbeddedResource, ImageContent, TextContent
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
|
|
14
|
+
from ..connectors.base import BaseConnector
|
|
15
|
+
from ..logging import logger
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _parse_mcp_tool_result(tool_result: CallToolResult) -> str:
|
|
19
|
+
"""Parse the content of a CallToolResult into a string.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
tool_result: The result object from calling an MCP tool.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
A string representation of the tool result content.
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
ToolException: If the tool execution failed, returned no content,
|
|
29
|
+
or contained unexpected content types.
|
|
30
|
+
"""
|
|
31
|
+
if tool_result.isError:
|
|
32
|
+
raise ToolException(f"Tool execution failed: {tool_result.content}")
|
|
33
|
+
|
|
34
|
+
if not tool_result.content:
|
|
35
|
+
raise ToolException("Tool execution returned no content")
|
|
36
|
+
|
|
37
|
+
decoded_result = ""
|
|
38
|
+
for item in tool_result.content:
|
|
39
|
+
match item.type:
|
|
40
|
+
case "text":
|
|
41
|
+
item: TextContent
|
|
42
|
+
decoded_result += item.text
|
|
43
|
+
case "image":
|
|
44
|
+
item: ImageContent
|
|
45
|
+
decoded_result += item.data # Assuming data is string-like or base64
|
|
46
|
+
case "resource":
|
|
47
|
+
resource: EmbeddedResource = item.resource
|
|
48
|
+
if hasattr(resource, "text"):
|
|
49
|
+
decoded_result += resource.text
|
|
50
|
+
elif hasattr(resource, "blob"):
|
|
51
|
+
# Assuming blob needs decoding or specific handling; adjust as needed
|
|
52
|
+
decoded_result += (
|
|
53
|
+
resource.blob.decode()
|
|
54
|
+
if isinstance(resource.blob, bytes)
|
|
55
|
+
else str(resource.blob)
|
|
56
|
+
)
|
|
57
|
+
else:
|
|
58
|
+
raise ToolException(f"Unexpected resource type: {resource.type}")
|
|
59
|
+
case _:
|
|
60
|
+
raise ToolException(f"Unexpected content type: {item.type}")
|
|
61
|
+
|
|
62
|
+
return decoded_result
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class LangChainAdapter:
|
|
66
|
+
"""Adapter for converting MCP tools to LangChain tools."""
|
|
67
|
+
|
|
68
|
+
def __init__(self, disallowed_tools: list[str] | None = None) -> None:
|
|
69
|
+
"""Initialize a new LangChain adapter.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
disallowed_tools: List of tool names that should not be available.
|
|
73
|
+
"""
|
|
74
|
+
self.disallowed_tools = disallowed_tools or []
|
|
75
|
+
self._connector_tool_map: dict[BaseConnector, list[BaseTool]] = {}
|
|
76
|
+
|
|
77
|
+
def fix_schema(self, schema: dict) -> dict:
|
|
78
|
+
"""Convert JSON Schema 'type': ['string', 'null'] to 'anyOf' format.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
schema: The JSON schema to fix.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
The fixed JSON schema.
|
|
85
|
+
"""
|
|
86
|
+
if isinstance(schema, dict):
|
|
87
|
+
if "type" in schema and isinstance(schema["type"], list):
|
|
88
|
+
schema["anyOf"] = [{"type": t} for t in schema["type"]]
|
|
89
|
+
del schema["type"] # Remove 'type' and standardize to 'anyOf'
|
|
90
|
+
for key, value in schema.items():
|
|
91
|
+
schema[key] = self.fix_schema(value) # Apply recursively
|
|
92
|
+
return schema
|
|
93
|
+
|
|
94
|
+
async def load_tools_for_connector(self, connector: BaseConnector) -> list[BaseTool]:
|
|
95
|
+
"""Dynamically load tools for a specific connector.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
connector: The connector to load tools for.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
The list of tools that were loaded.
|
|
102
|
+
"""
|
|
103
|
+
# Check if we already have tools for this connector
|
|
104
|
+
if connector in self._connector_tool_map:
|
|
105
|
+
logger.debug(
|
|
106
|
+
f"Returning {len(self._connector_tool_map[connector])} existing tools for connector"
|
|
107
|
+
)
|
|
108
|
+
return self._connector_tool_map[connector]
|
|
109
|
+
|
|
110
|
+
# Create tools for this connector
|
|
111
|
+
connector_tools = []
|
|
112
|
+
|
|
113
|
+
# Make sure the connector is initialized and has tools
|
|
114
|
+
if not hasattr(connector, "tools") or not connector.tools:
|
|
115
|
+
logger.debug("Connector doesn't have tools, initializing it")
|
|
116
|
+
try:
|
|
117
|
+
await connector.initialize()
|
|
118
|
+
except Exception as e:
|
|
119
|
+
logger.error(f"Error initializing connector: {e}")
|
|
120
|
+
return []
|
|
121
|
+
|
|
122
|
+
# Now create tools for each MCP tool
|
|
123
|
+
for tool in connector.tools:
|
|
124
|
+
# Skip disallowed tools
|
|
125
|
+
if tool.name in self.disallowed_tools:
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
class McpToLangChainAdapter(BaseTool):
|
|
129
|
+
name: str = tool.name or "NO NAME"
|
|
130
|
+
description: str = tool.description or ""
|
|
131
|
+
# Convert JSON schema to Pydantic model for argument validation
|
|
132
|
+
args_schema: type[BaseModel] = jsonschema_to_pydantic(
|
|
133
|
+
self.fix_schema(tool.inputSchema) # Apply schema conversion
|
|
134
|
+
)
|
|
135
|
+
tool_connector: BaseConnector = connector # Renamed variable to avoid name conflict
|
|
136
|
+
handle_tool_error: bool = True
|
|
137
|
+
|
|
138
|
+
def _run(self, **kwargs: Any) -> NoReturn:
|
|
139
|
+
"""Synchronous run method that always raises an error.
|
|
140
|
+
|
|
141
|
+
Raises:
|
|
142
|
+
NotImplementedError: Always raises this error because MCP tools
|
|
143
|
+
only support async operations.
|
|
144
|
+
"""
|
|
145
|
+
raise NotImplementedError("MCP tools only support async operations")
|
|
146
|
+
|
|
147
|
+
async def _arun(self, **kwargs: Any) -> Any:
|
|
148
|
+
"""Asynchronously execute the tool with given arguments.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
kwargs: The arguments to pass to the tool.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
The result of the tool execution.
|
|
155
|
+
|
|
156
|
+
Raises:
|
|
157
|
+
ToolException: If tool execution fails.
|
|
158
|
+
"""
|
|
159
|
+
logger.debug(f'MCP tool: "{self.name}" received input: {kwargs}')
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
tool_result: CallToolResult = await self.tool_connector.call_tool(
|
|
163
|
+
self.name, kwargs
|
|
164
|
+
)
|
|
165
|
+
try:
|
|
166
|
+
# Use the helper function to parse the result
|
|
167
|
+
return _parse_mcp_tool_result(tool_result)
|
|
168
|
+
except Exception as e:
|
|
169
|
+
# Log the exception for debugging
|
|
170
|
+
logger.error(f"Error parsing tool result: {e}")
|
|
171
|
+
# Shortened line:
|
|
172
|
+
return (
|
|
173
|
+
f"Error parsing result: {e!s};"
|
|
174
|
+
f" Raw content: {tool_result.content!r}"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
except Exception as e:
|
|
178
|
+
if self.handle_tool_error:
|
|
179
|
+
return f"Error executing MCP tool: {str(e)}"
|
|
180
|
+
raise
|
|
181
|
+
|
|
182
|
+
connector_tools.append(McpToLangChainAdapter())
|
|
183
|
+
|
|
184
|
+
# Store the tools for this connector
|
|
185
|
+
self._connector_tool_map[connector] = connector_tools
|
|
186
|
+
|
|
187
|
+
# Log available tools for debugging
|
|
188
|
+
logger.debug(
|
|
189
|
+
f"Loaded {len(connector_tools)} new tools for"
|
|
190
|
+
f" connector: {[tool.name for tool in connector_tools]}"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return connector_tools
|
|
194
|
+
|
|
195
|
+
async def create_langchain_tools(self, connectors: list[BaseConnector]) -> list[BaseTool]:
|
|
196
|
+
"""Create LangChain tools from MCP tools.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
connectors: List of MCP connectors to create tools from.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
A list of LangChain tools that wrap MCP tools.
|
|
203
|
+
"""
|
|
204
|
+
tools = []
|
|
205
|
+
for connector in connectors:
|
|
206
|
+
# Create tools for this connector
|
|
207
|
+
connector_tools = await self.load_tools_for_connector(connector)
|
|
208
|
+
tools.extend(connector_tools)
|
|
209
|
+
|
|
210
|
+
# Log available tools for debugging
|
|
211
|
+
logger.debug(f"Available tools: {[tool.name for tool in tools]}")
|
|
212
|
+
return tools
|
mcp_use/agents/__init__.py
CHANGED
|
@@ -6,7 +6,11 @@ that are pre-configured for using MCP tools.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from .base import BaseAgent
|
|
9
|
-
from .langchain_agent import LangChainAgent
|
|
10
9
|
from .mcpagent import MCPAgent
|
|
10
|
+
from .server_manager import ServerManager
|
|
11
11
|
|
|
12
|
-
__all__ = [
|
|
12
|
+
__all__ = [
|
|
13
|
+
"BaseAgent",
|
|
14
|
+
"MCPAgent",
|
|
15
|
+
"ServerManager",
|
|
16
|
+
]
|