🔌

AWS S3 と連携する MCP サーバーを作ってみてわかったこと 🪣🔌🤖

に公開

MCP とは?

Model Context Protocol (MCP)の説明としてはざっくり以下です。

  • コア機能: AI モデルが外部ツールやデータソースにアクセスできるようにする
  • 主なメリット: 学習データを超えて AI 機能を拡張する
  • 例え: AI モデル用の「USB-C」のような役割 - 汎用的なコネクター
  • 実装: 開発者が LLM に接続できる MCP サーバーを作成する

MCP アーキテクチャ

公式 MCP ドキュメントによると、MCP は言語モデルと外部コンポーネント間の標準化された通信プロトコルを確立します:

  • クライアント・サーバーアーキテクチャ: LLM は機能を公開する MCP サーバーに接続

コアコンポーネント:

  • Tool: 特定のアクション(検索や計算など)を実行する機能
  • Resource: 外部データ(ファイル、データベース、API)へのアクセスポイント

※ 他にも Prompt, Sampling Roots などのコンポーネントがありますが、この記事では触れません。

┌────────────────┐     ┌───────────────────────────────┐
│  LLM Platform  │     │          MCP Server           │
│                │     │                               │
│ ┌────────────┐ │     │  ┌────────┐     ┌─────────┐   │
│ │ Claude/GPT │ │     │  │MCP SDK │<--->│Custom   │   │
│ └────────────┘ │     │  │        │     │Server   │   │
│       ▲        │     │  └────────┘     └────┬────┘   │
│       │        │     │                      │        │
│ ┌────────────┐ │     │                      ▼        │
│ │MCP Client  │◄├─────┤              ┌─────────────┐  │
│ └────────────┘ │     │              │External API │  │
└────────────────┘     │              └─────────────┘  │
                       └───────────────────────────────┘

このアーキテクチャにより、LLM は以下のことが可能になります:

  • 学習データを超えたリアルタイム情報にアクセスする
  • カスタム統合不要で特殊なツールを使用する
  • 保護されたリソースに制御された方法でアクセスする

aws-s3-mcp: AWS S3 と連携する MCP サーバー

この動画では、予め AWS S3 バケット内に保存した PDF ファイルを取得し、その内容を要約するデモ

https://github.com/user-attachments/assets/d05ff0f1-e2bf-43b9-8d0c-82605abfb666

実装

aws-s3-mcpサーバーは 3 つのコアツールを実装しています:

  1. list-buckets: 利用可能な S3 バケットを表示
  2. list-objects: 特定のバケット内のファイルを表示
  3. get-object: ファイルコンテンツの取得と処理(ex. PDF の場合はバイナリからテキスト変換)

使用した主要技術:

  • TypeScript: 型安全性と最新の開発機能のため
  • AWS SDK v3: S3 との連携
  • MCP SDK: @modelcontextprotocol/sdkからプロトコル実装のため
  • pdf-parse: PDF ファイルからテキストを抽出するため

実装の概要としては以下のような内容:

// すべてのツール実装で使用するIMCPToolインターフェース定義
export interface IMCPTool<
  TParams extends Record<string, z.ZodType> = Record<string, z.ZodType>
> {
  // ツール名
  readonly name: string;

  // ツールの説明
  readonly description: string;

  // パラメータ定義
  readonly parameters: TParams;

  // ツールの実行
  execute(args: InferZodParams<TParams>): Promise<{
    content: {
      type: "text";
      text: string;
      [key: string]: unknown;
    }[];
    isError?: boolean;
    [key: string]: unknown;
  }>;
}

// 実装例: List Buckets Tool
export class ListBucketsTool implements IMCPTool {
  readonly name = "list-buckets";
  readonly description = "List available S3 buckets";
  readonly parameters = {} as const;

  constructor(private s3Resource: S3Resource) {}

  async execute() {
    try {
      const buckets = await this.s3Resource.listBuckets();
      return {
        content: [
          {
            type: "text" as const,
            text: JSON.stringify(buckets, null, 2),
          },
        ],
      };
    } catch (error) {
      return createErrorResponse(
        error,
        `Error listing buckets: ${
          error instanceof Error ? error.message : String(error)
        }`
      );
    }
  }
}

MCP サーバーのセキュリティ考慮事項

AWS S3 のような特にクラウドリソースにアクセスする MCP サーバーでは、セキュリティが重要です。

実際に Equixly 2025 セキュリティ分析によると、MCP サーバーにはいくつかの一般的な脆弱性があります:

  • 🚨 コマンドインジェクション: 分析された MCP サーバーの 43%が脆弱
  • 🔍 パストラバーサル: サーバーの 22%が影響を受ける
  • 🌐 サーバーサイドリクエストフォージェリ(SSRF): サーバーの 30%がリスクあり

