😎

MCPのOAuth2認可フローをAmazon Bedrock AgentCore Gatewayで検証してみる

に公開

みなさま、こんにちは。自分のMCPをリモートで公開したいなあ、そんなことはありませんか?そこで悩ましい点が、「Remote MCPをセキュアに公開する方法」です。非常に多くの企業が検討を進めているテーマですね。

2025年10月時点では、まだRemote MCPにおける安心安全な認証認可フローは議論が進んでおり、すでにGitHubなど様々な企業がRemote MCPを公開する中、企業によって対応状況はまちまちであり、標準的なフローは定まっていません。

そこで現時点で対応しておくべき標準的な認可フローについて、実装レベルで検証してみました。加えて、私が今後推そうと思っているAmazon Bedrock AgentCore Gateway(以降 AgentCore Gatewayとします)を利用して、この認可フローに準拠してるかも合わせて検証してみたので、その結果をまとめていきたいと思います。

Remote MCPの標準的な認可フローとは?

一般的にローカルMCPにおける課題は以下のようなものでした。

  • 事前に発行されたアクセス用トークンを持ち続ける必要がある(Tokenは手動でリフレッシュが必要)
  • ローカルモジュールを参照しているので、複数メンバーが利用する場合のバージョン管理や可視性が下がる

対してRemote MCPでは、事前にトークンが不要になり様々なAgentに共通のモジュールを公開できるようになります。これは大きなメリットですね。

では、Remote MCPを公開するにあたって推奨されている認証認可フローはどのようなものでしょうか。MCPの公式ドキュメントでは、以下のような記述がされております。

Overview

  1. Authorization servers MUST implement OAuth 2.1 with appropriate security measures for both confidential and public clients.
  2. Authorization servers and MCP clients SHOULD support the OAuth 2.0 Dynamic Client Registration Protocol (RFC7591).
  3. MCP servers MUST implement OAuth 2.0 Protected Resource Metadata (RFC9728). MCP clients MUST use OAuth 2.0 Protected Resource Metadata for authorization server discovery.
  4. Authorization servers MUST provide OAuth 2.0 Authorization Server Metadata (RFC8414). MCP clients MUST use the OAuth 2.0 Authorization Server Metadata.

https://mcp-staging-aaronpk-enterprise-mcp.mintlify.app/specification/2025-06-18/basic/authorization

この記事では上記のフローを文章や図で説明するのではなく、実際に実装されたMCPを利用して動きを見ていこうと思います。

実際に認可フローを検証してみる

さきほどのドキュメントから、期待される動作は以下の流れになります。

  1. MCP ClientからMCP Serverにトークンなしでアクセスした際、HTTP401とともにヘッダーにResource metadata の問い合わせ先が入った状態で買ってくる(RFC9728)
  2. 1で得たエンドポイントに、認可サーバーの情報を問い合わせ、取得する(RFC9728)
  3. 認可サーバーに対してAuthorization Server Metadataを問い合わせ、取得する(RFC8414)
  4. Authorization Server Metadataから取得した/register エンドポイントに、クライアント登録のリクエストを送り、認可サーバー側でクライアント登録が完了する(RFC7591)
  5. Authorization Server Metadataから取得した/authorizeエンドポイントに認可リクエストを送り、認証ページにリダイレクトする
  6. 認証が完了し、アクセストークンを得た状態で元のページに遷移する

これを検証するのに、Cloudflareさんが素晴らしいMCPサーバーのサンプルを公開しているので、こちらを利用していこうと思います。

https://github.com/cloudflare/ai/tree/main/demos/remote-mcp-github-oauth

上記を立ち上げて、MCP Inspectorでアクセスをしてみます。OAuth2のクライアントID/クライアントシークレットや、アクセストークンは特に定義していません。

すると、MCP Server側で以下のログがどどっと出てきます。

[wrangler:info] GET /sse 401 Unauthorized (7ms)
[wrangler:info] GET /.well-known/oauth-protected-resource 404 Not Found (2ms)
[wrangler:info] GET /.well-known/oauth-authorization-server 200 OK (1ms)
[wrangler:info] GET /.well-known/oauth-protected-resource/sse 404 Not Found (1ms)
[wrangler:info] GET /.well-known/oauth-protected-resource 404 Not Found (1ms)
[wrangler:info] GET /.well-known/oauth-authorization-server/sse 404 Not Found (1ms)
[wrangler:info] GET /.well-known/oauth-authorization-server 200 OK (2ms)
[wrangler:info] POST /register 201 Created (11ms)
[wrangler:info] GET /authorize 200 OK (9ms)

一つ一つ見ていきましょう。

[wrangler:info] GET /sse 401 Unauthorized (7ms)

こちらは以下のMCPのドキュメントに書かれているように、トークンを入れない状態でMCPにリクエストをかけると、401のUnauthorized responseとresource metadataが埋め込まれたヘッダーが返ってくるというものです。

WWW-Authenticate Header: Include the resource metadata URL in the WWW-Authenticate HTTP header under resource_metadata when returning 401 Unauthorized responses, as described in RFC9728 Section 5.1.
2.3.1 Authorization Server Location

