Corres CI en tu backend. Linteas tu frontend. Tus contenedores de Docker tienen healthchecks. Todo en tu stack tiene una estrategia de testing — excepto las conexiones MCP de las que tu agente depende en cada maldita llamada.

El 19 de abril, el equipo de MCP publicó su roadmap 2026. Cuatro prioridades: autorización, registro, primitivas de UX enriquecidas y capacidades agénticas. Testing, health checks, validación de contratos — no están en la lista. No se mencionan. No están planeados. 😾

Así que estás solo. Aquí te va cómo testear servidores MCP hoy con las herramientas que realmente existen.

Con qué cuentas

El ecosistema MCP tiene aproximadamente 17,000 servidores registrados. Auditorías de la comunidad encuentran que más o menos la mitad responden de forma confiable en cualquier momento dado. ¿Tu agente se conecta a tres servidores? Estadísticamente, uno de ellos está fallando ahora mismo.

Testomat.io publicó el estudio más completo sobre herramientas de testing para MCP el 8 de abril. Su conclusión es directa: nada habla MCP de forma nativa para testing. Todo es cinta adhesiva sobre frameworks HTTP genéricos. Ningún test runner entiende el transporte MCP. Ninguna librería de aserciones sabe cómo luce una respuesta válida de una herramienta. Estás construyendo todo el stack de testing desde cero para cada servidor del que dependes.

Aquí está el inventario completo de lo que existe — y cómo hacerlo funcionar.

MCP Inspector: el punto de partida manual

MCP Inspector es la herramienta oficial de depuración — piensa en Postman pero para MCP. Te conectas a un servidor, llamas herramientas manualmente, inspeccionas respuestas.

Lo que te da:

  • Descubrimiento e invocación interactiva de herramientas
  • Inspección de respuestas JSON en crudo
  • Diagnóstico de conexión para transportes stdio y HTTP+SSE

Lo que no te da:

  • Integración con CI
  • Detección de regresiones
  • Suites de tests automatizados
  • Validación de respuestas contra ningún schema

Es un desarmador. Útil para husmear durante el desarrollo, inútil para prevenir regresiones en producción. Necesitas un test harness. 😹

Tests wrapper (el enfoque de cinta adhesiva)

La mayoría de los equipos que testean MCP hoy escriben tests wrapper — suites de pytest o Jest que llaman herramientas directamente a través del MCP client SDK y hacen aserciones sobre lo que regresa.

# Ejemplo con pytest — testeando una herramienta de servidor MCP
import json
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def test_search_tool_returns_results():
    server = StdioServerParameters(
        command="npx",
        args=["-y", "@example/mcp-search-server"]
    )
    async with stdio_client(server) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            
            result = await session.call_tool(
                "search",
                arguments={"query": "test query", "limit": 5}
            )
            
            assert result.content is not None
            assert len(result.content) > 0
            assert result.content[0].type == "text"
            
            data = json.loads(result.content[0].text)
            assert "results" in data
            assert len(data["results"]) <= 5

Esto funciona hasta que el servidor upstream cambia el formato de respuesta. Lo cual pasa en silencio, sin versionado, sin changelogs — el spec de MCP no tiene convención de semver, no tiene equivalente a un lockfile, no tiene mecanismo para anunciar breaking changes. Tu aserción verifica data["results"] — el servidor lo renombra a data["items"] un martes a las 2 AM. Mejor caso: tu test se pone rojo. Peor caso: el campo sigue existiendo pero la estructura interna cambia, tu test sigue verde, tu agente alucina con datos malformados, y pagas por cada token alucinado.

Contract testing sin contratos

La brecha fundamental: los servidores MCP no publican schemas de respuesta. El spec describe lo que una herramienta debería hacer en lenguaje natural. No ofrece ningún contrato legible por máquina para validar.

El workaround: genera el tuyo.

# Paso 1: Registra respuestas reales a lo largo del tiempo
from genson import SchemaBuilder

builder = SchemaBuilder()
for response in recorded_responses:  # recopila estas de staging/dev
    builder.add_object(json.loads(response))

inferred_schema = builder.to_schema()
# Guarda esto en tu repo como el "contrato"

# Paso 2: Valida en CI
from jsonschema import validate, ValidationError

def test_tool_response_matches_contract():
    response = call_mcp_tool("search", {"query": "test"})
    try:
        validate(instance=response, schema=inferred_schema)
    except ValidationError as e:
        pytest.fail(f"Contract violation: {e.message}")

El proceso: registra respuestas reales del servidor durante una semana. Infiere un JSON Schema a partir de esas respuestas usando un generador de schemas. Commitea ese schema en tu repo. Valida las respuestas futuras contra él en CI.

Es contract testing de ingeniería inversa. No es elegante. Pero atrapa cambios silenciosos del upstream que de otra forma llegarían a producción sin ser detectados. Cuando el schema se rompe, tu pipeline se rompe — ruidosamente, en CI, no en silencio en el output de tu agente. 😸

Monitoreo de salud: constrúyelo o reza

Tu orquestador pingea contenedores Docker. Tu load balancer revisa /health. Los servidores MCP no ofrecen endpoint de salud — el spec no define ninguno. Un servidor está respondiendo o no lo está, y te enteras cuando la llamada de herramienta de tu agente se queda colgada.

Construye tu propio health check:

import asyncio
from datetime import datetime

