mcp-use 1.3.12__py3-none-any.whl → 1.4.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.

Files changed (108) hide show
  1. mcp_use/__init__.py +1 -1
  2. mcp_use/adapters/.deprecated +0 -0
  3. mcp_use/adapters/__init__.py +18 -7
  4. mcp_use/adapters/base.py +12 -185
  5. mcp_use/adapters/langchain_adapter.py +12 -219
  6. mcp_use/agents/adapters/__init__.py +17 -0
  7. mcp_use/agents/adapters/anthropic.py +93 -0
  8. mcp_use/agents/adapters/base.py +316 -0
  9. mcp_use/agents/adapters/google.py +103 -0
  10. mcp_use/agents/adapters/langchain_adapter.py +212 -0
  11. mcp_use/agents/adapters/openai.py +111 -0
  12. mcp_use/agents/base.py +1 -1
  13. mcp_use/agents/managers/__init__.py +19 -0
  14. mcp_use/agents/managers/base.py +36 -0
  15. mcp_use/agents/managers/server_manager.py +131 -0
  16. mcp_use/agents/managers/tools/__init__.py +15 -0
  17. mcp_use/agents/managers/tools/base_tool.py +19 -0
  18. mcp_use/agents/managers/tools/connect_server.py +69 -0
  19. mcp_use/agents/managers/tools/disconnect_server.py +43 -0
  20. mcp_use/agents/managers/tools/get_active_server.py +29 -0
  21. mcp_use/agents/managers/tools/list_servers_tool.py +53 -0
  22. mcp_use/agents/managers/tools/search_tools.py +328 -0
  23. mcp_use/agents/mcpagent.py +386 -485
  24. mcp_use/agents/prompts/system_prompt_builder.py +1 -1
  25. mcp_use/agents/remote.py +15 -2
  26. mcp_use/auth/.deprecated +0 -0
  27. mcp_use/auth/__init__.py +19 -4
  28. mcp_use/auth/bearer.py +11 -12
  29. mcp_use/auth/oauth.py +11 -620
  30. mcp_use/auth/oauth_callback.py +16 -207
  31. mcp_use/client/__init__.py +1 -0
  32. mcp_use/client/auth/__init__.py +6 -0
  33. mcp_use/client/auth/bearer.py +23 -0
  34. mcp_use/client/auth/oauth.py +629 -0
  35. mcp_use/client/auth/oauth_callback.py +215 -0
  36. mcp_use/client/client.py +356 -0
  37. mcp_use/client/config.py +106 -0
  38. mcp_use/client/connectors/__init__.py +20 -0
  39. mcp_use/client/connectors/base.py +470 -0
  40. mcp_use/client/connectors/http.py +304 -0
  41. mcp_use/client/connectors/sandbox.py +332 -0
  42. mcp_use/client/connectors/stdio.py +109 -0
  43. mcp_use/client/connectors/utils.py +13 -0
  44. mcp_use/client/connectors/websocket.py +257 -0
  45. mcp_use/client/exceptions.py +31 -0
  46. mcp_use/client/middleware/__init__.py +50 -0
  47. mcp_use/client/middleware/logging.py +31 -0
  48. mcp_use/client/middleware/metrics.py +314 -0
  49. mcp_use/client/middleware/middleware.py +266 -0
  50. mcp_use/client/session.py +162 -0
  51. mcp_use/client/task_managers/__init__.py +20 -0
  52. mcp_use/client/task_managers/base.py +145 -0
  53. mcp_use/client/task_managers/sse.py +84 -0
  54. mcp_use/client/task_managers/stdio.py +69 -0
  55. mcp_use/client/task_managers/streamable_http.py +86 -0
  56. mcp_use/client/task_managers/websocket.py +68 -0
  57. mcp_use/client.py +12 -344
  58. mcp_use/config.py +20 -97
  59. mcp_use/connectors/.deprecated +0 -0
  60. mcp_use/connectors/__init__.py +46 -20
  61. mcp_use/connectors/base.py +12 -455
  62. mcp_use/connectors/http.py +13 -300
  63. mcp_use/connectors/sandbox.py +13 -306
  64. mcp_use/connectors/stdio.py +13 -104
  65. mcp_use/connectors/utils.py +15 -8
  66. mcp_use/connectors/websocket.py +13 -252
  67. mcp_use/exceptions.py +33 -18
  68. mcp_use/logging.py +1 -1
  69. mcp_use/managers/.deprecated +0 -0
  70. mcp_use/managers/__init__.py +56 -17
  71. mcp_use/managers/base.py +13 -31
  72. mcp_use/managers/server_manager.py +13 -119
  73. mcp_use/managers/tools/__init__.py +45 -15
  74. mcp_use/managers/tools/base_tool.py +5 -16
  75. mcp_use/managers/tools/connect_server.py +5 -67
  76. mcp_use/managers/tools/disconnect_server.py +5 -41
  77. mcp_use/managers/tools/get_active_server.py +5 -26
  78. mcp_use/managers/tools/list_servers_tool.py +5 -51
  79. mcp_use/managers/tools/search_tools.py +17 -321
  80. mcp_use/middleware/.deprecated +0 -0
  81. mcp_use/middleware/__init__.py +89 -50
  82. mcp_use/middleware/logging.py +14 -26
  83. mcp_use/middleware/metrics.py +30 -303
  84. mcp_use/middleware/middleware.py +39 -246
  85. mcp_use/session.py +13 -149
  86. mcp_use/task_managers/.deprecated +0 -0
  87. mcp_use/task_managers/__init__.py +48 -20
  88. mcp_use/task_managers/base.py +13 -140
  89. mcp_use/task_managers/sse.py +13 -79
  90. mcp_use/task_managers/stdio.py +13 -64
  91. mcp_use/task_managers/streamable_http.py +15 -81
  92. mcp_use/task_managers/websocket.py +13 -63
  93. mcp_use/telemetry/events.py +58 -0
  94. mcp_use/telemetry/telemetry.py +71 -1
  95. mcp_use/telemetry/utils.py +1 -1
  96. mcp_use/types/.deprecated +0 -0
  97. mcp_use/types/sandbox.py +13 -18
  98. {mcp_use-1.3.12.dist-info → mcp_use-1.4.0.dist-info}/METADATA +68 -43
  99. mcp_use-1.4.0.dist-info/RECORD +111 -0
  100. mcp_use/cli.py +0 -581
  101. mcp_use-1.3.12.dist-info/RECORD +0 -64
  102. mcp_use-1.3.12.dist-info/licenses/LICENSE +0 -21
  103. /mcp_use/{observability → agents/observability}/__init__.py +0 -0
  104. /mcp_use/{observability → agents/observability}/callbacks_manager.py +0 -0
  105. /mcp_use/{observability → agents/observability}/laminar.py +0 -0
  106. /mcp_use/{observability → agents/observability}/langfuse.py +0 -0
  107. {mcp_use-1.3.12.dist-info → mcp_use-1.4.0.dist-info}/WHEEL +0 -0
  108. {mcp_use-1.3.12.dist-info → mcp_use-1.4.0.dist-info}/entry_points.txt +0 -0
