mcprepo.ai

Publicado el

- 14 min read

Depuración de repositorios MCP: una guía práctica de resolución de problemas para fallos en el mundo real

Imagen de Depuración de repositorios MCP: una guía práctica de resolución de problemas para fallos en el mundo real

Depuración de repositorios MCP: Guía práctica para resolver fallos reales

¿Tienes poco tiempo? La verdad es simple: la mayoría de los problemas en repositorios MCP se reducen a contratos desalineados, fallos silenciosos en el transporte o deriva invisible de la configuración. Vamos a solucionarlo.

Qué entendemos por “repositorios MCP”

Cuando los equipos dicen “repositorio MCP”, normalmente se refieren a una base de código que implementa servicios del Model Context Protocol: un servidor MCP que expone herramientas, recursos y prompts a un cliente compatible con MCP mediante JSON-RPC. El repo puede contener código del servidor, bindings del protocolo (TypeScript, Python u otros SDKs), manifiestos, fixtures de pruebas, arneses de integración y scripts de despliegue. En otras palabras, es la superficie del contrato donde la automatización se encuentra con la solicitud del usuario. Depurarlo bien implica saber dónde pueden romperse los contratos: protocolo, transporte, lógica de negocio, entorno y proceso de release.

Empieza con un bucle corto y repetible

Tu mejor herramienta es un bucle de retroalimentación rápido. Antes de sumergirte en trazas de paquetes, crea un repro conciso y repetible:

  • Define el comando o acción del cliente que falla con lo mínimo posible.
  • Fija sus entradas: variables de entorno, secretos, payloads de ejemplo.
  • Captura salidas estables: logs, intercambios JSON, mensajes de error.
  • Limita experimentos a diez minutos; si no hay progreso, baja una capa más (protocolo, luego transporte, luego lógica del servicio, luego runtime).

Este bucle te protege de dar palos de ciego y obliga a formular hipótesis observables.

Lista de comprobación de salud en cinco minutos

Si solo tienes cinco minutos, haz esto:

  • Versiones: ¿SDK, runtime, cliente y servidor alineados? ¿Hay cambios incompatibles en las release notes?
  • Puntos de entrada: ¿El servidor arranca sin errores? ¿Hay avisos en el inicio? ¿El cliente descubre capacidades?
  • Transporte: ¿Se establecen conexiones? ¿Hay advertencias de TLS o framing? ¿Time outs?
  • Permisos: ¿El servidor tiene acceso a rutas del sistema de ficheros, salida de red y permisos para crear procesos?
  • Secretos: ¿Tokens presentes, no caducados y con el scope correcto?
  • Límites de tasa: ¿Hay 429s o throttling del proveedor en los logs?
  • CORS/proxy: Para transportes WebSocket o HTTP, ¿algún proxy reescribe cabeceras?
  • Catálogos de recursos: ¿Puede el cliente listar recursos y prompts sin error?
  • Prueba rápida de herramienta: Invoca una herramienta trivial o no-op. Si eso falla, es sistémico.

Entender los dominios de fallo

Piensa por capas. Cada capa tiene síntomas característicos.

  • Capa de protocolo (JSON-RPC, esquemas MCP): nombres de métodos mal tipeados, parámetros erróneos, campos faltantes, formas de resultado inesperadas, desajustes de ID de correlación.
  • Capa de transporte (stdio, WebSocket, orquestación de procesos): deadlocks por buffering, finales de línea, límites de tamaño de payload, lectores lentos, proxies rotos.
  • Capa de lógica de negocio (herramientas, recursos, prompts): errores de permisos, fallos de dependencias, errores en APIs externas.
  • Capa de entorno (SO, contenedor, CI): problemas de codificación, diferencias de rutas, locales faltantes, timeouts, DNS.
  • Capa de ciclo de vida (build, versionado, release): artefactos inconsistentes, cachés obsoletos, código generado incompatible.

La mayoría de los bugs “de protocolo” son en realidad problemas de entorno o transporte disfrazados. Investiga la capa más baja que puedas probar con evidencias.