async def check_mcp_health(server_params, timeout=10):
    try:
        async with asyncio.timeout(timeout):
            async with stdio_client(server_params) as (read, write):
                async with ClientSession(read, write) as session:
                    await session.initialize()
                    tools = await session.list_tools()
                    return {
                        "status": "healthy",
                        "tools_available": len(tools.tools),
                        "checked_at": datetime.utcnow().isoformat()
                    }
    except (asyncio.TimeoutError, Exception) as e:
        return {
            "status": "unhealthy",
            "error": str(e),
            "checked_at": datetime.utcnow().isoformat()
        }

Ejecuta esto con un cron. Alerta en fallos consecutivos. Revisa no solo la conectividad sino la lista de herramientas — los servidores agregan y eliminan herramientas sin aviso, y tu agente esperando search_v2 después de que el servidor la eliminó silenciosamente produce el tipo de fallo que parece un bug del agente pero no lo es.

Inyección de fallos: la parte que todos se saltan

Tu agente llama una herramienta. La herramienta hace timeout. ¿Qué pasa después?

Si no has testeado esto, la respuesta es: el modelo improvisa. Puede reintentar infinitamente. Puede alucinar la respuesta esperada. Puede disculparse con el usuario y no hacer nada. No lo vas a saber hasta que producción te lo muestre, y producción cobra por token la lección. 🙀

Envuelve tu cliente MCP para simular fallos:

import random

class ChaosProxy:
    """Envuelve una sesión MCP real para inyectar fallos durante testing."""
    def __init__(self, real_session, failure_rate=0.1, corruption_rate=0.05):
        self.session = real_session
        self.failure_rate = failure_rate
        self.corruption_rate = corruption_rate
    
    async def call_tool(self, name, arguments):
        # Simular timeout
        if random.random() < self.failure_rate:
            raise TimeoutError(f"Simulated MCP timeout on {name}")
        
        result = await self.session.call_tool(name, arguments)
        
        # Simular respuesta corrupta
        if random.random() < self.corruption_rate:
            return self._corrupt_response(result)
        
        return result
    
    def _corrupt_response(self, result):
        # Retorna un envelope MCP válido con contenido basura
        # Testea si tu agente maneja datos malformados con gracia
        ...

Corre tu agente a través de este proxy con una tasa de fallo del 10%. Observa cómo maneja timeouts, datos basura y herramientas faltantes. Corrige lo que se rompa. Sube la tasa. Repite hasta que tu agente degrade con gracia en vez de alucinar con confianza.

El stack completo de testing

Así se ve un deployment MCP testeado hoy — todo hecho a mano, nada estandarizado:

Capa Herramienta Qué atrapa
Exploración manual MCP Inspector "¿Esta herramienta existe y responde?"
Tests unitarios Wrappers pytest/Jest Forma de respuesta, comportamiento básico
Tests de contrato JSON Schema inferido Cambios silenciosos de formato upstream
Monitoreo de salud Cron personalizado + alertas Caídas de servidor, drift en lista de herramientas
Inyección de fallos Wrapper de chaos proxy Comportamiento del agente bajo condiciones degradadas
Tests de integración Ejecuciones end-to-end del agente Regresiones del pipeline completo

Total de herramientas estandarizadas que el spec de MCP provee para algo de esto: cero. Cada capa que construyes, también la mantienes, depuras y reconstruyes cuando los cambios de transporte rompen tu infraestructura de testing. 😾

Las trampas que te van a morder

Contaminación de estado. Las herramientas MCP pueden tener efectos secundarios — escribir datos, borrar registros, cobrar dinero. El spec no define un modo mock. O construyes un servidor falso para testing, corres contra producción (peligroso), o mantienes un entorno de staging por cada dependencia MCP (caro). La mayoría de los equipos testean contra producción y rezan. Rezar no es una estrategia de testing.

Desajuste de transporte. Tus tests corren sobre stdio. Producción corre sobre HTTP+SSE. Se comportan diferente bajo carga, hacen timeout diferente, fallan diferente. Testea ambos transportes o acepta que tu entorno de testing no coincide con producción.

Expiración de auth. Los tokens OAuth expiran. Tu CI corre a las 3 AM. El token expiró a las 2 AM. Tu test falla, no porque el servidor se rompió, sino porque auth lo hizo. Maneja el token refresh en el setup de tests o vas a perseguir fallos fantasma por horas.

Drift en la lista de herramientas. El servidor agrega una herramienta, elimina otra, renombra un parámetro — sin notificación, sin version bump. Testea el descubrimiento de herramientas como parte de tus health checks. Haz diff de la lista de herramientas contra un snapshot conocido y bueno. Alerta ante cambios.

Ahora eres peligroso

Puedes testear servidores MCP. No porque el protocolo te ayude — el roadmap del 19 de abril confirma que no va a priorizar esto pronto — sino porque la validación con JSON Schema, la ingeniería del caos y el monitoreo de salud son problemas ya resueltos. Puedes atornillarlos a la superficie sin tests de MCP con Python regular y un cron job.

El setup es feo. El mantenimiento es manual. Todo el stack va a necesitar reconstruirse cuando el spec eventualmente agregue primitivas de testing — si es que algún día lo hace.

Pero tu agente ahora tiene dependencias testeadas en lugar de plegarias. Esa es la diferencia entre "funcionó en el demo" y "funciona en producción". Una de esas te paga el sueldo. La otra te consigue un mensaje de Slack a las 2 AM de alguien que confió en tu agente con algo importante. 😼

Roadmap MCP 2026 (19 de abril de 2026)Testomat.io — Herramientas de Testing para Servidores MCP