mcp-use 1.2.5__tar.gz → 1.2.7__tar.gz
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-1.2.7/.github/pull_request_template.md +43 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/PKG-INFO +38 -2
- {mcp_use-1.2.5 → mcp_use-1.2.7}/README.md +36 -0
- mcp_use-1.2.7/docs/building-custom-agents.mdx +175 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/docs.json +17 -4
- mcp_use-1.2.7/docs/favicon.svg +8 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/quickstart.mdx +48 -0
- mcp_use-1.2.7/mcp_use/adapters/__init__.py +10 -0
- mcp_use-1.2.7/mcp_use/adapters/base.py +178 -0
- mcp_use-1.2.7/mcp_use/adapters/langchain_adapter.py +161 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/agents/mcpagent.py +17 -10
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/agents/server_manager.py +4 -2
- {mcp_use-1.2.5 → mcp_use-1.2.7}/pyproject.toml +2 -2
- mcp_use-1.2.5/docs/favicon.svg +0 -14
- mcp_use-1.2.5/mcp_use/adapters/__init__.py +0 -5
- mcp_use-1.2.5/mcp_use/adapters/langchain_adapter.py +0 -212
- {mcp_use-1.2.5 → mcp_use-1.2.7}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/.github/workflows/publish.yml +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/.github/workflows/tests.yml +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/.gitignore +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/.pre-commit-config.yaml +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/LICENSE +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/README.md +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/api-reference/introduction.mdx +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/development.mdx +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/essentials/configuration.mdx +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/essentials/connection-types.mdx +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/essentials/debugging.mdx +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/essentials/llm-integration.mdx +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/images/hero-dark.png +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/images/hero-light.png +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/introduction.mdx +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/logo/dark.svg +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/logo/light.svg +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/docs/snippets/snippet-intro.mdx +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/examples/airbnb_mcp.json +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/examples/airbnb_use.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/examples/blender_use.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/examples/browser_mcp.json +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/examples/browser_use.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/examples/chat_example.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/examples/filesystem_use.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/examples/http_example.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/examples/multi_server_example.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/__init__.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/agents/__init__.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/agents/base.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/agents/prompts/system_prompt_builder.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/agents/prompts/templates.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/client.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/config.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/connectors/__init__.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/connectors/base.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/connectors/http.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/connectors/stdio.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/connectors/websocket.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/logging.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/session.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/task_managers/__init__.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/task_managers/base.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/task_managers/sse.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/task_managers/stdio.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/mcp_use/task_managers/websocket.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/pytest.ini +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/static/image.jpg +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/tests/conftest.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/tests/unit/test_client.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/tests/unit/test_config.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/tests/unit/test_http_connector.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/tests/unit/test_logging.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/tests/unit/test_session.py +0 -0
- {mcp_use-1.2.5 → mcp_use-1.2.7}/tests/unit/test_stdio_connector.py +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Pull Request Description
|
|
2
|
+
|
|
3
|
+
## Changes
|
|
4
|
+
|
|
5
|
+
Describe the changes introduced by this PR in a concise manner.
|
|
6
|
+
|
|
7
|
+
## Implementation Details
|
|
8
|
+
|
|
9
|
+
1. List the specific implementation details
|
|
10
|
+
2. Include code organization, architectural decisions
|
|
11
|
+
3. Note any dependencies that were added or modified
|
|
12
|
+
|
|
13
|
+
## Example Usage (Before)
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
# Include example code showing how things worked before (if applicable)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Example Usage (After)
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
# Include example code showing how things work after your changes
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Documentation Updates
|
|
26
|
+
|
|
27
|
+
* List any documentation files that were updated
|
|
28
|
+
* Explain what was changed in each file
|
|
29
|
+
|
|
30
|
+
## Testing
|
|
31
|
+
|
|
32
|
+
Describe how you tested these changes:
|
|
33
|
+
- Unit tests added/modified
|
|
34
|
+
- Manual testing performed
|
|
35
|
+
- Edge cases considered
|
|
36
|
+
|
|
37
|
+
## Backwards Compatibility
|
|
38
|
+
|
|
39
|
+
Explain whether these changes are backwards compatible. If not, describe what users will need to do to adapt to these changes.
|
|
40
|
+
|
|
41
|
+
## Related Issues
|
|
42
|
+
|
|
43
|
+
Closes #[issue_number]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-use
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
4
4
|
Summary: MCP Library for LLMs
|
|
5
5
|
Author-email: Pietro Zullo <pietro.zullo@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -18,7 +18,7 @@ Requires-Dist: aiohttp>=3.9.0
|
|
|
18
18
|
Requires-Dist: jsonschema-pydantic>=0.1.0
|
|
19
19
|
Requires-Dist: langchain-community>=0.0.10
|
|
20
20
|
Requires-Dist: langchain>=0.1.0
|
|
21
|
-
Requires-Dist: mcp
|
|
21
|
+
Requires-Dist: mcp>=1.5.0
|
|
22
22
|
Requires-Dist: pydantic>=2.0.0
|
|
23
23
|
Requires-Dist: python-dotenv>=1.0.0
|
|
24
24
|
Requires-Dist: typing-extensions>=4.8.0
|
|
@@ -69,6 +69,7 @@ Description-Content-Type: text/markdown
|
|
|
69
69
|
| ⚙️ **Dynamic Server Selection** | Agents can dynamically choose the most appropriate MCP server for a given task from the available pool |
|
|
70
70
|
| 🧩 **Multi-Server Support** | Use multiple MCP servers simultaneously in a single agent |
|
|
71
71
|
| 🛡️ **Tool Restrictions** | Restrict potentially dangerous tools like file system or network access |
|
|
72
|
+
| 🔧 **Custom Agents** | Build your own agents with any framework using the LangChain adapter or create new adapters |
|
|
72
73
|
|
|
73
74
|
|
|
74
75
|
# Quick start
|
|
@@ -503,6 +504,41 @@ if __name__ == "__main__":
|
|
|
503
504
|
asyncio.run(main())
|
|
504
505
|
```
|
|
505
506
|
|
|
507
|
+
# Build a Custom Agent:
|
|
508
|
+
|
|
509
|
+
You can also build your own custom agent using the LangChain adapter:
|
|
510
|
+
|
|
511
|
+
```python
|
|
512
|
+
import asyncio
|
|
513
|
+
from langchain_openai import ChatOpenAI
|
|
514
|
+
from mcp_use.client import MCPClient
|
|
515
|
+
from mcp_use.adapters.langchain_adapter import LangChainAdapter
|
|
516
|
+
from dotenv import load_dotenv
|
|
517
|
+
|
|
518
|
+
load_dotenv()
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
async def main():
|
|
522
|
+
# Initialize MCP client
|
|
523
|
+
client = MCPClient.from_config_file("examples/browser_mcp.json")
|
|
524
|
+
llm = ChatOpenAI(model="gpt-4o")
|
|
525
|
+
|
|
526
|
+
# Create adapter instance
|
|
527
|
+
adapter = LangChainAdapter()
|
|
528
|
+
# Get LangChain tools with a single line
|
|
529
|
+
tools = await adapter.create_tools(client)
|
|
530
|
+
|
|
531
|
+
# Create a custom LangChain agent
|
|
532
|
+
llm_with_tools = llm.bind_tools(tools)
|
|
533
|
+
result = await llm_with_tools.ainvoke("What tools do you have avilable ? ")
|
|
534
|
+
print(result)
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
if __name__ == "__main__":
|
|
538
|
+
asyncio.run(main())
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
```
|
|
506
542
|
|
|
507
543
|
# Debugging
|
|
508
544
|
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
| ⚙️ **Dynamic Server Selection** | Agents can dynamically choose the most appropriate MCP server for a given task from the available pool |
|
|
31
31
|
| 🧩 **Multi-Server Support** | Use multiple MCP servers simultaneously in a single agent |
|
|
32
32
|
| 🛡️ **Tool Restrictions** | Restrict potentially dangerous tools like file system or network access |
|
|
33
|
+
| 🔧 **Custom Agents** | Build your own agents with any framework using the LangChain adapter or create new adapters |
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
# Quick start
|
|
@@ -464,6 +465,41 @@ if __name__ == "__main__":
|
|
|
464
465
|
asyncio.run(main())
|
|
465
466
|
```
|
|
466
467
|
|
|
468
|
+
# Build a Custom Agent:
|
|
469
|
+
|
|
470
|
+
You can also build your own custom agent using the LangChain adapter:
|
|
471
|
+
|
|
472
|
+
```python
|
|
473
|
+
import asyncio
|
|
474
|
+
from langchain_openai import ChatOpenAI
|
|
475
|
+
from mcp_use.client import MCPClient
|
|
476
|
+
from mcp_use.adapters.langchain_adapter import LangChainAdapter
|
|
477
|
+
from dotenv import load_dotenv
|
|
478
|
+
|
|
479
|
+
load_dotenv()
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
async def main():
|
|
483
|
+
# Initialize MCP client
|
|
484
|
+
client = MCPClient.from_config_file("examples/browser_mcp.json")
|
|
485
|
+
llm = ChatOpenAI(model="gpt-4o")
|
|
486
|
+
|
|
487
|
+
# Create adapter instance
|
|
488
|
+
adapter = LangChainAdapter()
|
|
489
|
+
# Get LangChain tools with a single line
|
|
490
|
+
tools = await adapter.create_tools(client)
|
|
491
|
+
|
|
492
|
+
# Create a custom LangChain agent
|
|
493
|
+
llm_with_tools = llm.bind_tools(tools)
|
|
494
|
+
result = await llm_with_tools.ainvoke("What tools do you have avilable ? ")
|
|
495
|
+
print(result)
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
if __name__ == "__main__":
|
|
499
|
+
asyncio.run(main())
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
```
|
|
467
503
|
|
|
468
504
|
# Debugging
|
|
469
505
|
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Building Custom Agents
|
|
3
|
+
description: Learn how to build custom agents using MCPClient and integrate tools with different agent frameworks
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Building Custom Agents
|
|
7
|
+
|
|
8
|
+
MCP-Use provides flexible options for building custom agents that can utilize MCP tools. This guide will show you how to create your own agents by leveraging the existing adapters, particularly focusing on the LangChain adapter.
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
MCP-Use allows you to:
|
|
13
|
+
|
|
14
|
+
1. Access powerful tools from MCP through connectors
|
|
15
|
+
2. Convert those tools to different frameworks using adapters
|
|
16
|
+
3. Build custom agents that utilize these tools
|
|
17
|
+
|
|
18
|
+
While MCP-Use provides a built-in `MCPAgent` class, you may want to create your own custom agent implementation for more flexibility or to integrate with other frameworks.
|
|
19
|
+
|
|
20
|
+
## Using the LangChain Adapter
|
|
21
|
+
|
|
22
|
+
The `LangChainAdapter` is a powerful component that converts MCP tools to LangChain tools, enabling you to use MCP tools with any LangChain-compatible agent.
|
|
23
|
+
|
|
24
|
+
### Basic Example
|
|
25
|
+
|
|
26
|
+
Here's a simple example of creating a custom agent using the LangChain adapter with the simplified API:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import asyncio
|
|
30
|
+
from langchain_openai import ChatOpenAI
|
|
31
|
+
from langchain.agents import AgentExecutor, create_tool_calling_agent
|
|
32
|
+
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
33
|
+
|
|
34
|
+
from mcp_use.client import MCPClient
|
|
35
|
+
from mcp_use.adapters import LangChainAdapter
|
|
36
|
+
|
|
37
|
+
async def main():
|
|
38
|
+
# Initialize the MCP client
|
|
39
|
+
client = MCPClient.from_config_file("path/to/config.json")
|
|
40
|
+
|
|
41
|
+
# Create adapter instance
|
|
42
|
+
adapter = LangChainAdapter()
|
|
43
|
+
|
|
44
|
+
# Get LangChain tools directly from the client with a single line
|
|
45
|
+
tools = await adapter.create_tools(client)
|
|
46
|
+
|
|
47
|
+
# Initialize your language model
|
|
48
|
+
llm = ChatOpenAI(model="gpt-4o")
|
|
49
|
+
|
|
50
|
+
# Create a prompt template
|
|
51
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
52
|
+
("system", "You are a helpful assistant with access to powerful tools."),
|
|
53
|
+
MessagesPlaceholder(variable_name="chat_history"),
|
|
54
|
+
("human", "{input}"),
|
|
55
|
+
MessagesPlaceholder(variable_name="agent_scratchpad"),
|
|
56
|
+
])
|
|
57
|
+
|
|
58
|
+
# Create the agent
|
|
59
|
+
agent = create_tool_calling_agent(llm=llm, tools=tools, prompt=prompt)
|
|
60
|
+
|
|
61
|
+
# Create the agent executor
|
|
62
|
+
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
|
63
|
+
|
|
64
|
+
# Run the agent
|
|
65
|
+
result = await agent_executor.ainvoke({"input": "What can you do?"})
|
|
66
|
+
print(result["output"])
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
asyncio.run(main())
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Note how the API simplifies tool creation - all you need is to create an adapter instance and call its `create_tools` method:
|
|
73
|
+
```python
|
|
74
|
+
adapter = LangChainAdapter()
|
|
75
|
+
tools = await adapter.create_tools(client)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
You don't need to worry about sessions, connectors, or initialization. The adapter handles everything for you.
|
|
79
|
+
|
|
80
|
+
## Contributing New Adapters
|
|
81
|
+
|
|
82
|
+
MCP-Use welcomes contributions for integrating with different agent frameworks. The adapter architecture is designed to make this process straightforward.
|
|
83
|
+
|
|
84
|
+
### Adapter Architecture
|
|
85
|
+
|
|
86
|
+
MCP-Use provides a `BaseAdapter` abstract class that handles most of the common functionality:
|
|
87
|
+
- Managing tool caching
|
|
88
|
+
- Loading tools from connectors
|
|
89
|
+
- Handling connector initialization
|
|
90
|
+
- Iterating through tools from multiple connectors
|
|
91
|
+
|
|
92
|
+
To create an adapter for a new framework, you only need to implement one required method:
|
|
93
|
+
|
|
94
|
+
- `_convert_tool`: Convert a single MCP tool to your framework's tool format
|
|
95
|
+
|
|
96
|
+
### Creating a New Adapter
|
|
97
|
+
|
|
98
|
+
Here's a simple template for creating a new adapter:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from typing import Any
|
|
102
|
+
|
|
103
|
+
from mcp_use.adapters.base import BaseAdapter
|
|
104
|
+
from mcp_use.connectors.base import BaseConnector
|
|
105
|
+
from your_framework import YourFrameworkTool # Import your framework's tool class
|
|
106
|
+
|
|
107
|
+
class YourFrameworkAdapter(BaseAdapter):
|
|
108
|
+
"""Adapter for converting MCP tools to YourFramework tools."""
|
|
109
|
+
|
|
110
|
+
def _convert_tool(self, mcp_tool: dict[str, Any], connector: BaseConnector) -> YourFrameworkTool:
|
|
111
|
+
"""Convert an MCP tool to your framework's tool format.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
mcp_tool: The MCP tool to convert.
|
|
115
|
+
connector: The connector that provides this tool.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
A tool in your framework's format, or None if conversion failed.
|
|
119
|
+
"""
|
|
120
|
+
try:
|
|
121
|
+
# Implement your framework-specific conversion logic
|
|
122
|
+
converted_tool = YourFrameworkTool(
|
|
123
|
+
name=mcp_tool.name,
|
|
124
|
+
description=mcp_tool.description,
|
|
125
|
+
# Map the MCP tool properties to your framework's tool properties
|
|
126
|
+
# You might need custom handling for argument schemas, function execution, etc.
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
return converted_tool
|
|
130
|
+
except Exception as e:
|
|
131
|
+
self.logger.error(f"Error converting tool {mcp_tool.name}: {e}")
|
|
132
|
+
return None
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Using Your Custom Adapter
|
|
136
|
+
|
|
137
|
+
Once you've implemented your adapter, you can use it with the simplified API:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from your_module import YourFrameworkAdapter
|
|
141
|
+
from mcp_use.client import MCPClient
|
|
142
|
+
|
|
143
|
+
# Initialize the client
|
|
144
|
+
client = MCPClient.from_config_file("config.json")
|
|
145
|
+
|
|
146
|
+
# Create an adapter instance
|
|
147
|
+
adapter = YourFrameworkAdapter()
|
|
148
|
+
|
|
149
|
+
# Get tools with a single line
|
|
150
|
+
tools = await adapter.create_tools(client)
|
|
151
|
+
|
|
152
|
+
# Use the tools with your framework
|
|
153
|
+
agent = your_framework.create_agent(tools=tools)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Tips for Implementing an Adapter
|
|
157
|
+
|
|
158
|
+
1. **Schema Conversion**: Most frameworks have their own way of handling argument schemas. You'll need to convert the MCP tool's JSON Schema to your framework's format.
|
|
159
|
+
|
|
160
|
+
2. **Tool Execution**: When a tool is called in your framework, you'll need to pass the call to the connector's `call_tool` method and handle the result.
|
|
161
|
+
|
|
162
|
+
3. **Result Parsing**: MCP tools return structured data with types like text, images, or embedded resources. Your adapter should parse these into a format your framework understands.
|
|
163
|
+
|
|
164
|
+
4. **Error Handling**: Ensure your adapter handles errors gracefully, both during tool conversion and execution.
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
## Conclusion
|
|
168
|
+
|
|
169
|
+
Building custom agents with MCP-Use offers tremendous flexibility while leveraging the power of MCP tools. By combining different connectors and adapters, you can create specialized agents tailored to specific tasks or integrate MCP capabilities into existing agent frameworks.
|
|
170
|
+
|
|
171
|
+
The adapter architecture makes it easy to extend MCP-Use to support new frameworks - you just need to implement the `_convert_tool` method to bridge between MCP tools and your framework of choice.
|
|
172
|
+
|
|
173
|
+
With the simplified API, you can create tools for your framework directly from an MCPClient by instantiating the appropriate adapter and calling its `create_tools` method, hiding all the complexity of session and connector management.
|
|
174
|
+
|
|
175
|
+
We welcome contributions to expand the adapter ecosystem - if you develop an adapter for a new framework, please consider contributing it back to the project!
|
|
@@ -15,19 +15,32 @@
|
|
|
15
15
|
"groups": [
|
|
16
16
|
{
|
|
17
17
|
"group": "Getting Started",
|
|
18
|
-
"pages": [
|
|
18
|
+
"pages": [
|
|
19
|
+
"introduction",
|
|
20
|
+
"quickstart"
|
|
21
|
+
]
|
|
19
22
|
},
|
|
20
23
|
{
|
|
21
24
|
"group": "Essentials",
|
|
22
|
-
"pages": [
|
|
25
|
+
"pages": [
|
|
26
|
+
"essentials/configuration",
|
|
27
|
+
"essentials/llm-integration",
|
|
28
|
+
"essentials/debugging",
|
|
29
|
+
"essentials/connection-types",
|
|
30
|
+
"building-custom-agents"
|
|
31
|
+
]
|
|
23
32
|
},
|
|
24
33
|
{
|
|
25
34
|
"group": "API Reference",
|
|
26
|
-
"pages": [
|
|
35
|
+
"pages": [
|
|
36
|
+
"api-reference/introduction"
|
|
37
|
+
]
|
|
27
38
|
},
|
|
28
39
|
{
|
|
29
40
|
"group": "Development",
|
|
30
|
-
"pages": [
|
|
41
|
+
"pages": [
|
|
42
|
+
"development"
|
|
43
|
+
]
|
|
31
44
|
}
|
|
32
45
|
]
|
|
33
46
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg width="303" height="303" viewBox="0 0 303 303" fill="white" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect height="100%" width="100%" rx="55px" fill="white"/>
|
|
3
|
+
<path d="M106.066 106.066C86.5398 125.592 54.8816 125.592 35.3554 106.066V106.066C15.8291 86.5397 15.8291 54.8815 35.3554 35.3552V35.3552C54.8816 15.829 86.5398 15.829 106.066 35.3552V35.3552C125.592 54.8815 125.592 86.5397 106.066 106.066V106.066Z" fill="black"/>
|
|
4
|
+
<path d="M267.286 267.286C247.76 286.812 216.102 286.812 196.576 267.286V267.286C177.049 247.76 177.049 216.102 196.576 196.576V196.576C216.102 177.049 247.76 177.049 267.286 196.576V196.576C286.813 216.102 286.813 247.76 267.286 267.286V267.286Z" fill="black"/>
|
|
5
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M181.957 230.04L211.425 259.508L260.922 210.011L232.851 181.94C204.215 181.726 175.645 170.695 153.796 148.846C131.947 126.997 120.915 98.4264 120.702 69.7903L92.631 41.7193L43.1335 91.2168L72.6014 120.685C100.313 121.56 127.765 132.573 148.917 153.725C170.069 174.877 181.082 202.328 181.957 230.04Z" fill="black"/>
|
|
6
|
+
<circle cx="70.3209" cy="232.321" r="50" fill="black"/>
|
|
7
|
+
<circle cx="232.321" cy="70.3209" r="50" fill="black"/>
|
|
8
|
+
</svg>
|
|
@@ -121,6 +121,54 @@ Example configuration file (`browser_mcp.json`):
|
|
|
121
121
|
}
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
+
## Working with Adapters Directly
|
|
125
|
+
|
|
126
|
+
If you want more control over how tools are created, you can work with the adapters directly. The `BaseAdapter` class provides a unified interface for converting MCP tools to various framework formats, with `LangChainAdapter` being the most commonly used implementation.
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
import asyncio
|
|
130
|
+
from langchain_openai import ChatOpenAI
|
|
131
|
+
from langchain.agents import AgentExecutor, create_tool_calling_agent
|
|
132
|
+
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
133
|
+
|
|
134
|
+
from mcp_use.client import MCPClient
|
|
135
|
+
from mcp_use.adapters import LangChainAdapter
|
|
136
|
+
|
|
137
|
+
async def main():
|
|
138
|
+
# Initialize client
|
|
139
|
+
client = MCPClient.from_config_file("browser_mcp.json")
|
|
140
|
+
|
|
141
|
+
# Create an adapter instance
|
|
142
|
+
adapter = LangChainAdapter()
|
|
143
|
+
|
|
144
|
+
# Get tools directly from the client
|
|
145
|
+
tools = await adapter.create_tools(client)
|
|
146
|
+
|
|
147
|
+
# Use the tools with any LangChain agent
|
|
148
|
+
llm = ChatOpenAI(model="gpt-4o")
|
|
149
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
150
|
+
("system", "You are a helpful assistant with access to powerful tools."),
|
|
151
|
+
MessagesPlaceholder(variable_name="chat_history"),
|
|
152
|
+
("human", "{input}"),
|
|
153
|
+
MessagesPlaceholder(variable_name="agent_scratchpad"),
|
|
154
|
+
])
|
|
155
|
+
|
|
156
|
+
agent = create_tool_calling_agent(llm=llm, tools=tools, prompt=prompt)
|
|
157
|
+
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
|
158
|
+
|
|
159
|
+
result = await agent_executor.ainvoke({"input": "Search for information about climate change"})
|
|
160
|
+
print(result["output"])
|
|
161
|
+
|
|
162
|
+
if __name__ == "__main__":
|
|
163
|
+
asyncio.run(main())
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The adapter pattern makes it easy to:
|
|
167
|
+
|
|
168
|
+
1. Create tools directly from an MCPClient
|
|
169
|
+
2. Filter or customize which tools are available
|
|
170
|
+
3. Integrate with different agent frameworks
|
|
171
|
+
|
|
124
172
|
## Using Multiple Servers
|
|
125
173
|
|
|
126
174
|
The `MCPClient` can be configured with multiple MCP servers, allowing your agent to access tools from different sources. This capability enables complex workflows spanning various domains (e.g., web browsing and API interaction).
|
|
@@ -0,0 +1,10 @@
|
|
|
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 .base import BaseAdapter
|
|
8
|
+
from .langchain_adapter import LangChainAdapter
|
|
9
|
+
|
|
10
|
+
__all__ = ["BaseAdapter", "LangChainAdapter"]
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base adapter interface for MCP tools.
|
|
3
|
+
|
|
4
|
+
This module provides the abstract base class that all MCP tool adapters should inherit from.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from typing import Any, TypeVar
|
|
9
|
+
|
|
10
|
+
from ..client import MCPClient
|
|
11
|
+
from ..connectors.base import BaseConnector
|
|
12
|
+
from ..logging import logger
|
|
13
|
+
|
|
14
|
+
# Generic type for the tools created by the adapter
|
|
15
|
+
T = TypeVar("T")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BaseAdapter(ABC):
|
|
19
|
+
"""Abstract base class for converting MCP tools to other framework formats.
|
|
20
|
+
|
|
21
|
+
This class defines the common interface that all adapter implementations
|
|
22
|
+
should follow to ensure consistency across different frameworks.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, disallowed_tools: list[str] | None = None) -> None:
|
|
26
|
+
"""Initialize a new adapter.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
disallowed_tools: list of tool names that should not be available.
|
|
30
|
+
"""
|
|
31
|
+
self.disallowed_tools = disallowed_tools or []
|
|
32
|
+
self._connector_tool_map: dict[BaseConnector, list[T]] = {}
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
async def create_tools(
|
|
36
|
+
cls, client: "MCPClient", disallowed_tools: list[str] | None = None
|
|
37
|
+
) -> list[T]:
|
|
38
|
+
"""Create tools from an MCPClient instance.
|
|
39
|
+
|
|
40
|
+
This is the recommended way to create tools from an MCPClient, as it handles
|
|
41
|
+
session creation and connector extraction automatically.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
client: The MCPClient to extract tools from.
|
|
45
|
+
disallowed_tools: Optional list of tool names to exclude.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
A list of tools in the target framework's format.
|
|
49
|
+
|
|
50
|
+
Example:
|
|
51
|
+
```python
|
|
52
|
+
from mcp_use.client import MCPClient
|
|
53
|
+
from mcp_use.adapters import YourAdapter
|
|
54
|
+
|
|
55
|
+
client = MCPClient.from_config_file("config.json")
|
|
56
|
+
tools = await YourAdapter.create_tools(client)
|
|
57
|
+
```
|
|
58
|
+
"""
|
|
59
|
+
# Create the adapter
|
|
60
|
+
adapter = cls(disallowed_tools=disallowed_tools)
|
|
61
|
+
|
|
62
|
+
# Ensure we have active sessions
|
|
63
|
+
if not client.active_sessions:
|
|
64
|
+
logger.info("No active sessions found, creating new ones...")
|
|
65
|
+
await client.create_all_sessions()
|
|
66
|
+
|
|
67
|
+
# Get all active sessions
|
|
68
|
+
sessions = client.get_all_active_sessions()
|
|
69
|
+
|
|
70
|
+
# Extract connectors from sessions
|
|
71
|
+
connectors = [session.connector for session in sessions.values()]
|
|
72
|
+
|
|
73
|
+
# Create tools from connectors
|
|
74
|
+
return await adapter._create_tools_from_connectors(connectors)
|
|
75
|
+
|
|
76
|
+
async def load_tools_for_connector(self, connector: BaseConnector) -> list[T]:
|
|
77
|
+
"""Dynamically load tools for a specific connector.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
connector: The connector to load tools for.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
The list of tools that were loaded in the target framework's format.
|
|
84
|
+
"""
|
|
85
|
+
# Check if we already have tools for this connector
|
|
86
|
+
if connector in self._connector_tool_map:
|
|
87
|
+
logger.debug(
|
|
88
|
+
f"Returning {len(self._connector_tool_map[connector])} existing tools for connector"
|
|
89
|
+
)
|
|
90
|
+
return self._connector_tool_map[connector]
|
|
91
|
+
|
|
92
|
+
# Create tools for this connector
|
|
93
|
+
connector_tools = []
|
|
94
|
+
|
|
95
|
+
# Make sure the connector is initialized and has tools
|
|
96
|
+
success = await self._ensure_connector_initialized(connector)
|
|
97
|
+
if not success:
|
|
98
|
+
return []
|
|
99
|
+
|
|
100
|
+
# Now create tools for each MCP tool
|
|
101
|
+
for tool in connector.tools:
|
|
102
|
+
# Convert the tool and add it to the list if conversion was successful
|
|
103
|
+
converted_tool = self._convert_tool(tool, connector)
|
|
104
|
+
if converted_tool:
|
|
105
|
+
connector_tools.append(converted_tool)
|
|
106
|
+
|
|
107
|
+
# Store the tools for this connector
|
|
108
|
+
self._connector_tool_map[connector] = connector_tools
|
|
109
|
+
|
|
110
|
+
# Log available tools for debugging
|
|
111
|
+
logger.debug(
|
|
112
|
+
f"Loaded {len(connector_tools)} new tools for connector: "
|
|
113
|
+
f"{[getattr(tool, 'name', str(tool)) for tool in connector_tools]}"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
return connector_tools
|
|
117
|
+
|
|
118
|
+
@abstractmethod
|
|
119
|
+
def _convert_tool(self, mcp_tool: dict[str, Any], connector: BaseConnector) -> T:
|
|
120
|
+
"""Convert an MCP tool to the target framework's tool format.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
mcp_tool: The MCP tool to convert.
|
|
124
|
+
connector: The connector that provides this tool.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
A tool in the target framework's format.
|
|
128
|
+
"""
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
async def _create_tools_from_connectors(self, connectors: list[BaseConnector]) -> list[T]:
|
|
132
|
+
"""Create tools from MCP tools in all provided connectors.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
connectors: list of MCP connectors to create tools from.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
A list of tools in the target framework's format.
|
|
139
|
+
"""
|
|
140
|
+
tools = []
|
|
141
|
+
for connector in connectors:
|
|
142
|
+
# Create tools for this connector
|
|
143
|
+
connector_tools = await self.load_tools_for_connector(connector)
|
|
144
|
+
tools.extend(connector_tools)
|
|
145
|
+
|
|
146
|
+
# Log available tools for debugging
|
|
147
|
+
logger.debug(f"Available tools: {len(tools)}")
|
|
148
|
+
return tools
|
|
149
|
+
|
|
150
|
+
def _check_connector_initialized(self, connector: BaseConnector) -> bool:
|
|
151
|
+
"""Check if a connector is initialized and has tools.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
connector: The connector to check.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
True if the connector is initialized and has tools, False otherwise.
|
|
158
|
+
"""
|
|
159
|
+
return hasattr(connector, "tools") and connector.tools
|
|
160
|
+
|
|
161
|
+
async def _ensure_connector_initialized(self, connector: BaseConnector) -> bool:
|
|
162
|
+
"""Ensure a connector is initialized.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
connector: The connector to initialize.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
True if initialization succeeded, False otherwise.
|
|
169
|
+
"""
|
|
170
|
+
if not self._check_connector_initialized(connector):
|
|
171
|
+
logger.debug("Connector doesn't have tools, initializing it")
|
|
172
|
+
try:
|
|
173
|
+
await connector.initialize()
|
|
174
|
+
return True
|
|
175
|
+
except Exception as e:
|
|
176
|
+
logger.error(f"Error initializing connector: {e}")
|
|
177
|
+
return False
|
|
178
|
+
return True
|