Amazon Bedrock AgentCore GatewayでMCPサーバーを作成し、Claude Desktopから接続してみた

Amazon Bedrock AgentCore GatewayでMCPサーバーを作成し、Claude Desktopから接続してみた

AgentCore Gatewayを使い、Lambda上の社員名簿検索ツールをMCPサーバーとして公開し、Claude Desktopから接続する検証を行いました。認証、ツール定義、実際の動作確認までの全体を紹介します。
2026.11.05

はじめに

クラスメソッドテクノロジーズの武蔵です。

最近社内のイベントをきっかけに登山の楽しさを知りました。おすすめの山があれば教えてください。

最近、AgentCoreに触れる機会が増えてきました。できることが多く更新も頻繁なため苦戦していますが、魅力や実用性も強く感じています。
そこで、個人的に実施した検証をブログに残します。

今回はAgentCoreの機能であるAgentCore Gatewayを利用した検証です。

AgentCore Gatewayとは?

AgentCore Gatewayとは、LambdaやAPIをMCPサーバーとして公開できるAmazon Bedrock AgentCoreの機能です。
MCPサーバーを自分で用意する場合に必要な、サーバーのホスティングや認証の仕組みをGatewayに任せられます。

今回は、ダミーの社員マスタをDynamoDBに置き、Lambdaで検索ツールを実装し、AgentCore GatewayでMCPサーバーとして公開します。
Claude Desktopから「<社員名>さんの役職は?」と聞いて答えさせるところまでを検証します。

全体構成図

事前準備

検証で使用するダミーデータを投入したDynamoDBと、ツールとなるLambdaは、Terraformで作成しておきます。Lambdaが正常に動くことを確認してから、MCPサーバーの作成に入ります。

DynamoDB

項目 設定値
テーブル名 employees
パーティションキー employee_id(文字列)
GSI department-title-index(department / title)、name-index(name_normalized)

ダミーデータは次の8件です。このほかに、検証用として全員に salary(給与)を入れています。

employee_id name department title manager_id
E0001 山田 太郎 経営企画部 部長
E0002 佐藤 花子 開発部 テックリード E0005
E0003 鈴木 一郎 人事部 課長 E0001
E0004 高橋 美咲 開発部 エンジニア E0002
E0005 田中 健 開発部 部長 E0001
E0006 佐藤 誠 営業部 主任 E0007
E0007 伊藤 由美 営業部 部長 E0001
E0008 渡辺 翔 人事部 担当 E0003

name_normalized には氏名から空白を除いた値(例: 佐藤花子)を入れています。

Lambda

関数名は employee-directory-tools です。1つの関数で次の3つのツールを受け持ちます。

ツール名 引数 処理
get_employee name 氏名(姓のみ・部分一致可)で社員を検索
search_employees department、title(任意) 部署・役職で社員を一覧
get_reporting_line employee_id 上長をトップまで順にたどる

Gatewayから呼ばれると、event には引数だけが入ります。ツール名は context.client_context.custom["bedrockAgentCoreToolName"] に ターゲット名___ツール名 の形式で入るため、___ の後ろを取り出して処理を振り分けます。

ツール名による処理の振り分け

def _tool_name(event, context):
    cc = getattr(context, "client_context", None)
    custom = getattr(cc, "custom", None) or {}
    return custom.get("bedrockAgentCoreToolName", "").split("___")[-1]

ツール名は、後で登録するインラインスキーマの name と一致させます。

また、DynamoDBから読んだ項目をそのまま返さず、返してよい項目だけに絞ってから返します。salary は含めていないため、Claudeには給与が渡りません。

返却項目の絞り込み

PUBLIC_FIELDS = ["employee_id", "name", "name_kana", "department", "title", "email", "manager_id"]

def _public(item):
    return {k: item[k] for k in PUBLIC_FIELDS if k in item}

作成したLambdaの関数ARNは、ターゲットの設定で使うので控えておきます。

Cognitoユーザープールの作成

Gatewayの入口で検証するアクセストークン(JWT)をCognitoで発行します。認証の流れは次のとおりです。

Cognitoによる認証の流れ

ユーザープールとアプリクライアントを作成する

  1. Cognitoコンソールで「ユーザープール」→「ユーザープールを作成」を押します。
  2. アプリケーションタイプで「マシン間アプリケーション」を選びます。
  3. ユーザープール名は自動生成された名前になるので、わかりやすい名前に変更します。

リソースサーバーとスコープを作成する

リソースサーバーでは、このトークンでどのAPIにアクセスしてよいかを設定します。

  1. ユーザープールの「アプリケーション統合」→「リソースサーバー」で「リソースサーバーを作成」を押し、次のように設定します。
項目 設定値
リソースサーバー名 employee-directory
識別子 employee-directory
カスタムスコープ名 read
  1. 作成すると、スコープ文字列は employee-directory/read になります。

Cognitoのリソースサーバー設定画面

