PTENES
MÓDULO 3.8

⚠️ Manejo de errores

Aprende a gestionar fallas de forma elegante: validación, try/except, timeouts y logging.

6
Temas
25
Minutos
Intermedio
Nivel
Práctico
Tipo
1

⚠️ Tipos de errores en MCP

Los Servers MCP están sujetos a diversos tipos de fallas. Comprender cada categoría de error es el primer paso para tratarlos adecuadamente. Un buen server no es aquel que nunca falla, sino aquel que falla de forma predecible, informativa y recuperable.

💎 Concepto principal

Los errores en un server MCP se dividen en cuatro categorías principales: errores de entrada (parámetros inválidos, tipos incorrectos, valores fuera del rango esperado); errores de ejecución (errores en el código, división entre cero, clave inexistente en un diccionario); errores de red (API externa fuera de servicio, timeout de conexión, DNS no resuelto); y errores de permisos (acceso denegado a un archivo, token vencido, credenciales no válidas). Cada tipo requiere una estrategia de manejo diferente.

📊 Datos e investigación

Los estudios de ingeniería de software muestran que más del 60% de los incidentes en producción se deben a un manejo inadecuado de errores, no a los errores en sí. En servers MCP, esto es aún más crítico porque el modelo de IA depende de mensajes de error claros para informar al usuario sobre lo ocurrido y sugerir los siguientes pasos. Un stack trace sin procesar no ayuda a nadie.

📋 Categorías de errores
Errores de entrada

Parámetros no válidos, tipos incorrectos, valores fuera del rango. Se pueden detectar antes de ejecutar la lógica principal. Se previenen con validación.

Errores de ejecución

Errores en el código, KeyError, IndexError y división por cero. Ocurren durante el procesamiento. Se previenen con try/except y pruebas.

Errores de red

API fuera de servicio, timeout, DNS no resuelto. Son imprevisibles y transitorios. Se manejan con reintentos y mensajes claros.

Errores de permisos

Acceso denegado, token vencido, credenciales no válidas. Requieren una acción del usuario o del administrador. Mensaje claro sobre lo que falta.

2

🛡️ Validación de entrada

La primera línea de defensa contra errores es la validación de entradas. Antes de procesar cualquier dato, verifica que los parámetros sean correctos: tipo, formato, rango y presencia. Nunca confíes en los datos que recibes. Devuelve mensajes claros cuando algo esté mal para que el modelo pueda informar al usuario de forma útil.

💎 Concepto principal

Una validación sólida al inicio de la tool evita errores en cascada:

@mcp.tool()
async def buscar_usuario(id: int) -> str:
# Validar tipo y rango
if id <= 0:
return "Error: el ID debe ser un número positivo."
if id > 999999:
return "Error: el ID está fuera del rango válido (1-999999)."
# Ahora sí, procesar...
❌ Evitar
  • •Confiar ciegamente en los datos recibidos
  • •Validar solo el tipo, ignorando el rango y el formato
  • •Mensajes de error genéricos ("Error interno")
  • •Dejar la validación para el final del procesamiento
✅ Hacer
  • •Validar todos los parámetros al inicio de la función
  • •Verificar tipo, rango, formato y presencia
  • •Devolver un mensaje claro que indique qué está mal
  • •Incluir el valor esperado en el mensaje de error
🚨 Alerta

Nunca expongas datos sensibles en mensajes de error. Evita devolver rutas de archivos del servidor, nombres de variables de entorno, cadenas de conexión a bases de datos o cualquier información que pueda usarse para explotar el sistema. Los mensajes de error deben ser útiles para el usuario, no para un atacante.

3

🔄 Try/Except en Tools

Incluso con una validación perfecta, pueden ocurrir errores de ejecución. La estructura try/except es tu red de seguridad: captura excepciones antes de que hagan caer el server y permite devolver mensajes de error útiles en lugar de stack traces incomprensibles.

💎 Concepto principal

Envuelve la lógica principal en try/except con excepciones específicas:

@mcp.tool()
async def processar_dados(datos: str) -> str:
try:
resultado = json.loads(dados)
valor = resultado["clave"]
return f"Valor encontrado: {valor}"
except json.JSONDecodeError:
return "Error: los datos no son JSON válido."
except KeyError las e:
return f"Error: clave {e} no encontrada en los datos."
except Exception las e:
return f"Error inesperado: {type(e).__name__}."
💡 Consejo práctico

Siempre captura las excepciones específicas antes que la genérica. Empieza con los errores más probables (ValueError, KeyError, json.JSONDecodeError) y termina con except Exception como red de seguridad final. Nunca uses except: sin tipo: esto captura incluso KeyboardInterrupt y SystemExit.

❌ Evitar
  • •except: sin tipo de excepción
  • •Devolver el stack trace completo al modelo
  • •Silenciar errores con pass
  • •Un único except genérico para todo
✅ Hacer
  • •Capturar primero las excepciones específicas
  • •Devolver un mensaje de error legible y útil
  • •Registrar el error completo (ver tema 6)
  • •Exception genérica como fallback final
4

📡 Errores de red

Cuando tus tools hacen solicitudes HTTP a APIs externas, los fallos de red son inevitables. El servidor de la API puede estar fuera de servicio, la conexión puede agotar el tiempo de espera o la respuesta puede tener un estado de error. Cada tipo de fallo de red requiere un manejo específico, con mensajes que ayuden al modelo a informar al usuario qué ocurrió.

