Referencia · Agentes de IA en redes sociales

OAuth en un servidor MCP: cómo autentica a un agente y qué se rompe

Por Antoine Blanco··7 min de lectura

Un servidor MCP remoto autentica a un agente como servidor de recursos OAuth 2.1. Responde a una llamada sin token con un 401 y una cabecera WWW-Authenticate, el cliente la sigue hasta los metadatos del servidor, ejecuta un flujo de código de autorización con PKCE y envía el token como cabecera bearer en cada petición. Aquí va cada paso, ejecutado en vivo hoy.

La autorización es opcional en MCP, y solo para transportes HTTP: un servidor stdio local lee sus credenciales del entorno. Todo lo que sigue viene de la revisión actual de la especificación, 2026-07-28, y cada respuesta es una llamada real a https://api.plugkit.co/mcp hecha el 16 de octubre de 2026.

El saludo, en cuatro respuestas

Paso 1. Llamar sin token y leer el reto. El servidor debe devolver un 401 con una cabecera WWW-Authenticate que apunte a sus metadatos.

curl -i -X POST https://api.plugkit.co/mcp \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
HTTP/2 401
www-authenticate: Bearer resource_metadata="https://api.plugkit.co/.well-known/oauth-protected-resource", scope="mcp:read mcp:write"
{"error":"Missing credentials. Send `Authorization: Bearer <api key or session token>`.","type":"authentication_error","code":"unauthorized"}

La pista de scope es un SHOULD en la especificación, no un MUST, y es la diferencia entre un cliente que pide los permisos correctos a la primera y uno que adivina. Los clientes deben tratar los scopes del reto como autoridad para la operación.

Paso 2. Pedir los metadatos del recurso protegido. Es la RFC 9728, y es un MUST para todo servidor MCP.

{"resource":"https://api.plugkit.co/mcp",
 "authorization_servers":["https://api.plugkit.co"],
 "scopes_supported":["mcp:read","mcp:write"],
 "bearer_methods_supported":["header"],
 "resource_documentation":"https://docs.plugkit.co"}

Paso 3. Pedir los metadatos del servidor de autorización. RFC 8414, u OpenID Connect Discovery; el servidor debe ofrecer al menos uno, y el cliente debe soportar los dos.

{"issuer":"https://api.plugkit.co",
 "authorization_endpoint":"https://api.plugkit.co/oauth/authorize",
 "token_endpoint":"https://api.plugkit.co/oauth/token",
 "registration_endpoint":"https://api.plugkit.co/oauth/register",
 "revocation_endpoint":"https://api.plugkit.co/oauth/revoke",
 "code_challenge_methods_supported":["S256"],
 "token_endpoint_auth_methods_supported":["none"],
 "client_id_metadata_document_supported":true,
 "authorization_response_iss_parameter_supported":true}

Paso 4. Ejecutar el flujo de código y volver a llamar con el token. Código de autorización con PKCE, el parámetro resource en las dos peticiones, y luego Authorization: Bearer <token> en absolutamente cada petición HTTP, incluidas las de una misma sesión.

Autenticación de un servidor MCP: de dónde sale el client ID

Esta es la parte que cambió, y la que casi todos los tutoriales siguen contando mal. La revisión actual enumera tres mecanismos y los ordena.

Mecanismo Estado en la revisión 2026-07-28 Qué envía el cliente como client_id
Client ID Metadata Documents SHOULD support Una URL HTTPS que el servidor consulta para leer los metadatos del cliente
Registro previo Permitido Un client ID que te entregaron por otra vía
Dynamic Client Registration (RFC 7591) MAY support, obsoleto Un client ID que viene de POST /register

El registro dinámico era un SHOULD en la revisión 2025-06-18. Ahora es explícitamente «deprecated and retained for backwards compatibility with authorization servers that do not support Client ID Metadata Documents». CIMD lo sustituye por algo más simple: el cliente usa una URL como identificador, el servidor de autorización consulta esa URL, lee los metadatos y valida las redirect URI. Sin llamada de registro y sin una ficha de cliente guardada por cliente.

El servidor de PlugKit de arriba anuncia las dos cosas, client_id_metadata_document_supported: true y un registration_endpoint activo, que es la postura correcta mientras los clientes se ponen al día.

OAuth 2.1 en MCP: PKCE, el parámetro resource y la vinculación de audiencia

Tres requisitos hacen el trabajo de seguridad, y los tres son MUST para los clientes.

  1. PKCE. Obligatorio en todos los clientes. S256 es el método que publica el servidor de arriba. Evita que un código de autorización interceptado lo canjee cualquiera que no sea el cliente que inició el flujo.
  2. El parámetro resource. RFC 8707, tanto en la petición de autorización como en la de token, llevando la URI canónica del servidor MCP: &resource=https%3A%2F%2Fapi.plugkit.co%2Fmcp. Los clientes deben enviarlo, lo soporte el servidor o no.
  3. Validación de la audiencia. El servidor debe verificar que el token se emitió para él, y debe rechazar cualquier otro. La especificación es categórica: un servidor MCP «MUST NOT accept or transit any other tokens».

Esta última tiene nombre. Si un servidor toma un token destinado a otro y lo reenvía hacia arriba, aparece el problema del delegado confundido: la API de destino confía en la llamada porque viene del servidor. El passthrough de tokens está prohibido, y por eso un servidor que llama a una API externa debe tener su propio token separado para ella. Esa es la mitad «servidor a plataforma» del problema, y tiene sus propios fallos, tratados en los tokens de acceso de redes sociales.

Qué se rompe

Cinco fallos, en el orden en que es probable que te los encuentres.

