en
MCP Stateless: Guía definitiva de migración y producción
productivity

MCP Stateless: Guía definitiva de migración y producción

Aprende cómo adaptar tus servidores MCP a la especificación stateless: adiós a sesiones y handshakes, enrutamiento por cabeceras Mcp-Method, MRTR y balanceo de carga L7 estándar.

T
ToolReview
Publicado: September 21, 2026

Model Context Protocol (MCP): La Gran Migración hacia Arquitecturas Stateless y Producción Masiva

Cuando Anthropic y la comunidad abierta introdujeron el Model Context Protocol (MCP) a finales de 2024, el protocolo transformó por completo la interoperabilidad entre Large Language Models (LLMs) y herramientas externas. Sin embargo, para los equipos de infraestructura y DevOps, el despliegue a gran escala acarreaba una fricción evidente: era un protocolo inherentemente stateful.

Depender de un ciclo de vida con negociación inicial de capacidades (initialize / initialized), mantener identificadores obligatorios (Mcp-Session-Id) y sostener túneles persistentes vía SSE (Server-Sent Events) o WebSockets obligaba a implementar afinidad de sesiones (sticky sessions), clusters de sincronización en Redis y configuraciones de red complejas que encarecían el escalado horizontal.

Con la llegada de la especificación 2026-07-28, el núcleo de MCP cambió radicalmente: MCP se convirtió en un protocolo 100% Stateless (sin estado). En esta guía desglosamos cada cambio arquitectónico, analizamos por qué el balanceo de carga ahora es trivial y explicamos cómo migrar servidores existentes paso a paso.


1. Anatomía del Cambio: ¿Qué se eliminó y qué llegó?

Característica Arquitectura Clásica (2024–2025) Nueva Especificación Stateless (2026-07-28)
Inicialización Handshake formal obligatorio (initialize $\to$ initialized) Eliminado. Cada petición es atómica y autocontenida
Identidad y Sesión Cabecera persistente Mcp-Session-Id en memoria/Redis Eliminado. Contexto e identidad viajan en el objeto _meta
Enrutamiento Inspección profunda del cuerpo JSON (Deep Packet Inspection) Cabeceras HTTP nativas: Mcp-Method y Mcp-Name
Interacción Humana (HITL) Conexiones bidireccionales abiertas o streams SSE MRTR (Multi Round-Trip Requests): patrón Request/Retry
Procesos Largos Bloqueo de socket o timeouts HTTP Tasks Extension: polling asíncrono seguro (tasks/get, tasks/update)
Infraestructura Instancias con memoria compartida y sticky sessions Edge Computing, Serverless (Scale-to-Zero) y balanceo L4/L7 Round-Robin

2. Los Cuatro Pilares del Nuevo MCP


                      ┌─────────────────────────────────┐
                      │    HTTP Ingress / API Gateway   │
                      │  (Enrutamiento por Mcp-Method)  │
                      └────────────────┬────────────────┘

            ┌──────────────────────────┼──────────────────────────┐
            ▼                          ▼                          ▼
   ┌─────────────────┐        ┌─────────────────┐        ┌─────────────────┐
   │ Pod / Serverless│        │ Pod / Serverless│        │ Pod / Serverless│
   │  Instance #1    │        │  Instance #2    │        │  Instance #3    │
   │ (Sin sesión)    │        │ (Sin sesión)    │        │ (Sin sesión)    │
   └─────────────────┘        └─────────────────┘        └─────────────────┘

1. Desacople del Handshake y Sesiones en _meta

Anteriormente, si una réplica fallaba o si el balanceador de carga redirigía una petición a un nodo distinto, el servidor rechazaba la solicitud por falta del contexto inicial. En la especificación actual, cada llamada HTTP POST es autocontenida:

{
  "jsonrpc": "2.0",
  "id": "req-98421",
  "method": "tools/call",
  "params": {
    "name": "query_database",
    "arguments": {
      "query": "SELECT count(*) FROM billing_records;"
    },
    "_meta": {
      "protocolVersion": "2026-07-28",
      "clientId": "enterprise-agent-runner-prod",
      "capabilities": {
        "roots": false,
        "mrtr": true
      }
    }
  }
}

