Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

Amazon Bedrock AgentCore で Lambda でAIエージェントを開発してみた(MCPで内部連携あり)

こんにちは、丸山です。
2025/10/13に、Amazon Bedrock AgentCore がついに一般公開(Generally Available)となりました!
もちろん、東京リージョンでも利用可能になっています。

「今年の re:Ivent に合わせて、12月ごろにGAかな」と勝手に予想していたのですが、見事に裏切られましたね。

aws.amazon.com

ということで、早速、Amazon Bedrock AgentCore で、AIエージェントを開発した内容を紹介してみたいと思います。

1. はじめに

1.1 Amazon Bedrock AgentCoreとは

Amazon Bedrock AgentCore は、AIエージェントを本格的に運用するために設計されたAWSの新しいサービス群です。
エージェントの実行環境、外部ツールとの連携、セキュリティ管理など、運用に必要な機能を包括的に提供します。

この記事ではその中でも AgentCore Gateway に注目します。
このサービスを利用することで、既存のリソース(LambdaやAPI)をMCPツールとしてエージェントに組み込むことが可能になります。
これにより、少ないコストで多機能なエージェントを構築できる点が大きな魅力です。

aws.amazon.com

1.2 AgentCoreのサービス概要

AgentCoreは複数のサービスから構成されており、本記事では以下のサービスを取り扱います。

AgentCore Gatewayの構成

サービス名 主な機能 特徴・メリット
AgentCore Runtime エージェントやMCPサーバーのサーバーレス実行 必要時のみ起動、自動スケーリング、様々なフレームワーク(LangChain、Strands等)に対応
AgentCore Gateway 外部ツール・APIの統合管理 既存のAPIやLambda関数をMCP対応ツールに変換
AgentCore Identity 認証・認可の安全な管理 認証・認可を一元管理、APIキーの暗号化保存、OAuth対応、セキュリティリスクを大幅軽減

1.3 概要・メリット

RuntimeやGateway、Identityを連携させることで、セキュリティ性を高めた上で、多機能なエージェントをデプロイすることが出来ます。

本記事では、エージェントがAgentCore Gateway経由で複数のツールを利用する構成例を紹介します。
これにより以下の利点が得られます。

  • エージェント機能の拡張
    • 外部APIやLambda関数をツールとして統合することで、エージェントの実行可能な処理範囲を拡張できます
  • 既存資産の有効活用
    • 既存のAPI/LambdaをMCPツール化してエージェントに公開することで、過去の投資を無駄にすることなく活用できます
  • 統合的なセキュリティ管理
    • Gatewayが認証・認可を一元的に処理するため、個別のツールごとにセキュリティ対策を実装する必要がありません

2. 検証アプリケーションの構成

2.1 概要

今回は、「Tavilyで調べたことのサマリをS3に配置する問い合わせAgent」を作って検証してみます。
以下のツールをAgentCore Gatewayターゲットとして登録します。 エージェントは、Gatewayを利用することで、単一のエンドポイントからツールを発見・呼び出せます。

  • Tavily検索ツール:外部APIを使用して最新情報を収集
  • ファイル保存ツール(Lambda):調査結果のサマリをS3に保存

2.2 構成図

検証で作成するシステムの構成

3. 実装

3.1 LambdaをGatewayを使ってMCPツールとして呼び出せるようにする

Lambdaのデプロイ

def lambda_handler(event, context):
    if not BUCKET:
        return {
            'statusCode': 500,
            'body': {'error': '環境変数 S3_PATH が未設定または不正です。'},
        }

    tool = _tool_name_from_context(context)
    title = event.get('title')
    text = event.get('text')

    if not title or not isinstance(title, str):
        return {'statusCode': 400, 'body': {'error': 'title は必須です。'}}
    if text is None:
        return {'statusCode': 400, 'body': {'error': 'text は必須です。'}}

    # 一つのLambda関数で複数のツールを実装する場合の例
    if tool == 's3_put_md':
        title = _force_ext(title, '.md')
        key = f'{PREFIX}/{title}' if PREFIX else title
        body = text.encode('utf-8')
        res = _put_and_presign(BUCKET, key, body, 'text/markdown; charset=utf-8')
        return {'statusCode': 200, 'body': res}

    elif tool == 's3_put_txt':
        title = _force_ext(title, '.txt')
        key = f'{PREFIX}/{title}' if PREFIX else title
        body = text.encode('utf-8')
        res = _put_and_presign(BUCKET, key, body, 'text/plain; charset=utf-8')
        return {'statusCode': 200, 'body': res}

    else:
        return {'statusCode': 400, 'body': {'error': f'未対応のツール名: {tool}'}}

スキーマファイルの配置