mcp_use/__init__.py CHANGED
@@ -12,7 +12,7 @@ from importlib.metadata import version
12
12
  from .logging import MCP_USE_DEBUG, Logger, logger # isort: skip
13
13
 
14
14
  # Now import other modules - observability must come after logging
15
- from . import observability # noqa: E402
15
+ from .agents import observability # noqa: E402
16
16
  from .agents.mcpagent import MCPAgent
17
17
  from .client import MCPClient
18
18
  from .config import load_config_file
File without changes
@@ -1,10 +1,21 @@
1
- """
2
- Adapters for converting MCP tools to different frameworks.
1
+ # mcp_use/adapters/__init__.py
2
+ import warnings
3
3
 
4
- This package provides adapters for converting MCP tools to different frameworks.
5
- """
4
+ from typing_extensions import deprecated
6
5
 
7
- from .base import BaseAdapter
8
- from .langchain_adapter import LangChainAdapter
6
+ from mcp_use.agents.adapters import BaseAdapter as _BaseAdapter
7
+ from mcp_use.agents.adapters import LangChainAdapter as _LangChainAdapter
9
8
 
10
- __all__ = ["BaseAdapter", "LangChainAdapter"]
9
+ warnings.warn(
10
+ "mcp_use.adapters is deprecated. Use mcp_use.agents.adapters. This import will be removed in version 1.4.0",
11
+ DeprecationWarning,
12
+ stacklevel=2,
13
+ )
14
+
15
+
16
+ @deprecated("Use mcp_use.agents.adapters.BaseAdapter")
17
+ class BaseAdapter(_BaseAdapter): ...
18
+
19
+
20
+ @deprecated("Use mcp_use.agents.adapters.LangChainAdapter")
21
+ class LangChainAdapter(_LangChainAdapter): ...
mcp_use/adapters/base.py CHANGED
@@ -1,190 +1,17 @@
1
- """
2
- Base adapter interface for MCP tools.
1
+ # mcp_use/adapters/base.py
2
+ import warnings
3
3
 
4
- This module provides the abstract base class that all MCP tool adapters should inherit from.
5
- """
4
+ from typing_extensions import deprecated
6
5
 
