
Migra tu servidor MCP al spec stateless 2026-07-28 (antes de que salga)
El spec MCP 2026-07-28 se vuelve stateless: SEP-2575 elimina el handshake initialize/initialized, así que la versión del protocolo, el client info y las capabilities viajan en _meta en cada request. Tu servidor remoto deja las sesiones sticky y corre tras un load balancer round-robin. Tasks pasa a extensión; tasks/list desaparece; -32002 cambia a -32602. El final sale el 28 de julio de 2026.
¿Qué cambió en MCP y cuál es la fecha límite?
El Release Candidate del spec 2026-07-28 ya está publicado, y el final sale el 28 de julio de 2026. Es la revisión más grande de MCP desde que el protocolo nació. Si corres un servidor MCP remoto en producción, no es un detalle de changelog: el piso se movió debajo de ti.
El spec MCP 2026-07-28 se vuelve stateless: SEP-2575 elimina el handshake initialize/initialized, así que la versión del protocolo, el client info y las capabilities viajan en _meta en cada request. Tu servidor remoto abandona las sesiones sticky y corre detrás de un load balancer round-robin. Tasks pasa a extensión; tasks/list desaparece; el código -32002 cambia a -32602. El final sale el 28 de julio de 2026.
La consecuencia de cabecera es operativa: tu servidor MCP remoto ya no necesita sesiones sticky, ni un session store compartido, ni deep-packet-inspection en el gateway. Corre detrás de un load balancer round-robin común y corriente. Eso es enorme para cualquiera que haya peleado con afinidad de sesión en un cluster.
Este post NO es un “qué es MCP” — para eso ya escribí la intro de MCP y APIs sobre la que se construye todo esto, y los fundamentos de agentes de IA. Esto es el mapa de migración: qué reescribir, qué se rompe y cuándo.
Y de una vez la parte honesta: hay una ventana de validación de 10 semanas para los implementadores de SDKs y clientes, más un runway de deprecación de 12 meses que llega hasta ~mediados de 2027. Así que planea la migración — no es una emergencia. Las fuentes están en el blog de MCP — Release Candidate 2026-07-28 y en modelcontextprotocol.io.
¿Por qué el MCP stateless cambia todo tu despliegue?
El corazón del cambio es SEP-2575. Vale la pena entender qué hacía el handshake viejo para ver por qué quitarlo cambia tu arquitectura entera.
Antes (spec basado en sesiones): el cliente y el servidor hacían un handshake initialize / initialized UNA sola vez al conectar. En ese intercambio viajaban la versión del protocolo, el client info y las client capabilities. A partir de ahí mantenían una sesión con estado durante toda la conexión. Todo lo que el servidor sabía del cliente vivía en esa sesión.
Después (SEP-2575): ese estado de conexión se mueve a _meta en CADA request. La versión del protocolo, el client info y las client capabilities ahora viajan en cada llamada. No hay sesión por conexión que mantener, porque cada request se describe a sí mismo.
El pago en infraestructura es concreto: sin sesiones sticky, sin session store compartido, sin deep-packet-inspection en el gateway. El servidor puede sentarse detrás de un load balancer round-robin común y rutear por un header Mcp-Method. Y hay una ganancia de caché: los clientes pueden cachear tools/list por todo el tiempo que permita el ttlMs del servidor, así que cualquier instancia puede responder un discovery cacheado sin re-hacer handshake.
Así se ve un request cargando su propio estado en _meta (ilustrativo — la forma exacta depende del SDK/spec):
{
"jsonrpc": "2.0",
"id": 42,
"method": "tools/call",
"params": {
"name": "emitir_cfdi",
"arguments": { "rfc": "XAXX010101000" },
"_meta": {
"protocolVersion": "2026-07-28",
"clientInfo": { "name": "nixbly-agent", "version": "1.4.0" },
"capabilities": { "tasks": {} }
}
}
}
Fíjate: no hubo initialize antes de esto. El request llega frío a cualquier instancia y trae todo lo que el servidor necesita para atenderlo.
Mi opinión, etiquetada como tal: este es el cambio que vuelve aburrido operar MCP remoto — y aburrido es exactamente lo que quieres en producción. El escalado horizontal stateless es el desbloqueo que la mayoría de los equipos realmente necesitaba; las sesiones sticky eran un impuesto que pagábamos sin querer.
Spec con sesiones (antes)
- Handshake initialize/initialized al conectar
- Sesión con estado por conexión
- Sesiones sticky obligatorias
- Session store compartido entre instancias
- Gateway con deep-packet-inspection
Spec stateless 2026-07-28
- _meta en cada request (sin handshake)
- Cada request se describe a sí mismo
- Load balancer round-robin común
- Sin session store compartido
- tools/list cacheable por ttlMs
¿Cómo se ve el ciclo de vida de un request stateless?
Para rutear bien conviene visualizar el ciclo. En el modelo stateless es directo: el cliente manda _meta (versión del protocolo + client info + capabilities) junto con el método → CUALQUIER instancia del servidor lo atiende → el servidor responde. No hay paso previo.
Como cada request se describe a sí mismo, el load balancer puede rutear round-robin sobre el header Mcp-Method sin afinidad de sesión ni pinning a una instancia. El discovery es cacheable: el cliente cachea tools/list según el ttlMs del servidor, así que un discovery repetido ni siquiera toca un handshake nuevo.
Contrasta con el loop viejo: antes la primera instancia retenía la sesión, así que cada request posterior tenía que aterrizar en la misma caja o re-jugar el handshake. Si esa caja moría, el cliente reconectaba desde cero.
Un boceto del request cargando _meta y Mcp-Method (ilustrativo). Nota: en el transporte Streamable HTTP la versión del protocolo también puede viajar como header MCP-Protocol-Version, así que confirma la forma exacta contra el ejemplo del spec:
curl -s https://mcp.example.com/rpc \
-H "Mcp-Method: tools/call" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "emitir_cfdi",
"_meta": {
"protocolVersion": "2026-07-28",
"clientInfo": { "name": "nixbly-agent", "version": "1.4.0" },
"capabilities": { "tasks": {} }
}
}
}'
El header Mcp-Method deja que el load balancer rutee sin abrir el body. Eso es lo que mata la necesidad de deep-packet-inspection.
Tasks ahora es una extensión: ¿cuándo la usas?
Aquí hay un cambio de estatus importante. Tasks era una feature experimental del core en el spec 2025-11-25. En 2026-07-28 pasa a ser una extensión — no es core, es opt-in, ya no está horneada en el protocolo.
La mecánica: un servidor puede responder un tools/call con un task handle. El cliente luego lo maneja con tasks/get, tasks/update y tasks/cancel. La creación de la tarea es dirigida por el servidor — el cliente no crea tareas, las recibe.
Y un detalle breaking que conviene marcar aquí también: tasks/list fue REMOVIDO. No construyas sobre él.
Es ideal para trabajo de larga duración. Piensa en un batch de CFDI — emitir muchas facturas a través de un PAC — o una reconciliación de Stripe que tarda minutos. En vez de mantener un request abierto esperando, regresas un handle y dejas que el cliente haga polling con tasks/get. Esto se conecta directo con correr infra de agentes en producción: los jobs largos no deberían bloquear conexiones.
Un tools/call que regresa un task handle, y el poll del cliente (ilustrativo — los nombres de campo exactos dependen del SDK):
// Respuesta del servidor a tools/call: un task handle
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"task": {
"id": "task_cfdi_batch_9f3",
"status": "working",
"pollInterval": 2000
}
}
}
// El cliente hace polling con tasks/get
{
"jsonrpc": "2.0",
"id": 8,
"method": "tasks/get",
"params": {
"taskId": "task_cfdi_batch_9f3",
"_meta": { "protocolVersion": "2026-07-28" }
}
}
Nota vendor-neutral: el patrón es el punto. Funciona igual contra cualquier PAC o cualquier procesador de pagos — no depende del proveedor. El servidor te dice “esto va largo, aquí tienes un handle”, y el cliente decide cuándo preguntar.
¿Y las MCP Apps y la nueva autorización?
Dos features aditivas más, ambas pensadas para builders.
MCP Apps (SEP-1865): los servidores ahora pueden enviar interfaces HTML interactivas que los hosts renderizan en un iframe sandboxed. Las tools declaran sus templates de UI por adelantado, así que el host puede precargarlos (prefetch), cachearlos y hacerles security-review antes de renderizarlos. Para un builder esto significa que puedes mandar una interfaz real — un panel de confirmación de pago o un preview de factura — dentro del host, en vez de aventarle JSON crudo al modelo y cruzar los dedos a que lo presente bien.
Autorización: se endureció para alinearse más de cerca con OAuth y OpenID Connect. Menos shims de auth caseros, más flujos estándar. Eso ataca el riesgo de confused deputy: alinear con OAuth/OIDC vuelve más limpio acotar el servidor a los privilegios del usuario real. Pero ojo — la auth sigue viviendo en tu API, no en el protocolo. MCP estandariza el flujo; tú sigues siendo responsable de scopes y permisos reales.
Mantén ambas cosas vendor-neutral en tu cabeza: son patrones, no productos.
¿Qué breaking changes te van a morder?
Aquí van con nombres y códigos exactos. Esto es lo que vas a tener que grepear en tu código.
tasks/listfue REMOVIDO. Cualquier cliente o servidor que dependa de él se rompe. Reescribe alrededor detasks/get/tasks/update/tasks/cancel.- Roots, Sampling y Logging están DEPRECADOS. Siguen funcionando durante el runway, pero planea moverte de ellos.
- El código de error “resource not found” se mueve del no-estándar
-32002al estándar JSON-RPC-32602. Actualiza cualquier código que haga match sobre el número viejo. - Migras DESDE el spec con estado / basado en sesiones (el handshake
initialize+ las sesiones). Esa es la superficie que estás reescribiendo.
Y la política de deprecación, exacta: las features deprecadas siguen funcionando en toda versión del spec publicada dentro de los 12 meses posteriores al 28 de julio de 2026 — un runway hasta mediados de 2027 como mínimo.
¿Cómo migras sin romper tu agente?
El plan ordenado. Hazlo en este orden y no rompes nada en el camino.
Paso 1 — Lee el RC contra tu servidor. Haz inventario de dónde dependes del handshake initialize, de sesiones, de tasks/list, de Roots/Sampling/Logging y del -32002. Esto es un grep, no una adivinanza.
Paso 2 — Mueve el estado de conexión a _meta por request. La versión del protocolo, el client info y las capabilities ahora viajan en cada llamada. Adapta tu handler para leerlos de _meta en vez de esperar un handshake previo.
Paso 3 — Quita las sesiones sticky / el session store compartido. Deja que cualquier instancia responda; rutea round-robin sobre Mcp-Method; cachea tools/list según ttlMs. Aquí es donde simplificas tu infra.
Paso 4 — Adopta la extensión Tasks para jobs largos (batch de CFDI, reconciliación de Stripe). Regresa un task handle y deja que el cliente haga polling con tasks/get.
Paso 5 — Arregla los breaking changes. Quita el uso de tasks/list, migra fuera de Roots/Sampling/Logging, cambia -32002 por -32602.
Paso 6 — Valida en la ventana de 10 semanas. Se espera que los SDKs Tier 1 publiquen soporte dentro de ella; prueba la interoperabilidad cliente+servidor antes de que aterrice el final.
La honestidad del timeline: 10 semanas de validación para mantenedores de SDKs e implementadores de clientes, más 12 meses de runway de deprecación hasta ~mediados de 2027. Así que planea la migración, no la trates como emergencia.
- Lee el RC contra tu servidorinventaría initialize, sesiones, tasks/list, Roots/Sampling/Logging, -32002
- Mueve el estado de conexión a _meta por requestprotocolVersion, clientInfo y capabilities en cada llamada
- Quita sticky sessions; rutea round-robincualquier instancia responde; cachea tools/list por ttlMs
- Adopta Tasks para jobs largosregresa un task handle, el cliente hace polling con tasks/get
- Arregla los breaking changesfuera tasks/list, fuera Roots/Sampling/Logging, -32002 a -32602
- Valida en la ventana de 10 semanasprueba interoperabilidad cliente+servidor antes del final
FAQ: migrar al spec MCP stateless
¿Tengo que migrar para el 28 de julio de 2026? No. Las features deprecadas siguen funcionando en toda versión del spec publicada dentro de los 12 meses de esa fecha — un runway hasta ~mediados de 2027. Planéalo, no entres en pánico.
¿Qué reemplaza exactamente el handshake initialize?
SEP-2575. La versión del protocolo, el client info y las capabilities viajan en _meta en cada request, así que no hay sesión de conexión.
¿De verdad mi servidor remoto puede correr detrás de un load balancer común ahora?
Sí. Sin sesiones sticky, sin session store compartido; rutea round-robin sobre el header Mcp-Method y cachea tools/list según ttlMs.
¿Tasks desapareció?
No. Pasó de core experimental a extensión. Usa tasks/get / tasks/update / tasks/cancel; tasks/list fue removido; la creación de la tarea la dirige el servidor con un task handle desde tools/call.
¿Cuál es el cambio de código de error que no me puedo saltar?
“resource not found” se mueve de -32002 al estándar -32602. Actualiza cualquier código que haga match sobre el número viejo.
¿Qué está deprecado que probablemente estoy usando? Roots, Sampling y Logging están deprecados — siguen funcionando durante el runway, pero planea moverte de ellos.
Planea la migración, no entres en pánico
El modelo de una sola respiración: MCP se vuelve stateless (las capabilities en _meta por request), Tasks pasa a extensión, las MCP Apps agregan UIs en iframe sandboxed, la auth se alinea a OAuth/OIDC, y hay un puñado de breaking changes que limpiar.
El desbloqueo de infra es el premio real: servidores stateless detrás de un load balancer round-robin, con discovery cacheable. Eso es operación aburrida, y aburrido es bueno.
Tranquilo con los tiempos: 10 semanas de validación más 12 meses de runway de deprecación hasta mediados de 2027 — hay tiempo para hacerlo bien.
El primer movimiento concreto: lee el RC del 28 de julio de 2026, grepea tu servidor por el handshake initialize / tasks/list / -32002, y empieza a mover el estado de conexión a _meta. Si quieres más contexto, tengo más guías de IA sobre cómo se arma todo esto.
Esto es la misma plomería que corre bajo los agentes en producción en Nixbly. El protocolo cambió; el trabajo de integración es directo si lo planeas en orden.