El problema
Un servidor MCP interno pasa de 6 a 40 herramientas en tres meses. Cada nueva herramienta se añadió siguiendo el mismo patrón inicial: una descripción de una sola línea, expuesta directamente en el catálogo global que Claude recibe al inicio de cada sesión. El contexto se sobrecargó, la precisión en la selección de herramientas se degradó (el modelo confunde update_invoice con update_invoice_line_item con frecuencia) y, cuando una ejecución falla, el error devuelto es la excepción cruda de Python con todo el stack trace. El agente reintenta a ciegas. Falla nuevamente. Reintenta una tercera vez. Tres turnos después, el error persiste — porque la causa era una credencial vencida, no una inestabilidad temporal de red, y ningún número de reintentos podría haberlo solucionado.
Aquí se mezclan dos retos arquitectónicos distintos: cómo se expone el catálogo de herramientas y cómo se comunican los errores de ejecución al modelo. Resolver solo uno de ellos deja al sistema expuesto al otro.
Los errores son respuestas estructuradas, no obstáculos
Un error de herramienta mal diseñado devuelve texto libre — un mensaje pensado para un humano que lee logs, no para un modelo que debe decidir la siguiente acción de control de flujo. Un error bien diseñado es un contrato estructurado con al menos tres campos esenciales: el tipo de error, si es seguro reintentar (retryable) y una instrucción clara de recuperación.
{
"error_type": "rate_limited",
"retryable": true,
"guidance": "Espere e intente nuevamente con retroceso exponencial (backoff)."
}
frente a
{
"error_type": "invalid_credentials",
"retryable": false,
"guidance": "Escale a un operador humano — la credencial configurada no es válida."
}
La diferencia fundamental no es el tono, sino la acción correcta. rate_limited es una condición transitoria — el bucle debe esperar y reintentar. invalid_credentials es un fallo terminal hasta que alguien actualice el secreto — insistir solo desperdicia presupuesto de tokens y tiempo mientras el problema de fondo sigue sin resolverse. El distractor clásico en los escenarios de examen es prescribir "añadir más reintentos" como solución universal ante cualquier fallo — una estrategia que funciona para errores transitorios pero enmascara peligrosamente los fallos terminales.
Esta taxonomía se generaliza a cualquier sistema: fallos que se resuelven solos con el tiempo (rate limits, timeouts de red, indisponibilidad momentánea) frente a fallos que requieren intervención (autenticación inválida, permisos denegados, violaciones de reglas de negocio). Un arnés maduro enruta ambas categorías por ramas claramente diferenciadas.
Descubrimiento progresivo: deja de volcar el catálogo completo
El segundo problema — 40 herramientas compitiendo por atención en cada turno — exige una solución estructural, no ajustes de redacción en prompts. En lugar de enumerar todas las herramientas en cada mensaje, expón una herramienta de búsqueda (search_tools(query)) o un recurso de catálogo por categorías, permitiendo que Claude cargue la definición completa únicamente de las herramientas relevantes para la subtarea activa. Esto es el descubrimiento progresivo: las capacidades existen, pero el contexto no está obligado a cargarlas todas simultáneamente.
El mismo principio aplica a esquemas voluminosos de bases de datos y especificaciones de API: pertenecen a recursos MCP que se consultan bajo demanda, no a texto estático incrustado en cada llamada a herramientas. Si una herramienta SQL necesita el esquema de 30 tablas para operar, el esquema es un recurso recuperado cuando es necesario — no un bloque de 2.000 tokens repetido en cada system prompt.
La pregunta arquitectónica central: ¿qué debe estar en el contexto inmediato ahora y qué solo necesita estar accesible bajo demanda? El catálogo de herramientas pertenece a la segunda categoría. El error recién ocurrido pertenece a la primera — y debe llegar estructurado para que el modelo tome decisiones correctas, no solo reacciones a ciegas.
Ponlo en práctica
En el laboratorio de esta lección recibirás excepciones crudas de un servicio externo simulado y deberás transformarlas en contratos de error estructurados (error_type, retryable, guidance), decidiendo caso por caso si la respuesta adecuada es reintentar con backoff o escalar inmediatamente a un operador humano.