【MCP】Claude DesktopからLambda関数を呼び出しS3のファイルを取得する（lambda-tool-mcp-server）

# 目的
最近MCPの動きがとても速いですね。
今回はMCPを使うことで何ができるのか。
それを体験できるハンズオンとなっています。

:::note info
**今回作るもの**
[AWS lambda-tool-mcp-server](https://github.com/awslabs/mcp/tree/main/src/lambda-tool-mcp-server)を使い、AWS環境にあるS3バケットの情報をローカルのClaude Desktopから自然言語指示で取得する
:::

https://github.com/awslabs/mcp/tree/main/src/lambda-tool-mcp-server

・全体構成
- MCPクライアントにはClaude Desktopを使います。
- MCPサーバーにはAWS公式のlambda-tool-mcp-serverをローカルコンテナで使います。
- MCPツールにはS3と連携させたLambda関数を使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/198d9265-d5ad-4208-b8c5-aa82618e3e41.png)

・デモ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/f919a834-7d9f-409f-9f10-2ae2ef3ff962.png)


# 前提条件
- [Docker](https://www.docker.com/ja-jp/products/docker-desktop/)がインストールされていることとします。
- [Claude Desktop](https://claude.ai/download)がインストールされていることとします。
    - Claude Desktopは開発者モードにしておく必要があります。
    - [Claude Desktopを開発者モードにする](https://qiita.com/eiji-noguchi/items/a24881f5b5e32710f028#claude-for--desktop%E3%82%92%E9%96%8B%E7%99%BA%E3%83%A2%E3%83%BC%E3%83%89%E3%81%AB%E3%81%99%E3%82%8B)
- 本手順はWindows（WSL）環境を使います。
- MCPサーバーからLambda関数実行のためのAWS認証情報には`AWS_ACCESS_KEY_ID`および`AWS_SECRET_ACCESS_KEY`を使います。


# AWS リソースの作成
まずはAWS側の準備で、赤枠の部分を構築してきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/bd1ad1b3-a296-4a1d-b3ee-8f223ad357a0.png)

AWSからLambda関数の[サンプル](https://github.com/awslabs/mcp/tree/main/src/lambda-tool-mcp-server/examples)が提供されており、`sam`コマンドで一気に立ち上げることもできますが、
ここでは自作のLambda関数を使うことでよりMCPへの理解を深めます。

## S3バケットの作成
まずはバケットを作成します。
今回はダミーで構いません。
設定値もデフォルトで作ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/1494c88d-2b65-49d2-b8ae-ef40c11cd9d6.png)

作成したバケット内には適当なファイルを入れておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/d08a36f7-a940-41df-b263-7945159e21ba.png)


## ロールの作成
Lambda用のロールを作成します。
Lambda関数の実行とS3へのアクセスポリシーをアタッチしておきます。

| 項目 | 内容 |
|------|------|
| 名前 | lambda-s3-full-access-role |
| 信頼ポリシー | ※下記参照 |
| 許可ポリシー | • AWSLambdaBasicExecutionRole<br>• AmazonS3FullAccess |

<details><summary>※ 信頼ポリシー</summary>

```terminal: 信頼ポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole"
            ],
            "Principal": {
                "Service": [
                    "lambda.amazonaws.com"
                ]
            }
        }
    ]
}
```
</details>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/32695228-e57c-470f-b702-0d454da68119.png)


## Lambdaの作成
### S3バケットの一覧を取得するLambda関数
#### ① Lambda関数の作成

| 項目 | 設定値 |
|------|--------|
| 関数名 | lambda-tool-mcp-s3-bucket-list |
| ランタイム | Python 3.13 |
| アーキテクチャ | x86_64 |
| 既存のロール名 | lambda-s3-full-access-role |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/dee96648-e42c-406a-b415-73b6e55269ec.png)

#### ② コードを記述
今回はシンプルにすべてのS3バケット名を取得する関数になります。

