Cap 8: Errores Estructurados y tool_choice

Por: Artiko
claude-certifiederrorstool-choicemcprecovery

MCP isError Flag

Cuando un MCP tool falla, debe comunicar el fallo usando el flag isError: true en la respuesta. Esto le indica al agente que la operación no fue exitosa y debe tomar una decisión de recovery.

{
  "content": [
    {
      "type": "text",
      "text": "Customer not found: ID 'cust_999' does not exist in the active customer database."
    }
  ],
  "isError": true
}

Sin isError, el agente puede interpretar un mensaje de error como un resultado válido y continuar el flujo incorrectamente.

Categorías de errores

No todos los errores son iguales. Clasificarlos permite al agente tomar decisiones de recovery apropiadas:

Transient (reintentar)

Fallos temporales que pueden resolverse con un retry:

Validation (corregir input)

El input proporcionado no cumple los requisitos:

Business (regla de negocio)

La operación viola una política o regla del dominio:

Permission (acceso denegado)

El caller no tiene permisos para la operación:

El problema de errores uniformes

Cuando todos los errores retornan el mismo formato genérico:

{
  "content": [{ "type": "text", "text": "Operation failed" }],
  "isError": true
}

El agente no puede decidir si debe reintentar, corregir el input, informar al usuario, o escalar. Esto causa loops de retry infinitos o abandonos prematuros.

Structured Error Metadata

Incluye metadata estructurada que permita al agente tomar decisiones:

{
  "content": [
    {
      "type": "text",
      "text": "Cannot apply 50% discount. Maximum allowed discount is 30% per company policy."
    }
  ],
  "isError": true,
  "_meta": {
    "errorCategory": "business",
    "isRetryable": false,
    "errorCode": "DISCOUNT_LIMIT_EXCEEDED",
    "maxAllowed": 30,
    "requested": 50
  }
}

Campos recomendados

CampoTipoPropósito
errorCategorystringtransient, validation, business, permission
isRetryableboolean¿Tiene sentido reintentar?
errorCodestringCódigo máquina-legible para lógica condicional
descriptionstringExplicación human-readable para el usuario

Business rules: retriable false + explicación

Para errores de reglas de negocio, siempre marca isRetryable: false e incluye una explicación que el agente pueda transmitir al usuario:

{
  "isError": true,
  "_meta": {
    "errorCategory": "business",
    "isRetryable": false,
    "description": "Las reservaciones deben hacerse con al menos 24 horas de anticipación."
  }
}

El agente sabe que no debe reintentar y tiene un mensaje claro para el usuario.

Recovery patterns

Local recovery en subagentes

Cada subagente debe manejar sus propios errores transient y de validación localmente:

Subagente de búsqueda:
  1. Intenta search_products(query)
  2. Si timeout → retry con backoff (hasta 3 intentos)
  3. Si validation error → corregir query y reintentar
  4. Si business/permission error → propagar al coordinator

Propagar solo errores irresolubles al agente coordinador. No escales timeouts que se pueden resolver con un retry.

Distinguir access failures de empty results

Dos situaciones muy diferentes:

// Access failure — algo salió mal, reintentar
{
  "isError": true,
  "_meta": { "errorCategory": "transient", "isRetryable": true }
}

// Valid empty result — la búsqueda funcionó, no hay matches
{
  "content": [{ "type": "text", "text": "No results found for query 'xyz'" }],
  "isError": false,
  "_meta": { "resultCount": 0 }
}

Un isError: false con 0 resultados no es un error — es una respuesta válida que el agente debe aceptar sin reintentar.

tool_choice: controlando la selección

El parámetro tool_choice en la API controla cómo Claude selecciona tools:

auto (default)

Claude decide libremente si usar un tool o responder con texto:

{ "tool_choice": { "type": "auto" } }

Apropiado para: la mayoría de conversaciones donde el modelo debe decidir cuándo es relevante usar herramientas.

any (forzar alguna herramienta)

Claude debe usar algún tool — no puede responder solo con texto:

{ "tool_choice": { "type": "any" } }

Apropiado para: pasos de un pipeline donde siempre se necesita una acción.

Forced (tool específico)

Claude debe usar un tool particular:

{ "tool_choice": { "type": "tool", "name": "search_database" } }

Apropiado para: pasos predeterminados donde sabemos exactamente qué tool se necesita.

Límites de tools por agente

El problema de demasiados tools

La calidad de selección se degrada conforme aumenta el número de tools disponibles:

Tools disponiblesCalidad de selección
4-5Excelente — selección precisa
8-10Buena — errores ocasionales
15+Degradada — misrouting frecuente

Scoped tool access

En lugar de dar 18 tools a un solo agente, distribuye por rol:

Agente de búsqueda: search_products, filter_results, sort_results, get_details
Agente de compra: create_order, apply_discount, process_payment, send_confirmation
Agente de soporte: get_ticket, update_status, search_knowledge_base, escalate

Cada agente tiene 4-5 tools de su dominio + acceso limitado a tools cross-role de alta frecuencia (ej: todos pueden usar get_customer_info).

Regla práctica

Si un agente tiene más de 5-6 tools, pregúntate si debería ser dos agentes.


← Cap 7: MCP Servers · Índice · Cap 9: CLAUDE.md Jerarquía →