
WebアプリをAIから操作できるようにした話(第1回)— MCPサーバー化の動機とアーキテクチャ
このシリーズ: 全4回
概要
チームで使っているタスク管理アプリ(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 など)と外部サービスを繋ぐ標準仕様です。
仕組みは非常にシンプルです:
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 として素直に実装できます。
通信の流れ:
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回で詳しく解説します。
アーキテクチャ全体像
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 |
ディレクトリ構成
追加・変更したファイルは以下の通りです:
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 を実装するコードを解説します。
バイブコーディングで実装する
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はnullID と区別できず誤った実装をする - Lambda の制約を伝える: セッション状態を持てないこと、長時間接続ができないことを伝えないと、SSE接続を維持しようとするコードが生成される
次回: 第2回: MCP Streamable HTTPの実装 では、JSON-RPC 2.0 ハンドラーと各エンドポイントの実装コードを解説します。