アプリクライアントにスコープを割り当てる

  1. 「アプリケーションクライアント」から作成したアプリケーションクライアントを開き、「ログインページ」タブの「編集」を押します。
  2. OAuth 2.0 許可タイプが「クライアント認証情報」になっていることを確認します。
  3. カスタムスコープで employee-directory/read にチェックを入れて保存します。

後の手順で使う値を控える

値 確認場所 例
ユーザープールID ユーザープールの概要 ap-northeast-1_AbCdEf123
Discovery URL ユーザープールIDから組み立てる https://cognito-idp.ap-northeast-1.amazonaws.com/<ユーザープールID>/.well-known/openid-configuration
クライアントID アプリケーションクライアントの詳細 1abc...
クライアントシークレット 同上(「クライアントシークレットを表示」) 公開しないこと
Cognitoドメイン 「ドメイン」タブ https://ap-northeast-1abcdef.auth.ap-northeast-1.amazoncognito.com

AgentCore Gatewayの作成

  1. Amazon Bedrock AgentCoreコンソールの左メニューで「ゲートウェイ」→「ゲートウェイを作成」を押します。
  2. 次のように設定します。
項目 設定値
ゲートウェイ名 employee-directory-gw
IAMアクセス許可 デフォルトロールを作成
指示 下記の文面
セマンティック検索を有効にする 無効
例外レベルのデバッグ 無効
セッションを有効にする 無効
サポート対象バージョン すべて選択

「指示」に入れる文面は次のとおりです。

社内の社員名簿(ダミーデータ)を検索するツールを提供します。
- 氏名から部署・役職・メールを調べるときは get_employee を使う
- 部署や役職で社員を一覧するときは search_employees を使う
- 上長や組織上の位置を調べるときは get_reporting_line を使う
同姓の社員が複数いる場合は、候補を示してユーザーに確認すること。
  1. ほかの項目は未設定のまま「次へ」を押します。

インバウンド認証の設定

  1. Inbound Auth typeで「JSON Web Tokens(JWT)を使用」を選び、次のように設定します。
項目 設定値
Discovery URL 控えておいたDiscovery URL
Allowed clients 控えておいたクライアントID
Allowed scopes employee-directory/read

Allowed audiencesは空のままにします。Cognitoのアクセストークンには aud クレームが含まれないため、設定すると認証に失敗します。

  1. 「次へ」を押します。

ターゲットの設定

ターゲットとは、Gatewayが仕事を頼む先のことです。Gatewayを受付窓口にたとえると次のとおりです。

ターゲットのたとえ

  1. 次のように設定します。
項目 設定値
ターゲットプロトコルを選択 MCP target
ターゲット名 EmployeeDirectory
ターゲットタイプ Lambda ARN
Lambda ARN 控えておいたLambdaの関数ARN
アウトバウンド認証設定 IAMロール

ターゲット名はツール名の接頭辞になります(例: EmployeeDirectory___get_employee)。

  1. ターゲットスキーマで「インラインスキーマを定義」を選び、次のJSONを貼り付けます。description はClaudeがツールを選ぶ判断材料になるため、どんな質問のときに使うかまで具体的に書いています。
[
  {
    "name": "get_employee",
    "description": "氏名(姓のみ・部分一致も可)から社員の部署、役職、メールアドレス、上長IDを取得する。「〇〇さんの役職は?」「〇〇さんの所属は?」と聞かれたときに使う。",
    "inputSchema": {
      "type": "object",
      "properties": {
        "name": {"type": "string", "description": "社員の氏名。例: 佐藤 花子、佐藤"}
      },
      "required": ["name"]
    }
  },
  {
    "name": "search_employees",
    "description": "部署名(必須)と役職(任意)で社員を一覧する。「開発部のメンバーは?」「営業部の部長は誰?」と聞かれたときに使う。",
    "inputSchema": {
      "type": "object",
      "properties": {
        "department": {"type": "string", "description": "部署名。例: 開発部"},
        "title": {"type": "string", "description": "役職名。例: 部長"}
      },
      "required": ["department"]
    }
  },
  {
    "name": "get_reporting_line",
    "description": "社員IDから上長を順にたどり、本人からトップまでのレポートラインを返す。「〇〇さんの上司は?」と聞かれたときに、get_employeeで社員IDを調べてから使う。",
    "inputSchema": {
      "type": "object",
      "properties": {
        "employee_id": {"type": "string", "description": "社員ID。例: E0004"}
      },
      "required": ["employee_id"]
    }
  }
]
  1. 「次へ」を押します。
  2. 最後のステップで「ゲートウェイを作成」を押します。
  3. ゲートウェイの詳細画面の「ターゲット」タブで、ターゲットのステータスが Ready になるまで待ちます。Ready になる前に接続すると、ツール一覧が空で返ってきます。
  4. 詳細画面に表示される「ゲートウェイリソース URL」を控えます。https://employee-directory-gw-xxxx.gateway.bedrock-agentcore.ap-northeast-1.amazonaws.com/mcp の形式です。

アクセストークンを取得する

  1. 値を環境変数に入れます。