Lambda関数をAgentCore Gatewayのターゲットとして追加する際は、MCPツールスキーマを定義する必要があります。
スキーマの定義は、インラインとS3に配置する二つの選択肢がありますが、今回はS3に配置します。 以下のJSONファイルを適当に配置してください。 スキーマの詳細な仕様については、AWS公式ドキュメントを参照してください。

[
  {
    "name": "s3_put_md",
    "description": "Markdown(.md)をS3に保存し、署名付きGET URLを返す。",
    "inputSchema": {
      "type": "object",
      "properties": {
        "title": {
          "type": "string",
          "description": "ファイル名(拡張子付き)"
        },
        "text": {
          "type": "string",
          "description": "Markdown本文(UTF-8)"
        }
      },
      "required": ["title", "text"]
    }
  },
  {
    "name": "s3_put_txt",
    "description": "テキスト(.txt)をS3に保存し、署名付きGET URLを返す。",
    "inputSchema": {
      "type": "object",
      "properties": {
        "title": {"type": "string"},
        "text": {"type": "string"}
      },
      "required": ["title", "text"]
    }
  }
]

3.2 TavilyをMCPツールとして呼び出せるようにする

TavilyのAPIKey発行

Tavily公式サイトAPIキーを取得し、AgentCore Identityに設定します。

Tavily用AgentCore Identityの作成

Tavily用のIdentityを作成し、APIキーを安全に管理します。
AWS Console上でAgentCore Identityのタブに移動して、以下の手順でAPIキーを登録します。

3.3 AgentCore Gatewayの作成

TavilyとLambdaを利用できるAgentCore Gatewayを作成し、両方のツールを統合します。
AWS Console上でAgentCore Gatewayのタブに移動して、以下の手順でGatewayを作成します。

3.4 AgentCore Gateway用AgentCore Identity設定

AgentCore IdentityでAgentCore Gatewayを利用するためのOAuthクライアントを作成します。

まず、AgentCore Gateway作成時に、自動作成されたCognitoリソースを確認します。
そのために、AWS Console上でAgentCore Gatewayのタブに移動して、作成したGatewayをクリックし、詳細画面を開きます。

次に、AWS Console上でAgentCore Identityのタブに移動して、以下の手順でOAuthクライアントを登録します。

3.5 AgentCore Runtime デプロイ

環境

  • uv
  • docker

必要ライブラリのインストール

> uv add bedrock-agentcore strands-agents 
> uv add --dev bedrock-agentcore-starter-toolkit

エージェント実装 (agent.py):

import os

from bedrock_agentcore import BedrockAgentCoreApp
from bedrock_agentcore.identity.auth import requires_access_token
from mcp.client.streamable_http import streamablehttp_client
from strands import Agent
from strands.tools.mcp import MCPClient

app = BedrockAgentCoreApp()

# AgentCore Gateway URL
GATEWAY_URL = os.environ['AGENTCORE_GATEWAY_URL']
# AgentCore Gatewayにアクセスするために作成したIdentityの名前
OAUTH_PROVIDER = os.environ['AGENTCORE_GATEWAY_OAUTH_PROVIDER']
# Cognitoリソースに紐づくカスタムスコープ
OAUTH_SCOPE = os.environ['AGENTCORE_GATEWAY_OAUTH_SCOPES'].split(',')


# アクセストークンを取得する
@requires_access_token(
    provider_name=OAUTH_PROVIDER, scopes=OAUTH_SCOPE, auth_flow='M2M'
)
async def get_access_token(*, access_token) -> str:
    """Fetch access token using Bedrock AgentCore identity service."""
    return access_token


@app.entrypoint
async def invoke(payload):
    """Your AI agent function"""
    # 引数access_tokenが必要だと認識されるが、実際には不要であるためpylint: disable=E1125をつける
    access_token = await get_access_token()  # pylint: disable=E1125

    mcp_client = MCPClient(
        lambda: streamablehttp_client(
            # AgentCore Gatewayの認証用にBearerトークンを付与する
            GATEWAY_URL,
            headers={'Authorization': f'Bearer {access_token}'},
        )
    )

    user_message = payload['prompt']
    with mcp_client:
        tools = mcp_client.list_tools_sync()
        agent = Agent(tools=tools)
        async for event in agent.stream_async(user_message):
            if 'data' in event:
                yield event['data']


if __name__ == '__main__':
    app.run()

依存関係ファイル作成 agent.pyで利用しているライブラリを書いたrequirements.txtを作成します。

bedrock-agentcore
strands-agents

プラットフォーム設定
AgentCoreRuntimeはLinux ARM64プラットフォームのみをサポートしているため、x86環境でデプロイする場合は、 手動でプラットフォームを追加する必要があります。

・プラットフォーム確認

> docker buildx ls

x86環境での出力結果

NAME/NODE     DRIVER/ENDPOINT   STATUS    BUILDKIT   PLATFORMS
default*      docker
 \_ default    \_ default       running   v0.16.0    linux/amd64 (+3), linux/386