Diagnósticos a nivel de protocolo que realmente ayudan

  • Repite el contrato: Imprime las peticiones y respuestas con IDs, nombres de método y parámetros truncados. Conserva logs completos para reproducibilidad, pero redacta secretos.
  • Valida el esquema: Usa validación JSON estricta en builds de desarrollo. Falla ruidosamente ante campos desconocidos o claves requeridas ausentes.
  • Correlación: Etiqueta cada línea de log con el id JSON-RPC. Sin correlación, la concurrencia oculta la cadena real de errores.
  • Deriva de capacidades: En el arranque, vuelca las capacidades anunciadas, nombres de herramientas y rutas de recursos. Si el cliente consulta una herramienta que el servidor nunca anunció, has encontrado un desajuste (posiblemente un manifiesto obsoleto o un directorio no montado).
  • Idempotencia y reintentos: Si el cliente reintenta por fallos de red, asegúrate de que las acciones de la herramienta sean idempotentes o detecta y desduplica invocaciones duplicadas.

Atento a estos “olores” de protocolo:

  • “Method not found”: Tipografía, desajuste de versión o handler no registrado.
  • “Invalid params”: Formas, tipos o claves anidadas erróneas. Compara el esquema que el código espera con los payloads reales.
  • “Internal error”: Captura y registra excepciones originales con trazas en el límite.

Peligros del transporte y soluciones rápidas

Servidores basados en stdio:

  • Flush agresivo: Si tu runtime hace buffering de stdout, el cliente puede quedarse bloqueado. Desactiva el buffering o flush tras cada mensaje.
  • Finales de línea: Inconsistencias CRLF vs LF entre plataformas pueden romper lectores ingenuos.
  • Deadlocks: Nunca registres en stdout si stdout es el canal del protocolo. Envía logs a stderr o a un fichero, o usa un logger estructurado que segregue streams.
  • Payloads grandes: Fragmenta o streamnea resultados grandes; algunos lectores imponen límites de tamaño.

Servidores basados en WebSocket:

  • Ping/pong: Las keepalives importan. Configura timeouts y heartbeats; descarta conexiones obsoletas con gracia.
  • Proxies: Los proxies corporativos suelen romper o reescribir cabeceras. Prueba una conexión directa o un túnel de confianza.
  • Framing: Asegúrate de enviar frames de texto para JSON; frames binarios pueden confundir clientes que esperan texto.

General:

  • Backpressure: Un cliente lento puede bloquear escrituras. Usa colas acotadas y timeouts; muestra avisos cuando descargas o difieres mensajes.
  • Timeouts: Define timeouts explícitos en cliente y servidor y regístralos de forma distinta a los fallos de negocio.
  • TLS: SNI o certificados mal configurados pueden funcionar localmente pero fallar en CI. Registra sujetos de certificado y su caducidad en el arranque.

Arreglar el “funciona en mi máquina”

Comprueba la realidad del entorno:

  • Locale y encoding: Diferencias de locale o manejo de Unicode pueden corromper JSON o rutas de ficheros.
  • Permisos de ficheros: Herramientas que crean ficheros temporales pueden necesitar directorios escribibles; asegura TMPDIR/TEMP consistentes.
  • Salida de red: Los runners de CI en subredes privadas suelen requerir NAT o proxy específicos. Prueba con una llamada externa mínima para verificar egress.
  • Desfase horario: Tokens con ventanas estrechas fallan si el reloj del sistema se desequilibra. Sincroniza hora o verifica NTP.

Builds en contenedor:

  • Fija versiones: Las imágenes base y mirrors cambian. Usa tags explícitos y lockfiles.
  • Fugas multi-stage: Dependencias solo de build no deben ser necesarias en runtime; si lo son, producción falla aunque dev funcione.
  • Problemas por no ser root: Al bajar privilegios, verifica propiedad de rutas y directorios R/W.

Diagnosticar fallos en la ejecución de herramientas

Las herramientas invocadas por un servidor MCP se comportan como mini servicios. Fallos comunes:

  • PATH y virtualenv: La herramienta usa un runtime no instalado en producción. Muestra el PATH efectivo y la versión del intérprete al arrancar la herramienta.
  • Permisos: Los sandboxes restringen forks, red o filesystem. Proporciona mensajes de error claros cuando las reglas del sandbox bloquean acciones.
  • Agotamiento de recursos: Pools de hilos y subprocesses pueden hacer deadlock bajo carga. Añade timeouts por herramienta y mata invocaciones colgadas.
  • APIs externas: Añade circuit breakers para proveedores inestables. Cachea metadatos estables. Expone un modo “dry run” que valida credenciales sin efectos secundarios.

