Site icon Efficient Coder

Code Execution with MCP: Transforming AI Agent Efficiency and Overcoming Context Window Challenges

Building More Efficient AI Agents: How Code Execution with MCP Solves Context Window Challenges

Introduction: The AI Agent Connectivity Problem

In today’s rapidly evolving artificial intelligence landscape, AI agents are handling increasingly complex tasks that require integration with multiple external systems and data sources. However, as these agents need to connect with more tools and data sources, a critical challenge emerges: how can agents maintain high performance while interacting with hundreds or thousands of tools?

This challenge brings us to the Model Context Protocol (MCP), an open standard for connecting AI agents to external systems. Think of MCP as a universal adapter that enables seamless communication between AI agents and various tools and data sources. Before MCP, connecting agents to external systems required custom integrations for each pairing—much like having a different type of power plug for every electronic device you own. This approach created fragmentation and duplicated effort that made it difficult to scale truly connected systems.

Since its launch in November 2024, MCP has seen rapid adoption. The developer community has built thousands of MCP servers, software development kits are available for all major programming languages, and the industry has embraced MCP as the de facto standard for connecting agents to tools and data.

The Scaling Challenge: When More Tools Become a Problem

Today, developers routinely build AI agents with access to hundreds or thousands of tools across dozens of MCP servers. While this connectivity represents significant progress, it introduces new challenges that can impact agent efficiency and performance.

The Token Consumption Crisis

As MCP usage scales, two common patterns emerge that increase agent cost and latency:

1. Tool Definitions Overwhelm the Context Window

Most MCP clients load all tool definitions upfront directly into the agent’s context window, exposing them to the model using direct tool-calling syntax. These tool definitions typically include detailed descriptions, parameter requirements, and return types.

Consider what these tool definitions look like in practice:

gdrive.getDocument
     Description: Retrieves a document from Google Drive
     Parameters:
                documentId (required, string): The ID of the document to retrieve
                fields (optional, string): Specific fields to return
     Returns: Document object with title, body content, metadata, permissions, etc.
salesforce.updateRecord
    Description: Updates a record in Salesforce
    Parameters:
               objectType (required, string): Type of Salesforce object (Lead, Contact, Account, etc.)
               recordId (required, string): The ID of the record to update
               data (required, object): Fields to update with their new values
     Returns: Updated record object with confirmation

These tool descriptions occupy valuable space in the context window, increasing response time and operational costs. When agents connect to thousands of tools, they must process hundreds of thousands of tokens before even reading a user’s request.

2. Intermediate Tool Results Consume Additional Tokens

Most MCP clients allow models to directly call MCP tools. For example, if you ask your agent to “Download my meeting transcript from Google Drive and attach it to the Salesforce lead,” the model typically makes sequential calls like this:

TOOL CALL: gdrive.getDocument(documentId: "abc123")
        → returns "Discussed Q4 goals...\n[full transcript text]"
           (loaded into model context)

TOOL CALL: salesforce.updateRecord(
			objectType: "SalesMeeting",
			recordId: "00Q5f000001abcXYZ",
  			data: { "Notes": "Discussed Q4 goals...\n[full transcript text written out]" }
		)
		(model needs to write entire transcript into context again)

Every intermediate result must pass through the model. In this example, the full call transcript flows through the context window twice. For a typical two-hour sales meeting transcript, this could mean processing an additional 50,000 tokens. Even larger documents may exceed context window limits entirely, breaking the workflow completely.

When working with large documents or complex data structures, models also become more prone to making mistakes when copying data between tool calls, further reducing efficiency.

MCP Architecture Diagram

The diagram above illustrates how traditional MCP clients load tool definitions into the model’s context window and orchestrate a message loop where each tool call and result passes through the model between operations.

The Solution: Code Execution with MCP

As code execution environments become more common for AI agents, an elegant solution emerges: presenting MCP servers as code APIs rather than direct tool calls. This approach allows agents to write code that interacts with MCP servers, addressing both major challenges simultaneously.

How Code Execution Transforms Agent Efficiency

