mirror of
https://github.com/mcp-use/mcp-use.git
synced 2026-09-14 18:06:01 +08:00
0cc3c1cbf0
- Corrected the Cloudflare link in the Code Mode section to point to the appropriate resource. - Ensured consistency in references to enhance user navigation and information accuracy.
382 lines
11 KiB
Plaintext
382 lines
11 KiB
Plaintext
---
|
||
title: "Code Mode"
|
||
description: "Execute MCP tools via code for 98.7% reduction in context overhead"
|
||
icon: "code"
|
||
tag: "New"
|
||
---
|
||
|
||
<Card img="/images/codemode.png">
|
||
Code Mode enables AI agents to interact with MCP tools through code execution instead of direct tool calls. Based on research from [Anthropic](https://www.anthropic.com/engineering/code-execution-with-mcp) and [Cloudflare](https://blog.cloudflare.com/code-mode/), this approach reduces context consumption by up to **98.7%** for complex workflows.
|
||
</Card>
|
||
|
||
|
||
|
||
## Quick Start
|
||
|
||
<CodeGroup>
|
||
```python Client Usage
|
||
from mcp_use import MCPClient
|
||
|
||
client = MCPClient(config="config.json", code_mode=True)
|
||
await client.create_all_sessions()
|
||
|
||
result = await client.execute_code("""
|
||
# Discover tools
|
||
search_result = await search_tools("github")
|
||
tools = search_result['results']
|
||
|
||
# Call tools as functions
|
||
pr = await github.get_pull_request(owner="facebook", repo="react", number=12345)
|
||
|
||
return {"title": pr["title"]}
|
||
""")
|
||
```
|
||
|
||
```python Agent Usage
|
||
from langchain_openai import ChatOpenAI
|
||
from mcp_use import MCPAgent, MCPClient, CODE_MODE_AGENT_PROMPT
|
||
|
||
client = MCPClient(config="config.json", code_mode=True)
|
||
|
||
agent = MCPAgent(
|
||
llm=ChatOpenAI(model="gpt-4"),
|
||
client=client,
|
||
system_prompt=CODE_MODE_AGENT_PROMPT
|
||
)
|
||
|
||
result = await agent.run("Analyze React repository")
|
||
```
|
||
</CodeGroup>
|
||
|
||
## Why Code Mode?
|
||
|
||
Traditional MCP clients load all tool definitions upfront and pass intermediate results through the model context. This creates two problems:
|
||
|
||
1. **Tool definitions overload context** - 150+ tools = 150,000+ tokens before processing any request
|
||
2. **Intermediate results consume tokens** - Each tool result flows through the model, even when just passing data between tools
|
||
|
||
Code Mode solves both by having agents write code that executes in a separate environment.
|
||
|
||
## Key Advantages
|
||
|
||
### 1. Progressive Disclosure
|
||
|
||
Agents load only the tools they need, when they need them:
|
||
|
||
```python
|
||
result = await client.execute_code("""
|
||
# Search for relevant tools instead of loading all upfront
|
||
search_result = await search_tools("github pull request")
|
||
github_tools = search_result['results']
|
||
|
||
# Only the 3 PR-related tools are loaded, not all 150+ tools
|
||
pr = await github.get_pull_request(...)
|
||
""")
|
||
```
|
||
|
||
**Benefit**: 2,000 tokens instead of 150,000 tokens (98.7% reduction)
|
||
|
||
### 2. Context-Efficient Tool Results
|
||
|
||
Large datasets are processed in the execution environment before returning to the agent:
|
||
|
||
```python
|
||
result = await client.execute_code("""
|
||
# Fetch 10,000 rows
|
||
all_issues = await github.list_issues(owner="microsoft", repo="vscode")
|
||
print(f"Processing {len(all_issues)} issues")
|
||
|
||
# Filter locally (doesn't consume agent context)
|
||
critical = [i for i in all_issues if 'critical' in str(i.get('labels'))]
|
||
|
||
# Return only summary, not 10,000 rows
|
||
return {
|
||
"total": len(all_issues),
|
||
"critical": len(critical),
|
||
"top_5": critical[:5]
|
||
}
|
||
""")
|
||
```
|
||
|
||
**Benefit**: Agent sees 5 issues instead of 10,000
|
||
|
||
### 3. More Powerful Control Flow
|
||
|
||
Loops, conditionals, and error handling use familiar code patterns instead of chaining individual tool calls:
|
||
|
||
```python
|
||
result = await client.execute_code("""
|
||
# Poll for deployment notification
|
||
found = False
|
||
attempts = 0
|
||
|
||
while not found and attempts < 10:
|
||
messages = await slack.get_channel_history(channel='C123456')
|
||
found = any('deployment complete' in m.text for m in messages)
|
||
|
||
if not found:
|
||
await asyncio.sleep(5)
|
||
attempts += 1
|
||
print(f"Attempt {attempts}: waiting...")
|
||
|
||
return {"found": found, "attempts": attempts}
|
||
""")
|
||
```
|
||
|
||
**Benefit**: More efficient than alternating between tool calls and sleep commands through the agent loop
|
||
|
||
### 4. Privacy-Preserving Operations
|
||
|
||
Intermediate results stay in the execution environment by default:
|
||
|
||
```python
|
||
result = await client.execute_code("""
|
||
# Fetch customer data with PII
|
||
customers = await crm.get_customer_list()
|
||
|
||
# Process PII locally - never enters model context
|
||
for customer in customers:
|
||
await salesforce.update_record(
|
||
objectType='Lead',
|
||
recordId=customer['id'],
|
||
data={'Email': customer['email'], 'Phone': customer['phone']}
|
||
)
|
||
print(f"Updated customer {customer['id']}")
|
||
|
||
# Return only count, not PII data
|
||
return {"updated": len(customers)}
|
||
""")
|
||
```
|
||
|
||
**Benefit**: Sensitive data flows through the workflow without entering the model's context
|
||
|
||
## Real-World Example: File System Exploration
|
||
|
||
This example demonstrates how Code Mode dramatically simplifies complex workflows. An agent tasked with "list files and rename them" performs the entire operation efficiently.
|
||
|
||
|
||
<Frame>
|
||
<img src="/images/codemode.gif" alt="Code Mode in Action" />
|
||
</Frame>
|
||
|
||
### Discovery: Finding the Right Tools
|
||
|
||
The agent starts by searching for filesystem tools:
|
||
|
||
```python
|
||
# Agent calls search_tools
|
||
result = await search_tools('filesystem list')
|
||
tools = result['results']
|
||
print(f"Found {result['meta']['result_count']} tools out of {result['meta']['total_tools']} total")
|
||
```
|
||
|
||
```json Result (16 filesystem tools found)
|
||
{
|
||
"meta": {
|
||
"total_tools": 50,
|
||
"namespaces": ["filesystem"],
|
||
"result_count": 16
|
||
},
|
||
"results": [
|
||
{"name": "list_directory", "server": "filesystem"},
|
||
{"name": "list_directory_with_sizes", "server": "filesystem"},
|
||
{"name": "move_file", "server": "filesystem"},
|
||
{"name": "read_file", "server": "filesystem"},
|
||
...
|
||
]
|
||
}
|
||
```
|
||
|
||
<Note>
|
||
**Code Mode Advantage**: The agent discovered 16 tools using ~200 tokens, compared to ~8,000+ tokens if all filesystem tool definitions were pre-loaded into the system prompt.
|
||
</Note>
|
||
|
||
### Execution: Processing Files Efficiently
|
||
|
||
The agent writes a single Python script to complete the task:
|
||
|
||
```python
|
||
# Agent-generated code
|
||
# 1. List files
|
||
files_str = await filesystem.list_directory_with_sizes(path="/path/to/folder")
|
||
|
||
# 2. Parse and filter locally (doesn't consume LLM context)
|
||
lines = files_str.strip().split('\n')
|
||
file_list = [line for line in lines if line.startswith('[FILE]')]
|
||
|
||
# 3. Rename files using move_file
|
||
for file_line in file_list:
|
||
filename = file_line.split()[1] # Extract filename
|
||
if '_example' not in filename:
|
||
source = f"/path/to/folder/{filename}"
|
||
# Split extension
|
||
name, ext = filename.rsplit('.', 1)
|
||
dest = f"/path/to/folder/{name}_example.{ext}"
|
||
await filesystem.move_file(source=source, destination=dest)
|
||
|
||
# 4. Return summary, not raw data
|
||
return {"renamed": len(file_list), "total_files": len(lines)}
|
||
```
|
||
|
||
### Efficiency Comparison
|
||
|
||
| Metric | Without Code Mode | With Code Mode | Improvement |
|
||
|--------|-------------------|----------------|-------------|
|
||
| **Tool Calls** | 18 (1 list + 1 move × 17 files) | 1 (`execute_code`) | **94% fewer** |
|
||
| **Context Tokens** | ~25,000 (tool defs + results) | ~1,500 (meta tools) | **94% reduction** |
|
||
| **Latency** | 18 round trips | 1 execution | **17x faster** |
|
||
|
||
<Info>
|
||
By writing code instead of chaining tool calls, the agent processed the file list locally and only returned the summary. This avoided passing the raw directory listing (and each rename confirmation) through the LLM context.
|
||
</Info>
|
||
|
||
## API Reference
|
||
|
||
### MCPClient
|
||
|
||
#### `__init__(code_mode=True)`
|
||
|
||
```python
|
||
client = MCPClient(
|
||
config="config.json",
|
||
code_mode=True # Enable code execution mode
|
||
)
|
||
```
|
||
|
||
#### `execute_code(code: str, timeout: float = 30.0)`
|
||
|
||
Execute Python code with MCP tool access.
|
||
|
||
**Returns:**
|
||
```python
|
||
{
|
||
"result": Any, # Return value
|
||
"logs": list[str], # Captured print()
|
||
"error": str | None, # Error if failed
|
||
"execution_time": float # Seconds
|
||
}
|
||
```
|
||
|
||
#### `search_tools(query: str = "", detail_level: str = "full")`
|
||
|
||
Search available tools across all servers.
|
||
|
||
**Returns:** Dictionary with:
|
||
- `meta`: Dictionary containing `total_tools`, `namespaces`, and `result_count`
|
||
- `results`: List of tool information dictionaries matching the query
|
||
|
||
**Detail levels:** `"names"`, `"descriptions"`, `"full"`
|
||
|
||
## What's Available in Code
|
||
|
||
### Functions
|
||
|
||
- **`search_tools(query, detail_level)`** - Discover tools
|
||
- **`server.tool_name(**kwargs)`** - Call any MCP tool
|
||
- **`__tool_namespaces`** - List of server names
|
||
|
||
> **Note:** Tool names are automatically sanitized to be valid Python identifiers. For example, a tool named `list-files` becomes `list_files`.
|
||
|
||
### Builtins
|
||
|
||
```python
|
||
# Data: list, dict, set, tuple, str, int, float, bool
|
||
# Iteration: range, enumerate, zip, map, filter
|
||
# Aggregation: len, sum, min, max, sorted, any, all
|
||
# Async: asyncio
|
||
# Exceptions: Exception, ValueError, TypeError, etc.
|
||
```
|
||
|
||
**Restricted:** `import`, `open`, `eval`, file I/O
|
||
|
||
## Performance
|
||
|
||
From Anthropic's research:
|
||
|
||
| Traditional | Code Mode | Improvement |
|
||
|------------|-----------|-------------|
|
||
| 150,000+ tokens (tool defs) | 2,000 tokens | **98.7% reduction** |
|
||
| 16 API iterations | 1 execution | **88% fewer calls** |
|
||
| All results in context | Only summary | **68% fewer tokens** |
|
||
|
||
## Examples
|
||
|
||
### Tool Chaining
|
||
|
||
```python
|
||
result = await client.execute_code("""
|
||
pr = await github.get_pull_request(owner="facebook", repo="react", number=12345)
|
||
|
||
if pr['state'] == 'open':
|
||
await slack.post_message(
|
||
channel="#dev",
|
||
text=f"PR needs review: {pr['title']}"
|
||
)
|
||
return {"notified": True}
|
||
|
||
return {"notified": False}
|
||
""")
|
||
```
|
||
|
||
### Data Processing
|
||
|
||
```python
|
||
result = await client.execute_code("""
|
||
files = await filesystem.list_directory(path="/private/tmp")
|
||
lines = files.strip().split('\\n')
|
||
|
||
dirs = [l for l in lines if l.startswith('[DIR]')]
|
||
files_only = [l for l in lines if l.startswith('[FILE]')]
|
||
|
||
return {
|
||
"total": len(lines),
|
||
"directories": len(dirs),
|
||
"files": len(files_only)
|
||
}
|
||
""")
|
||
```
|
||
|
||
### Error Handling
|
||
|
||
```python
|
||
result = await client.execute_code("""
|
||
try:
|
||
data = await api.fetch_data(id="123")
|
||
return {"success": True, "data": data}
|
||
except Exception as e:
|
||
print(f"Failed: {e}")
|
||
return {"success": False, "error": str(e)}
|
||
""")
|
||
```
|
||
|
||
## Agent Integration
|
||
|
||
Agents only see 2 tools when `code_mode=True`:
|
||
|
||
- **`execute_code`** - Execute Python code with tool access
|
||
- **`search_tools`** - Discover available tools
|
||
|
||
All other MCP tools are accessible within code execution.
|
||
|
||
```python
|
||
from mcp_use import CODE_MODE_AGENT_PROMPT
|
||
|
||
system_prompt = f"""
|
||
{CODE_MODE_AGENT_PROMPT}
|
||
|
||
Additional instructions...
|
||
"""
|
||
```
|
||
|
||
## References
|
||
|
||
- [Anthropic: Code Execution with MCP](https://www.anthropic.com/engineering/code-execution-with-mcp)
|
||
- [Cloudflare: Building AI Agents](https://blog.cloudflare.com/code-mode/)
|
||
- [UTCP: Code Mode Library](https://github.com/universal-tool-calling-protocol/code-mode)
|
||
|
||
## See Also
|
||
|
||
- [Direct Tool Calls](/python/client/direct-tool-calls) - Traditional tool calling
|
||
- [Tools](/python/client/tools) - Understanding MCP tools
|
||
- [Multi-Server Setup](/python/client/multi-server-setup) - Multiple servers
|