Buena higiene:

  • Distingue errores de usuario de errores del sistema. Los errores de usuario deben ser accionables (entrada errónea), los errores del sistema deben producir un código único para triage.
  • Emite métricas: conteos de éxitos, fallos por tipo, duraciones y profundidad de colas.

Catálogos de recursos y prompts que no mienten

Al listar recursos o prompts:

  • Regenera catálogos al inicio y al recargar en caliente. Listas obsoletas causan “resource not found” aunque el fichero exista.
  • Normaliza rutas: Sensibilidad a mayúsculas y rutas relativas difieren entre SO. Almacena rutas canónicas absolutas internamente.
  • Control de acceso: Filtra catálogos por cliente o rol de forma determinista; documenta por qué un recurso está oculto.

Si falla la lectura de un recurso, incluye la ruta resuelta, los permisos y el resultado de stat del fichero en los logs de depuración.

Depuración de rendimiento sin adivinar

Mide antes de optimizar:

  • Presupuesto de latencia: Descompón la latencia de extremo a extremo en transporte, colas, ejecución de herramientas y llamadas externas. Registra cada segmento.
  • Cold starts: Imports perezosos pueden añadir segundos. Precarga módulos y calienta caches durante la inicialización del servidor.
  • Concurrencia: Define límites realistas. Demasiada paralelización provoca thrashing; muy poca detiene llamadas de alta latencia.
  • Caché: Memoiza resultados deterministas costosos. Acota tamaños de caché para evitar presión de memoria.
  • Tamaño del payload: Comprime o pagina resultados grandes. Ofrece muestreo de recursos para uso exploratorio.

Panel de fusilamiento para tests inestables

Los flakes son generalmente bugs de timing u orden:

  • Race en init: El cliente envía peticiones antes de que el servidor anuncie capacidades. Bloquea hasta completar el arranque o devuelve una respuesta clara de “not ready”.
  • Cancelaciones: Confirma que respetas y propagas señales de cancelación; las tareas zombis persisten si no.
  • Excepciones async silenciadas: Asegúrate de que las excepciones no manejadas hagan fallar los tests o al menos marquen fallos; tareas silenciosas destruyen la confianza.
  • Puertos aleatorios: Usa rangos de puertos fijos o lógica de pre-bind para evitar colisiones raras en CI.

Ejecuta tests con configuraciones de estrés: más concurrencia, latencia artificial e inyección de fallos. Captura seeds para reproducibilidad.

Haz que los logs paguen alquiler

Unos buenos logs acortan las caídas:

  • Estructura: Usa logs JSON con campos para ids de correlación, método, herramienta, duración, estado, id de usuario/sesión (si aplica) y clase de error.
  • Niveles que importan: info para flujo, warn para rutas degradadas, error para garantías rotas. Evita spam de debug en prod; actívalo a demanda.
  • Muestreo: Mantén logs de payloads detallados muestreados para evitar costes preservando utilidad forense.
  • Redacción: Borra automáticamente tokens y PII. Un solo secreto filtrado puede convertir un incidente menor en una brecha.

Introduce una taxonomía consistente de errores. Por ejemplo: EPROTO (protocolo), EXTERNAL (proveedor), ERESOURCE (filesystem), ECONFIG (secrets/config), ERATE (throttling), ECANCELED (cancelación). La taxonomía acelera el triage.

Observabilidad más allá de los logs

  • Métricas: Contadores de llamadas, errores por clase, golpes de rate limit; histogramas de latencias; gauges de profundidad de cola y herramientas activas.
  • Tracing: Span boundaries en recepción del protocolo, dispatch, inicio de herramienta, llamada externa y envío de respuesta. Propaga ids de trace en los logs.
  • Alertas: Umbrales en tasa de error sostenida, latencia P95/P99 y bucles de reconexión. La fatiga por alertas es real; ajusta umbrales semanalmente hasta estabilizar.

Versionado, esquemas y seguridad del contrato

  • Versionado semántico: Trata cambios relacionados con el protocolo como breaking salvo que se demuestre lo contrario. No cueles cambios de esquema en releases de parche.
  • Feature flags: Controla nuevas capacidades; permite a los clientes optar. Anuncia flags en la carga de capacidades.
  • Tests de contrato: Mantén fixtures doradas de request/response. Ejecútalas en cada build para evitar deriva accidental.

