Serverless Operations, inc

>_cd /blog/id_m7u19d1h655

title

Amazon Bedrock AgentCore (3) Gateway :API や Lambda を OAuth やセキュリティ統制を統合してMCP Serverとして公開させる

今日は、Amazon Bedrock AgentCore Gatewayをさわっていきます。

AgentCore Gateway は、AI エージェントと外部ツール(APIやLambda 関数など)との間を仲介し、それらをModel Context Protocol(MCP)対応のツールとして変換・公開できるサービスです。HTTP や認証の複雑さを抽象化し、安全かつスケーラブルにツール連携が可能です。

既存の REST API(OpenAPI/Smithy 定義)や Lambda 関数を、わずかなコードで MCP 対応ツールに変換可能です。その際MCPの規格で用いられる認可プロトコルであるOAuth2.1の実装も自動で行ってくれます。

ツールの統合にも対応しており、複数の API や Lambda を組み合わせて、単一の MCP エンドポイントとして提供することもでき、これにより、エージェントは多様な機能をひとまとめにした統合エンドポイントを実現できます。

APIやLambdaだけではなく、Salesforce、Slack、Jira、Asana、Zendesk などの著名ツールと1クリックで連携が可能となりMCPの可能性を広げるサービスがGatewayです。

さっそくやってみる

では早速やっていきます。サンプルはこちらににあります。

まず必要なモジュールをインストールします。

pip install boto3
pip install bedrock-agentcore-starter-toolkit
pip install strands-agents

strands-agents

ここでインストールしている strands-agents は、AWSが公開しているPythonのオープンソースSDKです。「質問に答えるAI」「ツールを呼び出すAI」「複数のAIが協力する仕組み」を、わかりやすいコードで作れるようになります。Bedrockとは別に単独で動作させることも可能でOpenAI, AnthropicなどのモデルをBedrockを介さずに直接呼び出すことも可能です。

この記事ではGatewayでMCPを作成する手順で利用しますが、将来的には生成AI活用において、もう一つの期待されているプロトコルであるA2A (Agent-to-Agent)の対応も予定されています。

GatewayとサンプルLambda関数の起動

以下のサンプルスクリプトを実行します。

from bedrock_agentcore_starter_toolkit.operations.gateway.client import GatewayClient
import json
import logging

region = "us-east-1"
client = GatewayClient(region_name=region)
client.logger.setLevel(logging.DEBUG)

# create cognito authorizer
cognito_response = client.create_oauth_authorizer_with_cognito("TestGateway")

# create the gateway.
gateway = client.create_mcp_gateway(
    # the name of the Gateway - if you don't set one, one will be generated.
    name=None,
    # the role arn that the Gateway will use - if you don't set one, one will be created.
    # NOTE: if you are using your own role make sure it has a trust policy that trusts bedrock-agentcore.amazonaws.com
    role_arn=None,
    # the OAuth authorization server details. If you are providing your own authorization server, then pass an input of the following form: {"customJWTAuthorizer": {"allowedClients": ["<INSERT CLIENT ID>"], "discoveryUrl": "<INSERT DISCOVERY URL">}}
    authorizer_config=cognito_response["authorizer_config"],
    # enable semantic search
    enable_semantic_search=True,
)

# create a lambda target.
lambda_target = client.create_mcp_gateway_target(
    # the gateway created in the previous step
    gateway=gateway,
    # the name of the Target - if you don't set one, one will be generated.
    name=None,
    # the type of the Target
    target_type="lambda",
    # the target details - set this to define your own lambda if you pre-created one. Otherwise leave this None and one will be created for you.
    target_payload=None,
     # you will see later in the tutorial how to use this to connect to APIs using API keys and OAuth credentials.
    credentials=None,
)

# get access token
access_token = client.get_access_token_for_cognito(cognito_response["client_info"])