With code execution, agents can load only the tools they need and process data in the execution environment before passing results back to the model. This fundamental shift in approach delivers dramatic improvements in efficiency.

There are several ways to implement code execution with MCP. One effective approach involves generating a file tree of all available tools from connected MCP servers. Here’s what this implementation looks like using TypeScript:

servers
├── google-drive
│   ├── getDocument.ts
│   ├── ... (other tools)
│   └── index.ts
├── salesforce
│   ├── updateRecord.ts
│   ├── ... (other tools)
│   └── index.ts
└── ... (other servers)

Each tool corresponds to a specific file with a structure like this:

// ./servers/google-drive/getDocument.ts
import { callMCPTool } from "../../../client.js";

interface GetDocumentInput {
  documentId: string;
}

interface GetDocumentResponse {
  content: string;
}

/* Read a document from Google Drive */
export async function getDocument(
  input: GetDocumentInput,
): Promise<GetDocumentResponse> {
  return callMCPTool<GetDocumentResponse>("google_drive__get_document", input);
}

With this structure, our earlier Google Drive to Salesforce example transforms from multiple tool calls into clean, efficient code:

// Read transcript from Google Docs and add to Salesforce prospect
import * as gdrive from "./servers/google-drive";
import * as salesforce from "./servers/salesforce";

const transcript = (await gdrive.getDocument({ documentId: "abc123" })).content;
await salesforce.updateRecord({
  objectType: "SalesMeeting",
  recordId: "00Q5f000001abcXYZ",
  data: { Notes: transcript },
});

The agent discovers tools by exploring the filesystem: listing the ./servers/ directory to find available servers (like google-drive and salesforce), then reading the specific tool files it needs (like getDocument.ts and updateRecord.ts) to understand each tool’s interface. This approach enables the agent to load only the definitions it needs for the current task.

The efficiency gains from this approach are substantial. Real-world implementations have demonstrated token usage reduction from 150,000 tokens to just 2,000 tokens—representing time and cost savings of 98.7%.

Cloudflare has published similar findings, referring to code execution with MCP as “Code Mode.” Their research confirms the same core insight: large language models excel at writing code, and developers should leverage this strength to build agents that interact more efficiently with MCP servers.

Key Benefits of Code Execution with MCP

Code execution with MCP enables agents to use context more efficiently through several powerful mechanisms. Beyond the obvious token savings, this approach offers significant advantages in privacy, state management, and operational flexibility.

Progressive Disclosure of Tools

AI models demonstrate remarkable proficiency in navigating filesystems and code structures. By presenting tools as code in a filesystem hierarchy, we enable models to read tool definitions on-demand rather than loading everything upfront.

This progressive disclosure approach can be further enhanced by implementing a search_tools function that helps agents find relevant tool definitions efficiently. For example, when working with a Salesforce integration, the agent can search for “salesforce” and load only those tools needed for the current task.

The search functionality can include a detail level parameter that allows the agent to select how much information it needs—from just tool names to full definitions with complete schema information. This granular control helps the agent conserve context space while still finding the right tools for each task.

Context-Efficient Handling of Tool Results

When working with large datasets, code execution allows agents to filter and transform results directly in the execution environment before returning them to the model context. Consider the difference in approaches when fetching data from a large spreadsheet:

// Without code execution - all data flows through context
TOOL CALL: gdrive.getSheet(sheetId: 'abc123')
        → returns 10,000 rows in context to filter manually

// With code execution - filter in the execution environment
const allRows = await gdrive.getSheet({ sheetId: 'abc123' });
const pendingOrders = allRows.filter(row =>
  row["Status"] === 'pending'
);
console.log(`Found ${pendingOrders.length} pending orders`);
console.log(pendingOrders.slice(0, 5)); // Only log first 5 for review

With code execution, the agent sees only five representative rows instead of 10,000. This pattern extends to aggregations, joins across multiple data sources, or extracting specific fields—all without bloating the context window with unnecessary data.

Enhanced Control Flow and Logic Execution

