メインコンテンツへスキップ
三田工場 技術サイト
WebアプリをAIから操作できるようにした話(第1回)— MCPサーバー化の動機とアーキテクチャ

WebアプリをAIから操作できるようにした話(第1回)— MCPサーバー化の動機とアーキテクチャ

Architecture9分で読めます

このシリーズ: 全4回

  1. 第1回: MCPサーバー化の動機とアーキテクチャ ← 今ここ
  2. 第2回: MCP Streamable HTTPの実装
  3. 第3回: Bearer Token認証とDynamoDBトークン管理
  4. 第4回: Claude Codeから繋げるときの落とし穴

概要

チームで使っているタスク管理アプリ(Team Task Scheduler)を、AIツールから直接操作できる MCPサーバー として公開しました。

これにより「Claude Code 上で /task-flow 今週締め切りのタスクを教えて と入力するだけで、アプリのデータを自然言語で照会・更新できる」ようになりました。

このシリーズでは、その実装の全体像を順番に解説します。

こんな人向け

  • 既存のWebアプリを AI ツールから操作できるようにしたい
  • MCPサーバーを自前で実装してみたいが、どこから手をつければいいかわからない
  • Next.js + AWS Lambda 構成で MCP サーバーを動かしたい
  • Claude Code に自分のアプリを接続したい

なぜMCPサーバーにしようと思ったか

Team Task Scheduler は Next.js + DynamoDB + AWS Lambda で動くチームのタスク管理アプリです。ガントチャートビューや AI 業務報告機能を持っています。

このアプリを作り込むほど、「Claude Code の会話の中でタスクの状態を直接参照・更新できたら便利なのに」 と感じる場面が増えてきました。

例えば:

  • コードを書きながら「このタスクの進捗を50%に更新して」と話しかけたい
  • 「今週自分が担当している未完了タスクを教えて」と聞きたい
  • 「このバグ修正が完了したらタスクをCLOSEにして」と指示したい

従来はブラウザを開いてアプリの UI を操作する必要がありましたが、MCP サーバーとして公開すれば Claude Code の会話から直接操作 できます。

MCP(Model Context Protocol)とは

MCP は Anthropic が策定したオープンプロトコルで、AI ツール(Claude Code など)と外部サービスを繋ぐ標準仕様です。

仕組みは非常にシンプルです:

text
Claude Code

    │  JSON-RPC 2.0 over HTTP

MCPサーバー(あなたのアプリ)

    │  通常のAPI呼び出し

データベース・外部サービス

Claude Code はMCPサーバーに対して「どんな操作ができるか(tools/list)」を問い合わせ、ユーザーの指示に応じて「その操作を実行して(tools/call)」というリクエストを送ります。

サーバー側は「こういう操作ができます」という定義(ツール定義)と、実際に処理するハンドラーを実装するだけでOKです。

通信プロトコル:Streamable HTTP

MCPの HTTP 通信方式には 2 種類あります:

方式 説明 状態
HTTP+SSE(旧) GET でSSEストリームを開きっぱなしにする 非推奨
Streamable HTTP(新) POST でリクエスト、レスポンスは同一接続で返す 推奨

今回は Streamable HTTP を採用しました。Claude Code(v2.1.121以降)が対応しており、Next.js の API Route として素直に実装できます。

通信の流れ:

text
1. POST /api/mcp  ← initialize(ハンドシェイク)
2. POST /api/mcp  ← notifications/initialized(通知)
3. POST /api/mcp  ← tools/list(利用可能ツール一覧)
4. POST /api/mcp  ← tools/call(ツール実行)

また、Claude Code はセッション開始時に GET /api/mcp でSSE接続を試みます。これについては第4回で詳しく解説します。

アーキテクチャ全体像

text
Claude Code(開発者のPC)

    │  HTTPS + Bearer Token

CloudFront


API Gateway + Lambda

    ├── POST /api/mcp  ←── MCPサーバー本体(今回実装)
    │       │
    │       ├── initialize, tools/list
    │       └── tools/call → 各ツールハンドラー

    ├── GET  /api/mcp  ←── SSEハンドシェイク用

    └── 既存のWebアプリAPI

            └── DynamoDB(タスク・プロジェクトデータ)

既存の Next.js アプリに /api/mcp というエンドポイントを追加するだけで、同じ Lambda・同じ DynamoDB を使いながら MCP サーバーとして機能するようになります。新しいサーバーは不要 です。