```python: lambda_function.py
import boto3

def lambda_handler(event, context):
    s3 = boto3.client('s3')
    response = s3.list_buckets()
    buckets = [bucket['Name'] for bucket in response['Buckets']]
        
    return {
        'Buckets': buckets
    }
```

<details><summary>レスポンス内容</summary>

```json: レスポンス内容
{
  "Buckets": [
    "hello-noguchi-bucket",
    "nice-noguchi-bucket"
  ]
}
```
</details>

#### ③ 説明を追加
一般設定からLambda関数の説明を記載します。

:::note info

ここの記載内容でAIがLambda関数の機能を理解するため、しっかり書きましょう。
:::

```
Get a list of buckets in S3.
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/3e06ad45-e6a2-47c2-b48b-74a9b0dacd8e.png)


### S3バケットのファイルの一覧を取得するLambda関数
#### ① Lambda関数の作成

| 項目 | 設定値 |
|------|--------|
| 関数名 | lambda-tool-mcp-s3-file-list |
| ランタイム | Python 3.13 |
| アーキテクチャ | x86_64 |
| 既存のロール名 | lambda-s3-full-access-role |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/5f360f2f-107f-404d-9eed-265d3789947b.png)

#### ② コードを記述
今回は指定されたS3バケット名にあるファイルを一覧取得する関数になります。

```python: lambda_function.py
import boto3
import json

def lambda_handler(event, context):
   s3 = boto3.client('s3')
   
   bucket_name = event.get('bucket_name')
   
   response = s3.list_objects_v2(Bucket=bucket_name)
   
   files = []
   if 'Contents' in response:
       files = [obj['Key'] for obj in response['Contents']]
   
   return {
        'fileName': files
   }
```

<details><summary>リクエスト内容</summary>

```json: リクエスト内容
{
  "bucket_name": "hello-noguchi-bucket"
}
```
</details>

<details><summary>レスポンス内容</summary>

```json: レスポンス内容
{
  "fileName": [
    "hello_file1.txt",
    "hello_file2.txt"
  ]
}
```
</details>


#### ③ 説明を追加
一般設定からLambda関数の説明を記載します。

:::note info

ここの記載内容でAIがLambda関数の機能を理解するため、しっかり書きましょう。
:::

```
Get a list of files in the S3 bucket.
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/d59fcb67-6dc1-40ae-9667-a70f3d3bf481.png)


## スキーマの作成
EventBridgeのスキーマを設定します。
ここではLambda関数`lambda-tool-mcp-s3-file-list`がどのようなリクエストを受け付けるかを定義します。
今回はパラメータ`bucket_name`をstring型で受け取ることを前提としています。

:::note info

ここの記載内容でAIがLambda関数の使い方を理解するため、しっかり書きましょう。
:::

| 項目 | 設定値 |
|------|--------|
| スキーマレジストリ | 適当なレジストリ（なければ新規作成） |
| スキーマ名 | S3FileListSchema |
| スキーマタイプ | JSON Schema Draft 4 |
| スキーマ内容 | ※下記参照 |