export COGNITO_DOMAIN="https://ap-northeast-1abcdef.auth.ap-northeast-1.amazoncognito.com"
export CLIENT_ID="<クライアントID>"
export CLIENT_SECRET="<クライアントシークレット>"
export GW_URL="https://employee-directory-gw-xxxx.gateway.bedrock-agentcore.ap-northeast-1.amazonaws.com/mcp"
  1. アクセストークンを取得します。
export TOKEN=$(curl -s -X POST "$COGNITO_DOMAIN/oauth2/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials&scope=employee-directory/read" \
  | python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")
printf %s "$TOKEN" | wc -c

表示される文字数が1000前後なら取得できています。

トークンの有効期限は既定で60分です。期限が切れたらこのコマンドを再実行します。

  1. curlでツール一覧を確認します。
curl -s -X POST "$GW_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

レスポンスに EmployeeDirectory___get_employee など3つのツールが含まれていれば成功です。

  1. ツールを直接呼び出します。
curl -s -X POST "$GW_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"EmployeeDirectory___get_employee","arguments":{"name":"佐藤 花子"}}}'
{"jsonrpc":"2.0","id":2,"result":{"isError":false,"content":[{"type":"text","text":"{\"count\":1,\"results\":[{\"employee_id\":\"E0002\",\"name\":\"佐藤 花子\",\"name_kana\":\"サトウ ハナコ\",\"department\":\"開発部\",\"title\":\"テックリード\",\"email\":\"e0002@example.com\",\"manager_id\":\"E0005\"}]}"}]}}

Claude Desktopからの接続

アクセストークンは、あらかじめ ~/.config/employee-directory/.env に AUTH_HEADER="Bearer <アクセストークン>" の形で保存しておきます。

  1. Claude Desktopで「設定」→「開発者」→「設定を編集」を押します。
  2. 設定ファイル claude_desktop_config.json をテキストエディタで開きます。
  3. 次の内容を書きます。すでに mcpServers に別のサーバーがある場合は、"employee-directory": { ... } の部分だけをその中に追加します。
{
  "mcpServers": {
    "employee-directory": {
      "command": "/bin/sh",
      "args": [
        "-c",
        "set -a && . ~/.config/employee-directory/.env && exec npx -y mcp-remote <ゲートウェイリソース URL> --header 'Authorization:${AUTH_HEADER}'"
      ]
    }
  }
}

<ゲートウェイリソース URL> を控えておいた値に書き換えます。${AUTH_HEADER} は .env の値に置き換わります。

mcp-remoteによる接続構成

  1. ファイルを保存し、Claude Desktopを完全に終了してから起動し直します。
  2. 「設定」→「開発者」で employee-directory が running になっていることを確認します。

Claude Desktopとの会話で検証する

質問1: 氏名から社員を調べる

佐藤 花子さんの役職は?

佐藤 花子さんの役職を尋ねた結果

質問2: 同姓の社員が複数いる場合

佐藤さんの役職は?

佐藤さんの役職を尋ねた結果

質問3: 複数のツールを組み合わせる

高橋さんの上司の上司は誰?

高橋さんの上司の上司を尋ねた結果

ツールの連続呼び出し

質問4: 返さない項目を聞く

山田さんの給与は?

山田さんの給与を尋ねた結果

検証結果のまとめ

質問 確認できたこと
佐藤 花子さんの役職は? DynamoDBのデータをもとに回答する
佐藤さんの役職は? Gatewayの「指示」に沿って、同姓の候補を示して確認する
高橋さんの上司の上司は誰? 2つのツールを順に呼んで回答する
山田さんの給与は? 給与は回答しない

お片付け

検証後、次の順で削除しました。

  1. Claude Desktopの設定ファイルから employee-directory を削除し、Claude Desktopを再起動
  2. AgentCore Gatewayのターゲット、ゲートウェイの順に削除
  3. Gateway作成時に作られたIAMサービスロール
  4. Cognitoのユーザープール
  5. Lambda関数とその実行ロール、CloudWatch Logsのロググループ
  6. DynamoDBテーブル employees

まとめ

AgentCore Gatewayを使うと、既存のLambdaにツール定義を登録するだけでMCPサーバーとして公開でき、その手軽さを体感できました。
ターゲットにはLambdaのほか、OpenAPI等で定義した既存のAPIも登録できます。社内のデータやシステムを生成AIから使いたい場面は今後も増えると考えられるため、MCPサーバーを個別に作らずにGatewayからまとめて公開できる点は大きな強みだと考えています。

実際に試してみて、普段使っているClaudeから社員名簿を参照でき、業務などでの実用性を感じました。
他にも多くの機能があるので、引き続き検証してみたいと思います。


Claudeならクラスメソッドにお任せください

クラスメソッドは、Anthropic社とリセラー契約を締結しています。各種製品ガイドから、業種別の活用法、フェーズごとのお悩み解決などサービス支援ページにまとめております。まずはご覧いただき、お気軽にご相談ください。

サービス詳細を見る

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事