Cualquier instancia que reciba esta solicitud cuenta con la información necesaria para autenticar, validar la versión y procesar la llamada de inmediato, sin requerir una base de datos centralizada de sesiones como Redis.

2. Enrutamiento e Inspección por Cabeceras HTTP

Para aplicar límites de tasa (rate limiting), cortafuegos de aplicaciones web (WAF) o auditorías, las puertas de enlace (API Gateways) antes se veían forzadas a parsear el cuerpo JSON completo de cada paquete.

La especificación estandarizó las cabeceras a nivel de transporte:

POST /mcp HTTP/1.1
Host: mcp.internal.enterprise.com
Content-Type: application/json
Mcp-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: query_database
Authorization: Bearer eyJhbGciOi...

Un proxy inverso (como NGINX, Envoy, Traefik o Cloudflare Gateway) puede rechazar o autorizar la ejecución de una herramienta crítica (por ejemplo, drop_tables o transfer_funds) evaluando únicamente la cabecera Mcp-Name, sin tocar los buffers de memoria del payload.

3. MRTR (Multi Round-Trip Requests): Confirmaciones sin Sockets Abiertos

¿Cómo solicita un servidor la confirmación del usuario para una acción sensible (Human-in-the-Loop) sin mantener un canal WebSocket o SSE abierto?

Bajo MRTR, el servidor responde con un estado controlado indicando que requiere información adicional:

{
  "jsonrpc": "2.0",
  "id": "req-98421",
  "result": {
    "resultType": "input_required",
    "prompt": "¿Autorizas la ejecución del snapshot en producción?",
    "fields": ["user_confirmation", "mfa_token"]
  }
}

El cliente solicita dicha confirmación y reintenta la misma petición original incluyendo las respuestas en el bloque inputResponses. La llamada puede ser procesada por un servidor completamente distinto al que generó la pregunta inicial, respetando la naturaleza stateless de la arquitectura.

4. Tasks Extension: Tareas Asíncronas de Larga Duración

Para trabajos que toman minutos u horas (como el entrenamiento de un modelo, el scraping de miles de URLs o la generación de un pipeline de datos), la extensión de Tasks implementa un modelo declarativo:

  • El cliente despacha la acción y recibe un taskId.
  • El progreso se monitorea mediante peticiones idempotentes tasks/get con intervalos de polling.
  • No existen bloqueos en el hilo principal ni conexiones HTTP abiertas en espera activa.

3. Por qué el Balanceo de Carga ahora es Trivial

Antes de esta revisión, operar MCP en plataformas como Kubernetes, Nomad o ECS requería:

  • Ingress con Cookie Affinity: Configurar sticky sessions basadas en cookies o IP para que el tráfico volviera siempre al contenedor que guardaba la sesión en memoria.
  • Problemas de distribución desigual: Un agente intensivo podía sobrecargar un solo nodo mientras el resto del clúster permanecía inactivo.
  • Fallas ante reinicios: El reinicio de un pod por auto-scaling o despliegues continuos causaba caídas inmediatas en las llamadas de los clientes.

Con la arquitectura sin estado:

  • Round-Robin L4/L7 puro: Cada petición puede caer en cualquier nodo o réplica sin coordinación previa.
  • Escalado a Cero (Scale-to-Zero): La infraestructura puede alojarse en Cloudflare Workers, AWS Lambda, Google Cloud Run o Azure Container Apps, reduciendo costos operativos a cero cuando no se procesan inferencias.
  • Despliegues Zero-Downtime: Los despliegues tipo Canary o Blue-Green se ejecutan sin interrumpir conexiones de larga duración.

4. Guía Práctica: Adaptando un Servidor MCP

A continuación, un ejemplo de cómo migrar un servidor moderno utilizando el SDK actualizado de MCP en Node.js / TypeScript:

Código: Implementación Stateless con Soporte para Cabeceras y MRTR

