MCP による AI Agents 活用の設計:AIによるインフラ操作

|
AI MCP Automation LLM Claude Cloudflare Infrastructure

Model Context Protocol(MCP)とAIを使って定型的なインフラ操作を自動化した記録。Claude DesktopとAWSをMCPで連携させてみた実装メモです。

Part 1: MCP とは

「AIに道具を渡すプロトコル」= 「AIが外部のツールやAPIを自分で呼び出せるようにする仕組み」

通常のAIチャット:
  ユーザー → [質問] → AI → [テキストで回答]

MCP使用時:
  ユーザー → [質問] → AI → [ツールを呼び出す判断]
                              ↓
                         [MCP Server]
                              ↓
                         [外部API・DBなどを実行]
                              ↓
                         [結果をAIに返す]
                              ↓
                      AI → [結果を踏まえて回答]

AIが外部API呼び出しや外部DB操作を実行できるようになります。


Part 2: MCP Server の実装(TypeScript)

プロジェクトのセットアップ

mkdir infra-mcp-server && cd infra-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk @aws-sdk/client-ecs \
  @aws-sdk/client-cloudwatch-logs @aws-sdk/client-ec2 \
  @aws-sdk/client-ecr zod
npm install -D typescript @types/node tsx
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./dist",
    "strict": true
  }
}

Tool の定義と実装

// src/server.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { CloudWatchLogsClient, FilterLogEventsCommand } from '@aws-sdk/client-cloudwatch-logs';
import { z } from 'zod';

const AWS_REGION = process.env.AWS_REGION ?? 'ap-northeast-1';
const logs  = new CloudWatchLogsClient({ region: AWS_REGION });
const server = new Server(
  { name: 'infra-mcp-server', version: '1.0.0' },
  { capabilities: { tools: {} } }
);

// ── Tool の一覧を返す ──────────────────────────────

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
     {
      name: 'search_cloudwatch_errors',
      description: '指定したロググループから ERROR ログを検索して返す。障害調査の最初のステップ。',
      inputSchema: {
        type: 'object',
        properties: {
          logGroupName: { type: 'string', description: 'CloudWatch ロググループ名' },
          minutesAgo:   { type: 'number', description: '何分前からのログを検索するか(デフォルト: 60)' },
          filterPattern:{ type: 'string', description: 'CloudWatch フィルターパターン(デフォルト: ERROR)' },
        },
        required: ['logGroupName'],
      }},
  ]
}));
// ── Tool の実行ロジック ───────────────────────────
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  switch (name) {
    // CloudWatch ログ検索
    case 'search_cloudwatch_errors': {
      const { logGroupName, minutesAgo = 60, filterPattern = 'ERROR' } = z.object({
        logGroupName:  z.string(),
        minutesAgo:    z.number().default(60),
        filterPattern: z.string().default('ERROR'),
      }).parse(args);

      const startTime = Date.now() - minutesAgo * 60 * 1000;
      const res = await logs.send(new FilterLogEventsCommand({
        logGroupName,
        startTime,
        filterPattern,
        limit: 20,
      }));

      const events = (res.events ?? []).map(e =>
        `[${new Date(e.timestamp ?? 0).toISOString()}] ${e.message?.trim()}`
      ).join('\n');

      return {
        content: [{
          type: 'text',
          text: events.length > 0
            ? `Found ${res.events?.length} events:\n\n${events}`
            : `No ${filterPattern} events in the last ${minutesAgo} minutes`,
        }],
      };
    }

    default:
      throw new Error(`Unknown tool: ${name}`);
  }
});

Tool の description は人間ではなく AI に向けて書きます。「いつこのToolを使うべきか」が伝わる説明にするほど、AIが適切なタイミングで呼び出してくれます。


Part 3: Claude Desktop での設定

{
  "mcpServers": {
    "infra": {
      "command": "node",
      "args": ["/path/to/infra-mcp-server/dist/server.js"],
      "env": {
        "AWS_REGION": "ap-northeast-1",
        "AWS_PROFILE": "my-aws-profile"
      }
    }
  }
}

Part 4: 「任せられる範囲」の設計

MCPでAIを活用するうえで大事なのは、どこまで任せるか 読み取り操作は問題になりづらく、破壊的操作は大事故と隣り合わせです。

設計例:
  ✅ AIに全委譲してよい操作(読み取り専用):
    - CloudWatch ログの検索・集計
    - Cost Explorer でのコスト照会
    - S3 バケットの一覧の確認
    → 何も変更しないので、誤判断しても被害なし

  ⚠️  AIが提案し、人間が承認する操作:
    - 古いイメージの削除(dry_run→確認→実行の2ステップ)
    - S3 オブジェクトの削除
    → AIが「何を、なぜ変更するか」を提示し、人間がYesを押す

  🚫 AIに渡さない、Toolとして定義しない操作:
    - terraform apply の実行
    - IAM ポリシーの変更
    - RDS インスタンスの削除
    - S3 バケット自体の削除
    - 本番環境の環境変数変更
    → MCP Server のコード上にToolとして存在させない
      = AIがそもそも実行できない構造

Toolの権限が上限 AIがどんなミスをしても、Toolとして実装されていない操作は実行できません。


Part 5: MCP Serverのセキュリティ設計

ローカル実行時の認証

// 環境変数から AWS 認証情報を取得(ハードコード禁止)
// ~/.aws/credentials の named profile か IAM Instance Profile を使う
const ecs = new ECSClient({
  region: process.env.AWS_REGION,
  // credentials は SDK が自動解決(環境変数・profile・IMDS の順)
});

// MCP Server に渡す IAM ポリシーは最小権限で
// 読み取り専用Toolなら ReadOnly ポリシーのみ
// 変更系Toolは対象リソースを ARN で絞る

Zod によるInput Validation

// 全 Tool の引数を Zod で厳密にバリデート
// AI が不正な引数(負の desired count 等)を渡しても弾かれる

const { desiredCount } = z.object({
  desiredCount: z.number().min(0).max(100),  // 0〜100 の範囲外は拒否
}).parse(args);

まとめ:

MCPを使ったAIエージェント活用の設計は 「AIの実行範囲をコードで定義する」 作業です。

スクリプトやcronによる自動化には、当然ですが判断がなく、状況変化やイレギュラーな場合に対応できません。 MCPによってToolを与えられたAIは、想定外の結果が出たら別のアプローチを試みる、といった臨機応変な対応を可能にします。 ただし、勝手に判断して実行してくれるが故に、出来ることの範囲(=権限)は人間が細心の注意を払って設計する必要があります。

観点 スクリプト自動化 MCP + AI Agent
定型手順の実行 ✅ 得意 ✅ 得意(かつ自然言語で指示可能)
状況に応じた判断 ❌ 苦手 ✅ 得意(ログの内容を読んで次の手を考える)
権限の制御 IAM で制御 IAM + Tool定義の2層で制御
実行の透明性 ログのみ AIの「思考過程」が可視化される
破壊的操作の安全性 スクリプトの品質次第 dry_run + 人間承認ステップを構造化できる

「AIにインフラを触らせるのは怖い」からこそ、怖い操作をToolとして定義しないという設計判断が何よりも大事になります。

この記事をシェア

Twitter / X
記事一覧に戻る
🤖
Cloud Assistant
Llama 3.3 × AI Gateway

こんにちは!クラウドエンジニアのポートフォリオサイトへようこそ。AWS構成・副業サービス・お仕事のご相談など、何でも聞いてください 👋