💎 Concepto principal

Con httpx, los principales errores de red son:

  • •httpx.ConnectError — no se pudo conectar al servidor (DNS, puerto cerrado, host inaccesible)
  • •httpx.TimeoutException — se agotó el tiempo límite de conexión o lectura
  • •httpx.HTTPStatusError — el servidor respondió con estado 4xx o 5xx

Maneja cada uno por separado para darle mensajes precisos al modelo.

📋 Tipos de errores de red y cómo tratarlos
ConnectError

Servidor inaccesible. Mensaje: "No se pudo conectar al servicio X. Verifica si el servicio está en línea." Reintentar puede ayudar si el problema es transitorio.

TimeoutException

Tiempo agotado. Mensaje: "La solicitud al servicio X tardó más de lo esperado." Considera aumentar el timeout o reintentar con backoff.

HTTPStatusError

Respuesta con error. 404 = recurso no encontrado, 401/403 = no autorizado, 500 = error en el servidor externo. Adapta el mensaje al status code.

🚨 Alerta

Ten cuidado con los reintentos infinitos. Si la API está fuera de servicio, intentar de nuevo sin límites bloqueará tu tool. Usa retry con backoff exponencial y un máximo de intentos (p. ej., 3 intentos con esperas de 1s, 2s, 4s). Si todos fallan, devuelve un mensaje claro que indique que el servicio no está disponible temporalmente.

5

⏱️ Tiempos de espera

Configurar timeouts es esencial en los servers MCP. El modelo de IA espera la respuesta de la tool para continuar: si la tool se bloquea en una solicitud HTTP sin timeout, el modelo queda esperando indefinidamente. Define siempre límites de tiempo para las operaciones que pueden tardar.

💎 Concepto principal

Siempre configura un timeout en las solicitudes HTTP:

async with httpx.AsyncClient(timeout=10.0) las client:
response = await client.get(url)

El valor timeout=10.0 significa que la solicitud se cancelará si tarda más de 10 segundos. Para API rápidas, 5-10 segundos es suficiente. Para operaciones pesadas, pueden ser necesarios 30 segundos o más, pero siempre con un límite definido.

💡 Consejo práctico

Puedes configurar timeouts granulares con httpx.Timeout(connect=5.0, read=10.0, write=5.0, pool=5.0). Esto permite distintos límites para la conexión, la lectura, la escritura y el pool. En la mayoría de los casos, timeout=10.0 como valor único es suficiente y más fácil de mantener.

❌ Evitar
  • •Solicitudes HTTP sin timeout (el valor predeterminado puede ser infinito)
  • •Timeouts demasiado largos (60s+) sin justificación
  • •Ignorar TimeoutException y dejar que el server se bloquee
  • •Timeout diferente para cada tool, sin un patrón
✅ Hacer
  • •Definir un timeout en cada solicitud HTTP
  • •Valores razonables: 5-15s para APIs estándar
  • •Capturar TimeoutException con un mensaje claro
  • •Estandarizar los timeouts en constantes del proyecto
6

📋 Registro y depuración

Los mensajes de error que se devuelven al modelo deben ser simples y útiles. Pero tú, como desarrollador, necesitas todos los detalles para diagnosticar problemas. Ahí es donde entra el logging: registrar errores detallados en stderr sin interferir con el protocolo MCP que usa stdout.

💎 Concepto principal

Configura el logging para registrar errores detallados en stderr:

import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()] # stderr por defecto
)
logger = logging.getLogger("mcp-server")
# Dentro de una tool:
except Exception las e:
logger.error(f"Error en buscar_usuario: {e}", exc_info=True)
return "Error al buscar al usuario. Inténtalo de nuevo."

O exc_info=True incluye el stack trace completo en el log, algo esencial para depurar. El protocolo MCP usa stdout para la comunicación, así que los logs en stderr no interfieren.

💡 Consejo práctico

Usa niveles de log adecuados: DEBUG para detalles de desarrollo, INFO para operaciones normales (tool invocada, parámetros recibidos), WARNING para situaciones sospechosas, pero no críticas, ERROR para fallas que impiden el funcionamiento. En producción, configura el nivel en INFO; en desarrollo, usa DEBUG.

📊 Datos e investigación

MCP Inspector muestra los logs del server en su interfaz, lo que facilita la depuración durante el desarrollo. Los logs estructurados (con timestamp, nivel y nombre del logger) son 3 veces más rápidos de diagnosticar que los prints sueltos, según estudios de ingeniería de software. Dedica tiempo a configurar correctamente el logging desde el principio: lo agradecerás cuando aparezca el primer bug en producción.

📝 Resumen del módulo

  • ✓ Los errores en MCP se dividen en cuatro categorías: entrada, ejecución, red y permisos.
  • ✓ La validación de entrada es la primera línea de defensa: comprueba el tipo, el rango y el formato antes de procesar.
  • ✓ Un try/except con excepciones específicas captura errores y devuelve mensajes útiles en lugar de stack traces.
  • ✓ Los errores de red (ConnectError, TimeoutException, HTTPStatusError) requieren un tratamiento individual.
  • ✓ Los timeouts son obligatorios en las solicitudes HTTP: el modelo no puede quedarse esperando para siempre.
  • ✓ El logging en stderr preserva el protocolo MCP y proporciona detalles esenciales para la depuración.

Siguiente Módulo: 3.9 — Probando con MCP Inspector