import express, { Request, Response } from "express";

const app = express();
app.use(express.json());

const SUPPORTED_VERSION = "2026-07-28";

// Middleware para validación de cabeceras obligatorias
app.use((req: Request, res: Response, next) => {
  const version = req.header("Mcp-Protocol-Version");
  const method = req.header("Mcp-Method");

  if (!version || version !== SUPPORTED_VERSION) {
    return res.status(400).json({
      jsonrpc: "2.0",
      error: {
        code: -32000,
        message: `Versión no soportada. Requiere: ${SUPPORTED_VERSION}`
      }
    });
  }

  // Comprobación de integridad entre Header y Body
  if (method && req.body.method && method !== req.body.method) {
    return res.status(400).json({
      jsonrpc: "2.0",
      error: {
        code: -32600,
        message: "Discrepancia entre cabecera Mcp-Method y JSON-RPC body"
      }
    });
  }

  next();
});

// Endpoint principal stateless
app.post("/mcp", async (req: Request, res: Response) => {
  const { id, method, params } = req.body;

  switch (method) {
    case "tools/list":
      return res.json({
        jsonrpc: "2.0",
        id,
        result: {
          tools: [
            {
              name: "deploy_service",
              description: "Despliega una nueva versión de servicio",
              inputSchema: {
                type: "object",
                properties: { serviceId: { type: "string" } },
                required: ["serviceId"]
              }
            }
          ]
        }
      });

    case "tools/call":
      const toolName = req.header("Mcp-Name") || params?.name;

      if (toolName === "deploy_service") {
        // Ejemplo de MRTR: si no hay confirmación en la llamada, se solicita
        if (!params?.inputResponses?.user_confirmed) {
          return res.json({
            jsonrpc: "2.0",
            id,
            result: {
              resultType: "input_required",
              prompt: `Confirmación requerida: ¿Proceder con el despliegue del servicio ${params.arguments.serviceId}?`,
              fields: ["user_confirmed"]
            }
          });
        }

        // Ejecución efectiva tras la resolución MRTR
        return res.json({
          jsonrpc: "2.0",
          id,
          result: {
            content: [
              {
                type: "text",
                text: `Servicio ${params.arguments.serviceId} desplegado exitosamente.`
              }
            ]
          }
        });
      }

      return res.status(404).json({
        jsonrpc: "2.0",
        id,
        error: { code: -32601, message: "Herramienta no encontrada" }
      });

    default:
      return res.status(400).json({
        jsonrpc: "2.0",
        id,
        error: { code: -32601, message: "Método no soportado en modo stateless" }
      });
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Servidor MCP Stateless activo en puerto ${PORT}`));

5. Checklist de Verificación para Producción

Antes de promover tus servidores a entornos productivos bajo el estándar 2026-07-28, valida los siguientes puntos:

  • Desactivar Sticky Sessions: En tu balanceador (ALB, NGINX o Traefik), desactiva la persistencia de afinidad y cambia el algoritmo a round-robin balanceado.
  • Desmantelar capas Redis de sesiones MCP: Elimina el almacenamiento centralizado de Mcp-Session-Id salvo que persistas telemetría ajena al protocolo.
  • Validación cruzada de Cabeceras: Asegúrate de que el API Gateway verifique que Mcp-Name y Mcp-Method coincidan con el payload para evitar ataques de request smuggling.
  • Políticas de Time-to-Live (TTL): Incorpora ttlMs en las respuestas de tools/list para que los clientes utilicen caches locales y reduzcan el número de llamadas redundantes.
  • Migración de tareas pesadas a Tasks Extension: Evita conexiones bloqueantes implementando la semántica asíncrona de dos fases.

Conclusión

La transición a una arquitectura sin estado marca la madurez operativa de MCP, transformándolo de una tecnología de prototipado a un componente estándar de infraestructura empresarial. Al remover las dependencias de sesiones y adoptar un esquema puramente HTTP, los servidores MCP disfrutan ahora de la misma resiliencia, simplicidad operativa y capacidad de escalado que cualquier API REST moderna.