OAuth para clientes MCP personalizados
Si estás creando tu propio cliente MCP (CLI, SDK, plugin de IDE), esta página describe nuestra implementación de OAuth: los estándares que admitimos, los endpoints, las reglas de redirect_uri y cómo depurar errores comunes. Los usuarios de Claude.ai y ChatGPT no necesitan esta página — usa el Quickstart en su lugar.
Estándares que implementamos
mcp-telegram.com cumple totalmente con las especificaciones OAuth en las que se basa el ecosistema MCP — sin extensiones propietarias ni secretos compartidos incrustados en los clientes.
- RFC 6749 — OAuth 2.0 Authorization Framework — authorization code grant básico con refresh tokens
- RFC 7591 — Dynamic Client Registration — cualquier cliente puede registrarse en /oauth/register sin coordinación previa
- RFC 7636 — PKCE (Proof Key for Code Exchange) — challenge S256 obligatorio para clientes públicos
- RFC 8252 — OAuth 2.0 for Native Apps — redirect URIs con IP loopback y flexibilidad de puerto efímero
- RFC 8414 — OAuth 2.0 Authorization Server Metadata — documento de discovery en /.well-known/oauth-authorization-server
- RFC 9728 — OAuth 2.0 Protected Resource Metadata — discovery del límite del recurso MCP
Endpoints
Authorization code flow con PKCE
Flujo estándar de RFC 6749 §4.1 + RFC 7636. Sin sorpresas — si tu librería de OAuth maneja «authorization code + PKCE», funcionará.
Registra tu cliente
POST /oauth/register con { redirect_uris: ["http://127.0.0.1:<puerto>/callback"], client_name: "nombre-de-tu-cliente" }. El servidor devuelve client_id + client_secret (el secret es opcional para clientes públicos con PKCE, pero recibirlo no hace daño).
Genera el par PKCE
Genera un code_verifier aleatorio de 43-128 caracteres y luego calcula code_challenge = BASE64URL(SHA256(code_verifier)). Guarda el verifier localmente para el paso 4.
Abre /oauth/authorize en un navegador
Redirige al usuario a /oauth/authorize?response_type=code&client_id=...&redirect_uri=...&state=...&code_challenge=...&code_challenge_method=S256. El servidor muestra un código QR; el usuario lo escanea en la app de Telegram para autenticarse.
Recibe el código de autorización
Tras escanear el QR, el servidor redirige a tu redirect_uri con ?code=...&state=.... Verifica que el parámetro state coincida con el que enviaste.
Intercambia el code por un token
POST /oauth/token con grant_type=authorization_code, code, redirect_uri, code_verifier, client_id. Recibirás un access_token (TTL de 10 años — ver Token Lifetime más abajo) y un refresh_token. Usa el access_token como Authorization: Bearer ... en las llamadas a /mcp.
Reglas de coincidencia de redirect_uri
Seguimos RFC 8252 §7.3 y §8.4 al pie de la letra. El algoritmo de coincidencia depende de si el URI registrado es un literal de IP loopback.
Loopback (http://127.0.0.1 o http://[::1])
Si registraste un URI loopback, el redirect_uri en el momento de authorize debe coincidir exactamente en scheme, host, path y query — pero el puerto puede ser distinto. Esto lo exige RFC 8252 §7.3 porque los clientes nativos vinculan un puerto efímero asignado por el sistema operativo que puede cambiar entre ejecuciones.
- Registrado http://127.0.0.1:36201/callback coincide con http://127.0.0.1:50000/callback en authorize ✅
- Registrado http://127.0.0.1:36201/callback NO coincide con http://127.0.0.1:50000/different-path — el path debe ser exacto
- Registrado http://[::1]:36201/cb NO coincide con http://127.0.0.1:36201/cb — IPv4 y IPv6 loopback son identificadores distintos
HTTPS (https://your-domain.example/...)
Se exige coincidencia exacta byte a byte, incluyendo path, query y puerto (RFC 6749 §3.1.2). Sin flexibilidad.
localhost (NO recomendado)
Tratamos http://localhost como un hostname normal — se exige coincidencia exacta, sin flexibilidad de puerto. RFC 8252 §8.3 recomienda usar literales de IP (127.0.0.1 / [::1]) en vez de localhost porque la resolución DNS depende de la implementación.
PKCE es obligatorio
code_challenge_method=S256 es obligatorio en cada petición de authorize. El método plain se rechaza. Si omites code_challenge por completo, el intercambio en /token fallará al validar el code_verifier.
Tiempo de vida del token
El TTL del access_token es deliberadamente largo (10 años) porque algunos clientes MCP no guardan el refresh_token de forma fiable. Aun así se emite un refresh_token y rota en cada refresh (RFC 6819 §5.2.2.3). El usuario puede revocar todos los tokens en cualquier momento en /my/sessions o cerrando sesión en Telegram. También puede hacer un POST explícito a /oauth/revoke (RFC 7009) para terminar la sesión.
Errores comunes
HTTP 400 «Invalid redirect_uri» en /oauth/authorize
El parámetro redirect_uri no coincide con ningún URI registrado para este client_id. Para clientes loopback: comprueba que scheme + host + path + query coincidan exactamente (solo el puerto es flexible). Para clientes HTTPS: se exige igualdad byte a byte — cuidado con las barras finales y las diferencias de URL-encoding.
HTTP 400 «Unknown client»
El client_id no existe en nuestra base de datos. O bien te saltaste el paso /oauth/register, o la respuesta del registro se perdió antes de que guardases el client_id, o el cliente fue revocado por el usuario en /my/clients.
El cliente muestra «Needs Auth» repetidamente
Si tu cliente guarda el access_token pero no el refresh_token, verás esto cuando el access_token caduque. Nuestros access tokens tienen un TTL de 10 años precisamente para mitigarlo, pero si tu cliente caduca los tokens por su cuenta antes de eso, tendrás que guardar el refresh_token o llamar a /oauth/revoke + volver a autenticarte bajo demanda.
Clientes probados
Compatibilidad confirmada con nuestro servidor. Si construyes algo nuevo y funciona, mándanos un PR para añadirlo aquí.
- Claude.ai web — mediante el connector MCP integrado
- ChatGPT Apps — mediante el connector MCP integrado
- Hermes Agent — cliente MCP open-source en CLI (flujo loopback RFC 8252)
- Cursor MCP — plugin de IDE (flujo loopback RFC 8252)
- Cualquier cliente que cumpla con RFC 6749 + RFC 7591 + RFC 7636 + RFC 8252 debería funcionar sin cambios en nuestro lado.
Varias cuentas de Telegram en una sola conexión OAuth
Desde v2.32.0 una única conexión OAuth puede contener varias identidades de Telegram y alternar entre ellas con una sola llamada de herramienta — sin ciclo Disconnect/Connect, sin registrar un nuevo cliente.
Liste lo que está vinculado
Llame a telegram-accounts-list. Verá su cuenta primary (vinculada a OAuth) marcada con ⭐ si está activa, además de las secundarias que haya añadido.
Vincule otra cuenta
Llame a telegram-accounts-add con una etiqueta opcional (p. ej. "testing"). La herramienta devuelve una URL de un solo uso (TTL 10 minutes) — ábrala en cualquier dispositivo y escanee el QR con la cuenta de Telegram que desea añadir.
Cambie la cuenta activa
Llame a telegram-accounts-switch con identifier=label, @username, account_id o 'primary'. La siguiente llamada a una herramienta telegram-* usará esa cuenta de inmediato. Sin reconexión.
Desvincule una secundaria
Llame a telegram-accounts-remove identifier=… sobre una secundaria. La cuenta de Telegram en sí NO se cierra — solo se elimina el vínculo aquí. La primary no puede eliminarse de esta forma; use el flujo Disconnect de su cliente para cerrar la sesión por completo.
Cada conexión OAuth está aislada: las cuentas que vincule mediante Hermes son invisibles para Claude.ai o ChatGPT, incluso si se trata de la misma identidad de Telegram. Para conectar cuentas distintas a distintos clientes MCP, registre cada cliente por separado y use telegram-accounts-add dentro de su propia sesión.