Cambios en la especificación de Model Context Protocol: qué hay de nuevo y qué se rompe

La revisión 2026-07-28 de Model Context Protocol convierte MCP en un protocolo sin estado: sin handshake de initialize, sin Mcp-Session-Id, con nuevas cabeceras de enrutamiento, listas cacheables y un patrón de reintento para la elicitación. Esta guía recoge todos los cambios, qué se rompe y el orden para migrar.

Cambios en la especificación de Model Context Protocol: qué hay de nuevo y qué se rompe
Cristian Da Conceicao
Fundador de Picasso IA

Si tu servidor MCP recuerda algo entre dos peticiones, la versión más reciente del protocolo acaba de convertir ese hábito en un error. La especificación 2026-07-28 elimina el handshake initialize, borra la cabecera Mcp-Session-Id y reconstruye MCP como un protocolo sencillo de petición y respuesta, en el que cada mensaje lleva lo que el servidor necesita para responderlo. Algunos cambios son pequeños: una cabecera aquí, un código de error renumerado allí. Otros romperán un servidor que funcionaba bien la semana pasada.

Este artículo ordena los cambios según lo mucho que duelen, usando como fuente de referencia el changelog oficial y la entrada de anuncio. Encontrarás los nombres exactos de los campos, los números de SEP, una tabla con lo que se elimina frente a lo que solo queda obsoleto y un orden de migración que puedes terminar en un solo sprint.

💡 Versión corta: las sesiones han desaparecido, las peticiones iniciadas por el servidor ahora usan un patrón de reintento, los resultados de las listas se pueden cachear, la autorización es más estricta y las tareas viven en una extensión. Roots, Sampling y Logging siguen funcionando, pero durante doce meses como mínimo.

Por qué esta revisión es diferente

Las revisiones anteriores añadían funciones. Esta elimina supuestos. El paso de una conexión con estado y bidireccional a un intercambio sin estado afecta a cada transporte, cada SDK y cada gateway que se sitúa delante de un servidor.

Páginas impresas de una especificación con notas en azul al margen sobre un escritorio de roble

Cinco revisiones, una sola dirección

VersiónCambio principal
2024-11-05Arquitectura cliente-servidor, JSON-RPC 2.0, herramientas, recursos, prompts, stdio y HTTP con SSE
2025-03-26Autorización basada en OAuth 2.1, Streamable HTTP sustituye a HTTP+SSE, anotaciones de herramientas, contenido de audio, procesamiento por lotes en JSON-RPC
2025-06-18Salida estructurada de herramientas, elicitation, enlaces a recursos, servidores clasificados como servidores de recursos OAuth, se elimina el procesamiento por lotes
2025-11-25Búsqueda de metadatos de OpenID Connect, consentimiento incremental de scopes, iconos, Client ID Metadata Documents, tareas experimentales
2026-07-28Núcleo sin estado, sin sesiones, Multi Round-Trip Requests, encabezados de enrutamiento, listas almacenables en caché, marco de extensiones

Lee la columna de la derecha de arriba abajo y la dirección es obvia. Cada revisión aleja MCP de un socket de larga duración, de tipo chat, y lo acerca a algo que un balanceador de carga, una CDN y un entorno serverless pueden gestionar sin tratamiento especial.

