$ desarrollomcp
Volver al blog
Avanzado

Code Mode y Ejecución Programática: El Futuro de MCP en Producción

Por DesarrolloMCP
|
#mcp #cloudflare #workers #typescript #python #anthropic #code-execution

Introducción

Dos innovaciones recientes están transformando cómo construimos agentes de IA con MCP: Cloudflare Code Mode y las técnicas avanzadas de tool use de Anthropic. Ambas comparten una premisa fundamental: los LLMs son excepcionales escribiendo código, pero limitados usando herramientas directamente.

En este artículo exploramos ambos enfoques, sus ventajas, y cómo implementarlos para construir agentes más eficientes y precisos en producción.

El problema fundamental

Por qué fallan las herramientas tradicionales

Los LLMs actuales enfrentan tres limitaciones críticas con tool-calling directo:

1. Sobrecarga de definiciones

Cargar todas las herramientas simultáneamente consume el contexto antes de hacer trabajo real:

// Problema: 100 herramientas = 72,000 tokens
const tools = await mcpClient.listTools();
// ¡95% del contexto usado antes de empezar!

Impacto: En un modelo con 200k de contexto, solo quedan ~10k tokens para trabajo real.

2. Procesado redundante de resultados intermedios

Cada llamada de herramienta requiere un nuevo pase de inferencia:

// 20 llamadas = 20 ciclos de inferencia
const data1 = await tool1(); // Pase 1
const data2 = await tool2(data1); // Pase 2
// ... 18 pases más
const final = await tool20(data19); // Pase 20

Impacto: Latencia multiplicada y tokens procesados innecesariamente.

3. Falta de experiencia de entrenamiento

Como señala Cloudflare: “Los LLMs han visto mucho código. No han visto muchas ‘llamadas de herramientas’.”

Los modelos tienen millones de ejemplos de código Python/TypeScript, pero pocos ejemplos reales de orquestar herramientas complejas.

Solución 1: Cloudflare Code Mode

Concepto: TypeScript en el Edge

Code Mode convierte servidores MCP en APIs de TypeScript ejecutables en V8 isolates de Cloudflare Workers.

// El modelo genera código TypeScript
import { getDocument } from "./servers/google-drive";
import { updateRecord } from "./servers/salesforce";

const doc = await getDocument({ documentId: "abc123" });
const actionItems = doc.content
  .split('\n')
  .filter(line => line.includes('ACCIÓN:'))
  .join('\n');

await updateRecord({
  objectType: "Meeting",
  recordId: "xyz789",
  data: { notes: actionItems }
});

Arquitectura técnica

1. Conversión automática de schemas

Los schemas MCP se transforman en TypeScript con documentación:

// Schema MCP
{
  "name": "getDocument",
  "inputSchema": {
    "properties": {
      "documentId": { "type": "string" }
    }
  }
}

// Se convierte en:
export async function getDocument(args: {
  documentId: string;
}): Promise<DocumentResult> {
  // Implementación...
}

2. Worker Loader API

Nueva API de Cloudflare para cargar código dinámicamente:

const worker = await env.CODE_MODE.createWorker({
  code: generatedCode,
  bindings: {
    gdrive: env.GDRIVE_BINDING,
    salesforce: env.SALESFORCE_BINDING
  },
  limits: {
    cpuMs: 10000,
    memoryMb: 128
  }
});

const result = await worker.execute();

Ventajas:

  • Inicio en milisegundos (V8 isolates vs containers)
  • Aislamiento completo de seguridad
  • Escalado global automático

3. Sistema de bindings seguros

Servidores MCP expuestos como bindings JavaScript:

// El código ve APIs seguras
const gdrive = {
  getDocument: async (args) => { /* seguro */ }
};

// NO puede hacer:
fetch("https://evil.com"); // ❌ Bloqueado
process.env.API_KEY;       // ❌ Aislado
require("fs");             // ❌ No disponible

Implementación práctica

Configuración en wrangler.toml

name = "my-code-mode-agent"
main = "src/index.ts"
compatibility_date = "2025-11-25"

[code_mode]
enabled = true

[[code_mode.mcp_servers]]
name = "gdrive"
type = "mcp"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-gdrive"]

[code_mode.limits]
cpu_ms = 10000
memory_mb = 128

Worker completo