print("Access Token:", access_token)
2025-08-21 16:05:01,742 - bedrock_agentcore.gateway - INFO - Starting EZ Auth setup: Creating Cognito resources...
2025-08-21 16:05:03,373 - bedrock_agentcore.gateway - INFO -   ✓ Created User Pool: us-east-1_aHUwqLzFg
2025-08-21 16:05:04,107 - bedrock_agentcore.gateway - INFO -   ✓ Created domain: agentcore-ff7b9aa6
2025-08-21 16:05:04,107 - bedrock_agentcore.gateway - INFO -   ⏳ Waiting for domain to be available...
2025-08-21 16:05:04,360 - bedrock_agentcore.gateway - INFO -   ✓ Domain is active
2025-08-21 16:05:04,760 - bedrock_agentcore.gateway - INFO -   ✓ Created resource server: TestGateway
2025-08-21 16:05:05,162 - bedrock_agentcore.gateway - INFO -   ✓ Created client: 1dc2256j76cibja9j11vj0d7ds
2025-08-21 16:05:05,163 - bedrock_agentcore.gateway - INFO -   ⏳ Waiting for DNS propagation of domain: agentcore-ff7b9aa6.auth.us-east-1.amazoncognito.com
2025-08-21 16:06:05,163 - bedrock_agentcore.gateway - INFO - ✓ EZ Auth setup complete!
2025-08-21 16:06:05,164 - bedrock_agentcore.gateway - INFO - Role not provided, creating an execution role to use
2025-08-21 16:06:06,287 - bedrock_agentcore.gateway - INFO - ✓ Role already exists: arn:aws:iam::917561075114:role/AgentCoreGatewayExecutionRole
2025-08-21 16:06:06,288 - bedrock_agentcore.gateway - INFO - ✓ Successfully created execution role for Gateway
2025-08-21 16:06:06,288 - bedrock_agentcore.gateway - INFO - Creating Gateway
2025-08-21 16:06:06,288 - bedrock_agentcore.gateway - DEBUG - Creating gateway with params: {
  "name": "TestGateway821f6366",
  "roleArn": "arn:aws:iam::917561075114:role/AgentCoreGatewayExecutionRole",
  "protocolType": "MCP",
  "authorizerType": "CUSTOM_JWT",
  "authorizerConfiguration": {
    "customJWTAuthorizer": {
      "allowedClients": [
        "1dc2256j76cibja9j11vj0d7ds"
      ],
      "discoveryUrl": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_aHUwqLzFg/.well-known/openid-configuration"
    }
  },
  "exceptionLevel": "DEBUG",
  "protocolConfiguration": {
    "mcp": {
      "searchType": "SEMANTIC"
    }
  }
}
2025-08-21 16:06:08,254 - bedrock_agentcore.gateway - INFO - ✓ Created Gateway: arn:aws:bedrock-agentcore:us-east-1:917561075114:gateway/testgateway821f6366-jektqq4ivm
2025-08-21 16:06:08,254 - bedrock_agentcore.gateway - INFO -   Gateway URL: https://testgateway821f6366-jektqq4ivm.gateway.bedrock-agentcore.us-east-1.amazonaws.com/mcp
2025-08-21 16:06:08,254 - bedrock_agentcore.gateway - INFO -   Waiting for Gateway to be ready...
2025-08-21 16:06:08,541 - bedrock_agentcore.gateway - INFO -
✅Gateway is ready
2025-08-21 16:06:10,653 - bedrock_agentcore.gateway - INFO - ✓ Created Lambda function: arn:aws:lambda:us-east-1:917561075114:function:AgentCoreLambdaTestFunction
2025-08-21 16:06:10,653 - bedrock_agentcore.gateway - INFO - ✓ Attaching access policy to: arn:aws:lambda:us-east-1:917561075114:function:AgentCoreLambdaTestFunction for arn:aws:iam::917561075114:role/AgentCoreGatewayExecutionRole
2025-08-21 16:06:10,920 - bedrock_agentcore.gateway - INFO - ✓ Attached permissions for role invocation: arn:aws:lambda:us-east-1:917561075114:function:AgentCoreLambdaTestFunction
2025-08-21 16:06:10,922 - bedrock_agentcore.gateway - INFO - Creating Target
2025-08-21 16:06:10,923 - bedrock_agentcore.gateway - INFO - {'gatewayIdentifier': 'testgateway821f6366-jektqq4ivm', 'name': 'TestGatewayTargetc949f50b', 'targetConfiguration': {'mcp': {'lambda': {'lambdaArn': 'arn:aws:lambda:us-east-1:917561075114:function:AgentCoreLambdaTestFunction', 'toolSchema': {'inlinePayload': [{'name': 'get_weather', 'description': 'Get weather for a location', 'inputSchema': {'type': 'object', 'properties': {'location': {'type': 'string'}}, 'required': ['location']}}, {'name': 'get_time', 'description': 'Get time for a timezone', 'inputSchema': {'type': 'object', 'properties': {'timezone': {'type': 'string'}}, 'required': ['timezone']}}]}}}}, 'credentialProviderConfigurations': [{'credentialProviderType': 'GATEWAY_IAM_ROLE'}]}
2025-08-21 16:06:10,923 - bedrock_agentcore.gateway - DEBUG - Creating target with params: {
  "gatewayIdentifier": "testgateway821f6366-jektqq4ivm",
  "name": "TestGatewayTargetc949f50b",
  "targetConfiguration": {
    "mcp": {
      "lambda": {
        "lambdaArn": "arn:aws:lambda:us-east-1:917561075114:function:AgentCoreLambdaTestFunction",
        "toolSchema": {
          "inlinePayload": [
            {
              "name": "get_weather",
              "description": "Get weather for a location",
              "inputSchema": {
                "type": "object",
                "properties": {
                  "location": {
                    "type": "string"
                  }
                },
                "required": [
                  "location"
                ]
              }
            },
            {
              "name": "get_time",
              "description": "Get time for a timezone",
              "inputSchema": {
                "type": "object",
                "properties": {
                  "timezone": {
                    "type": "string"
                  }
                },
                "required": [
                  "timezone"
                ]
              }
            }
          ]
        }
      }
    }
  },
  "credentialProviderConfigurations": [
    {
      "credentialProviderType": "GATEWAY_IAM_ROLE"
    }
  ]
}
2025-08-21 16:06:11,452 - bedrock_agentcore.gateway - INFO - ✓ Added target successfully (ID: PMEWWLLJWS)
2025-08-21 16:06:11,452 - bedrock_agentcore.gateway - INFO -   Waiting for target to be ready...
2025-08-21 16:06:14,043 - bedrock_agentcore.gateway - INFO -
✅Target is ready