公開したツール一覧

Team Task Scheduler では以下の43ツールを公開しました:

カテゴリ ツール
チーム・ユーザー team_list, team_get, user_list
プロジェクト project_list, project_get, project_create, project_update, project_delete
タスク task_list, task_get, task_create, task_update, task_delete, task_assignee_add, task_assignee_remove
アイテム item_list, item_get, item_create, item_update, item_delete, item_assignee_add, item_assignee_remove
マイルストーン milestone_list, milestone_create, milestone_update, milestone_delete
ベースライン baseline_list, baseline_create, baseline_delete
業務報告 work_report_list, work_report_create, work_report_update, work_report_delete
コメント comment_list, comment_create, comment_update, comment_delete
タグ tag_list, tag_create, tag_delete
依存関係 dependency_add, dependency_remove
アクティビティ activity_log_list

ディレクトリ構成

追加・変更したファイルは以下の通りです:

text
src/
├── app/api/
│   ├── mcp/
│   │   └── route.ts          # MCPエンドポイント(POST/GET/OPTIONS)
│   └── mcp-tokens/
│       ├── route.ts           # トークン一覧・発行
│       └── [id]/route.ts      # トークン失効
├── lib/mcp/
│   ├── auth.ts                # Bearer Token認証
│   ├── handler.ts             # JSON-RPC 2.0 ハンドラー
│   ├── server.ts              # 全ツールの集約
│   ├── types.ts               # 型定義
│   └── tools/
│       ├── project.ts         # プロジェクト操作ツール
│       ├── task.ts            # タスク操作ツール
│       ├── item.ts            # アイテム操作ツール
│       ├── comment.ts         # コメント操作ツール
│       ├── tag.ts             # タグ操作ツール
│       ├── milestone.ts       # マイルストーン操作ツール
│       ├── baseline.ts        # ベースライン操作ツール
│       ├── work-report.ts     # 業務報告操作ツール
│       ├── dependency.ts      # 依存関係操作ツール
│       └── misc.ts            # チーム・ユーザー・アクティビティ
└── components/settings/
    └── McpTokenSettings.tsx   # トークン管理UI

まとめ

  • 既存の Next.js + Lambda アプリに /api/mcp を追加するだけで MCP サーバーになる
  • MCP は JSON-RPC 2.0 over HTTP というシンプルなプロトコル
  • Claude Code から自然言語でアプリのデータを操作できるようになる

次回は実際に MCP Streamable HTTP を実装するコードを解説します。

バイブコーディングで実装する

text
Next.js 15(App Router)+ TypeScript + AWS Lambda 構成の既存Webアプリに
MCPサーバー機能を追加してください。

【要件】
- エンドポイント: POST /api/mcp(メインのJSON-RPC処理)
- エンドポイント: GET /api/mcp(SSEハンドシェイク用、空ストリームを返すだけでOK)
- プロトコル: MCP Streamable HTTP(protocolVersion: "2024-11-05")
- 認証: リクエストヘッダーの Authorization: Bearer <token> を検証

【MCPエンドポイントの動作】
- initialize → protocolVersion・capabilities・serverInfo を返す
- tools/list → 登録済みツール一覧を返す
- tools/call → ツール名とargumentsを受け取り対応するハンドラーを呼ぶ
- Notification(id フィールドなし)→ 202 No Content を返す
- バッチリクエスト(配列)→ 各要素を処理して配列で返す

Lambdaはステートレスなので、セッション状態は持たない。
型はすべて明示し、any/unknown は使わないこと。

AIに指示するときのポイント

  • 「Streamable HTTP」と明示する: 古い HTTP+SSE 方式(別エンドポイントにSSEストリームを常時接続する方式)と混同されないように、「MCP Streamable HTTP transport」と具体的に指定する
  • Notification の扱いを明示する: id フィールドが undefined(存在しない)場合はレスポンス不要(202)であることを明示しないと、AIは null ID と区別できず誤った実装をする
  • Lambda の制約を伝える: セッション状態を持てないこと、長時間接続ができないことを伝えないと、SSE接続を維持しようとするコードが生成される

次回: 第2回: MCP Streamable HTTPの実装 では、JSON-RPC 2.0 ハンドラーと各エンドポイントの実装コードを解説します。

関連記事