La versión en sí ya tiene soporte donde más importa. Los cuatro SDK de nivel 1 (TypeScript, Python, Go y C#) funcionan con la versión 2026-07-28, y el SDK de Rust la soporta en beta. Los mantenedores admiten que habrá "cierto costo de migración, sobre todo para los desarrolladores que dependían de los identificadores de sesión", y añaden que las pruebas tempranas hicieron el proceso más fácil.

El núcleo sin estado

Dos propuestas hacen la mayor parte del daño: SEP-2567 elimina las sesiones, y SEP-2575 elimina el handshake y reorganiza cómo fluyen las notificaciones.

Sin handshake, sin ID de sesión

La petición initialize y notifications/initialized han desaparecido, y también Mcp-Session-Id. Los endpoints de lista (tools/list, resources/list, prompts/list) ya no pueden variar según la conexión, porque ya no existe una identidad de conexión en la que basarse. Cuando una tool necesita estado entre llamadas, el servidor crea un identificador explícito, como un ID de carrito o un ID de espacio de trabajo, y el modelo lo devuelve como un argumento normal de la tool.

En lugar del handshake, cada petición lleva su propio contexto en _meta. Este esbozo muestra la forma, no es una copia de la especificación:

{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "tools/call",
  "params": {
    "name": "search_docs",
    "arguments": { "query": "stateless transport" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "example-client", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": { "elicitation": {} }
    }
  }
}

Una discrepancia de versión devuelve UnsupportedProtocolVersionError, y los servidores se identifican en cada resultado mediante io.modelcontextprotocol/serverInfo.

⚠️ El estado oculto es el riesgo real. Los mapas en memoria indexados por ID de sesión, los niveles de log por conexión y las listas de suscripciones por conexión dejan de funcionar. Son fáciles de pasar por alto en una búsqueda de código porque rara vez contienen la palabra "session".

Anunciar versiones y capacidades. Ahora los servidores deben implementar un nuevo RPC en el espacio de nombres server/ que informa de sus versiones de protocolo, capacidades e identidad admitidas. Los clientes pueden llamarlo primero para elegir una versión de antemano, y en STDIO funciona como una sonda de compatibilidad con versiones anteriores. El changelog lo menciona justo debajo de la eliminación del handshake, así que consulta la página del esquema para conocer el nombre exacto del método y la forma de la respuesta antes de integrarlo.

Qué sustituye al stream GET

El endpoint GET de HTTP, resources/subscribe, y resources/unsubscribe se sustituyen por una sola llamada: subscriptions/listen. Abre un único stream de respuesta POST de larga duración, y los clientes se suscriben a los tipos de notificación que les interesan:

  • toolsListChanged
  • promptsListChanged
  • resourcesListChanged
  • resourceSubscriptions

El servidor confirma y etiqueta cada notificación con io.modelcontextprotocol/subscriptionId. Los mensajes con ámbito de petición, como notifications/progress y notifications/message, se quedan en el stream de respuesta de la petición a la que pertenecen.

Hay tres eliminaciones más: ping, logging/setLevel y notifications/roots/list_changed. El nivel de log ahora se define por petición mediante io.modelcontextprotocol/logLevel, y un servidor no debe emitir notifications/message para una petición que no lo incluya.

También desaparece la reanudabilidad de SSE. No hay cabecera Last-Event-ID ni IDs de evento, así que si un stream de respuesta se corta, la petición en curso se pierde y el cliente debe volver a enviarla con un nuevo ID de petición. Una llamada a una tool que tarda noventa segundos en una conexión inestable ahora necesita la extensión de tareas, no la suerte.

Carteros clasificando sobres autocontenidos en casillas de madera

Multi Round-Trip Requests explicado

Por qué tuvieron que irse las peticiones del servidor

Antes de esta revisión, un servidor podía enviar elicitation/create, sampling/createMessage o roots/list en mitad de una llamada por un stream abierto. Eso ataba el cliente a una única instancia del servidor y exigía balanceo con sesión fija o almacenamiento compartido.

Multi Round-Trip Requests (SEP-2322) sustituye ese diseño. La especificación lo dice sin rodeos: los servidores deben enviar estas peticiones mediante el patrón MRTR, el patrón antiguo ya no tiene soporte y esto es un cambio que rompe la compatibilidad. Además, cada resultado lleva ahora un campo resultType obligatorio. Un valor es input_required, el otro marca un resultado normal y terminado, y los clientes tratan un campo ausente de un servidor antiguo como el tipo normal.

Cómo funciona el bucle de reintento

El flujo tiene cuatro pasos:

  1. El cliente envía una petición normal, por ejemplo tools/call.
  2. El servidor no puede terminar, así que devuelve un InputRequiredResult con lo que necesita.
  3. El cliente reúne las respuestas del usuario o de otra fuente.
  4. El cliente reintenta la petición original con inputResponses adjunto, usando un ID JSON-RPC nuevo.
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resultType": "input_required",
    "inputRequests": {
      "github_login": {
        "method": "elicitation/create",
        "params": {
          "mode": "form",
          "message": "Please provide your GitHub username",
          "requestedSchema": {
            "type": "object",
            "properties": { "name": { "type": "string" } },
            "required": ["name"]
          }
        }
      }
    },
    "requestState": "AEAD-protected blob"
  }
}

Solo tres peticiones del cliente pueden recibir este resultado: prompts/get, resources/read y tools/call. Cada InputRequiredResult necesita al menos uno de inputRequests o requestState, y un servidor no debe pedir una capacidad que el cliente nunca declaró. Como el reintento le indica al cliente cómo terminaron las cosas, se eliminan la notificación de finalización de la elicitación y el campo elicitationId de 2025-11-25.

Trata requestState como entrada de usuario

La cadena requestState pasa por el cliente, así que la especificación indica tratarla como controlada por un atacante. Si influye en la autorización, en el acceso a recursos o en la lógica de negocio, protege su integridad con un HMAC o AEAD y rechaza cualquier valor que no supere la verificación.

Para la protección frente a repetición, incluye tres cosas dentro del payload protegido y verifica cada una al recibirlo:

  • el principal autenticado
  • una caducidad corta
  • un identificador de la petición de origen, como el nombre del método y un resumen de sus parámetros principales