7
- from abc import ABC, abstractmethod
8
- from typing import TypeVar
6
+ from mcp_use.agents.adapters.base import BaseAdapter as _BaseAdapter
9
7
 
10
- from mcp.types import Prompt, Resource, Tool
8
+ warnings.warn(
9
+ "mcp_use.adapters.base is deprecated. Use mcp_use.agents.adapters.base. "
10
+ "This import will be removed in version 1.4.0",
11
+ DeprecationWarning,
12
+ stacklevel=2,
13
+ )
11
14
 
12
- from ..client import MCPClient
13
- from ..connectors.base import BaseConnector
14
- from ..logging import logger
15
15
 
16
- # Generic type for the tools created by the adapter
17
- T = TypeVar("T")
18
-
19
-
20
- class BaseAdapter(ABC):
21
- """Abstract base class for converting MCP tools to other framework formats.
22
-
23
- This class defines the common interface that all adapter implementations
24
- should follow to ensure consistency across different frameworks.
25
- """
26
-
27
- def __init__(self, disallowed_tools: list[str] | None = None) -> None:
28
- """Initialize a new adapter.
29
-
30
- Args:
31
- disallowed_tools: list of tool names that should not be available.
32
- """
33
- self.disallowed_tools = disallowed_tools or []
34
- self._connector_tool_map: dict[BaseConnector, list[T]] = {}
35
-
36
- async def create_tools(self, client: "MCPClient") -> list[T]:
37
- """Create tools from an MCPClient instance.
38
-
39
- This is the recommended way to create tools from an MCPClient, as it handles
40
- session creation and connector extraction automatically.
41
-
42
- Args:
43
- client: The MCPClient to extract tools from.
44
-
45
- Returns:
46
- A list of tools in the target framework's format.
47
-
48
- Example:
49
- ```python
50
- from mcp_use.client import MCPClient
51
- from mcp_use.adapters import YourAdapter
52
-
53
- client = MCPClient.from_config_file("config.json")
54
- tools = await YourAdapter.create_tools(client)
55
- ```
56
- """
57
- # Ensure we have active sessions
58
- if not client.active_sessions:
59
- logger.info("No active sessions found, creating new ones...")
60
- await client.create_all_sessions()
61
-
62
- # Get all active sessions
63
- sessions = client.get_all_active_sessions()
64
-
65
- # Extract connectors from sessions
66
- connectors = [session.connector for session in sessions.values()]
67
-
68
- # Create tools from connectors
69
- return await self._create_tools_from_connectors(connectors)
70
-
71
- async def load_tools_for_connector(self, connector: BaseConnector) -> list[T]:
72
- """Dynamically load tools for a specific connector.
73
-
74
- Args:
75
- connector: The connector to load tools for.
76
-
77
- Returns:
78
- The list of tools that were loaded in the target framework's format.
79
- """
80
- # Check if we already have tools for this connector
81
- if connector in self._connector_tool_map:
82
- logger.debug(f"Returning {len(self._connector_tool_map[connector])} existing tools for connector")
83
- return self._connector_tool_map[connector]
84
-
85
- # Create tools for this connector
86
-
87
- # Make sure the connector is initialized and has tools
88
- success = await self._ensure_connector_initialized(connector)
89
- if not success:
90
- return []
91
-
92
- connector_tools = []
93
- # Now create tools for each MCP tool
94
- for tool in await connector.list_tools():
95
- # Convert the tool and add it to the list if conversion was successful
96
- converted_tool = self._convert_tool(tool, connector)
97
- if converted_tool:
98
- connector_tools.append(converted_tool)
99
-
100
- # Convert resources to tools so that agents can access resource content directly
101
- resources_list = await connector.list_resources() or []
102
- if resources_list:
103
- for resource in resources_list:
104
- converted_resource = self._convert_resource(resource, connector)
105
- if converted_resource:
106
- connector_tools.append(converted_resource)
107
-
108
- # Convert prompts to tools so that agents can retrieve prompt content
109
- prompts_list = await connector.list_prompts() or []
110
- if prompts_list:
111
- for prompt in prompts_list:
112
- converted_prompt = self._convert_prompt(prompt, connector)
113
- if converted_prompt:
114
- connector_tools.append(converted_prompt)
115
- # ------------------------------
116
-
117
- # Store the tools for this connector
118
- self._connector_tool_map[connector] = connector_tools
119
-
120
- # Log available tools for debugging
121
- logger.debug(
122
- f"Loaded {len(connector_tools)} new tools for connector: "
123
- f"{[getattr(tool, 'name', str(tool)) for tool in connector_tools]}"
124
- )
125
-
126
- return connector_tools
127
-
128
- @abstractmethod
129
- def _convert_tool(self, mcp_tool: Tool, connector: BaseConnector) -> T:
130
- """Convert an MCP tool to the target framework's tool format."""
131
- pass
132
-
133
- @abstractmethod
134
- def _convert_resource(self, mcp_resource: Resource, connector: BaseConnector) -> T:
135
- """Convert an MCP resource to the target framework's resource format."""
136
- pass
137
-
138
- @abstractmethod
139
- def _convert_prompt(self, mcp_prompt: Prompt, connector: BaseConnector) -> T:
140
- """Convert an MCP prompt to the target framework's prompt format."""
141
- pass
142
-
143
- async def _create_tools_from_connectors(self, connectors: list[BaseConnector]) -> list[T]:
144
- """Create tools from MCP tools in all provided connectors.
145
-
146
- Args:
147
- connectors: list of MCP connectors to create tools from.
148
-
149
- Returns:
150
- A list of tools in the target framework's format.
151
- """
152
- tools = []
153
- for connector in connectors:
154
- # Create tools for this connector
155
- connector_tools = await self.load_tools_for_connector(connector)
156
- tools.extend(connector_tools)
157
-
158
- # Log available tools for debugging
159
- logger.debug(f"Available tools: {len(tools)}")
160
- return tools
161
-
162
- def _check_connector_initialized(self, connector: BaseConnector) -> bool:
163
- """Check if a connector is initialized and has tools.
164
-
165
- Args:
166
- connector: The connector to check.
167
-
168
- Returns:
169
- True if the connector is initialized and has tools, False otherwise.
170
- """
171
- return hasattr(connector, "tools") and connector.tools
172
-
173
- async def _ensure_connector_initialized(self, connector: BaseConnector) -> bool:
174
- """Ensure a connector is initialized.
175
-
176
- Args:
177
- connector: The connector to initialize.
178
-
179
- Returns:
180
- True if initialization succeeded, False otherwise.
181
- """
182
- if not self._check_connector_initialized(connector):
183
- logger.debug("Connector doesn't have tools, initializing it")
184
- try:
185
- await connector.initialize()
186
- return True
187
- except Exception as e:
188
- logger.error(f"Error initializing connector: {e}")
189
- return False
190
- return True
16
+ @deprecated("Use mcp_use.agents.adapters.base.BaseAdapter")
17
+ class BaseAdapter(_BaseAdapter): ...
@@ -1,225 +1,18 @@
1
- """
2
- LangChain adapter for MCP tools.
1
+ # mcp_use/adapters/langchain_adapter.py
2
+ import warnings
3
3
 
4
- This module provides utilities to convert MCP tools to LangChain tools.
5
- """
4
+ from typing_extensions import deprecated
6
5
 
