El Model Context Protocol (MCP) ya es el estándar para conectar agentes a herramientas y datos. ¿Por qué importa esto? Porque conectar agentes a cada sistema con integraciones custom crea fragmentación, trabajo duplicado y límites claros de escalabilidad. MCP busca resolver eso: implementas el protocolo una sola vez en el agente y desbloqueas todo un ecosistema de integraciones.
Desde su lanzamiento en noviembre de 2024, la adopción fue rápida: miles de servidores MCP, SDKs para los principales lenguajes y la industria tomando MCP como estándar. Pero con escala viene un problema práctico: entre definiciones de herramientas y resultados intermedios, el contexto de los modelos se infla, la latencia sube y los costos se disparan. ¿La solución? Usar ejecución de código como interfaz contra servidores MCP.
¿Por qué los agentes consumen tantos tokens?
Hay dos patrones comunes que hacen que los agentes sean ineficientes en costos y tiempo:
- Las definiciones de herramientas saturan la ventana de contexto.
- Los resultados intermedios de las herramientas pasan por el modelo y duplican tokens.
¿Te suena familiar? Si conectas cientos o miles de herramientas, cargar todas sus definiciones en la prompt hace que el modelo tenga que procesar cientos de miles de tokens antes de comenzar la tarea real.
Ejemplo típico de tool definition:
gdrive.getDocument Description: Retrieves a document from Google Drive Parameters:
- documentId (required, string)
- fields (optional, string) Returns: Document object with title, body content, metadata
Con miles de entradas así, el coste se acumula rápido. Y cuando el agente llama a una herramienta y el resultado (por ejemplo, una transcripción de 2 horas) vuelve al modelo, ese texto puede fluir dos veces por el contexto: al leerlo y al volver a insertarlo para una segunda llamada. Eso puede significar 50,000 tokens extras o más, o incluso exceder la ventana de contexto y romper el flujo.
Ejecución de código: qué es y cómo ayuda
La idea central es sencilla: presenta los servidores MCP como APIs de código en un entorno de ejecución. En vez de inyectar todas las definiciones al prompt, el agente escribe y ejecuta código que llama a las herramientas. Así solo cargas lo que necesitas y procesas datos antes de mostrárselos al modelo.
Una implementación común es generar un árbol de archivos con las herramientas disponibles. Por ejemplo, en TypeScript:
servers
├── google-drive
│ ├── getDocument.ts
│ └── index.ts
├── salesforce
│ ├── updateRecord.ts
│ └── index.ts
└── ...
Cada herramienta corresponde a un archivo:
// ./servers/google-drive/getDocument.ts
import { callMCPTool } from "../../../client.js";
interface GetDocumentInput { documentId: string }
interface GetDocumentResponse { content: string }
export async function getDocument(input: GetDocumentInput): Promise<GetDocumentResponse> {
return callMCPTool<GetDocumentResponse>('google_drive__get_document', input);
}
Y el flujo del agente que antes pasaba por el modelo se convierte en código que corre en la ejecución:
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 }
});
Con este patrón, el agente descubre herramientas listando el directorio ./servers/ y abre solo los archivos que necesita. En un caso real citado por Anthropic, esto redujo el uso de 150,000 tokens a 2,000 tokens, un ahorro de 98.7%.
Cloudflare llamó a esto "Code Mode" y el punto clave es claro: los LLMs escriben código muy bien; hay que aprovecharlo.
Beneficios prácticos
-
Progressive disclosure: el modelo lee definiciones bajo demanda. Puedes añadir un
search_toolsque devuelva solo nombre, descripción o la definición completa según un parámetrodetail_level. -
Resultados eficientes: en vez de pasar 10,000 filas al modelo, filtras y agregas en el entorno de ejecución y devuelves solo lo necesario.
Ejemplo de filtrado de hojas:
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)); // solo verás 5 filas
- Control de flujo más poderoso: loops, condicionales y reintentos quedan en código en vez de hacer round-trips con el modelo. Esto baja la latencia y el tiempo hasta el primer token.
Ejemplo de polling en Slack:
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');
- Privacidad y tokenización: los resultados intermedios pueden quedarse en el runtime. El cliente MCP puede tokenizar PII antes de que llegue al modelo y des-tokenizar solo cuando sea necesario en la llamada de destino. Eso permite flujos de datos donde emails, teléfonos o nombres nunca pasan por el prompt en texto plano.
Ejemplo de import de contactos con tokenización:
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 }
});
}
El runtime tokeniza row.email y row.phone antes de exponerlos al modelo. Cuando el cliente hace la llamada a Salesforce, se des-tokenizan localmente.
- Persistencia y skills: el sistema de archivos permite guardar resultados intermedios y funciones reutilizables. Un agente puede escribir una función, guardarla en
./skillsy volver a usarla en ejecuciones futuras, construyendo una caja de herramientas especializada.
Riesgos y requisitos operativos
La ejecución de código no es gratis en términos operativos. Requiere:
- Entornos de ejecución seguros y sandboxing.
- Límites de recursos y monitoreo para evitar abusos o loops infinitos.
- Políticas de seguridad y revisión de código generado por agentes.
Estos requisitos suman complejidad adicional frente a llamadas directas a herramientas, pero son el precio por reducir tokens, latencia y mejorar composición de herramientas.
Recomendaciones prácticas para implementarlo
- Empieza exponiendo herramientas como archivos de una estructura de servidores y prueba con cargas pequeñas.
- Implementa un
search_tools(detail_level)para que el agente descubra solo lo que necesita. - Añade tokenización automática de PII en el cliente MCP.
- Pon límites en tiempo de ejecución y memoria, y registra las llamadas para auditoría.
- Transforma scripts repetidos en
./skillsconSKILL.mdpara que el modelo aprenda a reutilizarlos.
Si trabajas en startups o en equipos producto, este patrón te permite escalar agentes conectados a muchas APIs sin que el costo por token te arruine la viabilidad del proyecto. Yo he visto equipos convertir integraciones fragmentadas en plataformas coherentes aplicando estas ideas: menos tokens, menos latencia, más resiliencia.
La ejecución de código con MCP aplica patrones clásicos de ingeniería de software al mundo de los agentes: modularidad, abstracción, y separación de responsabilidades. Es una forma práctica y comprobada de hacer que los agentes trabajen con muchos sistemas sin sobrecargar el modelo.
Fuente original
https://www.anthropic.com/engineering/code-execution-with-mcp