Estas medidas limitan la repetición, pero no garantizan un uso único. El canje de un solo uso debe aplicarse en el servidor.

Dos pares de manos pasando un formulario sujetapapeles por encima de un mostrador de madera

Cabeceras, caché y códigos de error

Cabeceras de enrutamiento para gateways

SEP-2243 exige Mcp-Method y Mcp-Name en cada petición POST de Streamable HTTP. El objetivo es operativo: los gateways y los WAF ahora pueden enrutar, medir y limitar el tráfico MCP sin analizar el cuerpo JSON. Las cabeceras personalizadas también pueden derivarse de los parámetros de la tool mediante x-mcp-header, y una discrepancia entre cabecera y cuerpo aparece como un error HeaderMismatch, que ahora existe en el esquema.

💡 Si tienes un gateway de API delante de un servidor MCP, este es el cambio que antes da resultados. Escribe reglas sobre las dos cabeceras en lugar de expresiones regulares sobre los cuerpos de las peticiones.

Switch de red con cables ethernet etiquetados a mano en primer plano macro

Pistas de caché y códigos de error

SEP-2549 añade una interfaz CacheableResult. Los resultados de tools/list, prompts/list, resources/list, resources/read y resources/templates/list deben incluir ahora:

  • ttlMs: una pista de frescura en milisegundos, para que los clientes puedan cachear en lugar de sondear
  • cacheScope: "public" o "private", que indica a los intermediarios compartidos si pueden almacenar la respuesta

Ambas complementan las notificaciones listChanged existentes. Los servidores también deben devolver las tools en un orden determinista, lo que ayuda a las cachés de los clientes y aumenta las tasas de acierto de la caché de prompts en el lado del modelo.

Cajón de un catálogo de tarjetas de biblioteca abierto con fichas fechadas

Los códigos de error también cambiaron, con una nueva política de asignación: de -32000 a -32019 sigue siendo definido por la implementación, y de -32020 a -32099 queda reservado para la especificación.

ErrorCódigo antiguoCódigo nuevo
Recurso no encontrado-32002-32602 (Invalid Params)
HeaderMismatch-32001-32020
MissingRequiredClientCapability-32003-32021
UnsupportedProtocolVersion-32004-32022

Si un cliente se basa en los números antiguos, interpretará mal los errores nuevos.

La autorización se vuelve más estricta

Comprobaciones del emisor y credenciales vinculadas

Tres cambios endurecen el flujo de OAuth:

  • SEP-2468: los servidores de autorización deben incluir el parámetro iss de RFC 9207, y los clientes deben validar un iss presente contra el emisor registrado antes de canjear el código de autorización.
  • SEP-2352: las credenciales de cliente quedan vinculadas al servidor de autorización que las emitió. Guárdalas por identificador de emisor, nunca las reutilices con otro servidor y regístrate de nuevo cuando cambie el servidor.
  • SEP-837: los clientes deben enviar un application_type adecuado durante el Dynamic Client Registration, lo que evita conflictos de URI de redirección de OpenID Connect en localhost.

El registro dinámico está de salida

El protocolo OAuth 2.0 Dynamic Client Registration (RFC 7591) queda obsoleto en favor de Client ID Metadata Documents. Sigue funcionando para los servidores de autorización que no tienen la opción más reciente, pero el anuncio dice que se eliminará en una versión posterior de la especificación. Planifica el cambio ahora, en lugar de hacerlo durante un incidente.

Mano sosteniendo una tarjeta de identificación frente a un lector junto a una puerta de cristal

Tareas, esquemas y extensiones

Las tareas pasan a una extensión

Las tareas experimentales salieron del protocolo básico y se convirtieron en la extensión oficial io.modelcontextprotocol/tasks (SEP-2663). El rediseño sustituye el método bloqueante tasks/result por un sondeo con tasks/get, añade tasks/update para que un cliente pueda enviar datos a una tarea en ejecución y elimina tasks/list. Ahora los servidores pueden devolver un handle de tarea sin que el cliente lo pida.

Ese último punto importa en trabajos largos. Un generador de informes lento ya no tiene que mantener abierto un stream de respuesta; devuelve un handle, el cliente sondea y una conexión caída no cuesta nada.

Comandas de pedido en una barra de cocina de acero inoxidable con un chef al fondo

Esquemas más flexibles y nuevos espacios de extensión

Adiciones más pequeñas que merecen una línea cada una:

  • inputSchema y outputSchema pueden usar cualquier construcción de JSON Schema 2020-12, y structuredContent puede ser cualquier valor JSON (SEP-2106), con nuevas reglas para la resolución de $ref y límites de recursos en las construcciones de composición.
  • ClientCapabilities y ServerCapabilities ganan un campo extensions para funciones opcionales más allá del núcleo.
  • El contexto de trazas de OpenTelemetry viaja en _meta a través de traceparent, tracestate y baggage (SEP-414).

