OAuth for custom MCP clients
If you're building your own MCP client (CLI, SDK, IDE plugin), this page describes our OAuth implementation: standards we support, endpoints, redirect_uri rules, and how to debug common errors. Claude.ai and ChatGPT users don't need this page — use the Quickstart instead.
Standards we implement
mcp-telegram.com is fully compliant with the OAuth specifications that the MCP ecosystem relies on — no proprietary extensions, no shared secrets baked into clients.
Endpoints
Authorization code flow with PKCE
Standard RFC 6749 §4.1 + RFC 7636 flow. No surprises — if your OAuth library handles "authorization code + PKCE", it will work.
Register your client
POST /oauth/register with { redirect_uris: ["http://127.0.0.1:«port»/callback"], client_name: "your-client-name" }. The server returns client_id + client_secret (the secret is optional for public PKCE clients but harmless to receive).
Generate PKCE pair
Generate a random 43-128 char code_verifier, then compute code_challenge = BASE64URL(SHA256(code_verifier)). Store the verifier locally for step 4.
Open /oauth/authorize in a browser
Redirect the user to /oauth/authorize?response_type=code&client_id=...&redirect_uri=...&state=...&code_challenge=...&code_challenge_method=S256. The server displays a QR code; the user scans it in the Telegram app to authenticate.
Receive the authorization code
After QR scan, the server redirects to your redirect_uri with ?code=...&state=.... Verify the state parameter matches what you sent.
Exchange code for token
POST /oauth/token with grant_type=authorization_code, code, redirect_uri, code_verifier, client_id. Receive an access_token (10-year TTL — see Token Lifetime below) and a refresh_token. Use the access_token as Authorization: Bearer ... on /mcp requests.
redirect_uri matching rules
We follow RFC 8252 §7.3 and §8.4 strictly. The matching algorithm depends on whether the registered URI is a loopback IP literal.
Loopback (http://127.0.0.1 or http://[::1])
If you registered a loopback URI, the authorize-time redirect_uri must match scheme, host, path, and query exactly — but the port may differ. This is required by RFC 8252 §7.3 because native clients bind an OS-assigned ephemeral port that may change between runs.
- Registered http://127.0.0.1:36201/callback matches authorize-time http://127.0.0.1:50000/callback ✅
- Registered http://127.0.0.1:36201/callback does NOT match http://127.0.0.1:50000/different-path — path must be exact
- Registered http://[::1]:36201/cb does NOT match http://127.0.0.1:36201/cb — IPv4 and IPv6 loopback are separate identifiers
HTTPS (https://your-domain.example/...)
Exact byte-for-byte match required, including path, query, and port (RFC 6749 §3.1.2). No flexibility.
localhost (NOT recommended)
We treat http://localhost as a regular hostname — exact match required, no port flexibility. RFC 8252 §8.3 recommends using IP literals (127.0.0.1 / [::1]) instead of localhost because DNS resolution is implementation-dependent.
Common errors
Tested clients
Confirmed to interoperate with our server. If you build something new and it works, send us a PR to add it here.
Multiple Telegram accounts on one OAuth connection
Since v2.32.0 a single OAuth connection can hold several Telegram identities and switch between them with one tool call — no Disconnect/Connect cycle, no new client registration.
List what's attached
Call telegram-accounts-list. You will see your primary (OAuth-bound) account marked with ⭐ if it's active, plus any secondaries you've added.
Attach another account
Call telegram-accounts-add with an optional label (e.g. "testing"). The tool returns a one-time URL (TTL 10 minutes) — open it on any device and scan the QR with the Telegram account you want to add.
Switch active account
Call telegram-accounts-switch with identifier=label, @username, account_id, or 'primary'. The next telegram-* tool call uses that account immediately. No reconnect.
Detach a secondary
Call telegram-accounts-remove identifier=… on a secondary. The Telegram account itself is NOT logged out — only the binding here. The primary cannot be removed this way; use your client's Disconnect flow to fully sign out.
Each OAuth connection is isolated: accounts you attach via Hermes are invisible to Claude.ai or ChatGPT, even if it's the same Telegram identity. To connect different accounts to different MCP clients, register each client separately and use telegram-accounts-add inside its own session.