Inicio / Artículos

Despliegue de un servidor MCP en EC2 tras el cambio en las especificaciones de sesiones sin estado

Mover un servidor MCP de localhost a EC2: HTTP streamable, nginx y autenticación por token, y qué significan las sesiones sin estado y OAuth 2.1 para una implementación real.

Editor: REACTAPP.TOP11 min de lectura2446 palabras

Fuentes: MCP Servers Explained: A Complete Guide to What I Learned Deploying One to AWS EC2

De localhost a un servidor real

Los tutoriales sobre MCP suelen ser abstractos. Muestran un cliente junto a un servidor, comparan el protocolo con un puerto USB-C o ejecutan un ejemplo de cinco líneas en localhost que nunca sale del portátil del desarrollador. El trabajo real comienza después: una herramienta escrita localmente debe funcionar en un servidor real, detrás de un proxy inverso real, donde un cliente real pueda acceder a ella a través de Internet. Es un problema distinto al que recibe poca atención.

La implementación descrita aquí comienza con un servidor MCP local, lo traslada a una instancia EC2 y lo sirve a través del transporte HTTP de transmisión en flujo, siendo nginx quien exige un token de autenticación de antemano. Funcionó sin problemas. Poco después, el protocolo pasó a estar bajo su gestión. El 28 de julio de 2026, la mayor revisión de la especificación MCP hasta la fecha pasó de versión candidata a versión final, lo que convirtió al protocolo en estatalmente sin estado. Los equipos suelen marcar “soporte MCP” como un único ítem, pero en realidad se divide en tres aspectos: transporte, autenticación y, desde esta actualización, escalabilidad. Una decisión errónea en cualquiera de ellos es lo que diferencia una herramienta de nivel demo de una que merece confianza en entornos de producción.

La cobertura aborda varias cuestiones: qué partes del problema define MCP y cuáles deja sin resolver, por qué el transporte basado en HTTP streamable reemplazó al basado en SSE, cómo nginx y un token de portador exponen un servidor local en EC2, qué cambios supone la reescritura sin estado, por qué un token estático se considera autenticado pero no cumple con los requisitos de autenticación según la especificación, y qué partes del despliegue tuvieron que modificarse para mantenerse al día.

Qué estandariza y qué no MCP

En teoría, el Protocolo de Contexto de Modelo establece una sola cosa: la forma en que una aplicación de IA encuentra e invoca herramientas y lee recursos proporcionados por un proceso de servidor separado, a través de mensajes JSON-RPC transmitidos por un canal de comunicación definido. La lógica de las herramientas, el diseño de los agentes y su despliegue quedan fuera de su alcance. Se trata de un estándar para conectar, no de un marco de trabajo. Anteriormente, cada aplicación de IA que quería acceder a algo como una API interna necesitaba una integración a medida. Con MCP, un único servidor sirve a todos los clientes que cumplan con los requisitos.

Visto de esa manera, queda claro por qué el despliegue supone dificultades. El protocolo describe la estructura de los mensajes pero no indica si el servidor puede ser accesible desde solo una computadora portátil o desde cualquier lugar, si algo lo protege o si es capaz de manejar varios clientes al mismo tiempo. El operador es quien responde a todas esas preguntas.

Por qué el despliegue público es diferente

  • Los servidores locales exponen casi nada, mientras que los públicos exponen mucho. Con una URL pública, el servidor se convierte en una API autenticada como cualquier otra, por lo que el manejo de tokens y la validación de entradas son igualmente importantes.
  • Antes, las reglas relacionadas con las sesiones y el escalado eran poco claras. Un error en las suposiciones podía hacer que el servidor fallara silenciosamente bajo carga concurrente o que se viera sobrecargado con sesiones persistentes que no necesitaba.
  • La especificación no está estancada. Una implementación basada en suposiciones de hace seis meses puede dejar de cumplir con los requisitos sin presentar ningún error, ya que los clientes simplemente acuerdan utilizar una versión más antigua del protocolo.

La arquitectura se ve así.

AI Client ── HTTPS POST ──▶ nginx (TLS termination, auth check, reverse proxy)
                                    │
                                    ▼
                          MCP Server Process
                          (Streamable HTTP transport)
                                    │
                       ┌────────────┴────────────┐
                    Tools                    Resources

Un principio guía todo esto. Una vez que un servidor MCP obtiene una URL pública, debe manejarse como cualquier API autenticada expuesta desde EC2, ya que estructuralmente es lo mismo. MCP es simplemente el formato de mensajes utilizado, mientras que las consideraciones de seguridad y escalabilidad son idénticas a las de cualquier backend.