La publicación de Cloudflare sobre la versión indica que su endpoint /mcp acepta tanto las nuevas peticiones sin estado como los clientes de 2025, lo que es un patrón sensato para cualquiera que tenga un servidor público.

Qué se rompe y cómo arreglarlo

Funciones eliminadas

Estas fallarán directamente frente a un par 2026-07-28:

EliminadoSustituto
initialize y notifications/initializedCampos _meta por petición
Cabecera Mcp-Session-IdHandles creados por el servidor en los argumentos de la tool
Endpoint GET de HTTP, resources/subscribe, resources/unsubscribesubscriptions/listen
ping, logging/setLevel, notifications/roots/list_changedlogLevel por petición en _meta
Reanudabilidad de Last-Event-IDVolver a emitir la petición, o usar tareas
tasks/list y tasks/result bloqueanteSondeo con tasks/get y tasks/update
elicitation/create, sampling/createMessage, roots/list iniciados por el servidorInputRequiredResult y inputResponses

Funciones obsoletas

Obsoleto no es eliminado. Estas funciones siguen funcionando al menos durante doce meses según la nueva política de ciclo de vida de funciones (SEP-2596), que define los estados Active, Deprecated y Removed y un registro público:

ObsoletoAlternativa sugerida
Roots (SEP-2577)Parámetros de tool, URI de recursos o configuración del servidor
Sampling (SEP-2577)Llamar directamente a la API del proveedor de LLM
Logging (SEP-2577)Escribir en stderr, o usar OpenTelemetry
Transporte HTTP+SSEStreamable HTTP
Valores includeContext "thisServer" y "allServers""none" u omitir el campo
Dynamic Client RegistrationClient ID Metadata Documents

Algunas publicaciones meten Roots, Sampling y Logging entre las eliminaciones. El texto de la especificación dice obsoleto, así que trátalos como un punto del calendario, no como una caída del servicio. Solo ping y logging/setLevel han desaparecido de verdad.

Calendario de pared con fechas marcadas en círculo con lápiz rojo

Un orden de migración que funciona

  1. Actualiza primero el SDK. Pasa a una versión de nivel 1 que soporte 2026-07-28 y lee sus notas de migración antes de tocar tu propio código.
  2. Busca el estado de sesión. Busca Mcp-Session-Id y cualquier mapa indexado por conexión. Sustituye cada uno por un handle explícito que se pase como argumento de la tool.
  3. Acepta ambas generaciones. Sirve clientes antiguos y nuevos desde el mismo endpoint durante la transición, como hace Cloudflare.
  4. Reescribe las llamadas iniciadas por el servidor. Convierte cada llamada de elicitación, sampling y roots en un InputRequiredResult con un requestState firmado.
  5. Añade los campos de caché. Devuelve ttlMs y cacheScope en los resultados de lista y lectura, y ordena las listas de tools de forma determinista.
  6. Actualiza las reglas del gateway. Enruta según Mcp-Method y Mcp-Name, y después retira las reglas que analizan el cuerpo.
  7. Corrige la autorización. Valida iss, guarda las credenciales por emisor y programa el paso a Client ID Metadata Documents.

Después prueba los casos difíciles: corta un stream de respuesta a mitad de una petición, reproduce un requestState caducado y ejecuta dos instancias del servidor sin enrutamiento con sesión fija. Si las tres se comportan bien, la migración es sólida.

💡 Consejo rápido: pega el código de gestión de sesiones de tu servidor y la sección del changelog de arriba en Claude Sonnet 5 en Picasso IA y pide una lista de todos los puntos en los que el estado se filtra entre peticiones. Revisa tú mismo el resultado, porque un modelo puede pasar por alto un mapa oculto dentro de una función auxiliar.

Crea tus propias imágenes

Los artículos técnicos como este dependen por completo de sus diagramas y sus imágenes de cabecera, y no necesitas un equipo de diseño para producirlos. Picasso IA reúne decenas de modelos de imagen en un solo lugar, así que puedes probar el mismo prompt con varios y quedarte con el mejor resultado.

Prueba Seedream 5 Pro para escenas fotorrealistas, GPT Image 2 para seguir el prompt con precisión, o Ideogram v4 Quality cuando tu imagen necesite texto legible. Describe la escena, elige una relación 16:9 y genera algunas variaciones antes de decidirte.

Espacio de trabajo tranquilo de una mañana de desarrollo con un cuaderno con diagrama y café

Abre Picasso IA, elige un modelo y crea la primera imagen para tu próximo artículo sobre MCP hoy mismo.

Compartir este artículo

Elige tu idioma