アプローチ:Docker と Deno による分離

これらのセキュリティリスクを確保するために、Docker と Deno が効果的な方法です。

Deno を使用した Dockerfile:

FROM denoland/deno:latest

WORKDIR /app

# セキュリティ強化のための非rootユーザー作成
USER deno

# セキュリティを強化するためのDenoのPermission flagを使用して特定の権限制約を使用
ENTRYPOINT ["deno", "run", \
  "--allow-net=s3.amazonaws.com", \
  "--allow-env=AWS_REGION,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY", \
  "--allow-read=/app", \
  "--allow-sys"]
CMD ["src/index.ts"]

これで以下のような要件の Dockerfile が作成されます:

  • コンテナ分離: Docker は潜在的な被害を制限するサンドボックスを提供
  • 非 Root 実行: denoユーザーが特権を制限
  • 権限ベースセキュリティ: Deno の明示的な権限システムが不正アクションを防止
  • ネットワークセキュリティ: 必要なエンドポイントへの接続のみを許可
  • 環境変数コントロール: 必要な環境変数のみを公開

安全な vs 不安全な設定

Claude Desktop で aws-s3-mcp サーバーを設定する場合、セキュリティはセットアップによって異なります:

安全でない設定:

"mcpServer": {
  "command": "npx",
  "args": ["aws-s3-mcp"],
  "env": {
    "AWS_ACCESS_KEY_ID": "your_key",
    "AWS_SECRET_ACCESS_KEY": "your_secret"
 }
}

安全な設定:

"mcpServer": {
 "command": "docker",
 "args": [
   "run",
   "-i",
   "--rm",
   "-e",
   "AWS_REGION",
   "-e",
   "S3_BUCKETS",
   "-e",
   "AWS_ACCESS_KEY_ID",
   "-e",
   "AWS_SECRET_ACCESS_KEY",
   "aws-s3-mcp:latest"
 ],
 "env": {
   "AWS_REGION": "us-east-1",
   "S3_BUCKETS": "bucket1,bucket2",
   "AWS_ACCESS_KEY_ID": "${YOUR_ACCESS_KEY}",
   "AWS_SECRET_ACCESS_KEY": "${YOUR_SECRET_KEY}"
 }
}

この設定により、Claude は分離のための Docker と認証情報のための環境変数を使用して、安全に AWS S3 バケットに接続します。claude_desktop_config.jsonファイルは以下の場所にあります:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\\Claude\\claude_desktop_config.json

設定後、変更を適用するために Claude Desktop を再起動してください。その後、Claude に S3 バケットとの対話を依頼できるようになります。

安全なアプローチでは、Docker 分離と環境変数を使用することで、認証情報の漏洩や不正アクセスのリスクを大幅に低減します。

残念ながら、main ブランチではまだ Docker + Deno による MCP サーバー起動の対応ができていないですが、別ブランチで Docker + Deno で、 MCP Inspector 上で動作はできます。

詳細に興味がある場合は、PR をチェックしてみてください。👇

https://github.com/samuraikun/aws-s3-mcp/pull/7

今は過度期で、ローカルで MCP サーバーを動かす必要はなくなる?

2025-3-26 に、MCP の仕様が更新され、Streamable HTTP が追加されました。
https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http

また、MCP の TypeScript SDK も更新され、Streamable HTTP に対応されました。
https://github.com/modelcontextprotocol/typescript-sdk/releases/tag/1.10.0

これにより、少なくとも TypeScript で MCP サーバーを開発する際は、今後は MCP サーバーをどこかしらにデプロイして、各 MCP クライアントはリモートの MCP サーバーに接続する形になると思います。他の言語の SDK も同様の対応がされるでしょう。
そのため、リモート MCP サーバーが普及すれば、ローカルで MCP サーバーを立てる必要はなくなっていくのではないかと思います。

実際にどう MCP サーバーをリモート MCP として実装するかは、こちらの記事が参考になりました。
https://azukiazusa.dev/blog/mcp-server-streamable-http-transport/

まとめ

AWS S3 と連携する MCP サーバーを作ってみた結果:

  • MCP 自体はシンプルなアーキテクチャで、SDK を使えば開発は難しくない
  • サードパーティの MCP サーバーを利用する場合、セキュリティに注意が必要
  • Docker と Deno を組み合わせることで、セキュリティを強化できる
  • MCP 自体が、Streamable HTTP に対応したので今後は Remote MCP Server が増え、ローカルで MCP を動かす必要はなくなっていきそう

Discussion