// src/index.ts
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const { prompt } = await request.json();

    // 1. Generar código con Claude
    const code = await generateTypeScript(prompt, env);

    // 2. Ejecutar en sandbox
    const worker = await env.CODE_MODE.createWorker({
      code,
      bindings: {
        gdrive: env.GDRIVE_BINDING,
        salesforce: env.SALESFORCE_BINDING
      }
    });

    // 3. Obtener resultado
    const result = await worker.execute();
    return Response.json(result);
  }
};

Solución 2: Programmatic Tool Calling de Anthropic

Concepto: Python orchestration

Anthropic permite que Claude escriba código Python que orquesta herramientas:

# Claude genera este código Python
import tools

# Obtener documento
doc = tools.google_drive.get_document(document_id="abc123")

# Procesar localmente (no pasa por el modelo)
action_items = [
    line.replace("ACCIÓN:", "").strip()
    for line in doc.content.split('\n')
    if "ACCIÓN:" in line
]

# Actualizar Salesforce
tools.salesforce.update_record(
    object_type="Meeting",
    record_id="xyz789",
    data={"notes": "\n".join(action_items)}
)

Tres técnicas complementarias

1. Tool Search Tool

Descubre herramientas bajo demanda en lugar de cargar todas:

# Antes: Cargar 100 herramientas = 72k tokens
all_tools = load_all_tools()

# Ahora: Buscar solo lo necesario = 8.7k tokens
relevant_tools = search_tools(query="google drive document")
# Encuentra solo: get_document, list_files, share_document

Reducción: 85% menos tokens (72k → 8.7k)

2. Programmatic Tool Calling

Orquesta múltiples llamadas en un solo bloque de código:

# 20 llamadas en un solo pase de inferencia
results = []
for item in items[:20]:
    data = tools.process(item)
    results.append(data)

# Sin esto: 20 pases de inferencia
# Con esto: 1 pase de inferencia

Reducción: Elimina 19 ciclos de inferencia en este caso

3. Tool Use Examples

Proporciona ejemplos concretos en las definiciones:

{
  "name": "update_record",
  "description": "Actualiza un registro en Salesforce",
  "examples": [
    {
      "input": {
        "object_type": "Contact",
        "record_id": "003xx000004TmiQAAS",
        "data": {"Email": "[email protected]"}
      },
      "description": "Actualizar email de contacto"
    }
  ]
}

Mejora: Precisión de 72% → 90% en parámetros complejos

Implementación con Claude

Configuración básica

import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    max_tokens=4096,
    tools=[
        {
            "type": "function",
            "function": {
                "name": "get_document",
                "description": "Obtiene documento de Google Drive",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "document_id": {"type": "string"}
                    }
                }
            }
        }
    ],
    # 🔥 Activar programmatic tool calling
    tool_choice={"type": "programmatic"}
)

Ejecutar código generado

# Claude devuelve código Python en response.content
generated_code = response.content[0].text

# Ejecutar en sandbox
from RestrictedPython import compile_restricted

compiled = compile_restricted(generated_code, '<string>', 'exec')
sandbox = {
    'tools': {
        'gdrive': gdrive_client,
        'salesforce': salesforce_client
    }
}

exec(compiled, sandbox)
result = sandbox.get('result')

Comparación de enfoques

AspectoCloudflare Code ModeAnthropic Programmatic
LenguajeTypeScriptPython
EjecuciónV8 isolates (edge)Sandbox local/servidor
EscaladoGlobal automáticoManual
LatenciaUltra-baja (edge)Depende de ubicación
SeguridadBindings + isolatesRestrictedPython
InicioMilisegundosVariable
Mejor paraProducción edgeDesarrollo rápido

Resultados de eficiencia

Caso de estudio real

Tarea: Extraer insights de 20 documentos y actualizar CRM

Enfoque tradicional (tool calling directo)

1. Cargar 100 herramientas: 72k tokens
2. Por cada documento:
   - Llamar get_document: 50k tokens
   - Procesar en modelo: 50k tokens
   - Actualizar CRM: +tokens
3. Total: ~72k + (20 × 100k) = 2,072k tokens

Con Code Mode / Programmatic

// Código generado: ~500 tokens
for (const docId of documentIds) {
  const doc = await gdrive.getDocument({ id: docId });

  // Procesar localmente (0 tokens)
  const insights = extractInsights(doc.content);

  await crm.update({ id: docId, insights });
}
// Total: ~500 tokens generación + ~1k resultado = 1.5k tokens

Reducción: 99.9% (2,072k → 1.5k tokens)

Benchmarks oficiales

