Qué rompe la nueva especificación de MCP en tu servidor
Índice de contenidos
- Puntos clave
- Qué significa que el núcleo sea ahora sin estado
- Qué viaja ahora en cada petición
- MRTR y cómo pedir datos al usuario sin un flujo abierto
- Por qué una pasarela ya puede autorizar sin leer el cuerpo
- Listas cacheables con ttlMs y cacheScope
- Qué es el marco de extensiones
- Qué queda deprecado y cuándo se retira de verdad
- Qué cambiar en tu servidor y en qué orden
- Qué cambia en la autorización
- En qué estado están los SDK
- Qué deja de ser cierto en lo que publicamos antes
- Preguntas frecuentes
- ¿Tengo que migrar mi servidor MCP ya?
- ¿Quitar la sesión hace mi servidor apátrida por arte de magia?
- ¿Quién gobierna hoy la especificación MCP?
- Conclusión
- Fuentes
La revisión 2026-07-28 convierte MCP en un protocolo sin estado. Desaparecen el intercambio initialize y la cabecera Mcp-Session-Id, y la versión de protocolo y las capacidades del cliente viajan dentro del campo _meta de cada petición. A cambio, Roots, Sampling y Logging quedan deprecados con doce meses de margen.
Tienes un servidor MCP en producción y acaba de salir una revisión que le quita el saludo inicial y la sesión. La especificación 2026-07-28 es la mayor rotura del protocolo desde que existe MCP remoto. Buena parte de lo que se publicó sobre servidores MCP en los dos últimos años describe una arquitectura que esta revisión deroga. Aquí está qué cambia, qué se deprecia y en qué orden tocar tu servidor.
Puntos clave
- El intercambio
initialize/notifications/initializedy la cabeceraMcp-Session-Iddesaparecen. Cada petición se describe a sí misma dentro de_meta. - Roots, Sampling y Logging quedan deprecados. La retirada más temprana es la primera revisión publicada en o después del 2027-07-28.
- Las peticiones del servidor al cliente pasan a resolverse con MRTR: el servidor responde
resultType: "input_required"y el cliente reintenta. Mcp-MethodyMcp-Nameson ahora obligatorias en cada POST, y el servidor debe rechazar con-32020cualquier desajuste entre cabecera y cuerpo.ping,logging/setLevely la reanudación de flujos conLast-Event-IDno se deprecian: se eliminan.
Qué significa que el núcleo sea ahora sin estado
Hasta esta revisión, una conversación MCP empezaba con un initialize, seguía con un notifications/initialized y quedaba anclada a una sesión que el servidor identificaba con la cabecera Mcp-Session-Id. Ese modelo obligaba a que todas las peticiones de un cliente cayeran en la misma instancia, o a compartir el estado de sesión entre instancias.
La revisión 2026-07-28 elimina las dos cosas: el intercambio inicial por SEP-2575 y la cabecera de sesión por SEP-2567. Cada petición lleva ahora su propia versión de protocolo y las capacidades del cliente dentro del campo _meta, con las claves io.modelcontextprotocol/protocolVersion y io.modelcontextprotocol/clientCapabilities. El cliente debería identificarse con io.modelcontextprotocol/clientInfo y el servidor debería devolver io.modelcontextprotocol/serverInfo en el _meta de cada resultado.
El resultado práctico es que cualquier petición puede caer en cualquier instancia detrás de un balanceador por turnos sin almacenamiento compartido. La sesión pegajosa deja de ser un requisito de protocolo.