2025-08-21 20:42:26,665 - bedrock_agentcore.gateway - INFO - Fetching test token from Cognito...
2025-08-21 20:42:26,665 - bedrock_agentcore.gateway - INFO -   Attempting to connect to token endpoint: https://agentcore-e9e39be6.auth.us-east-1.amazoncognito.com/oauth2/token
2025-08-21 20:42:27,576 - bedrock_agentcore.gateway - INFO - ✓ Got test token successfully
Access Token: eyJraWQiOiJ6VFVaWGs3YkRRK2FBKzA0bU9EWjk0SjlFNlY2NXIyYit5S1hPdTIwK240PSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIzY245dTJoNTczdmpqc2RsaGx1Y2hvNjU1byIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiVGVzdEdhdGV3YXlcL2ludm9rZSIsImF1dGhfdGltZSI6MTc1NTc3NjU0NywiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tXC91cy1lYXN0LTFfRHgyR3lha0hGIiwiZXhwIjoxNzU1NzgwMTQ3LCJpYXQiOjE3NTU3NzY1NDcsInZlcnNpb24iOjIsImp0aSI6IjU0YjFhNWYzLTc3YTgtNDJhYS04ZDkzLTg0MTczNzM5ZDcyOSIsImNsaWVudF9pZCI6IjNjbjl1Mmg1NzN2ampzZGxobHVjaG82NTVvIn0.S1Q33YfNy6vzRHOtZ_7r3CF_TGi_PffqJ42s5ZbP8IKfiUnZG3_ognARYFk2E9hSF1NHn0iLz7lKuErbFAY9G0vnc_Vg9FbVq5U-jKI_q9N-MXPJ1t2UaJehIZeyBk-N2kW_ZBchxLTGPKtURad1G--XhnPb3AR2y_2ih--9SVDwZRtw2M_gl8-SpVjtG7kPTduSFHfTeoWk6kIpe9SwRhfMpB-Uvn5QPoaZcUDRL6B8xDBmyMmUqQ1S2lFBo-UilAKaLS0uALLXpMNsr38-63WK7egbLr0A_YGL5SOyemPwDyfplaaw2qp_Nu0oxyVWJQxyJE837TpFQkJrIimHPg

AWSマネージメントコンソールを見るとOAuth認証用Cognito User Pool, テスト用Lambda関数、Bedrock AgentCore Gatewayがそれぞれ作成されていることがわかります。また出力された Access Token を手元にメモしておきます。

呼び出しテスト

いままの手順でLambda関数がMCPサーバとしてCognitoのOAuth認証付きで作成されGatewayがエンドポイントとして存在しています。

次にこれをテストしていきます。まずは動作に必要なトークンなどを環境変数にセットします。