1. Transporte HTTP transmisible por secuencias

HTTP transmisible por secuencias es un único punto de extremo HTTP que recibe solicitudes POST que contienen mensajes JSON-RPC. Sustituyó al anterior transporte HTTP+SSE, el cual requería un flujo persistente de server-sent-events además de las llamadas HTTP normales.

Un único punto de extremo POST es algo familiar para cualquier proxy inverso, balanceador de carga o gateway API, por lo que no hay dificultad para mantener abierto un flujo de larga duración a través de nginx o un ALB. El tráfico se comporta como una API HTTP normal, y el bloque location de nginx permanece breve.

location /mcp {
    proxy_pass http://127.0.0.1:8000;
    proxy_set_header Host $host;
    proxy_set_header Authorization $http_authorization;
    proxy_http_version 1.1;
    proxy_read_timeout 300s;
}

Un consejo para la producción: incluso con un transporte de un solo punto de entrada, mantenga el tiempo de espera de lectura del proxy lo más amplio posible. Las llamadas individuales a las herramientas pueden tardar legítimamente más tiempo que una solicitud típica de API, y un tiempo de espera demasiado estricto eliminará las llamadas que realmente tardan en completarse junto con aquellas que realmente están atascadas.

2. Autenticación con token de portador

En este esquema, un token fijo se encuentra en el encabezado Authorization y se verifica antes de que la solicitud llegue al proceso del servidor MCP, ya sea en nginx o en el middleware de la aplicación. Para cualquier contenido en una URL pública, es el nivel de seguridad menos aceptable, pero constituye un primer paso razonable. Sin embargo, el token nunca vence, no está vinculado a ningún servidor en particular y no ofrece protección si termina en un registro de logs. Solo indica que una solicitud contiene credenciales.

Un boceto de middleware para FastAPI comienza con las importaciones.

from fastapi import Request, HTTPException

Luego viene el propio cheque.

VALID_TOKEN = "your-rotated-secret-token"async def verify_bearer(request: Request):
    auth = request.headers.get("authorization", "")
    if auth != f"Bearer {VALID_TOKEN}":
        raise HTTPException(status_code=401, detail="Unauthorized")

Otro consejo: mantenga el encabezado Authorization en bruto fuera de los registros de acceso. Los formatos predeterminados de los registros de nginx y de la aplicación facilitan que se pase por alto, y una vez que está allí, el archivo de registro se convierte en una credencial filtrada.

3. Estadoless, el núcleo de la reescritura de julio de 2026

Con la especificación del 2026-07-28, las sesiones a nivel de protocolo desaparecen. Ya no existe el encabezado Mcp-Session-Id, y el transporte también elimina el flujo GET de larga duración que las versiones anteriores utilizaban para mantener alineados al cliente y al servidor a lo largo de una conversación. Cada solicitud lleva consigo todo lo que necesita.

La escala es el objetivo principal. El modelo anterior permitía que un servidor recordara información sobre un cliente entre llamadas, y cuando varias instancias operaban detrás de un balanceador de carga, esa memoria requería sesiones persistentes. Sin estado a nivel de protocolo, cualquier instancia puede manejar cualquier solicitud, lo que permite una verdadera escala horizontal y libera a los clientes de quedar atados a una sola máquina.

En la práctica, un servidor que conservaba estado en memoria sobre un cliente entre llamadas dejará de funcionar según las nuevas especificaciones. Todo estado relevante debe trasladarse al payload de la solicitud o a un almacenamiento externo como Redis, al cual todas las instancias puedan acceder.

4. Solicitudes de múltiples idas y venidas

Incluso un protocolo sin estado necesita una forma en la que el servidor pueda hacer una pregunta al cliente a mitad de una llamada a una herramienta, como solicitar confirmación o un parámetro faltante. La nueva especificación lo resuelve mediante Multi Round-Trip Requests. En lugar de mantener una conexión abierta, el servidor responde con un InputRequiredResult que enumera sus preguntas junto con un valor requestState opaco. El cliente recopila las respuestas y envía nuevamente la llamada original, añadiendo esas respuestas y devolviendo el estado sin cambios.

Esto es lo que hace posible el verdadero funcionamiento sin estado. Dado que todo lo que el servidor necesita para reanudar la llamada se encuentra en el payload que el cliente envía de vuelta, cualquier instancia, no necesariamente la que inició la llamada, puede realizar el intento de nuevo y completarla.

