MCP統合
ツール拡張システムとしてのModel Context Protocolをマスターする。
学ぶこと
Claude Codeには強力なビルトインツール群が付属しています — Read、Edit、Bash、Grep、Glob。しかし、データベースへのクエリ、社内Wikiの検索、デプロイメントパイプラインとのやり取りが必要な場合はどうでしょうか?Claudeにcurlでシェル実行させることもできますが、もっと良い方法があります:**Model Context Protocol(MCP)**です。
このセッションを終えると、以下がわかるようになります:
- MCPとは何か、なぜ存在するのか
- MCPサーバーがツール、リソース、プロンプトをどのように提供するか
- クライアント-サーバーアーキテクチャとトランスポートメカニズム
- プロジェクトでMCPサーバーを設定する方法
- MCPツールがClaude Codeのパーミッションシステムとどのように統合するか
- シンプルなMCPサーバーをゼロから構築する方法
課題
すべてのチームには独自のツールがあります。フロントエンドチームはFigma連携が必要です。データチームはSQLアクセスが必要です。DevOpsチームはKubernetes制御が必要です。各統合を直接Claude Codeに組み込むのは:
- 保守が不可能 — 数千もの統合、それぞれ異なるAPI
- セキュリティの悪夢 — すべての統合をClaude Codeに同梱する必要がある
- 柔軟性がない — 組織が独自の内部ツールを追加できない
このパターンは他の分野で馴染みのあるものです。Webブラウザはすべての機能を組み込んでいません — 拡張機能をサポートしています。コードエディタはすべての言語をバンドルしていません — プラグインをサポートしています。Claude Codeにも同じものが必要です:ツール拡張のための標準プロトコルです。
Without MCP:
┌──────────────────────────────────────────┐
│ Claude Code │
│ │
│ Built-in: Read, Edit, Bash, Grep... │
│ Custom: ??? (fork the codebase?) │
└──────────────────────────────────────────┘
With MCP:
┌──────────────────────────────────────────┐
│ Claude Code │
│ │
│ Built-in: Read, Edit, Bash, Grep... │
│ MCP: Database, Jira, Slack, │
│ Figma, K8s, your-custom-tool │
└──────────────────────────────────────────┘
仕組み
MCPアーキテクチャ
MCPはクライアント-サーバーモデルに従います。Claude Codeがクライアントです。各外部統合がサーバーです。標準プロトコルを通じて通信します:
┌─────────────────────────────────────────────────────┐
│ Claude Code (MCP Client) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Built-in │ │ MCP Conn │ │ MCP Conn │ ... │
│ │ Tools │ │ #1 │ │ #2 │ │
│ └──────────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │
└─────────────────────│──────────────│────────────────┘
│ │
┌───────▼──────┐ ┌────▼─────────┐
│ MCP Server │ │ MCP Server │
│ (Database) │ │ (Jira) │
│ │ │ │
│ Tools: │ │ Tools: │
│ - query │ │ - search │
│ - schema │ │ - create │
│ - explain │ │ - update │
└──────────────┘ └──────────────┘
各MCPサーバーは個別のプロセスです。Claude Codeはそれに接続し、提供するツールを発見し、それらのツールをビルトインツールとともにAIで利用可能にします。
MCPサーバーが提供するもの
MCPサーバーは3種類のケーパビリティを公開できます:
1. ツール — AIが呼び出せる関数(最も一般的)
{
"name": "database_query",
"description": "Execute a read-only SQL query against the project database",
"inputSchema": {
"type": "object",
"properties": {
"sql": { "type": "string", "description": "The SQL query to execute" }
},
"required": ["sql"]
}
}
2. リソース — AIが読み取れるデータ(ファイル、ドキュメント、ライブデータ)
{
"uri": "db://schema/users",
"name": "Users table schema",
"mimeType": "application/json"
}
3. プロンプト — 再利用可能なプロンプトテンプレート
{
"name": "code_review",
"description": "Review code for common issues",
"arguments": [
{ "name": "language", "description": "Programming language" }
]
}
実際にはツールが圧倒的に一般的です。AIがMCPツールの使用を決定すると、呼び出しはビルトインツールと同じエージェントループを通過します — AIからは違いが見えません。
トランスポートメカニズム
MCPは2つのトランスポートタイプをサポートします:
stdio — ローカルプロセス用(最も一般的)
Claude Code ──stdin/stdout──► MCP Server Process
サーバーは子プロセスとして実行されます。通信はstdinとstdoutパイプで行われ、CLIとSDKの通信方法(セッション13)と同一です。高速で安全で、ネットワーク設定は不要です。
SSE(Server-Sent Events) — リモートサーバー用
Claude Code ──HTTP/SSE──► Remote MCP Server
(running on a server)
サーバーはリモートマシンで実行されます。通信はストリーミング用のSSEを使ったHTTPで行われます。これにより、チーム全体で使用できる共有MCPサーバーが可能になります。
設定
MCPサーバーは.mcp.jsonファイルで設定します。Claude Codeはプロジェクトルートでこのファイルを探します:
{
"mcpServers": {
"database": {
"command": "npx",
"args": ["-y", "@mcp/postgres", "--connection-string", "postgresql://localhost:5432/mydb"],
"type": "stdio"
},
"memory": {
"command": "npx",
"args": ["-y", "@mcp/memory"],
"type": "stdio"
},
"company-wiki": {
"url": "https://mcp.internal.company.com/wiki",
"type": "sse"
}
}
}
各エントリは以下を定義します:
- 名前 — ツールのプレフィックス(例:
mcp__database__query) - command/url — サーバーの起動または接続方法
- タイプ — ローカルは
stdio、リモートはsse
ツールディスカバリ
起動時に、Claude Codeは設定された各MCPサーバーに接続し、「どのツールを提供していますか?」と尋ねます:
起動シーケンス:
─────────────────
1. Claude Codeが.mcp.jsonを読み込み
2. 各サーバーに対して:
a. プロセスを起動(stdio)または接続(sse)
b. 送信: { "method": "tools/list" }
c. 受信: ツール定義のリスト
d. 命名規則でツールを登録
結果:
┌──────────────────────────────────────────────┐
│ 利用可能なツール │
│ │
│ Built-in: │
│ Read, Edit, Bash, Glob, Grep, Write, │
│ TodoRead, TodoWrite, WebFetch... │
│ │
│ MCP (database): │
│ mcp__database__query │
│ mcp__database__schema │
│ mcp__database__explain │
│ │
│ MCP (memory): │
│ mcp__memory__add_observations │
│ mcp__memory__search_nodes │
│ mcp__memory__read_graph │
└──────────────────────────────────────────────┘
命名規則mcp__<server>__<tool>は衝突を防ぎます。2つのサーバーが両方ともsearchというツールを持つ場合、mcp__wiki__searchとmcp__jira__searchになります。
パーミッション統合
MCPツールはビルトインツールと同じパーミッションシステムを通過します。これはセキュリティにとって重要です:
AIがmcp__database__queryの呼び出しを決定
│
▼
┌─────────────────┐
│ Permission Check │
│ │
│ Is this tool │
│ allowed? │
│ │
│ - Check settings │
│ - Check hooks │
│ - Check scope │
└────┬────────┬────┘
│ │
Allowed Blocked
│ │
▼ ▼
Execute Ask user
tool for permission
ビルトインツールと同じように、MCPツールのパーミッションを設定で構成できます。PreToolUseフック(セッション15)はMCPツールの呼び出しを検査し、危険なものをブロックできます。
通信フロー
AIがMCPツールを使用する際の完全なフローです:
ユーザー: "今週何人のユーザーがサインアップしましたか?"
│
▼
┌─────────────────────────────────────────────┐
│ Agent Loop │
│ │
│ AIが決定: mcp__database__queryを使用 │
│ 入力: "SELECT COUNT(*) FROM users │
│ WHERE created_at > NOW() - '7d'" │
│ │
│ パーミッションチェック → 許可 │
│ │ │
│ ▼ │
│ Claude CodeがMCPサーバーに送信: │
│ { "method": "tools/call", │
│ "params": { │
│ "name": "query", │
│ "arguments": { "sql": "SELECT..." } │
│ } │
│ } │
│ │ │
│ ▼ │
│ MCPサーバーがクエリを実行、返却: │
│ { "result": { "content": [ │
│ { "type": "text", "text": "142" } │
│ ]} │
│ } │
│ │ │
│ ▼ │
│ 結果がtool_resultとして注入 │
│ AIが続行: "142人のユーザーが..." │
└─────────────────────────────────────────────┘
AIの視点からは、MCPツールの呼び出しはビルトインツールの呼び出しと同一です。ツール定義を見て、適切なパラメータで呼び出し、結果を受け取ります。プロトコルがその間のすべてを処理します。
重要なポイント
MCPは、コアを変更せずにClaude Codeを無限に拡張可能にするものです。 コードベースに統合を組み込む代わりに、MCPにより標準プロトコルを通じて任意のツールをプラグインできます。
これはソフトウェアで実証されたパターンを反映しています:
| システム | コア | 拡張プロトコル |
|---|---|---|
| Webブラウザ | レンダリングエンジン | Extension APIs |
| VS Code | エディタコア | Language Server Protocol |
| Unix | カーネル | stdin/stdoutパイプ |
| Claude Code | エージェントループ | MCP |
力は標準にあります。MCPがオープンプロトコルであるため、誰でもサーバーを構築できます。エコシステムはClaude Code自体から独立して成長します。あるチームが構築したデータベースMCPサーバーは、Claude Codeだけでなく、任意のMCPクライアントで動作します。
ハンズオン例
シンプルなMCPサーバーの構築
単一のツール — ワードカウンター — を提供する最小限のMCPサーバーです:
// word-counter-server.js
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "word-counter",
version: "1.0.0",
});
// ツールを登録
server.tool(
"count_words",
"Count words in a given text",
{
text: z.string().describe("The text to count words in"),
},
async ({ text }) => {
const wordCount = text.split(/\s+/).filter(Boolean).length;
const charCount = text.length;
return {
content: [
{
type: "text",
text: `Words: ${wordCount}, Characters: ${charCount}`,
},
],
};
}
);
// stdioでリスニング開始
const transport = new StdioServerTransport();
await server.connect(transport);
Claude Codeへの接続
サーバーをプロジェクトの.mcp.jsonに追加します:
{
"mcpServers": {
"wordcount": {
"command": "node",
"args": ["word-counter-server.js"],
"type": "stdio"
}
}
}
これで、このプロジェクトでClaude Codeを起動すると、AIはmcp__wordcount__count_wordsにアクセスできます。「この段落には何語ありますか?」と尋ねれば、AIはカスタムツールを使用します。
より実用的な例:ファイルメタデータサーバー
// file-metadata-server.js
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import fs from "fs/promises";
import path from "path";
const server = new McpServer({
name: "file-metadata",
version: "1.0.0",
});
server.tool(
"file_stats",
"Get detailed metadata about a file (size, dates, permissions)",
{
file_path: z.string().describe("Path to the file"),
},
async ({ file_path }) => {
const stats = await fs.stat(file_path);
return {
content: [{
type: "text",
text: JSON.stringify({
size_bytes: stats.size,
created: stats.birthtime.toISOString(),
modified: stats.mtime.toISOString(),
is_directory: stats.isDirectory(),
permissions: stats.mode.toString(8),
}, null, 2),
}],
};
}
);
server.tool(
"directory_size",
"Calculate total size of a directory recursively",
{
dir_path: z.string().describe("Path to the directory"),
},
async ({ dir_path }) => {
let totalSize = 0;
const entries = await fs.readdir(dir_path, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir_path, entry.name);
if (entry.isFile()) {
const stat = await fs.stat(fullPath);
totalSize += stat.size;
}
}
return {
content: [{
type: "text",
text: `Total size: ${(totalSize / 1024).toFixed(1)} KB (${entries.length} entries)`,
}],
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
これにより、AIにこれまでなかった2つの新しいケーパビリティ — 詳細なファイルメタデータとディレクトリサイズの計算 — が与えられます。Claude Codeを一切変更する必要はありません。
何が変わったか
| MCPなし | MCPあり |
|---|---|
| ビルトインツールの固定セット | 無制限の拡張性 |
| 新しい統合にはコード変更が必要 | サーバー設定をドロップイン |
| すべてのユーザーが同じツール | チームがツールセットをカスタマイズ |
| AIがカスタム作業にCLIシェル実行 | AIが構造化された型付きツールを使用 |
| ツール拡張の標準なし | オープンプロトコル、成長するエコシステム |
| セキュリティは統合ごとにアドホック | 統一されたパーミッションシステム |
次のセッション
MCPでツールを追加できるようになりました。しかし、ツールの使用方法に関するルールをどのように適用するのでしょうか?セッション15ではフックシステムを扱います — ツール実行の前後に発火するイベントサブスクライバーで、セキュリティゲート、監査ログ、組織ポリシーの適用を実現します。