Amazon Bedrock AgentCore GatewayのTargetにAgentCore RuntimeにデプロイしたMCP Serverを指定してみた

Amazon Bedrock AgentCore GatewayのTargetにAgentCore RuntimeにデプロイしたMCP Serverを指定してみた

2026.01.03

こんにちは、スーパーマーケットが大好きなコンサルティング部の神野です。

早速ですが、みなさんAgentCore GatewayのTargetにAgentCore RuntimeにホストしたMCP Serverを指定したことがありますか?

AWSの公式サンプルを見ると選択肢として指定できるのはわかりますが、どういった構成で実現できるのかは図をかいて理解してみたいと思い本記事を書いてみました。

https://github.com/awslabs/amazon-bedrock-agentcore-samples/tree/main/01-tutorials/02-AgentCore-gateway/05-mcp-server-as-a-target

AgentCore Gateway

改めてGatewayについておさらいですが、GatewayのTargetは以下を選択可能です。
Gatewayを介して外部サービスをMCPツールとして使用でき、中央集約可能にします。

CleanShot 2026-01-02 at 20.47.15@2x

  • Lambda関数
  • OpenAPI仕様のAPI
  • API Gateway
  • 統合サービス(SlackやGitHubなど)
  • Smithyモデル
  • MCP Server

この中でMCP Serverも指定できるので、RuntimeにデプロイしたMCP ServerもGateway経由で使用できると理解できます。ただ注意としてRuntimeのInbound AuthはIAMかJWTの認証に限定されて、GatewayのOutbound AuthはNo AuthかJWTしか選べません。パズルみたいな組み合わせですね・・・

それぞれの取りうる選択肢を見ていきます。

RuntimeのInbound Authの選択肢

公式ドキュメントからまとめるとIAM SigV4とJWT Bearer Tokenが選択可能です。
認証なしの選択肢はないので注意が必要です。

https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-oauth.html

認証方式 説明
IAM SigV4 デフォルトの認証方式。追加設定なしで他のAWS APIと同様に動作
JWT Bearer Token OpenID Connect準拠のJWTトークンによる認証。Discovery URL、許可するaudience/client/scopeを設定

RuntimeはIAM SigV4とJWT Bearer Tokenのどちらか一方のみ設定可能で、
両方を同時に使用することはできません。

GatewayのOutbound Authの選択肢

こちらも公式ドキュメントから引用してみてみます。

https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-outbound-auth.html

Target type No authorization Gateway service role OAuth (client credentials) OAuth (authorization code) API key
API Gateway stage No Yes No No Yes
Lambda function No Yes No No No
MCP server Yes No Yes No No
OpenAPI schema No No Yes Yes Yes
Smithy schema No Yes Yes Yes No

MCP ServerをTargetにした場合、Outbound Authはclient_credentials(M2M認証)のみ対応で、
authorization_code(ユーザー委任型の3LO)は使えない点に注意が必要です。

Gateway もRuntimeもAWS上のサービスなので、一番楽なのはIAM認証(Gateway service role)できれば良いのですが、
GatewayのOutbound Authが対応していないので、JWT認証になりそうです。この場合はM2M認証で下記のようなフローになってきます。

CleanShot 2026-01-02 at 19.42.46@2x

若干複雑ですね。今回はこの構成をTerraformでサクッと作ってGateway経由でRuntimeにデプロイしたMCP Serverを活用してみます。

システム構成図

今回は下記のような構成でTerraformで作成します。

CleanShot 2026-01-02 at 22.33.15@2x

ポイントとしては、RuntimeをJWTでGatewayとのM2M認証を行うことです。
RuntimeをTargetにした場合、現時点ではユーザー委任型の認証やIAMでの認証ができないため選択としてはM2Mの選択肢になるかと思います。

2つCognitoのユーザープールが出てくるのでそれぞれの役割を整理しておきます。

観点 Cognito User Pool A (Inbound) Cognito User Pool B (Outbound)
目的 ユーザー認証 サービス間認証
認証フロー ユーザーパスワード認証(USER_PASSWORD_AUTH) M2M認証(client_credentials)
Client Secret なし(公開クライアント) あり(機密クライアント)
主体 ユーザー Gateway(マシン)