Code execution enables the use of familiar programming constructs like loops, conditionals, and error handling instead of chaining individual tool calls. This approach results in more natural and efficient operation sequences.

For example, if you need to wait for a deployment notification in Slack, the agent can write compact, efficient code:

let found = false;
while (!found) {
  const messages = await slack.getChannelHistory({ channel: "C123456" });
  found = messages.some((m) => m.text.includes("deployment complete"));
  if (!found) await new Promise((r) => setTimeout(r, 5000));
}
console.log("Deployment notification received");

This approach proves significantly more efficient than alternating between MCP tool calls and sleep commands through the agent loop.

Additionally, writing conditional logic that executes in the code environment saves “time to first token” latency: rather than waiting for the model to evaluate each if-statement sequentially, the agent can let the code execution environment handle this more efficiently.

Privacy-Preserving Operations

When agents use code execution with MCP, intermediate results remain in the execution environment by default. This means the agent only sees data that you explicitly log or return, enabling sensitive information to flow through workflows without ever entering the model’s context.

For highly sensitive workloads, the agent harness can automatically tokenize sensitive data. Consider a scenario where you need to import customer contact details from a spreadsheet into Salesforce:

const sheet = await gdrive.getSheet({ sheetId: "abc123" });
for (const row of sheet.rows) {
  await salesforce.updateRecord({
    objectType: "Lead",
    recordId: row.salesforceId,
    data: {
      Email: row.email,
      Phone: row.phone,
      Name: row.name,
    },
  });
}
console.log(`Updated ${sheet.rows.length} leads`);

The MCP client can intercept this data and tokenize personally identifiable information before it reaches the model:

// What the agent actually sees when logging sheet.rows:
[
  { salesforceId: '00Q...', email: '[EMAIL_1]', phone: '[PHONE_1]', name: '[NAME_1]' },
  { salesforceId: '00Q...', email: '[EMAIL_2]', phone: '[PHONE_2]', name: '[NAME_2]' },
  ...
]

When this data is used in subsequent MCP tool calls, the tokens are resolved back to the actual values through a lookup in the MCP client. The real email addresses, phone numbers, and names flow securely from Google Sheets to Salesforce without ever passing through the model. This prevents the agent from accidentally logging or processing sensitive data while enabling deterministic security rules that control data flow between systems.

State Persistence and Reusable Skills

Code execution with filesystem access enables agents to maintain state across operations, significantly enhancing their capabilities for complex, multi-step tasks.

Agents can write intermediate results to files, enabling them to resume work and track progress:

const leads = await salesforce.query({
  query: "SELECT Id, Email FROM Lead LIMIT 1000",
});
const csvData = leads.map((l) => `${l.Id},${l.Email}`).join("\n");
await fs.writeFile("./workspace/leads.csv", csvData);

// Later execution continues from where it left off
const saved = await fs.readFile("./workspace/leads.csv", "utf-8");

Perhaps even more powerful is the ability for agents to persist their own code as reusable functions. Once an agent develops working code for a specific task, it can save that implementation for future use:

// In ./skills/save-sheet-as-csv.ts
import * as gdrive from "./servers/google-drive";
export async function saveSheetAsCsv(sheetId: string) {
  const data = await gdrive.getSheet({ sheetId });
  const csv = data.map((row) => row.join(",")).join("\n");
  await fs.writeFile(`./workspace/sheet-${sheetId}.csv`, csv);
  return `./workspace/sheet-${sheetId}.csv`;
}

// Later, in any agent execution:
import { saveSheetAsCsv } from "./skills/save-sheet-as-csv";
const csvPath = await saveSheetAsCsv("abc123");

This capability connects closely with the concept of Skills—folders containing reusable instructions, scripts, and resources that help models improve performance on specialized tasks. By adding a SKILL.md file to these saved functions, developers can create structured skills that models can reference and use effectively.

Over time, this approach allows agents to build a toolbox of higher-level capabilities, gradually evolving the scaffolding they need to work most effectively on specific types of tasks.

Implementation Considerations and Trade-offs