export ACCESS_TOKEN="eyJhbGciOiJ..."  # 先ほど手元にメモしたトークン
export MCP_URL="https://xxxxxx.gateway.bedrock-agentcore.us-east-1.amazonaws.com/mcp"
export MODEL_ID="anthropic.claude-v2:1"

MCP_URL は作成されたBedrock AgentCore Gatewayの詳細画面から取得でできます。

次に以下の gatewaytest.py を作成して実行します。

from strands import Agent
import logging
from strands.models import BedrockModel
from strands.tools.mcp.mcp_client import MCPClient
from mcp.client.streamable_http import streamablehttp_client
import os
import sys

def create_streamable_http_transport(mcp_url: str, access_token: str):
    return streamablehttp_client(mcp_url, headers={"Authorization": f"Bearer {access_token}"})


def get_full_tools_list(client):
    more_tools = True
    tools = []
    pagination_token = None
    while more_tools:
        tmp_tools = client.list_tools_sync(pagination_token=pagination_token)
        tools.extend(tmp_tools)
        if tmp_tools.pagination_token is None:
            more_tools = False
        else:
            pagination_token = tmp_tools.pagination_token
    return tools


def run_agent(mcp_url: str, access_token: str, bedrock_model_id: str):
    bedrockmodel = BedrockModel(
        inference_profile_id=bedrock_model_id,
    )

    mcp_client = MCPClient(lambda: create_streamable_http_transport(mcp_url, access_token))

    with mcp_client:
        tools = get_full_tools_list(mcp_client)
        print(f"Found the following tools: {[tool.tool_name for tool in tools]}")
        agent = Agent(model=bedrockmodel, tools=tools)
        print("\nThis is an interactive Strands Agent. Ask me something. When you're finished, say exit or quit: ")
        while True:
            user_input = input("> ")
            if user_input.lower() in ["exit", "quit", "bye"]:
                print("Goodbye!")
                break
            print("\nThinking...\n")
            resp = agent(user_input)
            if resp is not None:
                print(resp)


if __name__ == "__main__":
    # 環境変数から取得
    access_token = os.getenv("ACCESS_TOKEN")
    mcp_url = os.getenv("MCP_URL")
    model_id = os.getenv("MODEL_ID", "anthropic.claude-v2:1")

    if not access_token or not mcp_url:
        print("環境変数 ACCESS_TOKEN と MCP_URL を設定してください。", file=sys.stderr)
        sys.exit(1)

    run_agent(mcp_url, access_token, model_id)

実行すればLLMとの対話も可能なMCP Client機能付きAgentCore Runtimeが起動します。

python3 gatewaytest.py
Found the following tools: ['x_amz_bedrock_agentcore_search', 'TestGatewayTargetd94481de___get_time', 'TestGatewayTargetd94481de___get_weather']

This is an interactive Strands Agent. Ask me something. When you're finished, say exit or quit:
>

テスト用にデプロイされたMCP Serverとして起動するLambda関数は以下です。

import json

def lambda_handler(event, context):
    # Extract tool name from context
    tool_name = context.client_context.custom.get('bedrockAgentCoreToolName', 'unknown')

    if 'get_weather' in tool_name:
        return {
            'statusCode': 200,
            'body': json.dumps({
                'location': event.get('location', 'Unknown'),
                'temperature': '72°F',
                'conditions': 'Sunny'
            })
        }
    elif 'get_time' in tool_name:
        return {
            'statusCode': 200,
            'body': json.dumps({
                'timezone': event.get('timezone', 'UTC'),
                'time': '2:30 PM'
            })
        }
    else:
        return {
            'statusCode': 200,
            'body': json.dumps({'message': 'Unknown tool'})
        }

2つのtool(天気と時間)をダミーの固定値で答えるものが用意されています。これを先ほどのRuntimeで起動しているAgentから呼び出してみます。

> 横浜の天気は?

Thinking...

横浜の天気を調べますね。
Tool #1: TestGatewayTargetd94481de___get_weather
横浜の現在の天気は以下の通りです:

- **場所**: 横浜
- **気温**: 72°F(約22°C)
- **天候**: 晴れ

良いお天気ですね!横浜の現在の天気は以下の通りです:

- **場所**: 横浜
- **気温**: 72°F(約22°C)
- **天候**: 晴れ

良いお天気ですね!

無事Lambda関数をGatewayを使ってMCP Server化させることができました!

Written by
編集部

亀田 治伸

Kameda Harunobu

  • Facebook->
  • X->
  • GitHub->

Share

Facebook->X->
Back
to list
<-