Síntoma Estado Causa Solución
El cliente nunca arranca el flujo 401 Sin cabecera WWW-Authenticate, o sin metadatos de recurso Implementa la RFC 9728 y devuelve la cabecera en cada 401
Llamada a herramienta rechazada, y el token parece correcto 403 Al token le falta un scope que la operación necesita Devuelve error="insufficient_scope" con scope, y deja que el cliente eleve sus scopes
Bucle de peticiones de consentimiento en el navegador 401 Refresh token caducado o revocado, con un cliente que reintenta a ciegas Limita los reintentos y trata el fallo repetido como definitivo
Token rechazado por un segundo servidor 401 Token enviado a un servidor para el que no se emitió Envía el parámetro resource y valida la audiencia
El flujo termina contra el servidor equivocado ninguno Ataque de confusión de servidores, iss sin comprobar Guarda el emisor antes de redirigir y compáralo al volver

La de los scopes merece detalle, porque es nueva y fácil de equivocar. Cuando un token es válido pero demasiado estrecho, el servidor debería responder 403 con error="insufficient_scope" y los scopes que necesita la operación. El cliente reautoriza entonces con la unión de lo que ya tenía y de lo que acaban de pedirle, no solo el scope nuevo, o pierde los permisos que estaba usando antes. Los servidores deberían enviar todos los scopes que necesita la operación en un solo reto, en vez de soltarlos de uno en uno por ida y vuelta.

La comprobación de iss es la más silenciosa de las cinco, porque nada falla de forma visible. El cliente debe guardar el emisor de los metadatos validados antes de abrir el navegador, y luego comparar el iss que vuelve en el callback, sin ninguna normalización: sin igualar mayúsculas, sin barra final, sin limpiar el percent-encoding. El servidor de arriba pone authorization_response_iss_parameter_supported: true, así que un iss ausente en la respuesta debe rechazarse de plano.

Auth de un servidor MCP remoto: ¿OAuth o clave de API?

Las dos funcionan, y la decisión va de scopes y revocación, no de teatro de seguridad.

OAuth 2.1 Clave de API
Granularidad Scopes, el solo lectura es posible Acceso completo, sin scopes
Quién guarda el secreto El cliente, renovable Tú, en un fichero de configuración o una variable de entorno
Revocación Por aplicación conectada, por el usuario Rota la clave, y rompes a todos los consumidores
Encaja con Clientes interactivos, terceros Scripts, cron, tu propio backend

En el servidor de arriba, los dos scopes se separan limpiamente: mcp:read cubre perfiles, cuentas, publicaciones, conversaciones y analíticas; mcp:write añade publicar, enviar mensajes, responder comentarios y conectar o desconectar cuentas. Una clave de API lleva acceso completo y ningún scope, que es la razón honesta para preferir OAuth en todo lo que un modelo maneje de forma interactiva. Deja un agente en mcp:read una semana antes de permitirle escribir, como en Claude como gestor de tus redes sociales.

El mismo servidor es accesible desde Claude, ChatGPT, Claude Code, Cursor y VS Code, y cuesta 49 $ al mes por 5 cuentas conectadas, cancelas cuando quieras, con 7 días gratis y sin tarjeta. Si un servidor MCP es siquiera la forma correcta para tu integración es otra pregunta, respondida en MCP o API REST para tu agente; para un ejemplo real dentro de un cliente, mira el servidor MCP de Instagram.

Texto normativo completo: la especificación de autorización de MCP, leída el 16 de octubre de 2026.

Preguntas frecuentes

¿Un servidor MCP necesita OAuth?

Solo si es remoto y quieres autorización por usuario. La autorización es opcional en la especificación, y los servidores stdio locales no deberían usarla en absoluto, sino tomar las credenciales del entorno. Un servidor HTTP que sirve a varios usuarios debería implementarla, porque una clave de API da el mismo acceso completo a quien la tenga.

¿Qué versión de OAuth usa MCP?

OAuth 2.1, con PKCE obligatorio en todos los clientes, metadatos de recurso protegido (RFC 9728) obligatorios en todos los servidores, y el parámetro resource de la RFC 8707 obligatorio en las peticiones de autorización y de token. La revisión actual es la 2026-07-28, que además incorpora la identificación del emisor de la RFC 9207.

¿Sigue siendo obligatorio el registro dinámico de clientes en MCP?

No. Pasó de SHOULD en la revisión 2025-06-18 a MAY en la actual, y la especificación lo llama obsoleto, conservado para servidores que no soportan Client ID Metadata Documents. CIMD es la vía recomendada: el cliente usa una URL HTTPS como client ID y el servidor de autorización lee allí los metadatos.

¿Por qué mi cliente MCP me pide iniciar sesión una y otra vez?

Normalmente un refresh token caducado o revocado con un cliente que reintenta el flujo en lugar de parar. La especificación dice a los clientes que limiten los reintentos y traten el fallo repetido como definitivo. Comprueba si el usuario revocó la app, y si tu servidor de autorización rota los refresh tokens, algo que debe hacer con clientes públicos.

¿Qué significa un 403 de un servidor MCP?

El token es válido pero le falta un scope que la operación necesita. El servidor debería devolver error="insufficient_scope" junto con los scopes requeridos, y el cliente debería reautorizar pidiendo esos más todo lo que ya tenía. Un 401 significa credenciales ausentes o inválidas, y un 400 significa que la propia petición de autorización estaba mal formada.

AB
Antoine BlancoFundador de PlugKit. Gestiona sus propias cuentas de Instagram, YouTube y X a través de la API y del servidor MCP que se describen aquí.

Un solo plug para cada plataforma que toca tu agente

49 $ al mes por 5 cuentas conectadas, cancela cuando quieras. Todas las funciones en todos los planes.

Consigue tu clave de API →
Español ▾