ユーザー認証とM2M認証では要件が異なるため、ユーザープールを分離しています。

補足:GatewayのInbound AuthにIAMを使用する

今回はGateway の Inbound Auth でJWTを使用しますが、アクセストークンの払い出しが煩わしい場合は、下記ブログのようにInbound Auth はIAMで実現するのも良いかと思います。ただこちらとしてもAWS アカウントを持たないユーザーの利用や、非エンジニアへの展開などの課題があるかと思いますが選択肢としては考えられるかと思います。

https://dev.classmethod.jp/articles/agentcore-mcp-iam-auth-ai-coding-tools/

構成としては下記のようになります。

CleanShot 2026-01-02 at 22.36.22@2x

構築するMCP Server

簡単なMCP Serverを作成します。

agent/mcp_server.py
from mcp.server.fastmcp import FastMCP

mcp = FastMCP(host="0.0.0.0", stateless_http=True)

@mcp.tool()
def add_numbers(a: int, b: int) -> int:
    """Add two numbers together"""
    return a + b

@mcp.tool()
def multiply_numbers(a: int, b: int) -> int:
    """Multiply two numbers together"""
    return a * b

@mcp.tool()
def greet_user(name: str) -> str:
    """Greet a user by name"""
    return f"Hello, {name}! Nice to meet you."

if __name__ == "__main__":
    mcp.run(transport="streamable-http")

FastMCPを使用したシンプルなMCP Serverです。3つのツール(add_numbers, multiply_numbers, greet_user)を定義しています。
このMCP ServerをRuntimeにホストしてローカル環境から呼び出して使用してみます。

早速やってみる

サンプルコードは下記リポジトリに置いています。全体を確認したい際は下記を参照ください。

https://github.com/yuu551/agentcore-gateway-runtime-m2m-auth-demo

今回のポイントとなるGateway TargetのTerraformコードを見てみます。

gateway.tf
resource "aws_bedrockagentcore_gateway_target" "mcp_server" {
  name               = "${var.project_name}-mcp-target"
  gateway_identifier = aws_bedrockagentcore_gateway.main.gateway_id

  # Outbound Authentication: OAuth M2M (client_credentials)
  credential_provider_configuration {
    oauth {
      provider_arn = aws_bedrockagentcore_oauth2_credential_provider.m2m.credential_provider_arn
      scopes = [
        "${aws_cognito_resource_server.mcp.identifier}/tools.read",
        "${aws_cognito_resource_server.mcp.identifier}/tools.write",
        "${aws_cognito_resource_server.mcp.identifier}/tools.execute"
      ]
    }
  }

  # Target Configuration: MCP Server
  target_configuration {
    mcp {
      mcp_server {
        endpoint = "https://bedrock-agentcore.${data.aws_region.current.name}.amazonaws.com/runtimes/${urlencode(aws_bedrockagentcore_agent_runtime.mcp_server.agent_runtime_arn)}/invocations"
      }
    }
  }
}

credential_provider_configurationでM2M認証の設定を行い、
target_configurationでRuntimeのエンドポイントを指定しています。

Gateway Targetで参照しているCredential Providerは下記のように定義しています。

identity.tf
resource "aws_bedrockagentcore_oauth2_credential_provider" "m2m" {
  name                       = "${var.project_name}-m2m-oauth2-provider"
  credential_provider_vendor = "CustomOauth2"

  oauth2_provider_config {
    custom_oauth2_provider_config {
      client_id     = aws_cognito_user_pool_client.m2m.id
      client_secret = aws_cognito_user_pool_client.m2m.client_secret

      oauth_discovery {
        discovery_url = "https://cognito-idp.${data.aws_region.current.name}.amazonaws.com/${aws_cognito_user_pool.outbound.id}/.well-known/openid-configuration"
      }
    }
  }
}

CognitoのクライアントIDとシークレットを設定し、Discovery URLを指定しています。
GatewayはこのCredential Providerを使ってM2Mトークンを取得し、Runtimeへのリクエストに付与します。

前提

本記事で利用したバージョンは下記の通りです。

  • macOS 26.1
  • Terraform v1.11.4
  • AWS CLI 2.28.8
  • Docker 29.0.2
  • AWS Provider 6.27.0
  • リージョン:us-east-1