Config y secretos en los que puedas confiar

  • Fuente única: Mantén la configuración en un único lugar por entorno. Evita magia de variables de entorno por script.
  • Config tipada: Valida al arranque y falla rápido con lista clara de campos faltantes o malformados.
  • Higiene de secretos: Rota regularmente, limita scope, y registra los cuatro últimos caracteres para identificación. Añade una prueba que falle si faltan secretos pero pase si hay placeholders en dev.

Guardarraíles de CI/CD que detectan regresiones

  • Smoke tests: Arranca el servidor, lista capacidades, llama a una herramienta no-op y apaga. Ejecuta en cada commit.
  • Chequeos de contrato: Repite transcripciones JSON-RPC doradas; diff de respuestas. Falla si hay campos inesperados o faltan claves requeridas.
  • Fijado de dependencias: Bloquea dependencias a versiones exactas; renueva en un calendario.
  • Imágenes reproducibles: Construye una vez, promociona entre entornos; no reconstruyas por etapa.

Playbooks de incidentes que realmente seguirás

Prepara runbooks concisos y vivos:

  • El cliente no se conecta: Comprueba servidor, transporte, auth y capacidades. Prueba una consulta trivial de capacidades antes de llamadas a herramientas.
  • Invocaciones de herramientas agotando tiempo: Mide profundidad de cola y latencias externas; aumenta timeouts temporalmente y activa logs de depuración.
  • Alta tasa de errores tras un release: Haz rollback, biseca cambios, reproduce tests de contrato, inspecciona diff de dependencias.
  • Tormentas de rate limit: Retrocede, cachea y prioriza rutas críticas. Coordina con proveedores externos.

Incluye árboles de decisión y comandos para copiar/pegar. El tiempo ahorrado en incidentes se paga solo.

Image

Photo by Galina Nelyubova on Unsplash

Formas seguras de inspeccionar tráfico en vivo

  • Mirra, no mutes: Si añades logging de peticiones y respuestas, escríbelo a un sink fuera de banda, no al canal del protocolo.
  • Usa endpoints de depuración dedicados en non-prod: Reproduce peticiones capturadas allí.
  • Para WebSocket: Un proxy transparente puede revelar framing y tiempos. Si no es posible, instrumenta ambos extremos para registrar tiempos y tamaños de envío/recepción.

Ten cuidado con captura de paquetes en enlaces TLS; prefiere observación a nivel de aplicación para evitar la complejidad del manejo de claves.

Mensajes de error comunes y lo que suelen significar

  • “Method not found”: El servidor nunca registró el handler, o el cliente llama a una herramienta renombrada. Revisa la lista de capacidades anunciadas y descarta desajuste de versión.
  • “Invalid params”: El cliente envió una forma de payload que el servidor no acepta. Compara versiones de esquema; añade un volcado de las peticiones con tipos.
  • “Timeout”: Timeout de cliente demasiado agresivo o servidor con escasos recursos. Inspecciona histogramas de latencia y profundidad de cola.
  • “Connection closed”: Red intermitente o crash de proceso. Revisa códigos de salida del servidor y límites de memoria; monitoriza reinicios.
  • “Resource not found”: Catálogo obsoleto, desajuste de normalización de rutas, o filtro de control de acceso aplicado. Regenera el catálogo y registra la ruta resuelta.
  • “Permission denied”: ACLs del filesystem, mismatch de usuario en el contenedor o restricciones del sandbox. Registra UID/GID efectivos y permisos de directorio.

Arnés de reproducción: tu arma secreta

Crea un pequeño “protocol loopback” tester dentro del repo:

  • Alimenta requests conocidos-buenos y afirma respuestas exactas.
  • Aleatoriza el orden de campos de payload para detectar parsers frágiles.
  • Inyecta condiciones tipo red: lecturas retardadas, frames partidos y escrituras parciales.
  • Proporciona un toggle que cambie transportes (stdio vs WebSocket) para comparar comportamientos.

Mantén este arnés como un CLI que se ejecute localmente y en CI.

Cuándo hacer bisect y cómo

Si un bug apareció “recientemente”, no debatas: biseca:

  • Congela dependencias al último conjunto bueno y el conjunto actual. Si el bug cambia con las dependencias, has localizado la causa sin tocar código.
  • Usa git bisect en commits de merge, no en squash merges, para estrechar la superficie.
  • Biseca con tu smoke test, no con un test e2e complejo.