Los clientes deben dejar requestState sin modificar: ni inspeccionarlo ni editarlo. Consérvenlo y devuélvanlo tal como llegó, ya que un proceso que dependa de su integridad podría fallar.

5. Refuerzo de la autorización

La especificación revisada orienta a los servidores MCP remotos hacia OAuth 2.1 con PKCE y exige indicadores de recursos (RFC 8707), los cuales vinculan un token emitido al servidor para el cual fue diseñado.

El problema principal es la reutilización de tokens. Si se filtra un token portador estático, cualquier servidor que lo acepte puede convertirse en objetivo. Un token vinculado a un recurso cierra esa brecha, por lo que uno emitido para un servidor MCP no funcionará en otro, incluso si ambos dependen del mismo proveedor de identidad.

La configuración con token portador, con la que muchas personas comienzan, cumple con el requisito de que “este endpoint requiere autenticación”. Sin embargo, no alcanza el nivel de interoperabilidad ni la protección contra reproducciones que la nueva especificación exige de un servidor remoto compatible, y es necesario cerrar esta brecha antes de que la URL llegue a personas ajenas al equipo principal.

6. Política de obsolescencia y extensiones

Las funcionalidades de la especificación ahora siguen un ciclo de vida formal de Activo, Obsoleto y Eliminado, con al menos doce meses entre la obsolescencia y la eliminación. Las nuevas características, como la interfaz de usuario generada por el servidor o las tareas de larga duración, se introducen primero como extensiones opcionales en lugar de formar parte directamente del núcleo. Algunas características antiguas, como las operaciones roots, el muestreo y el registro en su forma original, están en camino a ser obsoletas en favor de sustitutos.

Para los operadores, eso significa que una integración funcional no se verá afectada de la noche a la mañana por una futura revisión, y las nuevas capacidades pueden adoptarse de forma deliberada, sin la presión de tener que mantenerse al día con todo lo que añade la especificación.

Recorrido completo de principio a fin

El camino desde un prototipo local hasta una implementación en EC2 actualizada según la especificación es el siguiente:

  1. Pruebas locales. El servidor funciona a través de stdio con un cliente local, sin conexión a red ni autenticación, lo que permite iteraciones rápidas.
  2. Cambio a HTTP transmisible por streams. El servidor se reconfigura para utilizar el transporte HTTP transmisible por streams y se despliega en una instancia EC2.
  3. nginx como intermediario. nginx finaliza el proceso TLS, verifica el token de autorización antes de que cualquier dato llegue al proceso MCP, y luego hace proxy inverso de la solicitud.
  4. Una llamada de herramienta simple. Un mensaje POST contiene una solicitud JSON-RPC, y el resultado vuelve en esa misma solicitud y respuesta.
  5. Negociación de versión. Con la especificación finalizada para el 28-07-2026, el cliente y el servidor negocian una revisión del protocolo. Un cliente que no se ha actualizado recurre automáticamente a la versión del 25-11-2025 sin fallar completamente.
  6. Se necesita más información. En lugar de mantener la conexión abierta, el servidor responde con un InputRequiredResult que indica qué datos aún falta solicitar.
  7. Reanudación. El cliente repite la llamada con las respuestas adjuntas y el requestState devuelto. El intento de reintentar no depende de una instancia específica, por lo que cualquier máquina detrás de nginx puede manejarlo.
  8. Fallas de autenticación. Las solicitudes sin token o con un token inválido son rechazadas por nginx. El código de la aplicación nunca las recibe.

Casos especiales

Operaciones lentas. Las tareas que antes dependían de un flujo mantenido abierto durante todo el proceso deben pasar a utilizar la extensión Tasks. Reconstruir una conexión persistente en un transporte sin esta funcionalidad es la dirección incorrecta.

Herramientas que nunca serán remotas. Un servidor que solo se ejecuta localmente junto a su cliente se beneficia mejor con stdio, y casi ninguna de las consideraciones de despliegue aquí aplican.

Clientes de versiones mixtas. Dado que los clientes antiguos recurren automáticamente a la versión 2025-11-25, un mismo despliegue puede servir razonablemente a ambas revisiones del protocolo durante un tiempo, por lo que no todos los clientes necesitan actualizarse al mismo ritmo que el servidor.

Desafíos de escalado y producción

Múltiples instancias. Bajo el modelo de sesión, mantener al cliente vinculado a la instancia que lo conocía implicaba sesiones persistentes o almacenamiento compartido de sesiones. Esa necesidad ya no existe, y para quienes operan más de una máquina, este es el principal beneficio de la reescritura.

TLS en una flota en crecimiento. Gestionar un certificado en cada instancia EC2 se vuelve rápidamente complicado. Un balanceador de carga gestionado que almacene un certificado ACM delante de toda la flota requiere mucho menos esfuerzo que la configuración TLS de nginx en cada máquina.

Emitencia y rotación de tokens. Los tokens portadores estáticos tienen un límite en términos de seguridad, y además representan un problema operativo cuando hay más de un par de clientes, ya que cada rotación requiere coordinación manual. La emisión basada en OAuth 2.1 soluciona tanto la deficiencia de seguridad como la carga de rotación al mismo tiempo.

Rastreo entre llamadas sin sesiones del lado del servidor. Dado que no existe una sesión que vincule una secuencia de llamadas en el servidor, los IDs de correlación incluidos en el payload de la solicitud se convierten en la única forma fiable de reconstruir qué hizo una única interacción con un agente a lo largo de múltiples llamadas.

Manejo del resumen en el cliente

La configuración de nginx y el middleware bearer-check se encargan del transporte y de la autenticación básica. A continuación se muestra un patrón mínimo para el lado del cliente en una solicitud de múltiples viajes.

async def call_tool_with_resume(client, tool_name, params):
    result = await client.call_tool(tool_name, params)
    if result.get("type") == "InputRequiredResult":
        answers = collect_answers(result["questions"])
        return await client.call_tool(
            tool_name,
            {**params, "answers": answers, "requestState": result["requestState"]},
        )
    return result

Lo importante es la última línea, donde requestState vuelve exactamente como lo proporcionó el servidor.

Errores comunes

  • Tratar “desplegado” como “listo para producción”. nginx junto con un token de acceso solo cumple con el mínimo requisito, no con todos. Se debe exigir al endpoint MCP los mismos estándares que cualquier API pública, con autenticación adecuada, registro detallado y limitación de frecuencia antes de compartir ampliamente la URL.
  • Depender de la memoria del servidor. Algunos despliegues iniciales confiaban silenciosamente en recordar al cliente de una solicitud anterior. Hay que asumir que cada solicitud llegará a una instancia diferente de la anterior, ya que la especificación actual lo permite exactamente así.
  • Fijación de una única versión de protocolo. Un cliente bloqueado a una versión específica deja de funcionar cuando el servidor se actualiza. Implemente negociaciones con un mecanismo de respaldo razonable, de modo que la actualización de un lado no afecte al otro.
  • Omisión de autenticación en herramientas internas. Una herramienta actualmente interna podría ser transferida posteriormente a un equipo externo, y en ese caso un token estático no es suficiente. Dado que el servidor podría abandonar un portátil o una VPC, opte por OAuth 2.1 e indicadores de recursos desde el primer día.

Prácticas que funcionan en producción

  • Evite estados que impidan la escalabilidad de su infraestructura. Todo lo que deba persistir entre llamadas debe encontrarse en el payload o en un almacenamiento externo.
  • Asocie cada token con el recurso al que está destinado, ya que un token aceptado por todos los servidores en los que confía tarde o temprano será utilizado donde no debería.
  • Negocie las versiones del protocolo y no asuma una en particular. Los clientes y los servidores rara vez se actualizan el mismo día, así que planifique para ese intervalo.
  • Verifique la autenticación en el extremo. Cuando nginx rechaza una solicitud inválida, el proceso MCP se mantiene más simple y expone menos información.
  • Deje intactos los campos opacos. requestState y otros similares existen para que el servidor pueda confiar en lo que devuelve, por lo que los clientes no deberían leerlos ni modificarlos.

Qué implica esto para el despliegue

En teoría, MCP es sencillo. El despliegue incluye las decisiones importantes, y la actualización de la especificación del 28 de julio de 2026 las modificó. Streamable HTTP es más fácil de ejecutar detrás de infraestructura ordinaria; el hecho de no tener estado hace que añadir una instancia EC2 sea una opción realista en lugar de un proyecto de gestión de sesiones, y el modelo de autorización ahora es adecuado para servidores orientados al público. Nada de esto resulta difícil una vez que se comprende, y es precisamente lo que los textos teóricos suelen omitir.

Leer más

  • Reevaluación del impuesto por tokens MCP: dos descripciones de herramientas provocaron el aumento — Una nueva ejecución de nueve servidores MCP tras 13 días muestra que las definiciones de herramientas pasaron de 36,320 a 38,738 tokens, casi todos debido a que un servidor reescribió sus descripciones existentes.