```json: ※スキーマ内容
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "title": "S3FileListInput",
  "description": "Input schema for listing files in an S3 bucket",
  "required": ["bucket_name"],
  "properties": {
    "bucket_name": {
      "type": "string",
      "pattern": "^[a-z0-9.-]{3,63}$",
      "description": "S3 bucket name (must follow AWS naming conventions)"
    }
  },
  "additionalProperties": false
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/4df61250-dca7-49bc-89e5-d2147efb41e6.png)

### スキーマの設定
EventBrigeでスキーマを作成したら、Lambda関数`lambda-toop-mcp-s3-file-list`のタグへ紐づけます。

| 項目 | 設定値 |
|------|--------|
| tool-input-schema-arn | <スキーマ ARN> |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/9faab598-b435-4f99-bf4f-a94b93f65108.png)

# MCPサーバーの準備
次にMCP側の準備で、赤枠の部分をローカルに構築してきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/3e050223-0db9-4609-8d96-e6f0514c11c4.png)


AWSから公式にいくつものMCPサーバーが提供されています。
まずは以下のリポジトリからコードを取得してください。

https://github.com/awslabs/mcp/tree/main

その中で、今回使うソースは[mcp/src/lambda-tool-mcp-server](https://github.com/awslabs/mcp/tree/main/src/lambda-tool-mcp-server)になります。

機能の概念や使い方は[README.md](https://github.com/awslabs/mcp/blob/main/src/lambda-tool-mcp-server/README.md)にも書かれているので一読をお勧めします。

フォルダ構成の概要はこちら↓
<details><summary>フォルダ構成説明</summary>

```
lambda-tool-mcp-server/
├── 📄 設定・ドキュメント
│   ├── pyproject.toml           # Python パッケージ設定（依存関係、ビルド設定）
│   ├── README.md               # プロジェクトの説明・使用方法
│   ├── CHANGELOG.md            # バージョン履歴
│   ├── LICENSE                 # Apache 2.0 ライセンス
│   ├── NOTICE                  # 法的通知
│   └── uv.lock                 # 依存関係ロックファイル
├── 🐳 Docker関連
│   ├── Dockerfile              # コンテナイメージ定義
│   └── docker-healthcheck.sh   # ヘルスチェックスクリプト
├── 📦 メインコード
│   └── awslabs/
│       ├── __init__.py
│       └── lambda_tool_mcp_server/
│           ├── __init__.py
│           └── server.py       # MCPサーバーのメイン実装
├── 📚 使用例
│   └── examples/
│       ├── README.md
│       └── sample_functions/   # サンプルLambda関数
│           ├── customer-create/
│           ├── customer-id-from-email/
│           ├── customer-info-from-id/
│           ├── samconfig.toml  # SAM設定
│           └── template.yml    # SAMテンプレート
└── 🧪 テスト
    ├── tests/
    │   ├── test_*.py          # 各種テストファイル
    │   ├── conftest.py        # pytest設定
    │   └── README.md
    └── run_tests.sh           # テスト実行スクリプト