・(x86環境でデプロイする場合)ARM64プラットフォームをインストール

> docker run --privileged --rm tonistiigi/binfmt --install arm64

・(x86環境でデプロイする場合)プラットフォームが追加されたことを確認

> docker buildx ls

▼出力結果(PLATFORMSにlinux/arm64が追加されている)

NAME/NODE     DRIVER/ENDPOINT   STATUS    BUILDKIT   PLATFORMS
default*      docker
 \_ default    \_ default       running   v0.16.0    linux/amd64 (+3), linux/arm64, linux/386

デプロイ実行

# プロファイル設定(agentcoreコマンドにはprofile指定オプションがないため)
> $Env:AWS_DEFAULT_PROFILE="<プロファイル名>"

# 設定
> uv run agentcore configure -e agent.py
コマンド実行時に、「Execution Role」「ECR Repository」「Detected dependency file」「Authorization Configuration」について質問されますが、「Execution Role」のみ作成したAgentCore Runtime用ロールを指定し、他はデフォルト設定(Enterを押すだけ)で構いません。

# ローカルビルドでデプロイ
> uv run agentcore launch --local-build --env AGENTCORE_GATEWAY_URL=<gatewayのurl> --env AGENTCORE_GATEWAY_OAUTH_PROVIDER=<identityの名前> --env AGENTCORE_GATEWAY_OAUTH_SCOPES=<Identityに関連するoauth scope>

動作確認
システムが正常に動作することを確認します。

import json
import os

import boto3

agent_arn = os.environ['AGENT_ARN']
prompt = input('User Message: ')

# Initialize the AgentCore client
agent_core_client = boto3.client('bedrock-agentcore')

# Prepare the payload
payload = json.dumps({'prompt': prompt}).encode()

# Invoke the agent
response = agent_core_client.invoke_agent_runtime(
    agentRuntimeArn=agent_arn, payload=payload, runtimeUserId='user1'
)

content = []
for line in response['response'].iter_lines(chunk_size=1024):
    if line:
        try:
            text = line.decode('utf-8')
        except UnicodeDecodeError:
            text = line.decode('utf-8', errors='replace')
        # SSE 形式なら "data: ..." の行を処理
        if text.startswith('data: '):
            text = text[len('data: ') :].strip()
            # つなげて出力した時に自然に見えるよう、ダブルクォーテーションを削除
            text = text.replace('"', '')
            print(text, end='')

出力結果

User Message: Amazon Bedrockについてサマリを作成してください。そして、そのサマリを共有するためのリンクをください。

Amazon Bedrockについて調査して、サマリを作成いたします。調査結果を基に、Amazon Bedrockのサマリを作成してMarkdownファイルとして保存いたします。Amazon Bedrockについてのサマリを作成し、共有用のリンクを生成いたしました。

## 📋 Amazon Bedrock サマリ完成

以下のリンクから、Amazon Bedrockの詳細なサマリをご覧いただけます:

**🔗 共有リンク**: <署名付きURL>

### サマリの主要内容:
- **Amazon Bedrockの概要**と基本的な特徴
- **主要機能**(ファンデーションモデルへのアクセス、カスタマイゼーション、運用管理)
- **利用用途**(カスタマーサポート、コンテンツ生成、業務効率化)
- **開発者・組織向けのメリット**
- **技術的詳細**とベストプラクティス

このリンクは**1時間有効**ですので、必要に応じて保存やダウンロードをお願いいたします。Amazon Bedrock を検討される際の参考資料としてご活用ください。

出力された署名付きURLを確認すると、生成されたMarkdownファイルを確認することが出来ました。

S3に出力されたサマリ

4. まとめ

AgentCore Gateway経由でLambda関数をMCPツールとして正常に呼び出すことができ、エージェントは以下の流れで動作することが確認できました:

ステップ 説明
ツール発見 tools/listでGatewayから利用可能なツール一覧を取得
Tavily検索 外部APIで最新情報を収集
サマリ生成 収集した情報を分析・要約
ファイル保存 サマリのファイルをS3に保存
ユーザーへの回答 エージェントの思考結果を出力

エージェントは状況に応じて適切なツールを自動選択し、AgentCore Gatewayを通じて複数の異なるツール(外部API + Lambda)を統合して自律的に活用できることが実証されました。

統合的な接続・認証・スケール運用をAgentCoreが担ってくれて、便利だと思いました。 今後、実務でもいろいろと有効活用できそうです!

Acroquest Technologyでは、キャリア採用を行っています。
  • Azure OpenAI/Amazon Bedrock等を使った生成AIソリューションの開発
  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • マイクロサービス、DevOps、最新のOSSクラウドサービスを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。 www.wantedly.com