Cloudflare Code Mode:

  • Reducción de tokens: 95-98%
  • Latencia: 70% más rápido (edge execution)
  • Costo: 97% menor

Anthropic Programmatic:

  • Reducción de tokens: 37% en promedio
  • Precisión: +18 puntos (72% → 90%)
  • Latencia: 19+ pases de inferencia eliminados

Implementación híbrida recomendada

Combinar ambos enfoques

// Worker de Cloudflare con Claude Programmatic
export default {
  async fetch(request: Request, env: Env) {
    const { task } = await request.json();

    // 1. Usar Tool Search para encontrar herramientas
    const relevantTools = await searchTools(task);

    // 2. Claude genera código TypeScript
    const code = await claude.generateCode({
      task,
      tools: relevantTools,
      examples: getExamples(relevantTools)
    });

    // 3. Ejecutar en Code Mode
    const worker = await env.CODE_MODE.createWorker({
      code,
      bindings: createBindings(relevantTools)
    });

    return Response.json(await worker.execute());
  }
};

Beneficios combinados

  1. Tool Search: Solo carga herramientas relevantes (85% menos tokens)
  2. Code Generation: Orquestación eficiente (elimina pases intermedios)
  3. Examples: Uso correcto de herramientas (90% precisión)
  4. Code Mode: Ejecución edge segura (latencia ultra-baja)

Resultado: 99%+ reducción de tokens, 90%+ precisión, latencia edge global

Casos de uso ideales

1. Procesamiento masivo de documentos

// Procesar 100 documentos eficientemente
const results = await Promise.all(
  documentIds.map(async (id) => {
    const doc = await gdrive.getDocument({ id });
    return {
      id,
      summary: doc.content.slice(0, 200),
      actionItems: extractActions(doc.content),
      wordCount: doc.content.split(' ').length
    };
  })
);

// Solo devuelve metadata agregada al modelo
return {
  totalDocs: results.length,
  totalActions: results.reduce((sum, r) => sum + r.actionItems.length, 0),
  avgWords: results.reduce((sum, r) => sum + r.wordCount, 0) / results.length
};

2. Integración multi-API compleja

// Combinar datos de 5 APIs diferentes
const [sales, inventory, orders, customers, analytics] = await Promise.all([
  salesforce.query('SELECT * FROM Sales WHERE Date = TODAY'),
  erp.getInventory({ warehouse: 'main' }),
  shopify.getOrders({ status: 'pending' }),
  crm.getCustomers({ tier: 'premium' }),
  analytics.getMetrics({ range: 'today' })
]);

// Procesar todo localmente
const insights = {
  lowStock: inventory.filter(i => i.quantity < 10).length,
  pendingValue: orders.reduce((sum, o) => sum + o.total, 0),
  topCustomer: customers.sort((a, b) => b.ltv - a.ltv)[0].name,
  conversionRate: analytics.visitors > 0
    ? (sales.length / analytics.visitors * 100).toFixed(2)
    : 0
};

return insights; // Solo 200 bytes vs 500kb de datos raw

3. Pipelines de transformación de datos

# Pipeline complejo de datos
import tools

# Obtener datos raw
raw_data = tools.database.query("""
  SELECT * FROM transactions
  WHERE date >= DATE_SUB(NOW(), INTERVAL 30 DAY)
""")

# Transformar localmente (sin pasar por modelo)
processed = []
for row in raw_data:
    if row['amount'] > 1000:
        processed.append({
            'date': row['date'].isoformat(),
            'amount': row['amount'],
            'category': categorize(row['description']),
            'risk_score': calculate_risk(row)
        })

# Agregar
summary = {
    'total_high_value': len(processed),
    'total_amount': sum(r['amount'] for r in processed),
    'avg_risk': sum(r['risk_score'] for r in processed) / len(processed),
    'high_risk_count': len([r for r in processed if r['risk_score'] > 0.7])
}

tools.slack.send_message(
    channel='#finance',
    text=f"High-value transactions summary: {summary}"
)

Seguridad en producción

1. Validación de código generado

import { parse } from "@typescript-eslint/parser";

