カスタム MCP クライアント向け OAuth
自前の MCP クライアント(CLI、SDK、IDE プラグイン)を開発している場合、このページでは私たちの OAuth 実装について説明します。サポートする標準、エンドポイント、redirect_uri のルール、よくあるエラーのデバッグ方法を解説します。Claude.ai や ChatGPT のユーザーにはこのページは不要です — 代わりに Quickstart をご覧ください。
実装している標準
mcp-telegram.com は MCP エコシステムが依存する OAuth 仕様に完全準拠しています — 独自拡張も、クライアントに埋め込まれた共有シークレットもありません。
- RFC 6749 — OAuth 2.0 Authorization Framework — refresh トークンを伴うベースの authorization code grant
- 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 redirect URI
- RFC 8414 — OAuth 2.0 Authorization Server Metadata — /.well-known/oauth-authorization-server の discovery ドキュメント
- RFC 9728 — OAuth 2.0 Protected Resource Metadata — MCP リソース境界の discovery
エンドポイント
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 クライアントでは任意ですが、受け取っても問題ありません)。
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 をトークンと交換する
POST /oauth/token に grant_type=authorization_code, code, redirect_uri, code_verifier, client_id を付けて送信します。access_token(TTL 10 年 — 下記の Token Lifetime を参照)と refresh_token を受け取ります。/mcp リクエストでは access_token を Authorization: Bearer ... として使用します。
redirect_uri のマッチングルール
私たちは RFC 8252 §7.3 および §8.4 を厳格に遵守しています。マッチングのアルゴリズムは、登録された URI が loopback IP リテラルかどうかに依存します。
ループバック (http://127.0.0.1 または http://[::1])
loopback URI を登録した場合、authorize 時の redirect_uri は scheme、host、path、query が完全に一致する必要があります — ただしポートは異なっていても構いません。ネイティブクライアントは OS が割り当てるエフェメラルポートにバインドし、これは実行ごとに変わる可能性があるため、RFC 8252 §7.3 によりこれが要求されています。
- 登録された http://127.0.0.1:36201/callback は authorize 時の 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 のループバックは別の識別子です
HTTPS (https://your-domain.example/...)
path、query、ポートを含めてバイト単位で完全一致が必要です (RFC 6749 §3.1.2)。柔軟性はありません。
localhost (推奨されません)
http://localhost は通常のホスト名として扱います — 完全一致が必要で、ポートの柔軟性はありません。RFC 8252 §8.3 では、DNS 解決が実装依存であるため、localhost ではなく IP リテラル (127.0.0.1 / [::1]) の使用を推奨しています。
PKCE は必須
すべての authorize リクエストで code_challenge_method=S256 が必須です。Plain method は拒否されます。code_challenge を完全に省略すると、/token 交換時の code_verifier 検証で失敗します。
トークンの有効期間
access_token の TTL は意図的に長く設定されています(10 年)。これは、一部の MCP クライアントが refresh_token を確実に永続化しないためです。refresh_token は引き続き発行され、refresh のたびにローテーションされます (RFC 6819 §5.2.2.3)。ユーザーはいつでも /my/sessions ですべてのトークンを取り消すか、Telegram からログアウトすることができます。また、明示的に POST /oauth/revoke (RFC 7009) を呼び出してセッションを終了させることも可能です。
よくあるエラー
/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 年に設定されていますが、クライアント側でより短い期間でトークンを期限切れにする場合は、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 に準拠したクライアントであれば、私たちの側でコードを変更することなく動作するはずです。
1 つの OAuth 接続で複数の Telegram アカウントを管理
v2.32.0 以降、1 つの OAuth 接続で複数の Telegram アイデンティティを保持し、ツール呼び出し 1 回で切り替えられるようになりました。Disconnect/Connect のサイクルも、新しいクライアント登録も不要です。
接続済みアカウントを確認する
telegram-accounts-list を呼び出します。プライマリ(OAuth にバインドされた)アカウントがアクティブな場合は ⭐ 付きで表示され、追加したセカンダリアカウントも一覧に表示されます。
別のアカウントを追加する
telegram-accounts-add を呼び出します。ラベル(例: "testing")はオプションで指定できます。ツールはワンタイム URL(TTL 10 分)を返すので、任意のデバイスで開き、追加したい Telegram アカウントで QR をスキャンしてください。
アクティブなアカウントを切り替える
telegram-accounts-switch を identifier=label、@username、account_id、または 'primary' を指定して呼び出します。次の telegram-* ツール呼び出しから、そのアカウントが即座に使用されます。再接続は不要です。
セカンダリアカウントを切り離す
セカンダリアカウントに対して telegram-accounts-remove identifier=… を呼び出します。Telegram アカウント自体はログアウトされず、ここでのバインディングだけが解除されます。プライマリはこの方法では削除できません。完全にサインアウトするには、クライアントの Disconnect フローを使用してください。
各 OAuth 接続は分離されています。Hermes 経由で追加したアカウントは、同じ Telegram アイデンティティであっても Claude.ai や ChatGPT からは見えません。異なる MCP クライアントに異なるアカウントを接続するには、各クライアントを個別に登録し、それぞれのセッション内で telegram-accounts-add を使用してください。