ただ、今回利用しているMCPサーバーはヘッダーにmetadataを入れていないため、MCP Client側の実装により同じエンドポイントにfallbackされています。

[wrangler:info] GET /.well-known/oauth-protected-resource 404 Not Found (2ms)

こちらは、RFC9728で定義されているProtected Resource Metadata Requestに基づいたリクエストになります。resource metadataに付与されたエンドポイントに対して、具体的な認可サーバーの場所が記載されたmetadataを問い合わせしています。

今回のMCPサーバーでは対応しておらず、前段と同様にMCP Client側で認可サーバーへのアクセスパスにfallbackされています。

[wrangler:info] GET /.well-known/oauth-authorization-server 200 OK (1ms)

こちらは、RFC8414で定義されているAuthorization Server Metadataに基づいたリクエストになります。issuer, authorization_endpoint, token_endpointなどが含まれたmetadataを認可サーバーにリクエストします。

Authorization Metadataの例

{
      "issuer":
        "https://server.example.com",
      "authorization_endpoint":
        "https://server.example.com/authorize",
      "token_endpoint":
        "https://server.example.com/token",
      "token_endpoint_auth_methods_supported":
        ["client_secret_basic", "private_key_jwt"],
      "token_endpoint_auth_signing_alg_values_supported":
        ["RS256", "ES256"],
      "userinfo_endpoint":
        "https://server.example.com/userinfo",
      "jwks_uri":
        "https://server.example.com/jwks.json",
      "registration_endpoint":
        "https://server.example.com/register",
    ....
     }

[wrangler:info] POST /register 201 Created (11ms)

こちらでは、RFC7591で定義されているDynamic Client Registrationをリクエストするためのエンドポイントです。今回のClientをMCP側の認可サーバーに登録してもらうようにリクエストします。

[wrangler:info] GET /authorize 200 OK (9ms)

上記は実際に認可リクエストを送った際に出力されたログです。以下のようなURLが返却されブラウザが遷移していることがわかります。PKCEの形式にそってクライアント側で生成したcode_challengeを送っています。

http://localhost:8788/authorize?response_type=code&client_id=xxxx&code_challenge=xxxx&code_challenge_method=S256&redirect_uri=http%3A%2F%2Flocalhost%3A6274%2Foauth%2Fcallback&state=xxxx

ブラウザ上では、/authorize のレスポンスとしてGitHubへのアクセス許可を確認するページを返してブラウザ上で表示されていることがわかります。

