
Amazon Bedrock AgentCore GatewayでMCPサーバーを作成し、Claude Desktopから接続してみた
はじめに
クラスメソッドテクノロジーズの武蔵です。
最近社内のイベントをきっかけに登山の楽しさを知りました。おすすめの山があれば教えてください。
最近、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コンソールで「ユーザープール」→「ユーザープールを作成」を押します。
- アプリケーションタイプで「マシン間アプリケーション」を選びます。
- ユーザープール名は自動生成された名前になるので、わかりやすい名前に変更します。
リソースサーバーとスコープを作成する
リソースサーバーでは、このトークンでどのAPIにアクセスしてよいかを設定します。
- ユーザープールの「アプリケーション統合」→「リソースサーバー」で「リソースサーバーを作成」を押し、次のように設定します。
| 項目 | 設定値 |
|---|---|
| リソースサーバー名 | employee-directory |
| 識別子 | employee-directory |
| カスタムスコープ名 | read |
- 作成すると、スコープ文字列は
employee-directory/readになります。

アプリクライアントにスコープを割り当てる
- 「アプリケーションクライアント」から作成したアプリケーションクライアントを開き、「ログインページ」タブの「編集」を押します。
- OAuth 2.0 許可タイプが「クライアント認証情報」になっていることを確認します。
- カスタムスコープで
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の作成
- Amazon Bedrock AgentCoreコンソールの左メニューで「ゲートウェイ」→「ゲートウェイを作成」を押します。
- 次のように設定します。
| 項目 | 設定値 |
|---|---|
| ゲートウェイ名 | employee-directory-gw |
| IAMアクセス許可 | デフォルトロールを作成 |
| 指示 | 下記の文面 |
| セマンティック検索を有効にする | 無効 |
| 例外レベルのデバッグ | 無効 |
| セッションを有効にする | 無効 |
| サポート対象バージョン | すべて選択 |
「指示」に入れる文面は次のとおりです。
社内の社員名簿(ダミーデータ)を検索するツールを提供します。
- 氏名から部署・役職・メールを調べるときは get_employee を使う
- 部署や役職で社員を一覧するときは search_employees を使う
- 上長や組織上の位置を調べるときは get_reporting_line を使う
同姓の社員が複数いる場合は、候補を示してユーザーに確認すること。
- ほかの項目は未設定のまま「次へ」を押します。
インバウンド認証の設定
- Inbound Auth typeで「JSON Web Tokens(JWT)を使用」を選び、次のように設定します。
| 項目 | 設定値 |
|---|---|
| Discovery URL | 控えておいたDiscovery URL |
| Allowed clients | 控えておいたクライアントID |
| Allowed scopes | employee-directory/read |
Allowed audiencesは空のままにします。Cognitoのアクセストークンには aud クレームが含まれないため、設定すると認証に失敗します。
- 「次へ」を押します。
ターゲットの設定
ターゲットとは、Gatewayが仕事を頼む先のことです。Gatewayを受付窓口にたとえると次のとおりです。

- 次のように設定します。
| 項目 | 設定値 |
|---|---|
| ターゲットプロトコルを選択 | MCP target |
| ターゲット名 | EmployeeDirectory |
| ターゲットタイプ | Lambda ARN |
| Lambda ARN | 控えておいたLambdaの関数ARN |
| アウトバウンド認証設定 | IAMロール |
ターゲット名はツール名の接頭辞になります(例: EmployeeDirectory___get_employee)。
- ターゲットスキーマで「インラインスキーマを定義」を選び、次の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"]
}
}
]
- 「次へ」を押します。
- 最後のステップで「ゲートウェイを作成」を押します。
- ゲートウェイの詳細画面の「ターゲット」タブで、ターゲットのステータスが Ready になるまで待ちます。Ready になる前に接続すると、ツール一覧が空で返ってきます。
- 詳細画面に表示される「ゲートウェイリソース URL」を控えます。
https://employee-directory-gw-xxxx.gateway.bedrock-agentcore.ap-northeast-1.amazonaws.com/mcpの形式です。
アクセストークンを取得する
- 値を環境変数に入れます。
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"
- アクセストークンを取得します。
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分です。期限が切れたらこのコマンドを再実行します。
- 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つのツールが含まれていれば成功です。
- ツールを直接呼び出します。
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 <アクセストークン>" の形で保存しておきます。
- Claude Desktopで「設定」→「開発者」→「設定を編集」を押します。
- 設定ファイル
claude_desktop_config.jsonをテキストエディタで開きます。 - 次の内容を書きます。すでに
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 の値に置き換わります。

- ファイルを保存し、Claude Desktopを完全に終了してから起動し直します。
- 「設定」→「開発者」で
employee-directoryが running になっていることを確認します。
Claude Desktopとの会話で検証する
質問1: 氏名から社員を調べる
佐藤 花子さんの役職は?

質問2: 同姓の社員が複数いる場合
佐藤さんの役職は?

質問3: 複数のツールを組み合わせる
高橋さんの上司の上司は誰?


質問4: 返さない項目を聞く
山田さんの給与は?

検証結果のまとめ
| 質問 | 確認できたこと |
|---|---|
| 佐藤 花子さんの役職は? | DynamoDBのデータをもとに回答する |
| 佐藤さんの役職は? | Gatewayの「指示」に沿って、同姓の候補を示して確認する |
| 高橋さんの上司の上司は誰? | 2つのツールを順に呼んで回答する |
| 山田さんの給与は? | 給与は回答しない |
お片付け
検証後、次の順で削除しました。
- Claude Desktopの設定ファイルから
employee-directoryを削除し、Claude Desktopを再起動 - AgentCore Gatewayのターゲット、ゲートウェイの順に削除
- Gateway作成時に作られたIAMサービスロール
- Cognitoのユーザープール
- Lambda関数とその実行ロール、CloudWatch Logsのロググループ
- DynamoDBテーブル
employees
まとめ
AgentCore Gatewayを使うと、既存のLambdaにツール定義を登録するだけでMCPサーバーとして公開でき、その手軽さを体感できました。
ターゲットにはLambdaのほか、OpenAPI等で定義した既存のAPIも登録できます。社内のデータやシステムを生成AIから使いたい場面は今後も増えると考えられるため、MCPサーバーを個別に作らずにGatewayからまとめて公開できる点は大きな強みだと考えています。
実際に試してみて、普段使っているClaudeから社員名簿を参照でき、業務などでの実用性を感じました。
他にも多くの機能があるので、引き続き検証してみたいと思います。












