Code Mode: Rethinking How AI Agents Interact with Tools
Introduction
AI agents are becoming increasingly capable of interacting with external systems. They can retrieve information, query databases, call APIs, and perform complex operations using tools.
One of the technologies that has made this possible is the Model Context Protocol (MCP).
MCP provides a standardized way for AI applications to discover and interact with external tools. Instead of building custom integrations for every API, developers can expose their functionality through MCP servers.
However, as agents become more sophisticated, a new challenge emerges.
What happens when a user request requires multiple dependent tool calls? What happens when the agent needs to retrieve hundreds of records, process them, and return only a small portion of the information?
Every intermediate tool response potentially becomes part of the LLM’s context.
This is where Code Mode comes into the picture.
In this article, we’ll understand the problem with traditional tool calling, explore how Code Mode addresses it,
1. Understanding the problem with traditional MCP tool calling
Let’s take a practical example.
Imagine we have an MCP server that exposes two tools:
list_hotels(city, limit)– Retrieves a list of hotels in a particular city.get_hotel_rating(hotel_id)– Retrieves the rating of an individual hotel.
Now, a user asks:
“Get me the ratings of the top 5 hotels in Bengaluru.”
Seems straightforward, right?
But let’s understand what happens behind the scenes.
The agent first needs to identify the available tools and understand which tools are required to fulfil the request.
It identifies that it needs to:
- Retrieve the list of five hotels.
- Get the rating of each hotel.
- Combine the hotel names and their respective ratings.
- Present the final result to the user.
With traditional tool calling, the workflow might look like this:
Step 1: Retrieve the hotels
The LLM invokes:
list_hotels(city="Bengaluru", limit=5)
The MCP server returns:
[
{"id": "H001", "name": "Hotel A"},
{"id": "H002", "name": "Hotel B"},
{"id": "H003", "name": "Hotel C"},
{"id": "H004", "name": "Hotel D"},
{"id": "H005", "name": "Hotel E"}
]Step 2: Retrieve individual ratings
The agent now needs to call get_hotel_rating() for each hotel.
For example:
get_hotel_rating("H001")
get_hotel_rating("H002")
get_hotel_rating("H003")
get_hotel_rating("H004")
get_hotel_rating("H005")These calls could execute sequentially or in parallel, depending on the agent framework.
Step 3: Aggregate the results
Each tool response is returned to the agent, which processes the results and generates the final response.
The problem is not necessarily the number of API calls. The problem is how the intermediate data flows through the LLM.
The LLM may need to receive:
- The hotel list.
- Each individual rating response.
- Tool definitions and their input schemas.
- Intermediate information required to orchestrate the next operation.
Even though the agent only needs the final hotel names and ratings, it has to deal with the intermediate information along the way.
As the number of dependent operations and the amount of returned data increase, this can consume a significant amount of context.
Imagine doing this for 100 hotels instead of 5.
Wouldn’t it be better if the agent could orchestrate these operations without sending every intermediate result back to the LLM?
That’s exactly the idea behind Code Mode.
2. What is Code Mode?
Code Mode is a tool-calling pattern introduced by Cloudflare that changes how an LLM interacts with external tools.
Instead of asking the LLM to invoke each tool individually, we allow it to write code that orchestrates multiple tool calls.
Think about the difference.
In traditional tool calling, the LLM decides which tool to call, receives the result, reasons about that result, and then decides what to do next.
With Code Mode, the LLM writes a small program that describes the entire workflow.
The program is executed in an isolated environment, and only the required output is returned to the LLM.
In simple terms:
Traditional MCP:
LLM → Tool Call → Result → LLM → Next Tool Call → Result → LLM
Code Mode:
LLM → Generated Code → Execute Multiple Tool Calls → Aggregated Result → LLM
The key difference is that the intermediate orchestration happens outside the LLM’s context.
An important clarification: Code Mode does not replace MCP. MCP can still provide the underlying tools, their descriptions, schemas, and connectivity. Code Mode changes how those tools are presented to and orchestrated by the model.
3. How does Code Mode solve the problem?
Let’s revisit our hotel-rating example.
Instead of exposing list_hotels() and get_hotel_rating() as individual operations that the LLM must repeatedly invoke, we expose them through a typed programming interface.
The LLM receives the available methods and their expected input and output structures.
For example:
interface Hotel {
id: string;
name: string;
}
interface HotelRating {
hotel_id: string;
rating: number;
}
interface HotelTools {
list_hotels(input: {
city: string;
limit: number;
}): Promise<Hotel[]>;
get_hotel_rating(input: {
hotel_id: string;
}): Promise<HotelRating>;
}These definitions help the LLM understand:
- Which methods are available.
- What parameters each method expects.
- What type of data each method returns.
- How the methods can be composed.
Now, instead of generating multiple individual tool calls, the LLM can generate a TypeScript program.
For example:
const hotels = await list_hotels({
city: "Bengaluru",
limit: 5
});
const results = await Promise.all(
hotels.map(async (hotel) => {
const rating = await get_hotel_rating({
hotel_id: hotel.id
});
return {
hotel_name: hotel.name,
rating: rating.rating
};
})
);
console.log(results);Let’s understand what this code does:
- Calls
list_hotels()to retrieve five hotels. - Iterates over the returned hotel records.
- Calls
get_hotel_rating()for each hotel. - Uses
Promise.all()to execute the independent rating requests concurrently. - Combines the hotel names and ratings.
- Returns the aggregated result.
Notice something important?
Get Kathiravan G’s stories in your inbox
Join Medium for free to get updates from this writer.
The LLM has generated one program that handles the entire workflow.
The hotel list and individual rating responses are processed within the code execution environment. They don’t need to be repeatedly sent back to the LLM for reasoning.
The LLM receives the final aggregated result and generates a natural-language response.
This is the fundamental advantage of Code Mode.
4. Where does the sandbox come into the picture?
We now have an LLM generating executable code dynamically.
But should we execute LLM-generated code directly on our application server?
Definitely not.
We cannot assume that generated code is always safe.
For example, generated code could attempt to:
- Access environment variables.
- Read local files.
- Make unauthorized network requests.
- Access resources outside its intended permissions.
- Perform unintended operations.
We therefore need an isolated execution environment.
This is where sandboxing becomes important.
Cloudflare’s Code Mode implementation uses isolated JavaScript execution environments based on V8 isolates through its Dynamic Worker Loader.
The architecture looks something like this:
In Cloudflare’s architecture, the generated code runs inside an isolated Worker.
The sandbox does not receive unrestricted network access. Instead, it accesses the connected MCP tools through controlled interfaces.
Those interfaces dispatch requests through the agent runtime, which handles the actual MCP communication.
This separation is important because the generated code does not need direct access to API credentials.
The sandbox receives authorized tool interfaces rather than unrestricted access to the underlying infrastructure.
Cloudflare uses V8 isolates instead of spinning up a full container for every code execution. This makes the execution environment lightweight and suitable for running short-lived generated programs.
5. What happens to MCP tool definitions?
This is another interesting part of Code Mode.
Normally, an MCP server exposes its functionality through individual tools, each with its own description and input schema.
In Code Mode, these tool definitions can be converted into a TypeScript API.
For example, an MCP tool might expose:
{
"name": "get_hotel_rating",
"description": "Get the rating of a hotel",
"inputSchema": {
"type": "object",
"properties": {
"hotel_id": {
"type": "string"
}
},
"required": ["hotel_id"]
}
}The Code Mode integration can transform this information into a TypeScript definition:
interface GetHotelRatingInput {
hotel_id: string;
}
interface GetHotelRatingOutput {
rating: number;
}
declare function get_hotel_rating(
input: GetHotelRatingInput
): Promise<GetHotelRatingOutput>;The LLM can now write code against this interface rather than repeatedly generating individual tool-call requests.
One important distinction:
TypeScript interfaces are used in this TypeScript-based implementation. Other languages can use equivalent typed representations, such as Python type definitions or TypedDict.
The goal is to give the LLM a structured and understandable representation of the available operations.
6. Traditional MCP vs Code Mode
Let’s compare both approaches.
Traditional MCP relies on the LLM to orchestrate tool interactions, where each tool is typically invoked individually and intermediate results are returned to the LLM for further reasoning and decision-making. As the workflow progresses, the context can grow due to repeated tool responses and tool definitions. Loops, conditional logic, and parallel execution are generally managed by the LLM or the surrounding agent framework. In contrast, Code Mode shifts orchestration to generated code, allowing multiple tool calls to be coordinated within a single execution. The generated code handles loops, conditions, and parallel operations, while intermediate results are processed within the sandbox rather than repeatedly sent back to the LLM. The sandbox acts as an orchestration layer that coordinates calls to MCP tool handlers, significantly reducing unnecessary context consumption and making complex workflows more efficient.
Does this mean traditional MCP is no longer useful?
Not at all.
For simple requests, such as retrieving the weather for a city or looking up a particular user, traditional tool calling is perfectly reasonable.
Code Mode becomes particularly useful when:
- Multiple tools need to be composed.
- One tool’s output becomes another tool’s input.
- Large collections need to be processed.
- Filtering and aggregation are required.
- The workflow contains loops and conditional logic.
- The agent has access to a large tool catalog.
The choice depends on the complexity of the task.
7. Does Code Mode eliminate context consumption?
No. It reduces unnecessary context consumption; it does not eliminate it.
The LLM still needs to understand:
- The available tool interfaces.
- The user’s request.
- The code it generates.
- The final result returned by the sandbox.
However, it no longer needs to receive every intermediate result just to decide what to do next.
There is another interesting optimization for systems with a very large number of tools.
Imagine an MCP server exposing thousands of operations.
Providing every tool definition to the LLM upfront can itself consume a huge amount of context.
A search-and-execute approach can help:
- The agent searches for the relevant operations.
- It retrieves the necessary definitions.
- It generates code using those operations.
- The sandbox executes the code.
- Only the relevant result is returned.
This is particularly interesting in Cloudflare’s Code Mode MCP implementation, where the entire API does not need to be exposed as thousands of individual model-facing tools.
8. Performance Comparison: Traditional MCP vs. Code Mode
The following results were recorded while executing a hotel-rating retrieval task, where the objective was to retrieve ratings for 20 hotels.
Conclusion
As AI agents become more capable, the challenge is no longer just about giving them access to more tools.
It’s also about making tool interactions efficient.
Traditional tool calling works well for straightforward operations, but complex workflows can introduce unnecessary context consumption and repeated LLM interactions.
Code Mode takes a different approach.
Instead of asking the LLM to orchestrate every operation individually, it allows the LLM to write code that coordinates multiple operations within an isolated execution environment.
The result is a more efficient way to handle dependent tool calls, data processing, loops, conditions, and aggregation.
The interesting shift is this: Instead of asking an LLM to execute a sequence of tool calls, we ask it to write a program that executes the sequence for us.
That’s what makes Code Mode an interesting direction for building more capable and efficient AI agents.





