Asegura tu servidor MCP con OAuth 2.1 en 60 minutos
Cuándo necesitas auth para tu servidor MCP y cuándo no. PKCE obligatorio, discovery vía .well-known, Resource Indicators (RFC 8707). Tres opciones de setup: WorkOS AuthKit, Auth0 for MCP, o tu propio Authorization Server.
Construiste un servidor MCP, primero corrió en local como stdio. Ahora quieres hostearlo como servidor Streamable HTTP para que otras personas o los plugins de Cursor/Claude.ai/VSCode puedan acceder a él. A más tardar ahí necesitas auth, si no cualquiera con una URL puede leer, escribir o llamar tools en tu servidor.
La spec de MCP exige OAuth 2.1 con PKCE como estándar de auth. Eso no es opcional. Aquí está cómo funciona en la práctica y cuál de las tres opciones de setup encaja con tu situación.
1. Cuándo necesitas auth y cuándo no
Primero la aclaración. Los servidores MCP locales que corren por stdio no necesitan OAuth. La spec de MCP dice explícitamente: las implementaciones stdio deberían leer las credenciales del entorno, no pasar por flows de OAuth. Pasas las API keys vía .env o el bloque env en la config de MCP, listo.
OAuth se vuelve obligatorio en cuanto tu servidor queda expuesto por HTTP. Streamable HTTP, Server-Sent Events, request-response clásico. En cuanto los datos van por la red y se trata de recursos protegidos, necesitas auth.
Tercer caso: servidor demo read-only sin datos sensibles. En teoría puedes correr sin auth si tu servidor solo expone datos públicos (por ejemplo un servidor MCP de clima). En la práctica eso causa problemas porque Claude.ai y otros clientes esperan el handshake de auth y se lían sin un header. Incluso para demos públicas vale la pena el setup mínimo.
2. Qué exige la spec
La spec de MCP 2025-06-18 exige cinco cosas si implementas OAuth.
Primero: OAuth 2.1, no OAuth 2.0. La diferencia es esencial. 2.1 exige PKCE para todos los flows (no solo clientes públicos), elimina el implicit grant por completo, y exige el exact-redirect-URI-matching. Quien implementa 2.0 está ya en el estado de hace 5 años.
Segundo: PKCE con el método S256. El cliente genera un code_verifier aleatorio, lo hashea como code_challenge con SHA256, lo envía en el authorization request, y en el token exchange envía el code_verifier original. Sin eso el cliente MCP ni siquiera arranca.
Tercero: discovery vía .well-known/oauth-protected-resource (RFC 9728). Cuando un cliente accede por primera vez a tu servidor MCP, envía un request sin token. Respondes con HTTP 401 y un header WWW-Authenticate que apunta a /.well-known/oauth-protected-resource. Ahí hay un documento JSON que apunta al authorization server.
Cuarto: Resource Indicators (RFC 8707). El cliente MCP debe enviar un parámetro resource en el authorization y token request que indique la URI canónica de tu servidor MCP. Ejemplo: &resource=https%3A%2F%2Fmcp.studiomeyer.io. Con eso el token queda ligado a tu servidor, un token robado no puede usarse de forma indebida para otro servidor MCP.
Quinto: token audience validation. Cuando entra un request con token, tienes que comprobar en el lado del servidor que el token se emitió realmente para tu URI canónica, no para otro servidor. Eso evita la vulnerabilidad "confused deputy".
3. Opción A, WorkOS AuthKit
Si no tienes un sistema de auth propio y quieres salir en vivo rápido, WorkOS es actualmente la solución más simple. AuthKit gestiona por ti todo el lado del authorization server de OAuth. Página de login, gestión de usuarios, emisión de tokens, PKCE, endpoints de discovery, todo listo.
Setup a grandes rasgos en 4 pasos:
- Crear una cuenta WorkOS (workos.com), un nuevo proyecto para tu servidor MCP, configurar el dominio AuthKit.
- En tu servidor MCP montar un endpoint
/.well-known/oauth-protected-resourceque apunte ahttps://your-domain.authkit.app/.well-known/oauth-authorization-server. - En el servidor validar cada request: leer el token
Authorization: Bearer ..., validarlo contra el endpoint JWKS de WorkOS (librería estándar de JWT verify), comprobar el claim de audience contra la URI de tu servidor MCP, si no 401. - La URL de login en tu cliente (Claude.ai etc.) apunta a la página Universal Login de WorkOS, desde ahí el usuario vuelve con un token.
El pricing actual es gratis hasta 1 millón de MAU con features estándar, después precios enterprise. Para el 99 por ciento de los servidores MCP esto no cuesta nada.
Ventaja: código propio mínimo, todo enterprise-ready (SAML, SCIM por si lo necesitas después). Desventaja: vendor lock-in. Dependes de la disponibilidad de WorkOS. Para servidores MCP de producción en 2026 esta es actualmente la recomendación de facto de la comunidad MCP.
4. Opción B, Auth0 for MCP
Auth0 tiene desde mayo 2026 un producto dedicado "Auth for MCP". Si de todos modos ya usas Auth0 para tu app, esa es la elección natural. Recibes features específicas de MCP como CIMD registration y on-behalf-of token exchange para AI agents por encima.
Patrón de setup parecido a WorkOS:
- Montar un tenant de Auth0, una nueva application del tipo "Machine to Machine" o "Native" según el cliente.
- Configurar los específicos de MCP: Universal Login como authorization server, PKCE obligatorio, activar el soporte de resource indicators.
- En el servidor MCP validación de JWT contra el endpoint JWKS de Auth0, audience en tu URL de MCP.
- Hacer disponibles los endpoints de discovery en Auth0, pegar un endpoint local
/.well-known/oauth-protected-resource.
Ventaja frente a WorkOS: features enterprise más profundas (anomaly detection, risk scoring), un pool mayor de devs que ya conocen Auth0, mejor integración SAML por si vendes en enterprise. Desventaja: tramos de pricing mayores, configuración algo más compleja. Auth0 fue comprada por Okta en 2021, lo que ha influido en el modelo de pricing y la velocidad.
Si aún no tienes una solución de identidad, WorkOS sale en vivo más rápido. Si ya usas Auth0, "Auth for MCP" va más fluido.
5. Opción C, Cloudflare Workers OAuth Library
Para self-hosters que no quieren un proveedor externo está la librería OAuth de Cloudflare. Implementa todo el lado del proveedor (DCR, PKCE, discovery) como un Cloudflare Worker. Standalone o combinada con Cloudflare Access (su producto SSO).
Esta es la variante que muchos servidores MCP de producción actuales usan internamente, a menudo como capa debajo de un proveedor como WorkOS o Auth0. A fecha de mayo 2026 la librería es open source, escrita en TypeScript, corre por completo en el entorno Worker.
Esfuerzo de setup mayor que A o B, pero tienes control total. Comprueba antes: ¿ya hosteas en Cloudflare de todos modos? ¿Tienes ancho de banda para operaciones de auth como mantenimiento adicional? Si ambas respuestas son sí, esta opción es a largo plazo más barata e independiente.
Además: como es una librería open source, puedes aplicar la capa de auth a varios servidores MCP a la vez sin montar una cuenta de WorkOS o Auth0 por servidor.
6. Setup de discovery, el paso decisivo
Da igual qué opción tomes, el cliente MCP espera una ruta de discovery clara. Esquema:
1. Client schickt MCP-Request ohne Token an https://mcp.example.com/mcp
2. Server antwortet 401 mit:
WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"
3. Client GETet https://mcp.example.com/.well-known/oauth-protected-resource
4. Server liefert JSON:
{
"resource": "https://mcp.example.com",
"authorization_servers": ["https://your-domain.authkit.app"]
}
5. Client GETet https://your-domain.authkit.app/.well-known/oauth-authorization-server
6. Authorization Server liefert Metadata mit Endpoints (authorize, token, jwks_uri).
Esa es la exigencia de la spec. Si falta uno de estos cinco pasos, el flow de auto-discovery falla y tu servidor no es usable por Claude.ai o Cursor.
El endpoint resource_metadata también puedes servirlo de forma estática. Un archivo HTML simple en tu servidor web con el body JSON, content type application/json, listo.
7. Validación del token en el servidor
En el servidor MCP tienes que validar cada request con un token. Pseudocódigo:
async function validateToken(req): Promise<TokenClaims> {
const auth = req.headers.get("authorization");
if (!auth || !auth.startsWith("Bearer ")) throw new Unauthorized();
const token = auth.slice(7);
const claims = await verifyJWT(token, JWKS_URI);
// Audience-Validation, RFC 8707
if (claims.aud !== "https://mcp.example.com") {
throw new Unauthorized("token audience mismatch");
}
// Expiry
if (claims.exp * 1000 < Date.now()) throw new Unauthorized("expired");
return claims;
}
El check de aud es crítico. Sin él, tokens para otros servicios podrían usarse de forma indebida para hablar con tu servidor MCP. Esa es la brecha de implementación más frecuente.
scope y sub (user ID) los lees del claim del token si necesitas permisos diferenciados o lógica per-user. El MCP estándar no lo usa de forma estricta, pero lo necesitarás en cuanto pases a multi-tenant.
8. Rotación de refresh tokens, a menudo pasada por alto
Los clientes públicos (o sea apps basadas en navegador o móviles como Claude.ai) deben rotar los refresh tokens. Es decir: cada vez que el cliente cambia un refresh token por un access token, el authorization server devuelve un nuevo refresh token y el viejo queda muerto.
Si usas WorkOS o Auth0, ellos lo hacen automáticamente. Si vas a self-host, tienes que implementarlo tú mismo. Los refresh tokens no rotativos están prohibidos en OAuth 2.1 porque si no un token robado puede usarse un número ilimitado de veces.
Comprueba tu proveedor: en self-host revisa los docs de la librería, en un proveedor los ajustes por defecto. En algunos proveedores la rotación de tokens hay que activarla explícitamente.
9. Las tres trampas
Falta de validación de audience. Te construyes el flow de OAuth, todo funciona, se emiten tokens, el servidor los acepta. Lo que olvidas: comprobar si el claim aud es la URI de tu servidor. Consecuencia: alguien recibe un token de otro servicio, lo envía a tu servidor MCP, y tú lo aceptas. La spec llama a eso "confused deputy". Fix obligatorio: validación de aud siempre.
El parámetro resource se olvida. El cliente MCP debe enviar el parámetro resource en cada authorization y token request. Si el cliente no lo hace (a menudo con clientes hechos a mano), el auth server emite tokens sin el claim de audience correcto. Workaround: documenta en los docs de tu servidor que los clientes MCP deben implementar los resource indicators de RFC 8707.
Exigencia de HTTPS ignorada. Todos los endpoints del authorization server deben correr por HTTPS, las redirect URIs deben ser o localhost o HTTPS. Si en dev pruebas a menudo con setups HTTP y luego le atornillas HTTPS a producción, rompes de forma sutil la cadena de confianza. Prueba en dev con certs self-signed locales o ngrok en lugar de con HTTP.
10. Cómo deberías empezar
Si aún no tienes un servidor MCP en producción: constrúyelo primero como servidor stdio, déjalo feature complete, despliega en local. Solo entonces piensa en el hosting HTTP y con ello en OAuth.
Si necesitas hosting HTTP: elige WorkOS AuthKit, monta la capa de auth alrededor en 1 a 2 horas, ship. Optimiza después cuando lleguen cargas o features especiales.
Si vendes en enterprise: elige Auth0 por la integración SAML/SCIM. Más esfuerzo de setup, pero el compliance enterprise cubierto.
Si eres DIY y consciente de costes: librería OAuth de Cloudflare Worker más Cloudflare Access. 2 a 4 días de setup, después escalas por casi nada.
Mira también el playbook mcp-server-publishen cuando tengas el servidor terminado y quieras distribuir en MCP marketplaces, ahí se trata de los discovery listings que son importantes más allá del setup de OAuth.
Source
Specs verificadas vía documentación oficial de MCP y docs de proveedor el 2026-05-07:
- modelcontextprotocol.io/specification/2025-06-18/basic/authorization (requisitos de OAuth 2.1, PKCE obligatorio, Resource Indicators, Discovery, token audience validation)
- workos.com/blog/best-mcp-server-authentication-providers (comparativa de proveedores mayo 2026, WorkOS AuthKit, Auth0 GA, librería de Cloudflare)
- prefect.io/resources/mcp-oauth (implementación FastMCP OAuth, ciclo de vida del token)
Recipes consultados en la Academy:
- Phase 6 MCP Authorization Patterns
- Recipe 6.4 Token Validation
- Lesson L4-06 MCP-Discovery und Marketplaces