Aprroveをクリックすると、GitHubの認証エンドポイント( https://github.com/login/oauth/authorize)にリダイレクトされ、GitHubの認証画面に飛びます。

https://github.com/login/oauth/authorize?client_id=xxxx&redirect_uri=http%3A%2F%2Flocalhost%3A8788%2Fcallback&scope=read%3Auser&state=xxxxxxxxxx&response_type=code

こちらをログインすると、アクセストークンが付与された状態でもともと開いていたMCP Inspectorの画面にcallbackされていることが確認できます。

http://localhost:6274/oauth/callback?code=kishi-k%3A{client_id}%{secret}&state=xxxxxxxx

試しに Toolsをアクセスすると、上記のトークン情報をヘッダーに入れてアクセスできていることが確認できました。

POST /sse/message?sessionId=3fddd2a701911972a706df7959e7e331c8965a6342cb116f77c5218bbf768e28 HTTP/1.1
Accept: text/event-stream
Authorization: Bearer kishi-k:{client_id}:{secret}

MCP Inspectorでは以下のようになります。

これでURLだけでRemote MCPにアクセスしてから、返ってきたアクセストークンを利用してMCPにアクセスできるところまで確認できました🎉

Amazon Bedrock AgentCore Gatewayの立ち位置

前段ではMCPにおける標準的な認可フローの確認ができました。今後MCPサーバー側がこのフローに準拠しなければいけないということは、自分自身でMCPを公開するときに、これらのリクエストにもMCPサーバー側が答えられるようにしなければいけないということになります。

一方でAWSでは「Amazon Bedrock AgentCore」というAgentやMCPを開発・公開するためのマネージドなサービスが最近GAとなりました。そのうちの一つに、「Amazon Bedrock AgentCore Gateway (以降 AgentCore Gatewayとします)」というMCPifyとしてMCPをマネージドでリモートに公開するサービスがあります。

個人的にAgentCoreのサービス群のうち、AgentCore Gatewayが最も魅力を感じているサービスなので、それについても記載しておきます。

従来ではRemoteMCPを公開するにあたって、以下のような課題を感じていました。

  • Agent側の課題:複数のMCPを扱うことで、アクセス情報が肥大化し管理が煩雑になる。MCP側のアクセス方法も統一化されておらず、Agent側の管理負荷は増すばかり。加えて、Agentごとにアクセス情報の管理を任せることになり、セキュリティリスクが懸念される

  • MCP側の課題:リモートに公開する際、公開方法をセキュアにやらなければならない。MCP側で定められている標準機能を独自で実装する必要がある

これをAgentCore Gatewayを利用することで、Agent側のアクセス管理の負荷、MCP側の共通機能部分の実装をGatewayに集約することができます。そのため、MCPの開発者は個々のMCP機能の実装に集中し、共通部分はAgentCore Gatewayに任せることができます。Agent側も、エンドポイントひとつを意識するだけで様々なMCPを活用することができます。これは個人的に大変魅力的でした。

ただまだGAしたてということもあり、まだすべてのユースケースに対応できているかは怪しいので、今後のリリース機能に期待したいところです。

もしAgentCore Gatewayがこのフローに対応していれば、ユーザー側は認可フローの実装を気にせずMCPに準拠し公開することができますが、このAgentCore Gatewayでは、OAuth2の認可フローに対応状況は公式には言及されていません。なので、試してみることにしました。

AgentCore Gatewayで検証してみる

実際に検証してみましょう。私のほうでAgentCoreでAgent+MCPの構成を簡単に立ち上げるサンプルを作成したので、もしよろしければご活用ください。Gatewayを作成するパートだけ実施いただければ大丈夫です。 この構成では、MCPサーバー側がAgentCore Gateway, 認可サーバー側がAmazon Cognito ユーザープールになります。

https://github.com/kishi-k/agentcore-basic-arch-sample

まずは、トークンを付与せずAgentCore GatewayのエンドポイントにGETしてみます。

curl -i -X POST https://github-mcp-xxxxxxxxxx.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp  \
  -H 'Content-Type: application/json' 
HTTP/2 401
date: Wed, 15 Oct 2025 12:53:40 GMT
content-type: application/json
content-length: 86
x-amzn-requestid: 3caa9769-cbda-4568-8cb2-4e1149ab28f5
www-authenticate: **Bearer resource_metadata="https://github-mcp-xxxxxxxxxx.gateway.bedrock-agentcore.us-west-2.amazonaws.com/.well-known/oauth-protected-resource"**
x-amzn-remapped-content-type: application/json

{"jsonrpc":"2.0","id":"ping","error":{"code":-32001,"message":"Missing Bearer token"}}

そうするとHTTP 401が返り、ヘッダーにresource_metadataのアクセス先が付与されています。こちらに対して、Resource Metadataをリクエストしてみると、AgentCore Gatewayで設定した認可サーバー(今回はAmazon Cognitoを指定)のエンドポイントが表示されていることがわかります。

curl https://github-mcp-xxxxxxxxxx.gateway.bedrock-agentcore.us-west-2.amazonaws.com/.well-known/oauth-protected-resource

{
    "authorization_servers":["https://cognito-idp.us-west-2.amazonaws.com/us-west-2_xxxxxxxxx"],
    "resource":"https://github-mcp-xxxxxxxxxx.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp"
}

これで、AgentCore GatewayがRFC9728に準拠していることが確認できました!🎉

ここからはおまけですが今回設定している認可サーバーに対して、認可サーバーのAuthorization Metadataを取得してみます。AmazonCognitoは、OpenID Connectの方式に準拠しているので、以下のようなリクエストを投げます。

 curl -i https://cognito-idp.us-west-2.amazonaws.com/us-west-2_xxxxxxxxc/.well-known/openid-configuration

すると、以下のようなメタデータを取得できます。

{
    "authorization_endpoint":"https://agentcore-xxxxxxxx.auth.us-west-2.amazoncognito.com/oauth2/authorize",
    "end_session_endpoint":"https://agentcore-xxxxxxxx.auth.us-west-2.amazoncognito.com/logout",
    "id_token_signing_alg_values_supported":["RS256"],
    "issuer":"https://cognito-idp.us-west-2.amazonaws.com/us-west-2_xxxxxxxx",
    "jwks_uri":"https://cognito-idp.us-west-2.amazonaws.com/us-west-2_xxxxxxxx/.well-known/jwks.json",
    "response_types_supported":["code","token"],
    "revocation_endpoint":"https://agentcore-xxxxxxxx.auth.us-west-2.amazoncognito.com/oauth2/revoke",
    "scopes_supported":["openid","email","phone","profile"],
    "subject_types_supported":["public"],
    "token_endpoint":"https://agentcore-xxxxxxxx.auth.us-west-2.amazoncognito.com/oauth2/token",
    "token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post"],
    "userinfo_endpoint":"https://agentcore-xxxxxxxx.auth.us-west-2.amazoncognito.com/oauth2/userInfo"
}

Amazon Cognitoを利用することで、RFC8414にも準拠したフローが実現可能そうです。

最後に

公式では記されていませんが、Remote MCPで標準化されつつある認証認可フローを確認し、AgentCore Gatewayでの対応状況を確認しました。AgentCore GatewayにもしMCPの認可フローを集約できれば、AgentCore Gatewayの価値もグッとあがってくると思います。

今回途中で紹介したサンプルは、AgentCoreを活用したAgentとRemote MCPの構成を簡単に実装したサンプルになっています。Agentの本番利用を見据えた最小構成として、ぜひご参考ください。

https://github.com/kishi-k/agentcore-basic-arch-sample

それでは!

アマゾン ウェブ サービス ジャパン (有志)

Discussion