While code execution with MCP offers significant benefits, it’s important to acknowledge the implementation complexity it introduces. Running agent-generated code requires a secure execution environment with appropriate sandboxing, resource limits, and monitoring.

These infrastructure requirements add operational overhead and security considerations that direct tool calls avoid. Organizations must carefully weigh the benefits of code execution—reduced token costs, lower latency, and improved tool composition—against these implementation costs.

Security considerations should include:

  • Proper sandboxing to prevent unauthorized system access
  • Resource limitations to prevent runaway processes
  • Monitoring and logging for audit purposes
  • Validation of code before execution in sensitive environments

Real-World Applications and Use Cases

To better understand the practical implications of code execution with MCP, let’s explore several real-world scenarios where this approach delivers significant value.

Data Processing and Transformation Pipelines

Consider a scenario where an agent needs to extract data from multiple sources, transform it, and load it into a target system. With traditional tool calling, this would require multiple sequential calls with all intermediate data passing through the context window.

With code execution, the agent can handle this entire workflow efficiently:

// Extract data from multiple sources
const userData = await db.query("SELECT * FROM users WHERE created_at > ?", [lastSync]);
const paymentData = await stripe.getCharges({ limit: 100 });
const supportTickets = await zendesk.getTickets({ status: "open" });

// Transform and enrich data in the execution environment
const enrichedData = userData.map(user => {
  const userPayments = paymentData.filter(p => p.customer === user.stripe_id);
  const userTickets = supportTickets.filter(t => t.requester_id === user.id);
  
  return {
    user_id: user.id,
    email: user.email,
    total_spent: userPayments.reduce((sum, p) => sum + p.amount, 0),
    open_tickets: userTickets.length,
    last_activity: user.last_login_at
  };
});

// Only send summarized results to the model context
console.log(`Processed ${enrichedData.length} user records`);
console.log("Sample of first 5 users:", enrichedData.slice(0, 5));

// Load the transformed data into the target system
await bigquery.insertRows("user_metrics", enrichedData);

This approach avoids sending thousands of raw data records through the model’s context window, dramatically reducing token consumption while maintaining the same functional outcome.

Complex Workflow Automation

For workflows involving multiple steps with conditional logic and error handling, code execution provides a more natural and efficient implementation approach:

// Automated deployment and monitoring workflow
async function deployAndMonitor() {
  try {
    // Start the deployment process
    const deployment = await k8s.startDeployment({
      image: "my-app:latest",
      replicas: 3
    });
    
    console.log(`Deployment initiated: ${deployment.id}`);
    
    // Monitor deployment progress
    let isReady = false;
    let attempts = 0;
    const maxAttempts = 30;
    
    while (!isReady && attempts < maxAttempts) {
      const status = await k8s.getDeploymentStatus(deployment.id);
      isReady = status.ready;
      
      if (!isReady) {
        console.log(`Deployment not ready yet, attempt ${attempts + 1}/${maxAttempts}`);
        await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds
        attempts++;
      }
    }
    
    if (!isReady) {
      throw new Error("Deployment timeout: exceeded maximum wait time");
    }
    
    // Execute post-deployment health checks
    const health = await healthCheck.runAll();
    
    // Notify relevant channels
    await slack.sendMessage("#deployments", 
      `Deployment ${deployment.id} completed successfully. Health checks: ${health.passed ? "PASSED" : "FAILED"}`
    );
    
    return { success: true, deploymentId: deployment.id, health: health };
    
  } catch (error) {
    // Handle errors and send alerts
    await slack.sendMessage("#deployments-alerts", 
      `Deployment failed: ${error.message}`
    );
    return { success: false, error: error.message };
  }
}

// Execute the complete workflow
const result = await deployAndMonitor();
console.log(`Workflow completed: ${result.success ? "SUCCESS" : "FAILURE"}`);

This implementation handles the entire deployment workflow in a single execution context, with proper error handling and status reporting, without requiring the model to process each intermediate step.

Best Practices for Implementation

