Un servidor MCP remoto que lee documentos o ejecuta tools no puede confiar en que el cliente sea conocido. OAuth 2.1 no es un botón de login: es el contrato que descubre identidad, limita scopes y permite validar cada llamada sin convertir la autorización en un prompt.
OAuth 2.1 para MCP es el mecanismo para que un cliente obtenga un token con permiso limitado y un servidor MCP remoto compruebe ese token antes de exponer tools, recursos o acciones. En MCP, el servidor protegido es un resource server; el host del agente es el OAuth client; y tu proveedor de identidad emite los access tokens.
TL;DR
La keyword principal es
OAuth 2.1 MCP. La intención es de implementación: publicar Protected Resource Metadata, descubrir el authorization server, usar Authorization Code + PKCE, definir scopes pequeños y validar issuer, audience, expiración y permisos en cada tool call.Mi postura: si tu MCP remoto puede tocar correo, documentos, datos de cliente o sistemas internos, no intentes resolver identidad con una API key compartida en una variable de entorno. Una key solo identifica una integración; no expresa quién pidió una acción ni qué alcance tenía. OAuth te da un contrato, pero sigues necesitando autorización de negocio en tu backend.
Qué cambió y por qué importa ahora
La revisión MCP 2026-07-28 endurece la autorización y elimina parte de la complejidad de sesiones del protocolo. Para OAuth, el cambio relevante es práctico: la especificación prioriza Client ID Metadata Documents (CIMD) para clientes que no tienen una relación previa con el servidor, deja Dynamic Client Registration como compatibilidad y exige discovery interoperable de metadata OAuth u OpenID Connect.
No conviertas eso en una migración cosmética. Un servidor MCP público no puede suponer que conoce de antemano todos los hosts que se conectarán. El flujo debe permitir discovery sin aceptar redirect URIs arbitrarias, tokens para otra audiencia o scopes enormes porque son más cómodos de configurar.
La propiedad evergreen es que el patrón no depende de un host concreto. Cambiarán SDKs y pantallas de consentimiento; seguirán siendo necesarios un resource identifier estable, metadata verificable, PKCE, token validation y una política de autorización que no viva dentro del modelo.
El servidor MCP valida el token antes de ejecutar una tool; el proveedor de identidad autentica y emite credenciales, pero no sustituye la política por tenant o recurso de tu aplicación.
El mapa mental correcto: cuatro roles, dos decisiones
Hay cuatro piezas. El cliente MCP (un host de agente) inicia la conexión y representa al usuario. El servidor MCP es el resource server que protege su endpoint HTTP. El authorization server autentica y emite tokens. Por último, tu API, base de datos o SaaS aguas abajo contiene el recurso real. No confundas el servidor MCP con el identity provider: uno recibe la tool call; el otro decide cómo se obtiene la identidad.
OAuth resuelve la primera decisión: ¿este cliente presenta un token válido para este recurso y con estos scopes? Tu aplicación resuelve la segunda: ¿este usuario de este tenant puede leer este documento o ejecutar esta acción ahora? El
scopeabre una capacidad general; la autorización de negocio revisa IDs, ownership, rol, estado y consecuencias.Por ejemplo,
tickets:readno autoriza a leer cualquier ticket. Autoriza a intentar la tool de lectura. El handler debe cargar el usuario desde claims verificadas y aplicar el filtro de tenant antes de consultar. Si pasas eluser_idque propone el modelo como autoridad, has vuelto a delegar seguridad al prompt.
Flujo OAuth 2.1 de un servidor MCP remoto
El cliente llama al endpoint MCP sin token o con token insuficiente. El servidor devuelve
401 Unauthorizedy unWWW-Authenticate: Bearerque apunta a su Protected Resource Metadata (PRM).El cliente descarga el documento PRM. Ahí descubre el
resourceque debe aparecer como audiencia, el authorization server permitido y los scopes que el recurso entiende. Si elresourcedel JSON no coincide exactamente con el recurso pedido, debe rechazarlo.El cliente descubre los endpoints OAuth u OpenID Connect del issuer, registra su identidad por pre-registro o CIMD cuando esté disponible y abre Authorization Code con PKCE. PKCE evita que otro proceso intercepte y canjee el código de autorización.
Tras consentimiento, el authorization server emite un access token dirigido a tu resource identifier. El cliente repite la llamada MCP con
Authorization: Bearer …. El servidor valida firma o introspección,iss,aud,exp, scopes y cualquier claim de tenant antes de despachar una tool.Cada tool ejecuta autorización propia, registra actor, cliente, tool, recurso y resultado, y devuelve un error de autorización seguro cuando corresponda. No guardes el access token en trazas, mensajes de error ni contenido de tool.
¿Te está sirviendo? Hay una dosis cada semana
Te resumo herramientas de IA para devs, agentes, MCP, seguridad y workflows en un email de 5 minutos. En español y sin ruido.
Protected Resource Metadata: la pieza que suele faltar
Protected Resource Metadata es un JSON servido por el resource server, no por el proveedor de login. Según RFC 9728 y MCP, publica el identificador del recurso y los authorization servers autorizados. En una ruta MCP como https://mcp.acme.test/remote, el cliente puede buscar https://mcp.acme.test/.well-known/oauth-protected-resource/remote o seguir el resource_metadata del challenge, que debe tener prioridad.
Lo que conviene comprobar
Evita meter aquí una lista fantasiosa de permisos. scopes_supported documenta lo que el servidor puede pedir; el challenge de una request concreta puede exigir un conjunto más preciso y el cliente debe tratar ese challenge como autoridad para ese intento. Es una forma de pedir consentimiento incremental sin entregar admin:* al primer clic.
Un ejemplo mínimo y explícito podría ser el siguiente. Los nombres de scopes son tuyos: diseña verbos y dominios que alguien de seguridad pueda revisar, no copias de los nombres de tools.
/.well-known/oauth-protected-resource/mcp
{
"resource": "https://mcp.example.com/mcp",
"authorization_servers": ["https://login.example.com"],
"scopes_supported": [
"issues:read",
"issues:write",
"deployments:read"
],
"resource_name": "Example engineering MCP"
}
Implementación Node: challenge, metadata y guard de token
El SDK MCP puede encargarse del transporte y del registro de tools, pero el borde HTTP debe seguir devolver metadata y rechazar tokens inválidos antes de llegar al modelo o a los sistemas internos. Este ejemplo usa Express y jose para mostrar el contrato; adapta los endpoints y claims a tu proveedor de identidad. En producción, cachea JWKS respetando sus cabeceras y mantén las URLs de issuer y audiencia en configuración revisada, no en input del usuario.
auth-boundary.mjs
import express from "express";
import { createRemoteJWKSet, jwtVerify } from "jose";
const app = express();
const resource = "https://mcp.example.com/mcp";
const issuer = "https://login.example.com";
const jwks = createRemoteJWKSet(new URL(`${issuer}/.well-known/jwks.json`));
app.get("/.well-known/oauth-protected-resource/mcp", (_req, res) => {
res.type("application/json").send({
resource,
authorization_servers: [issuer],
scopes_supported: ["issues:read", "issues:write"],
});
});
async function requireScope(req, res, next) {
const token = req.get("authorization")?.replace(/^Bearer\s+/i, "");
if (!token) {
res.set("WWW-Authenticate",
`Bearer resource_metadata="${resource.replace("/mcp", "/.well-known/oauth-protected-resource/mcp")}", scope="issues:read"`);
return res.sendStatus(401);
}
try {
const { payload } = await jwtVerify(token, jwks, { issuer, audience: resource });
const scopes = String(payload.scope || "").split(" ");
if (!scopes.includes("issues:read")) return res.sendStatus(403);
req.actor = { subject: payload.sub, tenant: payload.tenant_id };
return next();
} catch {
return res.sendStatus(401);
}
}
app.post("/mcp", requireScope, mcpHttpHandler);
No copies este fragmento sin decidir si tu access token es JWT, opaco o ambos. Un token opaco normalmente se valida por introspección contra el authorization server; un JWT se valida contra claves públicas confiables. En ambos casos, la audiencia debe ser el resource identifier de tu MCP, no el nombre genérico de tu producto.
Scopes, audiencia y acciones sensibles
Empieza con scopes legibles y estrechos:
repo:read,issues:read,issues:write,deployments:read. No concedastools:*si solo necesitas una consulta. Los scopes no deben depender de un prompt ni de los argumentos declarados por el LLM; se comprueban en el servidor antes de ejecutar la operación.Separa lectura de escritura. Para
issues:write, añade una aprobación explícita en el host o una confirmación en tu aplicación antes de mutar. Para acciones de alto impacto —borrar, desplegar, cambiar permisos, enviar comunicación externa— utiliza scopes específicos, un segundo control contextual y logs de auditoría. OAuth reduce blast radius; no vuelve segura una tool excesivamente poderosa.La claim
audes tu defensa contra token replay entre APIs. Un token emitido parahttps://api.example.comno debe servir parahttps://mcp.example.com/mcpsolo porque comparten issuer. Valida audiencia exacta, nostartsWith, no el hostname a ojo, y nunca aceptes una audiencia enviada por el cliente.CIMD, pre-registro y por qué DCR ya no es la primera opción
El registro de cliente responde a otra pregunta: ¿qué aplicación está pidiendo el token? Si controlas cliente y servidor, el pre-registro de client ID y redirect URIs es simple y robusto. Si esperas hosts desconocidos, MCP prioriza Client ID Metadata Documents: el client ID puede ser una URL HTTPS que publica metadata verificable del cliente.
Dynamic Client Registration puede seguir existiendo por compatibilidad, pero no debería ser el camino que abra registros ilimitados y redirect URIs sin validación. La especificación actual lo coloca como fallback. Trata cada mecanismo como una superficie de seguridad: limita métodos de autenticación, exige URIs exactas y registra el client ID que obtuvo consentimiento.
No prometas soporte universal antes de probar hosts reales. Algunos clientes aún llegarán con capacidades antiguas. Publica claramente qué versiones, mecanismo de registro y scopes admites; ofrece el fallback mínimo sin bajar la validación del token por «compatibilidad».
Errores que rompen autorización MCP
- Proteger solo la pantalla de consentimiento y dejar
/mcpsin validarAuthorizationen cada request. - Aceptar cualquier issuer que aparezca en un JWT o construir el JWKS URL con una claim no confiable.
- Comprobar firma y expiración, pero omitir audiencia, scopes, tenant y autorización del recurso concreto.
- Usar una API key global como identidad del usuario y registrar todas las acciones como si las hiciera el servidor.
- Devolver access tokens, authorization codes, cabeceras Bearer o datos de consentimiento en logs de trazas.
- Entregar
writeal conectar el servidor aunque el usuario solo quiera explorar datos de lectura. - Confiar en que el modelo no invocará una tool peligrosa si el system prompt dice que tenga cuidado.
Checklist de lanzamiento
El endpoint MCP remoto rechaza sin token y expone
WWW-Authenticateconresource_metadata.La Protected Resource Metadata devuelve
resourceexacto, authorization server permitido y scopes revisados.El cliente usa Authorization Code con PKCE y redirecciones registradas de forma exacta.
El servidor valida issuer, firma o introspección, audiencia, expiración y scope por request.
Cada tool aplica control de tenant, rol, propiedad y estado además del scope OAuth.
Lectura y escritura tienen scopes distintos; las mutaciones de impacto tienen aprobación y auditoría.
Tokens, códigos y cabeceras de autorización están redaccionados de logs, errores y trazas.
Hay tests para token de otra audiencia, scope insuficiente, issuer falso, tenant cruzado y request repetida.
Conclusión
La autorización MCP bien hecha no se nota cuando todo va bien: el host descubre la identidad necesaria, obtiene permiso mínimo y la tool funciona. Se nota cuando alguien conecta un cliente nuevo, intenta reutilizar un token contra otro recurso o pide una acción que no le corresponde; ahí el servidor debe fallar de forma predecible y auditable.
Mi recomendación es empezar con un solo recurso remoto y dos scopes de lectura/escritura, no con un catálogo enorme de permisos. Publica PRM, valida aud e iss, aplica autorización de negocio en cada tool y escribe los tests hostiles antes de abrir el servidor a más clientes. Es menos vistoso que una demo de agente, pero es lo que evita convertir MCP en una llave maestra.
Preguntas frecuentes
¿Qué es OAuth 2.1 para MCP?
Es el patrón de autorización que permite a un cliente MCP obtener un access token limitado y a un servidor MCP remoto validarlo antes de exponer tools o recursos protegidos.
¿Necesita OAuth un servidor MCP local por STDIO?
Normalmente no. Un servidor local puede usar credenciales del entorno o de una librería local; OAuth está pensado sobre todo para transportes HTTP remotos donde cliente y servidor no comparten una frontera de confianza.
¿Qué es Protected Resource Metadata en MCP?
Es un documento JSON del servidor MCP que declara el resource identifier, los authorization servers y scopes. El cliente lo descubre desde WWW-Authenticate o una ruta /.well-known/ para iniciar OAuth correctamente.
¿Basta con validar la firma del JWT?
No. También debes validar issuer, audiencia, expiración y scopes, y luego aplicar autorización de negocio por usuario, tenant y recurso concreto en la tool.
¿Debo usar Dynamic Client Registration en MCP?
Puede ser un fallback de compatibilidad. La especificación actual prefiere pre-registro cuando existe relación previa y Client ID Metadata Documents cuando cliente y servidor no se conocen de antemano.
¿OAuth protege contra prompt injection?
No directamente. OAuth limita quién puede invocar capacidades; sigue siendo necesario tratar contenido externo como no confiable, validar argumentos y exigir aprobación para efectos sensibles.
Cómo proteger un servidor MCP remoto con OAuth 2.1
- Delimitar recurso. Define una URL HTTPS estable para el endpoint MCP que será la audiencia esperada del token.
- Diseñar scopes. Separa lectura, escritura y acciones de alto impacto; evita permisos globales basados en nombres de tools.
- Publicar metadata. Sirve Protected Resource Metadata con resource exacto, issuer permitido y scopes soportados.
-
Emitir challenge. Devuelve 401 con
WWW-Authenticateyresource_metadatacuando no haya token o falte scope. - Configurar OAuth. Usa Authorization Code con PKCE, discovery OAuth/OIDC y redirect URIs registrados con coincidencia exacta.
- Validar access token. Comprueba firma o introspección, issuer, audiencia, expiración, scopes y claim de tenant en cada llamada.
- Autorizar tool. Evalúa usuario, tenant, rol, ID de recurso y estado de negocio antes de llamar a sistemas aguas abajo.
- Auditar sin secretos. Registra actor, client ID, tool, recurso y resultado; redacta token, código y cabeceras.
- Probar denegaciones. Añade casos de token de otra audiencia, scope insuficiente, issuer falso, tenant cruzado y mutación sin aprobación.
Fuentes y referencias
- MCP Authorization specification (2026-07-28)
- MCP: Understanding Authorization
- MCP Security Best Practices
- MCP 2026-07-28 release notes
- RFC 9728: OAuth Protected Resource Metadata
- RFC 8414: OAuth Authorization Server Metadata
- OAuth 2.1 draft
- OAuth Client ID Metadata Document draft
También te puede interesar
- MCP en producción: seguridad, permisos y supply chain
- MCP outputSchema y structuredContent para agentes
- Prompt injection en agentes de IA
- MCP Apps: UI interactiva para tools
- OpenTelemetry GenAI para agentes
Recibe una lectura semanal de herramientas IA para devs
Cada semana te resumo herramientas de IA para devs, agentes, MCP, seguridad y workflows en un email de 5 minutos. En español y sin ruido.

Top comments (0)