リポジトリのクローン

まずはリポジトリをクローンします。

実行コマンド
git clone https://github.com/yuu551/agentcore-gateway-runtime-m2m-auth-demo.git
cd agentcore-gateway-runtime-m2m-auth-demo

デプロイ

Terraformで一発デプロイします。

実行コマンド
terraform init
terraform apply --auto-approve

terraform applyで以下がすべて作成されます。

  • Cognito ユーザープール A (Inbound Auth用)
  • Cognito ユーザープール B (Outbound Auth用)
  • ECR Repository + Docker Image Build & Push
  • AgentCore Identity (Credential Provider)
  • AgentCore Runtime (MCP Server)
  • AgentCore Gateway + Target

Dockerイメージのビルド&プッシュも自動実行されます。
実行が完了したらCognitoのユーザーを作成し、トークンを発行してGateway経由でリクエストを送ってみます。

テストユーザー作成

Gateway呼び出し用のテストユーザーを作成します。

実行コマンド
INBOUND_USER_POOL_ID=$(terraform output -raw inbound_user_pool_id)
INBOUND_CLIENT_ID=$(terraform output -raw inbound_client_id)
export AWS_REGION=us-east-1 

aws cognito-idp admin-create-user \
  --user-pool-id $INBOUND_USER_POOL_ID \
  --username test-user \
  --temporary-password 'TempPass123!' \
  --message-action SUPPRESS

aws cognito-idp admin-set-user-password \
  --user-pool-id $INBOUND_USER_POOL_ID \
  --username test-user \
  --password 'TestPass123!' \
  --permanent

ユーザートークン取得

ユーザーを作成したら、IDとパスワードで認証を行なってアクセストークンを取得します。

実行コマンド
TOKEN=$(aws cognito-idp initiate-auth \
  --client-id $INBOUND_CLIENT_ID \
  --auth-flow USER_PASSWORD_AUTH \
  --auth-parameters USERNAME=test-user,PASSWORD='TestPass123!' \
  --query 'AuthenticationResult.AccessToken' \
  --output text)

Gateway経由でMCP Serverにアクセス

いよいよGateway経由でRuntimeのMCP Serverにアクセスしてみます!

tools/list

まずは利用可能なツール一覧を取得します。

実行コマンド
GATEWAY_URL=$(terraform output -raw gateway_url)

curl -X POST "$GATEWAY_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq
実行結果
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "inputSchema": {
          "type": "object",
          "properties": {
            "query": {
              "type": "string"
            }
          },
          "required": ["query"]
        },
        "name": "x_amz_bedrock_agentcore_search",
        "description": "A special tool that returns a trimmed down list of tools given a context. Use this tool only when there are many tools available and you want to get a subset that matches the provided context."
      },
      {
        "inputSchema": {
          "type": "object",
          "properties": {
            "a": { "type": "integer" },
            "b": { "type": "integer" }
          },
          "required": ["a", "b"]
        },
        "name": "m2m-auth-demo-mcp-target___add_numbers",
        "description": "Add two numbers together"
      },
      {
        "inputSchema": {
          "type": "object",
          "properties": {
            "name": { "type": "string" }
          },
          "required": ["name"]
        },
        "name": "m2m-auth-demo-mcp-target___greet_user",
        "description": "Greet a user by name"
      },
      {
        "inputSchema": {
          "type": "object",
          "properties": {
            "a": { "type": "integer" },
            "b": { "type": "integer" }
          },
          "required": ["a", "b"]
        },
        "name": "m2m-auth-demo-mcp-target___multiply_numbers",
        "description": "Multiply two numbers together"
      }
    ]
  }
}

定義した3つのツールに加えてGatewayの検索ツール(x_amz_bedrock_agentcore_search)も含め、計4つ取得できました!
次は実際にツールを呼び出してみます。

tools/call (add_numbers)

足し算のMCPツールを呼び出してみます。

実行コマンド
curl -X POST "$GATEWAY_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc":"2.0",
    "id":2,
    "method":"tools/call",
    "params":{
      "name":"m2m-auth-demo-mcp-target___add_numbers",
      "arguments":{"a": 5, "b": 3}
    }
  }' | jq