```
</details>


また、MCPサーバーを動かす方法には以下の2つの方法があります。
- PythonパッケージマネージャーでMCP サーバーを実行
- Docker コンテナでMCP サーバーを実行

今回はDockerを使います。
※READMEにPythonでの実行方法も記載されています。

## Dockerイメージのビルド

下記コマンドで対象のフォルダのDockerfileをビルドします。
```terminal
$ cd src/lambda-tool-mcp-server
$ docker build --no-cache -t awslabs/lambda-tool-mcp-server .
```

コマンドが成功したらDockerイメージが作成されているかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/d36eac82-0cd0-4dc4-bf4f-8a5e9ed1bef4.png)

# Claude DesktopのMCP構成を編集
この先の手順はClaude Desktopを開発者モードにしておく必要があります。
手順は以下を参考にしてください。

- [Claude Desktopを開発者モードにする](https://qiita.com/eiji-noguchi/items/a24881f5b5e32710f028#claude-for--desktop%E3%82%92%E9%96%8B%E7%99%BA%E3%83%A2%E3%83%BC%E3%83%89%E3%81%AB%E3%81%99%E3%82%8B)


まず、Claude Desktopの`claude_desktop_config.json`ファイルを編集し、以下を記載します。
`args`の内容は環境に応じて変更する必要がありますので、以下を参照に設定してください。

| 項目 | 設定値 |
|-----------|------|
| `--volume` | **AWS認証情報をマウント**<br> ※`.aws`の設定内容は下記参照 |
| `--env FUNCTION_LIST` | Lambda関数名<br>複数ある場合はカンマ区切りでつなげる |
| `--env FUNCTION_INPUT_SCHEMA_ARN_TAG_KEY` | Lambda関数のタグに設定したスキーマのタグKey名 |
| `--env AWS_REGION` | リージョン名 |
| `--env AWS_PROFILE` | 使用するAWSプロファイル |

<details><summary>※ .awsファイルの設定内容例</summary>

```./aws/credentials
[profile my_profile]
region = ap-northeast-1
output = json
```

```./aws/config
[my_profile]
aws_access_key_id = <IAMユーザーのアクセスキー>
aws_secret_access_key = <IAMユーザーのシークレットアクセスキー>
```
</details>

```json:claude_desktop_config.json
{
    "mcpServers": {
      "awslabs.lambda-tool-mcp-server": {
        "command": "docker",
        "args": [
            "run",
            "--rm",
            "--interactive",
            "--volume",
            "C:\\Users\\user\\.aws:/app/.aws:ro", 
            "--env",
            "FUNCTION_LIST=lambda-toop-mcp-s3-bucket-list,lambda-toop-mcp-s3-file-list",
            "--env",
            "FUNCTION_INPUT_SCHEMA_ARN_TAG_KEY=tool-input-schema-arn",
            "--env",
            "AWS_REGION=ap-northeast-1",
            "--env",
            "AWS_PROFILE=my_profile",
            "awslabs/lambda-tool-mcp-server:latest"
        ],
        "env": {},
        "disabled": false,
        "autoApprove": []
      }
    }
}
```

※他の`args`に設定できる項目については[README.md](https://github.com/awslabs/mcp/blob/main/src/lambda-tool-mcp-server/README.md)を参照してください。


ここまでくれば準備OKです。
お疲れ様でした。


## MCPサーバーの起動
Claude Desktopを起動します。
すると同時にコンテナが立ち上がりMCPサーバー「[sever.py](https://github.com/awslabs/mcp/blob/main/src/lambda-tool-mcp-server/awslabs/lambda_tool_mcp_server/server.py)」が起動されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/a9a1bb7d-ce64-471c-ba62-be99ea00b473.png)


この状態でClaude Desktopを見ると、先ほど作成したLambda関数がToolとして登録されていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/b997e43d-f890-43d6-9eb7-3915dece3998.png)


## MCPサーバーを使う
Claude Desktopに以下の指示を投げてみてください。
```
S3バケットの一覧を教えてください。
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/9b6215f8-9f89-47fc-ae25-7acee2d05484.png)


バケットの一覧が取得できました。
次にバケットの中身を聞いてみましょう。

```
hello-noguchi-bucketにはどのようなファイルが格納されていますか？
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/2f59cffe-826d-4600-88aa-13404834a1ca.png)

正しくファイルも取得できていますね。
ちなみに最初に外部連携許可を求められるかと思いますが、こちらは確認後許可してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621838/61e79e94-6354-46af-b7c9-28d3cb560142.png)


# (補足)
実際にどのようにMCPサーバーがLambda関数を認識、実行しているかは[sever.py](https://github.com/awslabs/mcp/blob/main/src/lambda-tool-mcp-server/awslabs/lambda_tool_mcp_server/server.py)を読み解くと理解が深まると思われますので、お時間がある方はぜひ。

https://github.com/awslabs/mcp/blob/main/src/lambda-tool-mcp-server/awslabs/lambda_tool_mcp_server/server.py

# まとめ
2024年11月にAnthropicからMCPが提唱され早半年がたちました。
今では多くのサービスがMCPサーバーとの連携を前提としたToolを出しており、MCPという概念が標準化されたといっても過言ではありません。
以前まで当たり前だったRAGも今ではMCPで代用できる部分が多く、技術の移り変わりの速さに焦りを感じております。

今回のLambda関数はシンプルにS3からバケットやファイルを取得するだけの処理でしたが、
Lambda関数に実装する機能次第でMCPができることがかなり広がるかと思います。

皆さんも早めにMCPを触っておきましょう！！
（これすらも少し経っただけで古いものになる時代かもしれませんが。。。）


# 仲間を募集しています！
ARIではエンジニア・ITコンサルタント・PM職全方位で仲間を募集しております。
カジュアル面談、随時受付中です！
ご興味ある方はこちらをご覧ください。

https://note.com/ari_hr/n/n4aed9ba75421