7
- import re
8
- from typing import Any, NoReturn
6
+ from mcp_use.agents.adapters.langchain_adapter import LangChainAdapter as _LangChainAdapter
9
7
 
10
- from jsonschema_pydantic import jsonschema_to_pydantic
11
- from langchain_core.tools import BaseTool
12
- from mcp.types import (
13
- CallToolResult,
14
- Prompt,
15
- ReadResourceRequestParams,
16
- Resource,
8
+ warnings.warn(
9
+ "mcp_use.adapters.langchain_adapter is deprecated. "
10
+ "Use mcp_use.agents.adapters.langchain_adapter. "
11
+ "This import will be removed in version 1.4.0",
12
+ DeprecationWarning,
13
+ stacklevel=2,
17
14
  )
18
- from pydantic import BaseModel, Field, create_model
19
15
 
20
- from ..connectors.base import BaseConnector
21
- from ..errors.error_formatting import format_error
22
- from ..logging import logger
23
- from .base import BaseAdapter
24
16
 
25
-
26
- class LangChainAdapter(BaseAdapter):
27
- """Adapter for converting MCP tools to LangChain tools."""
28
-
29
- def __init__(self, disallowed_tools: list[str] | None = None) -> None:
30
- """Initialize a new LangChain adapter.
31
-
32
- Args:
33
- disallowed_tools: list of tool names that should not be available.
34
- """
35
- super().__init__(disallowed_tools)
36
- self._connector_tool_map: dict[BaseConnector, list[BaseTool]] = {}
37
-
38
- def fix_schema(self, schema: dict) -> dict:
39
- """Convert JSON Schema 'type': ['string', 'null'] to 'anyOf' format and fix enum handling.
40
-
41
- Args:
42
- schema: The JSON schema to fix.
43
-
44
- Returns:
45
- The fixed JSON schema.
46
- """
47
- if isinstance(schema, dict):
48
- if "type" in schema and isinstance(schema["type"], list):
49
- schema["anyOf"] = [{"type": t} for t in schema["type"]]
50
- del schema["type"] # Remove 'type' and standardize to 'anyOf'
51
-
52
- # Fix enum handling - ensure enum fields are properly typed as strings
53
- if "enum" in schema and "type" not in schema:
54
- schema["type"] = "string"
55
-
56
- for key, value in schema.items():
57
- schema[key] = self.fix_schema(value) # Apply recursively
58
- return schema
59
-
60
- def _convert_tool(self, mcp_tool: dict[str, Any], connector: BaseConnector) -> BaseTool:
61
- """Convert an MCP tool to LangChain's tool format.
62
-
63
- Args:
64
- mcp_tool: The MCP tool to convert.
65
- connector: The connector that provides this tool.
66
-
67
- Returns:
68
- A LangChain BaseTool.
69
- """
70
- # Skip disallowed tools
71
- if mcp_tool.name in self.disallowed_tools:
72
- return None
73
-
74
- # This is a dynamic class creation, we need to work with the self reference
75
- adapter_self = self
76
-
77
- class McpToLangChainAdapter(BaseTool):
78
- name: str = mcp_tool.name or "NO NAME"
79
- description: str = mcp_tool.description or ""
80
- # Convert JSON schema to Pydantic model for argument validation
81
- args_schema: type[BaseModel] = jsonschema_to_pydantic(
82
- adapter_self.fix_schema(mcp_tool.inputSchema) # Apply schema conversion
83
- )
84
- tool_connector: BaseConnector = connector # Renamed variable to avoid name conflict
85
- handle_tool_error: bool = True
86
-
87
- def __repr__(self) -> str:
88
- return f"MCP tool: {self.name}: {self.description}"
89
-
90
- def _run(self, **kwargs: Any) -> NoReturn:
91
- """Synchronous run method that always raises an error.
92
-
93
- Raises:
94
- NotImplementedError: Always raises this error because MCP tools
95
- only support async operations.
96
- """
97
- raise NotImplementedError("MCP tools only support async operations")
98
-
99
- async def _arun(self, **kwargs: Any) -> str | dict:
100
- """Asynchronously execute the tool with given arguments.
101
-
102
- Args:
103
- kwargs: The arguments to pass to the tool.
104
-
105
- Returns:
106
- The result of the tool execution.
107
-
108
- Raises:
109
- ToolException: If tool execution fails.
110
- """
111
- logger.debug(f'MCP tool: "{self.name}" received input: {kwargs}')
112
-
113
- try:
114
- tool_result: CallToolResult = await self.tool_connector.call_tool(self.name, kwargs)
115
- try:
116
- return str(tool_result.content)
117
- except Exception as e:
118
- # Log the exception for debugging
119
- logger.error(f"Error parsing tool result: {e}")
120
- return format_error(e, tool=self.name, tool_content=tool_result.content)
121
-
122
- except Exception as e:
123
- if self.handle_tool_error:
124
- return format_error(e, tool=self.name) # Format the error to make LLM understand it
125
- raise
126
-
127
- return McpToLangChainAdapter()
128
-
129
- def _convert_resource(self, mcp_resource: Resource, connector: BaseConnector) -> BaseTool:
130
- """Convert an MCP resource to LangChain's tool format.
131
-
132
- Each resource becomes an async tool that returns its content when called.
133
- The tool takes **no** arguments because the resource URI is fixed.
134
- """
135
-
136
- def _sanitize(name: str) -> str:
137
- return re.sub(r"[^A-Za-z0-9_]+", "_", name).lower().strip("_")
138
-
139
- class ResourceTool(BaseTool):
140
- name: str = _sanitize(mcp_resource.name or f"resource_{mcp_resource.uri}")
141
- description: str = (
142
- mcp_resource.description or f"Return the content of the resource located at URI {mcp_resource.uri}."
143
- )
144
- args_schema: type[BaseModel] = ReadResourceRequestParams
145
- tool_connector: BaseConnector = connector
146
- handle_tool_error: bool = True
147
-
148
- def _run(self, **kwargs: Any) -> NoReturn:
149
- raise NotImplementedError("Resource tools only support async operations")
150
-
151
- async def _arun(self, **kwargs: Any) -> Any:
152
- logger.debug(f'Resource tool: "{self.name}" called')
153
- try:
154
- result = await self.tool_connector.read_resource(mcp_resource.uri)
155
- for content in result.contents:
156
- # Attempt to decode bytes if necessary
157
- if isinstance(content, bytes):
158
- content_decoded = content.decode()
159
- else:
160
- content_decoded = str(content)
161
-
162
- return content_decoded
163
- except Exception as e:
164
- if self.handle_tool_error:
165
- return format_error(e, tool=self.name) # Format the error to make LLM understand it
166
- raise
167
-
168
- return ResourceTool()
169
-
170
- def _convert_prompt(self, mcp_prompt: Prompt, connector: BaseConnector) -> BaseTool:
171
- """Convert an MCP prompt to LangChain's tool format.
172
-
173
- The resulting tool executes `get_prompt` on the connector with the prompt's name and
174
- the user-provided arguments (if any). The tool returns the decoded prompt content.
175
- """
176
- prompt_arguments = mcp_prompt.arguments
177
-
178
- # Sanitize the prompt name to create a valid Python identifier for the model name
179
- base_model_name = re.sub(r"[^a-zA-Z0-9_]", "_", mcp_prompt.name)
180
- if not base_model_name or base_model_name[0].isdigit():
181
- base_model_name = "PromptArgs_" + base_model_name
182
- dynamic_model_name = f"{base_model_name}_InputSchema"
183
-
184
- if prompt_arguments:
185
- field_definitions_for_create: dict[str, Any] = {}
186
- for arg in prompt_arguments:
187
- param_type: type = getattr(arg, "type", str)
188
- if arg.required:
189
- field_definitions_for_create[arg.name] = (
190
- param_type,
191
- Field(description=arg.description),
192
- )
193
- else:
194
- field_definitions_for_create[arg.name] = (
195
- param_type | None,
196
- Field(None, description=arg.description),
197
- )
198
-
199
- InputSchema = create_model(dynamic_model_name, **field_definitions_for_create, __base__=BaseModel)
200
- else:
201
- # Create an empty Pydantic model if there are no arguments
202
- InputSchema = create_model(dynamic_model_name, __base__=BaseModel)
203
-
204
- class PromptTool(BaseTool):
205
- name: str = mcp_prompt.name
206
- description: str = mcp_prompt.description
207
-
208
- args_schema: type[BaseModel] = InputSchema
209
- tool_connector: BaseConnector = connector
210
- handle_tool_error: bool = True
211
-
212
- def _run(self, **kwargs: Any) -> NoReturn:
213
- raise NotImplementedError("Prompt tools only support async operations")
214
-
215
- async def _arun(self, **kwargs: Any) -> Any:
216
- logger.debug(f'Prompt tool: "{self.name}" called with args: {kwargs}')
217
- try:
218
- result = await self.tool_connector.get_prompt(self.name, kwargs)
219
- return result.messages
220
- except Exception as e:
221
- if self.handle_tool_error:
222
- return format_error(e, tool=self.name) # Format the error to make LLM understand it
223
- raise
224
-
225
- return PromptTool()
17
+ @deprecated("Use mcp_use.agents.adapters.langchain_adapter.LangChainAdapter")
18
+ class LangChainAdapter(_LangChainAdapter): ...
@@ -0,0 +1,17 @@
1
+ """
2
+ Adapters for converting MCP tools to different frameworks.
3
+
4
+ This package provides adapters for converting MCP tools to different frameworks.
5
+ """
6
+
7
+ from .anthropic import AnthropicMCPAdapter
8
+ from .base import BaseAdapter
9
+ from .langchain_adapter import LangChainAdapter
10
+ from .openai import OpenAIMCPAdapter
11
+
12
+ try:
13
+ from .google import GoogleMCPAdapter
14
+
15
+ __all__ = ["BaseAdapter", "LangChainAdapter", "OpenAIMCPAdapter", "AnthropicMCPAdapter", "GoogleMCPAdapter"]
16
+ except ImportError:
17
+ __all__ = ["BaseAdapter", "LangChainAdapter", "OpenAIMCPAdapter", "AnthropicMCPAdapter"]
@@ -0,0 +1,93 @@
1
+ import re
2
+ from collections.abc import Callable, Coroutine
3
+ from typing import Any
4
+
5
+ from mcp.types import Prompt, Resource, Tool
6
+
7
+ from mcp_use.agents.adapters.base import BaseAdapter
8
+ from mcp_use.client.connectors.base import BaseConnector
9
+
10
+
11
+ def _sanitize_for_tool_name(name: str) -> str:
12
+ """Sanitizes a string to be a valid tool name for Anthropic."""
13
+ # Anthropic tool names can only contain a-z, A-Z, 0-9, and underscores,
14
+ # and must be 64 characters or less.
15
+ return re.sub(r"[^a-zA-Z0-9_]+", "_", name).strip("_")[:64]
16
+
17
+
18
+ class AnthropicMCPAdapter(BaseAdapter):
19
+ def __init__(self, disallowed_tools: list[str] | None = None) -> None:
20
+ """Initialize a new Anthropic adapter.
21
+
22
+ Args:
23
+ disallowed_tools: list of tool names that should not be available.
24
+ """
25
+ super().__init__(disallowed_tools)
26
+ # This map stores the actual async function to call for each tool.
27
+ self.tool_executors: dict[str, Callable[..., Coroutine[Any, Any, Any]]] = {}
28
+
29
+ self._connector_tool_map: dict[BaseConnector, list[dict[str, Any]]] = {}
30
+ self._connector_resource_map: dict[BaseConnector, list[dict[str, Any]]] = {}
31
+ self._connector_prompt_map: dict[BaseConnector, list[dict[str, Any]]] = {}
32
+
33
+ self.tools: list[dict[str, Any]] = []
34
+ self.resources: list[dict[str, Any]] = []
35
+ self.prompts: list[dict[str, Any]] = []
36
+
37
+ def _convert_tool(self, mcp_tool: Tool, connector: BaseConnector) -> dict[str, Any]:
38
+ """Convert an MCP tool to the Anthropic tool format."""
39
+ if mcp_tool.name in self.disallowed_tools:
40
+ return None
41
+
42
+ self.tool_executors[mcp_tool.name] = (
43
+ lambda connector=connector, name=mcp_tool.name, **kwargs: connector.call_tool(name, kwargs)
44
+ )
45
+
46
+ fixed_schema = self.fix_schema(mcp_tool.inputSchema)
47
+ return {"name": mcp_tool.name, "description": mcp_tool.description, "input_schema": fixed_schema}
48
+
49
+ def _convert_resource(self, mcp_resource: Resource, connector: BaseConnector) -> dict[str, Any]:
50
+ """Convert an MCP resource to a readable tool in Anthropic format."""
51
+ tool_name = _sanitize_for_tool_name(f"resource_{mcp_resource.name}")
52
+
53
+ if tool_name in self.disallowed_tools:
54
+ return None
55
+
56
+ self.tool_executors[tool_name] = (
57
+ lambda connector=connector, uri=mcp_resource.uri, **kwargs: connector.read_resource(uri)
58
+ )
59
+
60
+ return {
61
+ "name": tool_name,
62
+ "description": mcp_resource.description,
63
+ "input_schema": {"type": "object", "properties": {}},
64
+ }
65
+
66
+ def _convert_prompt(self, mcp_prompt: Prompt, connector: BaseConnector) -> dict[str, Any]:
67
+ """Convert an MCP prompt to a usable tool in Anthropic format."""
68
+ if mcp_prompt.name in self.disallowed_tools:
69
+ return None
70
+
71
+ self.tool_executors[mcp_prompt.name] = (
72
+ lambda connector=connector, name=mcp_prompt.name, **kwargs: connector.get_prompt(name, kwargs)
73
+ )
74
+
75
+ properties = {}
76
+ required_args = []
77
+ if mcp_prompt.arguments:
78
+ for arg in mcp_prompt.arguments:
79
+ prop = {"type": "string"}
80
+ if arg.description:
81
+ prop["description"] = arg.description
82
+ properties[arg.name] = prop
83
+ if arg.required:
84
+ required_args.append(arg.name)
85
+ parameters_schema = {"type": "object", "properties": properties}
86
+ if required_args:
87
+ parameters_schema["required"] = required_args
88
+
89
+ return {
90
+ "name": mcp_prompt.name,
91
+ "description": mcp_prompt.description,
92
+ "input_schema": parameters_schema,
93
+ }