En un turno de agente típico, el modelo puede invocar la misma tool varias veces seguidas para construir un resumen, comparar, o verificar antes de actuar:
list_inventory_items()add_inventory()list_inventory_items() (otra vez)Si tu tool toca una API externa, una DB lenta, o un servicio con rate limit, esa triple call te cuesta plata, latencia y a veces te tira el rate limiter encima.
La solución es un patrón viejo y conocido: cache con TTL. La novedad cuando lo aplicás a tools de un agente:
cached: true para diagnóstico.✓ Tools de lectura (idempotentes naturales). get_X, list_X, lookup_X.
✓ Tools cuyos datos cambian lento. Configuración, catálogos, datos de referencia.
✓ Tools caras (latencia alta o costo por call).
✗ Tools de escritura. Cada call hace algo distinto. No tiene sentido.
✗ Tools cuyos datos cambian rápido. Si tu TTL es más largo que la frecuencia de cambio real, devolvés datos viejos como si fueran nuevos.
✗ Tools con resultados dependientes del usuario sin separar la key. Si cacheás get_my_bookings() con key "default", todos los usuarios ven los bookings del primero. La key del cache tiene que incluir el contexto que distingue.
const cache = new Map(); // key → { data, fetchedAt }
const TTL_MS = 60_000;
async function handle({ deck }) {
const key = deck;
const cached = cache.get(key);
if (cached && Date.now() - cached.fetchedAt < TTL_MS) {
return { ok: true, data: cached.data, cached: true };
}
const data = await atmosphericApi.read(deck);
cache.set(key, { data, fetchedAt: Date.now() });
return { ok: true, data, cached: false };
}cached: true también es informaciónDevolver el flag cached: true cuando hay hit le permite al agente decisiones interesantes:
A la derecha tenés get_weather sin cache. Agregalo: cache in-memory con TTL de 60s, key por deck, flag cached.
Cachear bien es de las optimizaciones más baratas y de mayor impacto en MCPs reales. Una hora de trabajo, una orden de magnitud menos en costo de API.