function validateCode(code: string): boolean {
  // Lista negra de patrones peligrosos
  const forbidden = [
    /process\.env/,
    /require\(['"]fs['"]\)/,
    /import.*['"]http['"]/,
    /eval\(/,
    /Function\(/,
    /fetch\(/
  ];

  for (const pattern of forbidden) {
    if (pattern.test(code)) {
      throw new Error(`Código prohibido: ${pattern}`);
    }
  }

  // Validar sintaxis
  try {
    parse(code);
    return true;
  } catch (error) {
    throw new Error(`Sintaxis inválida: ${error.message}`);
  }
}

2. Límites de recursos

const LIMITS = {
  // CPU
  cpuMs: 10000, // 10 segundos máximo

  // Memoria
  memoryMb: 128,

  // Red
  maxMcpCalls: 50,
  maxConcurrentCalls: 10,

  // Tiempo total
  totalTimeoutMs: 30000,

  // Tamaño de datos
  maxResponseBytes: 10 * 1024 * 1024 // 10MB
};

3. Auditoría completa

interface ExecutionLog {
  timestamp: number;
  userId: string;
  prompt: string;
  generatedCode: string;
  executionTime: number;
  tokensUsed: number;
  mcpCallsMade: number;
  success: boolean;
  errors?: string[];
}

async function logExecution(log: ExecutionLog) {
  await auditDB.insert('executions', {
    ...log,
    codeHash: hash(log.generatedCode),
    promptHash: hash(log.prompt)
  });

  // Alertas para patrones sospechosos
  if (log.mcpCallsMade > 100) {
    await alert.send(`Unusual activity: ${log.mcpCallsMade} calls`);
  }
}

4. Rate limiting por usuario

class RateLimiter {
  async check(userId: string): Promise<void> {
    const key = `ratelimit:${userId}`;
    const current = await redis.incr(key);

    if (current === 1) {
      await redis.expire(key, 60); // 1 minuto
    }

    if (current > 100) {
      throw new Error('Rate limit exceeded');
    }
  }
}

Mejores prácticas

1. Descubrimiento progresivo

// No cargar todas las herramientas
const tools = await loadAllTools(); // 72k tokens

// Buscar solo lo necesario
const tools = await searchTools(userQuery); // 8.7k tokens

2. Procesamiento local de datos

// No devolver datos raw al modelo
return await gdrive.getDocument({ id }); // 50k tokens

// Procesar y resumir localmente
const doc = await gdrive.getDocument({ id });
   return {
     title: doc.metadata.title,
     summary: doc.content.slice(0, 200),
     actionCount: (doc.content.match(/ACCIÓN:/g) || []).length
   }; // ~100 tokens

3. Usar ejemplos en definiciones

const tools = [{
  name: "update_record",
  description: "Actualiza registro en Salesforce",
  // ✅ Incluir ejemplos concretos
  examples: [{
    input: {
      objectType: "Contact",
      recordId: "003xx000004TmiQ",
      data: { Email: "[email protected]" }
    },
    description: "Actualizar email de un contacto"
  }],
  parameters: { /* schema */ }
}];

4. Orquestar en paralelo

// ❌ Secuencial: 5 pases de inferencia
const a = await tool1();
const b = await tool2();
const c = await tool3();

// ✅ Paralelo: 1 pase de inferencia
const [a, b, c] = await Promise.all([
  tool1(),
  tool2(),
  tool3()
]);

Conclusión

Code Mode de Cloudflare y Programmatic Tool Calling de Anthropic representan el futuro de agentes de IA en producción:

Ventajas clave:

  • Eficiencia extrema: 95-99% reducción en tokens
  • Mejor rendimiento: Los LLMs escriben código mejor que usan herramientas
  • Mayor precisión: 90%+ con ejemplos y código estructurado
  • Seguridad robusta: Sandboxing con isolates o RestrictedPython
  • Escalabilidad: Edge computing global con Cloudflare

Cuándo usar estos enfoques:

  • ✅ Procesamiento de grandes volúmenes de datos
  • ✅ Integración con múltiples APIs (5+)
  • ✅ Pipelines de transformación complejos
  • ✅ Requisitos estrictos de eficiencia/costo
  • ✅ Aplicaciones en producción a escala

Cuándo usar tool calling tradicional:

  • ✅ Tareas simples con 2-3 herramientas
  • ✅ Prototipos rápidos
  • ✅ Casos donde seguridad de sandbox no es crítica
  • ✅ Latencia no es factor limitante

La combinación de ambas técnicas (Tool Search + Programmatic + Code Mode) ofrece lo mejor de ambos mundos: máxima eficiencia, precisión superior y ejecución edge global.

Con estas herramientas, construir agentes de IA que operan eficientemente en producción a escala ya no es un desafío técnico, sino una realidad alcanzable.


Post anterior: Ejecución de Código con MCP

Recursos: