Protección de servidores MCP: OAuth, vinculación de audiencia y el diputado confundido
- Entender por qué un servidor MCP remoto (HTTP) es un servidor de recursos OAuth 2.1, y no solo un endpoint con clave de API
- Seguir el handshake de descubrimiento: 401 → Metadatos de recurso protegido → Metadatos del servidor de autorización → token
- Explicar la vinculación de audiencia del token (RFC 8707) y por qué impide que el token de un servicio funcione en otro
- Nombrar la trampa del diputado confundido y la única regla que la cierra: nunca reenvíes el token de un cliente a una API upstream
- Aplicar una breve lista de verificación de endurecimiento antes de exponer un servidor MCP a internet
MCP pasó de ser una novedad a la forma predeterminada en que los agentes acceden a herramientas, lo que significa que los servidores MCP ahora se sitúan frente a datos reales y acciones reales. Un servidor local que lanzas sobre STDIO confía en su entorno: lee las credenciales de variables de entorno y no hay ninguna frontera de red que defender. En el momento en que conviertes ese mismo servidor en remoto (HTTP), cualquiera que pueda alcanzar la URL puede intentar llamarlo. Eso lo convierte en un problema de autorización, y la especificación MCP responde con OAuth 2.1, no con un esquema de clave de API a medida.
Esta página trata sobre el caso remoto. Si tu servidor es solo STDIO, la especificación dice explícitamente que no sigas el flujo OAuth: extrae las credenciales del entorno y continúa.
Los tres roles
OAuth divide el problema en tres partes. MCP se mapea sobre ellas de forma limpia:
El cambio mental clave: el servidor MCP nunca gestiona el inicio de sesión por sí mismo. Solo valida tokens que otro emitió. Esa separación es lo que te permite poner un proveedor de identidad estándar frente a un servidor que tú escribiste.
El handshake de descubrimiento
Un cliente no debería necesitar estar preconfigurado con el lugar donde autenticarse. MCP hace que el descubrimiento sea automático, impulsado por un 401:
- La primera solicitud sale sin credenciales. El servidor la rechaza con HTTP 401 Unauthorized y una cabecera WWW-Authenticate que apunta a su URL de metadatos de recurso.
- Hace un GET a /.well-known/oauth-protected-resource en el servidor. El campo authorization_servers del documento nombra al menos un servidor de autorización que el cliente puede usar.
- Hace un GET a /.well-known/oauth-authorization-server del AS para conocer los endpoints authorize y token y las capacidades soportadas.
- Si el cliente no tiene un client ID para este AS, puede hacer un POST a /register para obtener uno sin intervención humana, algo crucial porque un cliente no puede conocer de antemano cada servidor MCP.
- El cliente genera un verificador/desafío PKCE, abre el navegador en la URL authorize incluyendo el parámetro resource, el usuario da su consentimiento, y el cliente intercambia el código devuelto (con el verificador) por un token de acceso.
- Ahora cada solicitud lleva Authorization: Bearer <token>. El servidor lo valida y responde.
Fíjate en que no hay configuración de autenticación fija en el lado del cliente: el 401 arranca todo. Ese es el objetivo central: un agente puede conectarse a un servidor que nunca ha visto y descubrir cómo autenticarse.
Vinculación de audiencia: la regla que sostiene todo
Aquí está el modo de fallo que la vinculación de audiencia existe para prevenir. Supongamos que un usuario tiene un token emitido para calendar.example.com. Un servidor MCP malicioso (o simplemente descuidado) en evil.example.com engaña al cliente para que le envíe ese token. Si evil lo acepta, ahora puede darse la vuelta y llamar a la API de calendario como el usuario. El token de un servicio funcionó en otro. La frontera de seguridad de OAuth acaba de colapsar.
La solución son los Resource Indicators (RFC 8707):
- Tanto en la solicitud de autorización como en la solicitud de token, el cliente DEBE incluir un parámetro resource fijado a la URI canónica del servidor MCP que pretende llamar, p. ej. resource=https://mcp.example.com. Lo envía incluso si no está seguro de que el AS lo soporte.
- Cuando es compatible, el AS sella el token de modo que solo sea válido para ese servidor de recursos específico.
- Antes de hacer cualquier trabajo, el servidor MCP DEBE verificar que el token fue emitido para ÉL, comprobando el claim de audiencia (RFC 9068). Un token acuñado para cualquier otro recibe un 401, sin más.
Parámetro resource en la solicitud de autorización (codificado en URL)
&resource=https%3A%2F%2Fmcp.example.com
Las URIs canónicas son estrictas: https://mcp.example.com y https://mcp.example.com:8443/mcp son válidas; mcp.example.com (sin esquema) y https://mcp.example.com#frag (fragmento) no lo son. Prefiere la forma sin barra final por interoperabilidad.
El diputado confundido: nunca reenvíes el token
Este es el error que convierte un servidor MCP bienintencionado en el proxy de un atacante. Es el mismo problema del diputado confundido de la seguridad de agentes, afinado a una única regla concreta.
Un servidor MCP a menudo necesita llamar a una API upstream (GitHub, un servicio de base de datos, otro SaaS). La tentación es tomar el token que el cliente te entregó y reenviarlo upstream. No lo hagas. La especificación es tajante: el servidor MCP NO DEBE reenviar el token que recibió del cliente.
Por qué es peligroso: el token del cliente fue emitido para tu servidor como su audiencia. Si lo reenvías, la API upstream podría confiar en él como si viniera de ti, o asumir que ya lo validaste, y ahora un token con alcance para un salto está haciendo trabajo a dos saltos de distancia, fuera del modelo de consentimiento de nadie.
- Si tu servidor MCP llama a una API upstream, actúa como un cliente OAuth SEPARADO frente a esa API y obtiene su PROPIO token del servidor de autorización upstream. Dos tokens independientes, dos audiencias independientes. El token del cliente se detiene en tu puerta.
Una lista de verificación de endurecimiento previa al despliegue
Antes de que un servidor MCP remoto toque internet público:
- Todos los endpoints del AS DEBEN ser HTTPS. Las URIs de redirección DEBEN ser HTTPS o localhost, nada más.
- Rechaza cualquier token que no haya sido emitido específicamente para este servidor. Esta es la única comprobación que detiene la reutilización de tokens entre servicios.
- Los clientes DEBEN usar PKCE para que un código de autorización interceptado sea inútil sin el verificador correspondiente.
- El AS DEBE cotejar las URIs de redirección exactamente contra los valores registrados previamente, y los clientes DEBERÍAN usar y verificar el parámetro state; ambos defienden contra el phishing por redirección abierta.
- Emite tokens de acceso de vida corta para limitar el daño de una filtración; para clientes públicos, rota los tokens de refresco. Almacena los tokens de forma segura y nunca los registres en logs.
- Los tokens van en la cabecera Authorization, nunca en la cadena de consulta, donde acabarían en logs y referrers.
- La vinculación de audiencia es la puerta de transporte; aun así aplica el mínimo privilegio, el sandboxing y el humano en el bucle de /docs/security/securing-agents. La autenticación dice QUIÉN; no dice que la solicitud sea segura.
Ponte a prueba
Ponte a prueba
0/4Fuentes y lecturas adicionales
- Especificación de autorización de MCP (2025-06-18) — el flujo normativo, los roles y los requisitos MUST/SHOULD que esta página resume.
- Buenas prácticas de seguridad de MCP — el reenvío de tokens, el diputado confundido y por qué están prohibidos.
- RFC 8707 — Resource Indicators for OAuth 2.0 — el parámetro
resourcey la vinculación de audiencia. - RFC 9728 — OAuth 2.0 Protected Resource Metadata — cómo un servidor de recursos anuncia sus servidores de autorización.
- RFC 8414 — OAuth 2.0 Authorization Server Metadata y RFC 7591 — Dynamic Client Registration.
- Borrador de OAuth 2.1 — PKCE, seguridad de la comunicación y requisitos de manejo de tokens.
- Relacionado en AILmanac: Protección de agentes y herramientas · Inyección de prompts · MCP en Claude Code.