実行結果
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "8"
      }
    ],
    "isError": false,
    "structuredContent": {
      "result": 8
    }
  }
}

問題なく動作していますね!
もう一つのMCPツールも試してみます。

tools/call (greet_user)

名前に応じて簡単な挨拶を返すツールです。

実行コマンド
curl -X POST "$GATEWAY_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc":"2.0",
    "id":3,
    "method":"tools/call",
    "params":{
      "name":"m2m-auth-demo-mcp-target___greet_user",
      "arguments":{"name": "Alice"}
    }
  }' | jq
実行結果
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Hello, Alice! Nice to meet you."
      }
    ],
    "isError": false,
    "structuredContent": {
      "result": "Hello, Alice! Nice to meet you."
    }
  }
}

こちらもレスポンス返却されました!
無事Gateway経由でRuntimeのMCP Serverにアクセスできました!!よかった!!

気になったポイント

検証する中で個人的に気になったポイントを書いておきます。

Gateway TargetのエンドポイントURL形式

Gateway TargetにRuntimeを指定する際、エンドポイントURLの形式に注意が必要です。

# ARNベースのURL
endpoint = "https://bedrock-agentcore.${region}.amazonaws.com/runtimes/${urlencode(runtime_arn)}/invocations"

ARNをURLエンコードして指定する必要がありますし、エンドポイントは/invocationsで問題ないです。
最初/mcpだと思い込んでいたので少しハマりました・・・下記ドキュメントに呼び出し方法など書いてあるので参考になります。

https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-mcp.html

GatewayサービスロールのIAMポリシー

M2M認証を使用する場合、GatewayサービスロールのIAMポリシー設定に注意が必要です。GetResourceOauth2TokenGetSecretValueのリソース指定が不十分だとtools/callでエラーになります。

詳細な権限について知りたい場合は以下のドキュメントを参照してください。

https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-outbound-auth.html

https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/scope-credential-provider-access.html

サンプルなので緩めな権限ですが、今回は下記権限を付与しています。

iam.tf(クリックで展開)
resource "aws_iam_role_policy" "gateway_identity" {
  name = "${var.project_name}-gateway-identity-policy"
  role = aws_iam_role.gateway.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "GetWorkloadAccessToken"
        Effect = "Allow"
        Action = [
          "bedrock-agentcore:GetWorkloadAccessToken"
        ]
        Resource = [
          "arn:aws:bedrock-agentcore:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:workload-identity-directory/default",
          "arn:aws:bedrock-agentcore:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:workload-identity-directory/default/workload-identity/${var.project_name}-*"
        ]
      },
      {
        Sid    = "GetResourceOauth2Token"
        Effect = "Allow"
        Action = [
          "bedrock-agentcore:GetResourceOauth2Token"
        ]
        Resource = [
          "arn:aws:bedrock-agentcore:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:workload-identity-directory/default",
          "arn:aws:bedrock-agentcore:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:workload-identity-directory/default/workload-identity/*",
          "arn:aws:bedrock-agentcore:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:token-vault/default",
          "arn:aws:bedrock-agentcore:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:token-vault/default/oauth2credentialprovider/*"
        ]
      },
      {
        Sid    = "GetSecretValue"
        Effect = "Allow"
        Action = [
          "secretsmanager:GetSecretValue"
        ]
        Resource = [
          "arn:aws:secretsmanager:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:secret:bedrock-agentcore*"
        ]
      }
    ]
  })
}

GetResourceOauth2TokenはOAuth2のトークン取得、GetSecretValueはSecrets Managerに保存されたクライアントシークレットの取得に必要です。

おわりに

AgentCore GatewayのTargetにAgentCore RuntimeのMCP Serverを指定する構成を試してみました!
認証が若干複雑なように感じましたね・・・小規模なエージェントならエージェントのツールとして使ったり、Lambda関数をターゲットにした方がやりやすいケースがあるかもしれないですね。
またGatewayへはIAM認証を活用して接続するのも手かと思います。

本記事が少しでも参考になりましたら幸いです。
最後までご覧いただきありがとうございました!

この記事をシェアする

FacebookHatena blogX

関連記事