
Code Mode enables AI agents to interact with MCP tools through code execution instead of direct tool calls. Based on research from Anthropic and Cloudflare, this approach reduces context consumption by up to 98.7% for complex workflows.
Quick Start
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
tools = await search_tools("github")
# Call tools as functions
pr = await github.get_pull_request(owner="facebook", repo="react", number=12345)
return {"title": pr["title"]}
""")
Why Code Mode?
Traditional MCP clients load all tool definitions upfront and pass intermediate results through the model context. This creates two problems:
- Tool definitions overload context - 150+ tools = 150,000+ tokens before processing any request
- 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:
result = await client.execute_code("""
# Search for relevant tools instead of loading all upfront
github_tools = await search_tools("github pull request")
# 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:
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:
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:
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.
The agent starts by searching for filesystem tools:
# Agent calls search_tools
tools = await search_tools('filesystem list')
Result (16 filesystem tools found)
[
{"name": "list_directory", "server": "filesystem"},
{"name": "list_directory_with_sizes", "server": "filesystem"},
{"name": "move_file", "server": "filesystem"},
{"name": "read_file", "server": "filesystem"},
...
]
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.
Execution: Processing Files Efficiently
The agent writes a single Python script to complete the task:
# 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 |
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.
API Reference
MCPClient
__init__(code_mode=True)
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:
{
"result": Any, # Return value
"logs": list[str], # Captured print()
"error": str | None, # Error if failed
"execution_time": float # Seconds
}
Search available tools across all servers.
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
# 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
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
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
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
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.
from mcp_use import CODE_MODE_AGENT_PROMPT
system_prompt = f"""
{CODE_MODE_AGENT_PROMPT}
Additional instructions...
"""
References
See Also