為自訂 MCP 用戶端使用 OAuth
如果你正在開發自己的 MCP 用戶端(CLI、SDK、IDE 外掛),本頁介紹我們的 OAuth 實作:支援的標準、端點、redirect_uri 規則,以及如何排除常見錯誤。Claude.ai 和 ChatGPT 的使用者不需要本頁——請改用快速入門。
我們實作的標準
mcp-telegram.com 完全符合 MCP 生態系所依賴的 OAuth 規範——沒有專有擴充,也沒有把共用密鑰寫死在用戶端裡。
- RFC 6749 — OAuth 2.0 Authorization Framework — 基本的 authorization code grant 搭配 refresh token
- RFC 7591 — Dynamic Client Registration — 任何用戶端皆可透過 /oauth/register 自行註冊,無需事先協調
- RFC 7636 — PKCE (Proof Key for Code Exchange) — 公開用戶端必須使用 S256 challenge
- RFC 8252 — OAuth 2.0 for Native Apps — loopback IP 重新導向 URI 支援臨時連接埠的彈性
- RFC 8414 — OAuth 2.0 Authorization Server Metadata — 探索文件位於 /.well-known/oauth-authorization-server
- RFC 9728 — OAuth 2.0 Protected Resource Metadata — 用於探索 MCP 資源邊界
端點
搭配 PKCE 的 authorization code 流程
標準的 RFC 6749 §4.1 + RFC 7636 流程。沒有意外——如果你的 OAuth 函式庫能處理「authorization code + PKCE」,它就能正常運作。
註冊你的用戶端
POST /oauth/register,內容為 { redirect_uris: ["http://127.0.0.1:<port>/callback"], client_name: "your-client-name" }。伺服器會回傳 client_id 與 client_secret(對公開 PKCE 用戶端而言 secret 並非必要,但收到也無妨)。
產生 PKCE 配對
產生一個 43–128 字元的隨機 code_verifier,接著計算 code_challenge = BASE64URL(SHA256(code_verifier))。請在本地保存 verifier 以供步驟 4 使用。
在瀏覽器中開啟 /oauth/authorize
將使用者重新導向至 /oauth/authorize?response_type=code&client_id=...&redirect_uri=...&state=...&code_challenge=...&code_challenge_method=S256。伺服器會顯示 QR 碼;使用者用 Telegram 應用程式掃描以完成驗證。
接收 authorization code
掃描 QR 碼後,伺服器會以 ?code=...&state=... 重新導向回你的 redirect_uri。請驗證 state 參數與你送出的相符。
用 code 換取 token
POST /oauth/token,帶上 grant_type=authorization_code、code、redirect_uri、code_verifier、client_id。會收到 access_token(TTL 為 10 年——詳見下方 Token 生命週期)以及 refresh_token。在 /mcp 請求中以 Authorization: Bearer ... 使用 access_token。
redirect_uri 比對規則
我們嚴格遵循 RFC 8252 §7.3 與 §8.4。比對演算法取決於註冊的 URI 是否為 loopback IP 字面值。
Loopback (http://127.0.0.1 或 http://[::1])
如果你註冊的是 loopback URI,授權時的 redirect_uri 必須在 scheme、host、path 與 query 完全相符——但連接埠可以不同。RFC 8252 §7.3 要求如此,因為原生用戶端綁定的是作業系統指派的臨時連接埠,可能每次執行都會改變。
- 已註冊的 http://127.0.0.1:36201/callback 與授權時的 http://127.0.0.1:50000/callback 相符 ✅
- 已註冊的 http://127.0.0.1:36201/callback 與 http://127.0.0.1:50000/different-path 不相符——path 必須完全一致
- 已註冊的 http://[::1]:36201/cb 與 http://127.0.0.1:36201/cb 不相符——IPv4 與 IPv6 loopback 是不同的識別碼
HTTPS (https://your-domain.example/...)
必須逐位元組完全相符,包含 path、query 與連接埠 (RFC 6749 §3.1.2)。沒有任何彈性。
localhost(不建議)
我們把 http://localhost 視為一般主機名——必須完全相符,連接埠沒有彈性。RFC 8252 §8.3 建議使用 IP 字面值 (127.0.0.1 / [::1]) 而非 localhost,因為 DNS 解析會依實作而異。
PKCE 為強制要求
每個 authorize 請求都必須帶上 code_challenge_method=S256。Plain 方法會被拒絕。如果完全省略 code_challenge,/token 交換會在 code_verifier 驗證時失敗。
Token 生命週期
access_token 的 TTL 刻意設得很長(10 年),因為部分 MCP 用戶端無法可靠地保存 refresh_token。我們仍然會發出 refresh_token,並在每次刷新時輪換 (RFC 6819 §5.2.2.3)。使用者可以隨時在 /my/sessions 或登出 Telegram 來撤銷所有 token。也可以明確 POST 到 /oauth/revoke (RFC 7009) 來結束 session。
常見錯誤
在 /oauth/authorize 出現 HTTP 400 「Invalid redirect_uri」
redirect_uri 查詢參數不符合此 client_id 已註冊的任何 URI。Loopback 用戶端:檢查 scheme + host + path + query 是否完全相符(只有連接埠有彈性)。HTTPS 用戶端:需要完整逐位元組相等——注意尾端斜線與 URL 編碼的差異。
HTTP 400 「Unknown client」
我們的資料庫中找不到此 client_id。可能你跳過了 /oauth/register 步驟、註冊回應在你保存 client_id 之前就遺失,或者使用者透過 /my/clients 撤銷了該用戶端。
用戶端反覆顯示「Needs Auth」
如果你的用戶端保存了 access_token 但沒有保存 refresh_token,當 access_token 到期時就會看到這個錯誤。我們的 access token TTL 設為 10 年正是為了緩解此問題,但如果你的用戶端在較短的時間後自行讓 token 過期,那就需要保存 refresh_token,或在需要時呼叫 /oauth/revoke 並重新驗證。
已測試的用戶端
確認可與我們的伺服器互通。如果你做了新東西並且能正常運作,歡迎發 PR 加到這裡。
- Claude.ai web — 透過內建 MCP connector
- ChatGPT Apps — 透過內建 MCP connector
- Hermes Agent — 開源 CLI MCP 用戶端 (RFC 8252 loopback flow)
- Cursor MCP — IDE 外掛 (RFC 8252 loopback flow)
- 任何符合 RFC 6749 + RFC 7591 + RFC 7636 + RFC 8252 的用戶端,皆可在我們這端無需任何程式碼變更即正常運作。
單一 OAuth 連線管理多個 Telegram 帳號
自 v2.32.0 起,單一 OAuth 連線可承載多個 Telegram 身份,並僅透過一次工具呼叫即可在它們之間切換 — 無需 Disconnect/Connect 循環,也無需註冊新的用戶端。
列出已掛載的帳號
呼叫 telegram-accounts-list。您會看到綁定於 OAuth 的 primary 帳號,若其為當前作用中帳號則標示 ⭐,並列出您已新增的所有次要帳號。
掛載另一個帳號
呼叫 telegram-accounts-add,可選擇性地提供標籤(例如 "testing")。該工具會回傳一個一次性 URL(TTL 10 分鐘)— 請在任一裝置上開啟它,並以您欲新增的 Telegram 帳號掃描 QR 條碼。
切換作用中帳號
呼叫 telegram-accounts-switch,並傳入 identifier=label、@username、account_id 或 'primary'。下一次 telegram-* 工具呼叫即會立即使用該帳號,無需重新連線。
卸載次要帳號
對某個次要帳號呼叫 telegram-accounts-remove identifier=…。Telegram 帳號本身「不會」被登出 — 僅移除其與此處的綁定。primary 帳號無法透過此方式移除;請使用您用戶端的 Disconnect 流程以完整登出。
每個 OAuth 連線皆相互隔離:您透過 Hermes 掛載的帳號對 Claude.ai 或 ChatGPT 而言是不可見的,即使是相同的 Telegram 身份亦然。若欲將不同帳號連接到不同的 MCP 用戶端,請分別註冊每個用戶端,並在各自的會話中使用 telegram-accounts-add。