Este es el arranque que ya no existe. Las tres flechas del diagrama, initialize, su respuesta y initialized, son exactamente lo que la revisión retira.
Conviene leer la letra pequeña. Los responsables del proyecto lo dicen así en el anuncio de la revisión: "Dropping the protocol-level session doesn’t force your application to be stateless. If your server needs to carry state across calls, mint an explicit handle from a tool and have the model pass it back as an argument. We found this works better than session state hidden in the transport – the model can see the handle and thread it between tools."
Qué viaja ahora en cada petición
Una llamada a herramienta con la revisión nueva tiene esta forma:
POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": { "location": "Seattle, WA" },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" },
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}
El servidor sigue teniendo una vía para anunciarse: server/discover, que el servidor debe implementar y que el cliente puede llamar antes de nada para elegir versión por adelantado. La diferencia con el antiguo initialize es que ahora es opcional para quien llama y no abre ninguna sesión.
También se fue el flujo GET independiente. Las notificaciones de cambio se piden con subscriptions/listen, una única respuesta de larga duración a la que el cliente se suscribe por tipo: toolsListChanged, promptsListChanged, resourcesListChanged y resourceSubscriptions. El nivel de registro pasa a ser por petición mediante io.modelcontextprotocol/logLevel en _meta, y el servidor no debe emitir notifications/message para peticiones que no lo pidan.
MRTR y cómo pedir datos al usuario sin un flujo abierto
El patrón Multi Round-Trip Requests (SEP-2322) sustituye a las peticiones que antes iniciaba el servidor. La nota normativa de la especificación no deja margen: "Servers MUST send server-to-client requests (such as roots/list, sampling/createMessage, or elicitation/create) using the MRTR pattern. The previous pattern of server-initiated requests is no longer supported. This is a breaking change."
El mecanismo es un reintento. El servidor responde con resultType: "input_required", un mapa inputRequests con lo que necesita y un requestState opaco. El cliente reúne las respuestas, y reemite la petición original con inputResponses y con ese requestState copiado tal cual. El identificador JSON-RPC debe ser distinto entre el intento y el reintento, porque son peticiones independientes.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "input_required",
"inputRequests": {
"github_login": {
"method": "elicitation/create",
"params": {
"mode": "form",
"message": "Please provide your GitHub username"
}
}
},
"requestState": "AEAD-protected blob"
}
}
Solo tres peticiones admiten esta respuesta: prompts/get, resources/read y tools/call. En cualquier otra, el servidor no debe enviarla.
La parte que más gente va a implementar mal es requestState. La especificación obliga a tratarlo como entrada controlada por un atacante. Si influye en autorización, acceso a recursos o lógica de negocio, hay que protegerlo con HMAC o AEAD y rechazar lo que no verifique. Recomienda además meter dentro el principal autenticado, un tiempo de vida corto y un identificador de la petición de origen, para acotar la reutilización.
Por qué una pasarela ya puede autorizar sin leer el cuerpo
Cada POST del transporte Streamable HTTP debe llevar tres cabeceras: MCP-Protocol-Version, Mcp-Method (copiada de method) y Mcp-Name (copiada de params.name o params.uri, y solo en tools/call, resources/read y prompts/get). Son obligatorias para conformidad, por SEP-2243.
El objetivo declarado es que las pasarelas, los limitadores de tasa y los cortafuegos de aplicación enruten y midan sobre cabeceras en vez de abrir el JSON. Hay además una extensión, x-mcp-header, que permite al servidor marcar parámetros de una herramienta para que el cliente los refleje en cabeceras Mcp-Param-{Nombre}. Es opcional para el servidor pero el cliente debe admitirla, solo vale para tipos primitivos y los valores no ASCII se codifican con el centinela =?base64?…?=.
El contrapeso es que esas cabeceras no son gratis. Un servidor que procesa el cuerpo debe rechazar con 400 Bad Request y error -32020 (HeaderMismatch) cualquier petición cuya cabecera no coincida con el cuerpo. Así, un balanceador y el servidor no acaban decidiendo sobre fuentes de verdad distintas.
Y la propia especificación avisa a los intermediarios de que comprueben que MCP-Protocol-Version corresponde a una versión que exige esa validación antes de fiarse de la cabecera. Enrutar por cabecera sin esa comprobación es un agujero, no un atajo.
Listas cacheables con ttlMs y cacheScope
Los resultados de tools/list, prompts/list, resources/list, resources/read y resources/templates/list incorporan dos campos requeridos por SEP-2549 mediante la nueva interfaz CacheableResult. ttlMs es una pista de frescura en milisegundos que permite al cliente cachear en vez de sondear. cacheScope vale "public" o "private" y decide si un intermediario compartido puede guardar la respuesta.
Hay un detalle que pasa desapercibido y que importa si pagas tokens: el servidor debería devolver las herramientas de tools/list en un orden determinista. Un catálogo que se reordena en cada llamada invalida la caché de prompt del modelo aguas arriba. Ordenarlo es gratis y se nota en la factura.
Qué es el marco de extensiones
Las extensiones dejan de ser un apaño y pasan a tener identificador con prefijo de proveedor, con el formato {prefijo}/{nombre}. Las oficiales usan io.modelcontextprotocol. Hoy son cuatro: MCP Tasks, MCP Apps, OAuth Client Credentials y Enterprise-Managed Authorization.
Tasks es la que más afecta a quien ya tenía código: sale del núcleo experimental a la extensión io.modelcontextprotocol/tasks, cambia el bloqueante tasks/result por un tasks/get de sondeo, añade tasks/update para entrada del cliente y elimina tasks/list (SEP-2663).
Las extensiones se anuncian en el campo extensions de las capacidades, evolucionan por su cuenta y están siempre desactivadas por defecto: requieren activación explícita del desarrollador. Si tu cliente no admite una extensión, quien la ofrece debe degradar a comportamiento del núcleo o rechazar la petición.
Qué queda deprecado y cuándo se retira de verdad
La revisión estrena una política formal de ciclo de vida (SEP-2596) con tres estados y una ventana mínima de doce meses. El registro de funciones deprecadas es la referencia normativa, y sus fechas no coinciden con el resumen del anuncio:
| Función | Deprecada en | Migración | Retirada más temprana |
|---|---|---|---|
| Roots | 2026-07-28 |
Pasar ficheros o directorios como parámetros de herramienta, URIs de recurso o configuración | Primera revisión publicada en o después del 2027-07-28 |
| Sampling | 2026-07-28 |
Integrar directamente con la API del proveedor de LLM | Primera revisión publicada en o después del 2027-07-28 |
| Logging | 2026-07-28 |
Escribir a stderr en stdio, o usar OpenTelemetry |
Primera revisión publicada en o después del 2027-07-28 |
| Registro dinámico de clientes | 2026-07-28 |
Client ID Metadata Documents (CIMD) | Primera revisión publicada en o después del 2027-07-28 |
| Transporte HTTP+SSE | 2025-03-26 |
Streamable HTTP | Tres meses después de que SEP-2596 alcance Final |
Esa última fila merece un aviso. El anuncio de la revisión habla de un año de margen para HTTP+SSE, mientras que el registro normativo le da tres meses desde que la política llegue a Final. Cuando el blog y la especificación no coinciden, manda la especificación: HTTP+SSE es la deprecación con la salida más corta del lote, no la más larga.
Y hay una categoría aparte, la de lo que no se deprecia sino que se elimina sin ventana: ping, logging/setLevel, notifications/roots/list_changed, resources/subscribe, resources/unsubscribe, el flujo GET independiente y la reanudación con Last-Event-ID. Si tu respuesta larga se corta, ahora se pierde la petición entera y el cliente debe reemitirla con un identificador nuevo.
Qué cambiar en tu servidor y en qué orden
- Inventaría el uso de sesión. Busca cada punto donde guardas algo indexado por
Mcp-Session-Idy decide si pasa a un identificador explícito devuelto por una herramienta o a tu propio almacén. - Implementa
server/discover. Es lo único que el servidor está obligado a exponer de la parte nueva, y te deja anunciar versiones soportadas mientras conviven clientes viejos y nuevos. - Añade las cabeceras y su validación.
MCP-Protocol-Version,Mcp-MethodyMcp-Name, con rechazo400y-32020si no cuadran con el cuerpo. - Convierte Sampling, Elicitation y Roots a MRTR. Es el cambio con más código detrás, porque tu herramienta pasa de esperar una respuesta a terminar y volver a arrancar con estado firmado.
- Rellena
ttlMsycacheScopey ordenatools/listde forma determinista. - Ajusta los códigos de error.
HeaderMismatchpasa de-32001a-32020,MissingRequiredClientCapabilityde-32003a-32021,UnsupportedProtocolVersionde-32004a-32022, y el recurso no encontrado de-32002a-32602. - Cambia el registro por
stderro por OpenTelemetry, y quita Roots y Sampling de las capacidades nuevas.
Qué cambia en la autorización
Tres endurecimientos y una sustitución. El servidor de autorización debería devolver el parámetro iss de RFC 9207 y el cliente debe validarlo contra el emisor registrado antes de canjear el código (SEP-2468). Eso cierra el hueco de confusión de servidor de autorización.
El cliente debe indicar application_type en el registro dinámico (SEP-837). Es la razón por la que tantos flujos OAuth de aplicaciones de escritorio y de línea de comandos fallaban con un error de redirect_uri en localhost. Y las credenciales quedan ligadas al emisor que las creó: hay que indexarlas por identificador de emisor, no reutilizarlas con otro servidor de autorización y volver a registrarse si cambia (SEP-2352).
La sustitución es el registro dinámico de clientes de RFC 7591, ahora deprecado en favor de los Client ID Metadata Documents. Sigue funcionando por compatibilidad con servidores de autorización que no admitan CIMD, pero es código con fecha de caducidad.
En qué estado están los SDK
Comprobado contra los repositorios el 30 de agosto de 2026:
| SDK | Versión con 2026-07-28 |
Fecha | Estado hoy |
|---|---|---|---|
| TypeScript | @modelcontextprotocol/server y @modelcontextprotocol/client 2.0.0 |
2026-07-27 | Estable. La línea v1 se queda en @modelcontextprotocol/sdk 1.30.0 |
| Python | mcp 2.0.0 |
2026-07-28 | Estable, hoy 2.1.1 (2026-08-25) |
| Go | v1.7.0 | 2026-07-28 | Estable |
| C# | v2.0.0 | 2026-07-28 | Estable, hoy v2.2.0 (2026-08-13) |
| Rust | rmcp 3.0.0 |
2026-07-28 | Estable, hoy 3.1.4 (2026-08-20) |
Dos matices que se repiten mal por ahí. El primero: el anuncio del 28 de julio decía que el SDK de Rust admitía la revisión en beta, y ese mismo día se publicó rmcp 3.0.0 estable. Su README declara que implementa la especificación 2026-07-28 estable manteniendo compatibilidad con 2025-11-25 y anteriores. Citar "Rust en beta" a estas alturas es citar una foto de doce horas.
El segundo: la v1 de TypeScript no muere, recibe correcciones y parches de seguridad durante al menos seis meses desde la salida de la v2.
Qué deja de ser cierto en lo que publicamos antes
Este sitio tiene seis artículos sobre MCP y el más reciente es de mayo de 2026, así que todos describen el protocolo anterior. Merece la pena señalar qué frase concreta caduca en cada uno.
En el balance de madurez de MCP en 2025 escribimos que MCP es un protocolo de sesión con estado, recursos, notificaciones y permisos. Esa diferencia estructural era lo que había permitido el ecosistema. La revisión 2026-07-28 deroga exactamente esa frase: el núcleo es petición y respuesta sin estado.
La guía completa de MCP en 2026 describe el arranque de un servidor local como un intercambio de handshake antes de descubrir herramientas. Con la revisión nueva no hay handshake: el descubrimiento es una llamada opcional y cada petición se describe sola.
Construir un servidor MCP propio menciona que el cliente puede ofrecer al servidor muestreo, roots y elicitación. Las tres siguen existiendo, pero ya no se piden como antes y dos de ellas están deprecadas: si empiezas hoy, no las adoptes.
Los mapas de ecosistema consolidado y patrones multivendedor siguen siendo válidos en lo que cuentan de adopción. Y la instalación de un servidor MCP local para tu editor sigue funcionando porque stdio cambia mucho menos que HTTP.
Preguntas frecuentes
¿Tengo que migrar mi servidor MCP ya?
No hay obligación. La revisión 2025-11-25 sigue siendo válida y los clientes modernos vuelven al initialize cuando llegan a un servidor antiguo. La presión es de calendario: los deprecados no se retiran antes de la primera revisión publicada en o después del 2027-07-28, así que tienes casi un año para planificarlo.
¿Quitar la sesión hace mi servidor apátrida por arte de magia?
No. La especificación quita el estado del transporte, no de tu aplicación. Si necesitas continuidad entre llamadas, la recomendación de los responsables es emitir un identificador explícito desde una herramienta y que el modelo lo pase como argumento. Así el identificador es visible en el contexto.
¿Quién gobierna hoy la especificación MCP?
Anthropic donó MCP a la Agentic AI Foundation, un fondo dirigido bajo la Linux Foundation, el 9 de diciembre de 2025, junto con goose de Block y AGENTS.md de OpenAI como proyectos fundacionales. En ese momento el proyecto declaraba 97 millones de descargas mensuales de SDK y 10.000 servidores activos.
Conclusión
Si tu servidor MCP habla 2025-11-25 y funciona, no está roto y nadie va a apagarlo mañana. Lo que ha cambiado es que ya hay una fecha: los deprecados salen a partir del 2027-07-28 y el transporte HTTP+SSE tiene un plazo bastante más corto.
La migración que de verdad cuesta es MRTR, porque obliga a partir en dos cualquier herramienta que hoy pregunte algo a mitad de ejecución. Empieza por ahí y deja el orden de tools/list y los códigos de error para el final. El crecimiento del protocolo respalda la molestia: de 97 millones de descargas mensuales en diciembre de 2025 a cerca de 500 millones en julio de 2026. TypeScript y Python superan cada uno los mil millones acumulados.
The English version of this article is at What the new MCP specification breaks in your server.
Fuentes
- Blog de Model Context Protocol, la especificación 2026-07-28
- Model Context Protocol, cambios clave de la revisión 2026-07-28
- Model Context Protocol, registro de funciones deprecadas
- Model Context Protocol, patrón Multi Round-Trip Requests
- Model Context Protocol, transporte Streamable HTTP
- rmcp 3.0.0, notas de la version del SDK de Rust
- RFC 9207, identificacion del servidor de autorizacion en OAuth 2.0
- Linux Foundation, creacion de la Agentic AI Foundation