Una pequeña caja de herramientas que rinde mucho

  1. [jq] — Parse and filter JSON-RPC logs; build reproducible extracts for bug reports.
  2. [websocat] — Quick WebSocket tests; verify connectivity and message echoes.
  3. [mitmproxy] — Inspect and replay HTTP/WS flows in non-prod environments.
  4. [ripgrep] — Search code and logs fast; find silent “TODO” or experimental flags still enabled.
  5. [just] — Codify repeatable dev commands; standardize how the server starts, tests run, and logs collect.
  6. [direnv] — Keep per-repo env vars consistent; reduce “works on my machine.”
  7. [docker compose] — Recreate multi-service environments reliably for local reproduction.
  8. [gh CLI] — Fetch artifacts, PR diffs, and CI logs directly; speed up bisecting and rollback.

Documenta el uso de cada herramienta en CONTRIBUTING o DEVNOTES del repo.

Haz los mensajes de error humanos

Redacta mensajes que respondan a tres preguntas:

  • ¿Qué falló exactamente?
  • ¿Qué puede hacer el usuario a continuación?
  • ¿Dónde pueden mirar los mantenedores para obtener más contexto?

Ejemplo: “Tool invocation failed: EXTERNAL/403 from provider. Check token scope ‘read:files’. See logs with correlation id 8f2a for full trace.”

Seguridad mientras depuras

  • Nunca registres secretos en bruto. Enmascara por defecto; permite ver valores sin enmascarar solo en modo local seguro.
  • Evita copiar payloads de producción en issues públicos. Reproduce con fixtures depuradas.
  • Al adjuntar logs, comparte ventanas mínimas y redacta IDs. Una transcripción concisa y redactada vence a un volcado de 50 MB.

Documentación que evita tickets

Un README excelente para un repo MCP incluye:

  • Comandos de arranque rápido para local y Docker.
  • Versiones de SDK soportadas y su tabla de compatibilidad.
  • Requests y responses de ejemplo para cada herramienta y recurso.
  • Taxonomía de errores con mensajes de ejemplo.
  • Listas de comprobación de troubleshooting y problemas conocidos.
  • Cómo habilitar modo debug de forma segura en producción.

Añade una insignia o fecha de “Última verificación” para mantener la confianza en la doc.

Gobernanza: quién es responsable de qué

La claridad acelera las correcciones:

  • Propietarios por herramienta: lista de mantenedores y vías de escalado.
  • SLOs: Define objetivos de disponibilidad y latencia; alinea alertas en consecuencia.
  • Tren de releases: Decide cadencia de corte (semanal, quincenal) y cúmplela. Las sorpresas causan outages.
  • Deprecaciones: Puertas de versión y anuncios para retiradas. Proporciona notas de migración con ejemplos.

Recetas de ganancia rápida

  • Lecturas stdio atascadas: Cambia logs a stderr, configura escrituras con buffer por línea, añade flush tras cada mensaje JSON. Confirma con un pequeño test de echo.
  • “Method not found” misterioso: Vuelca la lista de capacidades al inicio y tras hot-reload. Compárala con la vista en caché del cliente.
  • CI inestable: Fija seeds, bloquea puertos, serializa tests con races conocidas y añade un 10% de margen a los timeouts mientras investigas.
  • Límites de proveedor: Cachea metadatos, backoff exponencial y muestra hints de “retry after” en mensajes de error al cliente.

Construye una cultura de cambios pequeños y visibles

Los cambios grandes y silenciosos generan outages en sábado. Prefiere:

  • Pull requests pequeños con notas de release precisas.
  • Feature flags con nombres de responsables.
  • Bumps de versión obvios para modificaciones que afectan al protocolo.
  • Smoke tests post-merge que puedan revertir automáticamente si fallan.

Un empujón final: mide y decide

Depurar repositorios MCP es menos cuestión de heroicidad y más de pensamiento sistémico. Instrumenta los bordes del protocolo, controla el entorno y respeta los contratos. Una vez que puedas ver el sistema con claridad, la mayoría de fallos “aleatorios” se convierten en arreglos de una línea: vaciar un buffer, fijar una versión o rechazar un payload inválido con gracia.

Debug MCP Server Like a PRO with MCP Inspector - YouTube How to Debug MCP Server with Anthropic Inspector? - Snyk The fastest way to debug MCP servers : r/modelcontextprotocol MCP Inspector: Test and Debug your MCP Server Locally - YouTube Debugging - Model Context Protocol

External References