5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[ADK] Vertex AI Agent Engineでユーザー認証付きMCPサーバーを使う

Last updated at Posted at 2025-12-05

この記事は 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_challengecode_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

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?