この記事は ADK Advent Calendar 2025 6日目の記事です。
はじめに
ADK(Agent Development Kit)はGoogleが提供するAIエージェント開発キットです。Vertex AI Agent Engineでフルサポートされており、本番環境へのデプロイが容易なため、ADKを選択する方も多いのではないでしょうか。
ADKはMCP(Model Context Protocol)にも対応していて、MCPサーバーを通じてSlackやGitHubなどの外部サービスと連携できます。
ただ、本番環境では「ユーザーAがSlackを使うときはユーザーAのアカウントで」という具合に、ユーザーごとのOAuth認証が必要になります。ここでADKとMCPの認証仕様に差分があり、少し工夫が必要でした。
この記事では、その差分と試行錯誤の結果を紹介します。
ADKの認証方式
ADKにはadk_request_credentialという認証の仕組みがあります。認証が必要なツールを実行しようとしたとき、ADKがクライアントアプリに認証を要求し、ユーザーにログイン画面を表示させる流れです。
参考: ADK Authentication Documentation
ADKが想定している認証フロー
1. MCPサーバーに接続(この時点では認証なし)
2. ツール実行時に認証が必要と判断
3. ADKが adk_request_credential を発行
4. クライアントアプリがログイン画面を表示
5. ユーザーがブラウザで認証
6. 認可コードがクライアントに返る
7. クライアントが認可コードをADKに送信
8. ADKがトークン交換・保存
9. ツール実行を再開
ポイント: ADKのOAuth実装はOAuth 2.0ベースで、PKCEには対応していません。
MCPの認証仕様
MCPサーバーが認証を要求する場合、OAuth 2.1準拠が必須と定められています。
OAuth 2.1では**PKCE(Proof Key for Code Exchange)**が必須です。PKCEは認可コード横取り攻撃を防ぐための仕組みで、code_challengeとcode_verifierというパラメータを使います。
MCPが想定している認証フロー
1. MCPサーバーへの接続時に認証を要求
(正確には、すべてのリクエストで401が返り認証フローが開始)
2. クライアントがPKCE付きの認証URLを生成
3. ユーザーがブラウザで認証
4. 認可コードがクライアントに返る
5. クライアントがPKCE付きでトークン交換
6. アクセストークンでMCPサーバーにアクセス
ポイント: MCPのOAuth実装はOAuth 2.1ベースで、PKCEが必須です。
課題と解決策
ここまでの内容をまとめると、ADKとMCPには以下の差分があります:
| 項目 | ADK | MCP |
|---|---|---|
| OAuth | 2.0 | 2.1 |
| PKCE | 未対応 | 必須 |
| 認証タイミング | ツール実行時 | 接続時(正確には401で発火) |
この差分を埋めるために、以下の対応が必要でした。
課題1: PKCE未対応
ADKはPKCEパラメータ(code_challenge/code_verifier)を生成しません。MCP仕様ではPKCEが必須なので、自前で生成する必要があります。
課題2: 認証タイミングの違い
ADKのadk_request_credentialはツール実行時に発火します。しかしMCP仕様では、すべてのHTTPリクエストにAuthorizationヘッダーが必要です。MCPサーバーへの接続(initialize)やツール一覧取得(tools/list)の時点で認証が必要になります。
そこでbefore_model_callbackを使って、LLMにリクエストを送る前にトークンをチェックし、なければ認証URLを返す方式にしました。
関連PR: google/adk-python#3342 - この問題を解決するパターンが提案されていますが、2025年12月時点で未マージです。
実装した認証フロー
上記の課題を解決するため、以下のフローを実装しました:
1. before_model_callbackでトークンの有無をチェック
2. トークンなし → PKCE対応の認証URLを生成して返却
3. ユーザーがブラウザで認証
4. Callback Serverがコールバックを受信、トークン交換
5. トークンをRedisに保存
6. 次回リクエスト時、トークンを使ってMCPサーバーに接続
before_model_callbackはADKが提供するフックで、LLMにリクエストを送る直前に処理を挟むことができます。ここでトークンをチェックし、なければLLM呼び出しをスキップして認証URLを返します。
補足: adk_request_credentialを使わなかった理由
本実装ではADKのadk_request_credentialを使わず、独自実装しました。そのためCallback ServerとRedisによるトークン管理が必要になっています。
独自実装にした理由:
- PKCEに対応するため、認証URL生成を自前で行う必要があった
- クライアントがサーバーアプリだったので、シンプルにテキストで認証URLを返す方式にした
adk_request_credentialを使う場合:
adk_request_credentialを使う場合、ADKのドキュメントにある通り、OAuthコールバックはクライアント側で受け取ります:
"Your application must have a mechanism (e.g., a web server route at the redirect_uri) to receive the user after they authorize the application"
この方式では、クライアントがコールバックを受け取り、認可コードをAgent Engineに送信します。ADKのAuthHandlerがトークンをsession stateに書き込み、VertexAiSessionService.append_eventでクラウドに永続化されるようなので、Callback ServerやRedisが不要になる可能性があります。
まとめ
ADKでMCP OAuth認証を実装する際の課題と解決策をまとめます:
| 課題 | 解決策 |
|---|---|
| PKCE未対応 |
code_challenge/code_verifierを自前で生成 |
| 認証タイミングの違い |
before_model_callbackでトークンチェック |
ADKとMCPの認証連携はドキュメントやサンプルが少なく、試行錯誤しながら実装しました。同じ課題に直面している方の参考になれば幸いです。
参考資料
仕様
GitHub
- google/adk-python#3342 - tools/list前の認証発火パターン(未マージ)
- google/adk-python#2061 - MCPToolset OAuth2対応