Organizations adopting code execution with MCP should consider these implementation best practices:

Security and Sandboxing

Implement robust security measures for code execution environments:

  • Resource Constraints: Limit CPU, memory, and execution time for agent-generated code
  • Network Restrictions: Control which endpoints the execution environment can access
  • Filesystem Sandboxing: Restrict file access to specific directories
  • Code Review Processes: Implement approval workflows for sensitive operations

Error Handling and Resilience

Build comprehensive error handling into your code execution patterns:

// Robust error handling example
async function robustDataProcessing() {
  try {
    const data = await externalService.getData({ timeout: 30000 });
    
    // Process data with validation
    const validRecords = data.filter(record => 
      record.id && record.email && isValidEmail(record.email)
    );
    
    if (validRecords.length === 0) {
      throw new Error("No valid records found in dataset");
    }
    
    const processed = await processRecords(validRecords);
    
    // Implement retry logic for external calls
    let success = false;
    let retries = 0;
    const maxRetries = 3;
    
    while (!success && retries < maxRetries) {
      try {
        await api.sendProcessedData(processed);
        success = true;
      } catch (apiError) {
        retries++;
        if (retries >= maxRetries) throw apiError;
        await new Promise(r => setTimeout(r, 2000 * retries)); // Exponential backoff
      }
    }
    
    return { success: true, processedCount: processed.length };
    
  } catch (error) {
    console.error("Data processing failed:", error.message);
    
    // Classify errors and handle appropriately
    if (error.code === 'RATE_LIMITED') {
      await notifyRateLimitIssue();
      return { success: false, error: 'rate_limit', retryAfter: error.retryAfter };
    } else if (error.code === 'AUTH_ERROR') {
      await refreshAuthentication();
      return { success: false, error: 'auth_error', requiresReauth: true };
    } else {
      return { success: false, error: 'processing_failed', message: error.message };
    }
  }
}

Performance Monitoring and Optimization

Implement monitoring to track the efficiency gains from code execution:

  • Token Usage Metrics: Compare token consumption before and after implementation
  • Execution Time Tracking: Monitor end-to-end task completion times
  • Error Rate Monitoring: Track success rates for code execution tasks
  • Resource Utilization: Monitor CPU, memory, and network usage in execution environments

Future Outlook and Community Impact

The adoption of code execution with MCP represents a significant evolution in how we design and implement AI agents. While many of the challenges addressed—context management, tool composition, state persistence—feel novel in the AI space, they have well-established solutions from decades of software engineering practice.

Code execution effectively applies these proven patterns to AI agents, enabling them to use familiar programming constructs to interact more efficiently with MCP servers. This approach bridges the gap between traditional software engineering and modern AI capabilities, creating more robust and efficient agent systems.

The MCP community continues to grow and evolve, with developers sharing implementations, best practices, and new servers. This collaborative ecosystem accelerates innovation and helps organizations avoid duplicating effort while building their AI agent capabilities.

Conclusion

The Model Context Protocol provides a foundational standard for connecting AI agents to diverse tools and data sources. However, as the number of connected systems grows, traditional approaches to tool integration can lead to inefficient token usage and performance degradation.

Code execution with MCP offers a powerful solution to these challenges, enabling agents to work more efficiently with large numbers of tools while significantly reducing token consumption and operational costs. By presenting tools as code APIs rather than direct tool calls, organizations can achieve dramatic efficiency improvements—often reducing token usage by over 98% while maintaining or even enhancing functional capabilities.

The benefits extend beyond mere efficiency gains. Code execution enables more natural control flow, enhanced privacy protection, state persistence across operations, and the development of reusable skills that compound in value over time.

While implementing code execution requires careful attention to security, sandboxing, and monitoring, the substantial benefits in reduced costs, lower latency, and improved tool composition make this approach worthwhile for organizations building sophisticated AI agent systems.

As AI agents become increasingly integral to business operations, adopting efficient patterns like code execution with MCP will be essential for building scalable, cost-effective, and powerful AI solutions that deliver real business value.

Exit mobile version