MCP(Model Context Protocol)完全解説:AIとツールを繋ぐ新標準プロトコル
MCP(Model Context Protocol)完全解説:AIとツールを繋ぐ新標準プロトコル
Anthropicが開発したMCP(Model Context Protocol)の仕組み、アーキテクチャ、セットアップ方法、実装コード例、活用事例を日本語で詳しく解説。
MCPとは何か?
2024年末にAnthropicが発表した**MCP(Model Context Protocol)**は、AIモデルが外部ツールやデータソースとやり取りするための標準プロトコルです。2025〜2026年にかけて急速に普及し、現在ではAI開発の世界で最も注目されている技術標準の一つとなっています。
簡単に言えば、MCPはAIモデルとさまざまなツール(データベース、ファイルシステム、外部API、開発ツールなど)を接続するための「共通言語」です。これにより、開発者は各ツールごとに異なるインテグレーションを作る必要がなくなり、一度MCP対応のサーバーを作れば、あらゆるMCP対応クライアント(AIモデル)から利用できるようになります。
なぜMCPが必要なのか?
MCPが登場する以前、AIモデルに外部ツールを使わせるためには、それぞれのAIシステム専用のカスタム統合を作成する必要がありました。OpenAI用の統合コード、Anthropic用の統合コード、Google用の統合コード――これらを別々に管理するのは非効率で、メンテナンスも大変でした。
MCPは、この問題を「USB-Cポートのような標準コネクタ」として解決します。MCPに対応したツールは、MCPに対応したどのAIモデルでも使えるようになるのです。
MCPのアーキテクチャ
MCPはクライアント・サーバーアーキテクチャを採用しています。
┌─────────────────────────────────────────────────────────┐
│ MCP クライアント │
│ (Claude Desktop、Cursor、カスタムアプリ) │
└─────────────────────┬───────────────────────────────────┘
│ MCP Protocol(JSON-RPC 2.0)
┌────────────┼────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ MCPサーバー│ │ MCPサーバー│ │ MCPサーバー│
│(ファイル)│ │(データベース)│(外部API)│
└──────────┘ └──────────┘ └──────────┘
主要コンポーネント
MCPホスト(Host): AIモデルを実行するアプリケーション(Claude Desktop、カスタムのAIアプリケーションなど)。ホストはMCPクライアントを管理し、AIモデルとMCPサーバーの間を仲介します。
MCPクライアント(Client): ホスト内でMCPサーバーとの接続を管理するコンポーネント。各MCPサーバーに対して1つのクライアントが対応します。
MCPサーバー(Server): 外部ツールやデータソースへのアクセスを提供する軽量なプログラム。開発者が実装する部分で、ファイルシステム、データベース、GitHub APIなど、様々な機能をAIモデルに提供します。
MCPのトランスポート層
MCPは複数のトランスポート方式をサポートしています:
- stdio(標準入出力):ローカル開発で最も一般的。クライアントとサーバーが同じマシン上で動作する場合に使用。
- HTTP + SSE(Server-Sent Events):リモートサーバーとの通信に使用。スケーラブルなデプロイに対応。
- WebSocket:双方向のリアルタイム通信が必要な場合に使用。
MCPが提供する機能
MCPサーバーは主に3つの種類の機能を提供できます:
1. ツール(Tools)
AIモデルが実行できる操作です。ファイルの読み書き、APIコールの実行、データベースクエリの発行などが含まれます。
{
"name": "read_file",
"description": "ファイルシステムからファイルを読み取る",
"inputSchema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "読み取るファイルのパス"
}
},
"required": ["path"]
}
}
2. リソース(Resources)
AIモデルが参照できるデータやコンテンツです。ファイル、データベースレコード、Webページのコンテンツなどが含まれます。
{
"uri": "file:///Users/username/documents/report.pdf",
"name": "四半期レポート",
"description": "2026年Q1の業績レポート",
"mimeType": "application/pdf"
}
3. プロンプト(Prompts)
再利用可能なプロンプトテンプレートです。特定のタスクに最適化されたプロンプトをサーバー側で定義し、クライアントから呼び出すことができます。
MCPサーバーの実装:TypeScript編
実際にMCPサーバーを実装してみましょう。ここでは、簡単なファイル操作とJSONデータの処理を行うMCPサーバーを作成します。
プロジェクトのセットアップ
mkdir my-mcp-server
cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk
npm install -D typescript @types/node ts-node
tsconfig.jsonを作成:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
}
}
基本的なMCPサーバーの実装
// src/index.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 * as fs from "fs/promises";
import * as path from "path";
// MCPサーバーのインスタンスを作成
const server = new Server(
{
name: "my-file-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// 利用可能なツールのリストを定義
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "read_file",
description: "指定したパスのファイルを読み取ります",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "読み取るファイルのパス",
},
},
required: ["path"],
},
},
{
name: "write_file",
description: "指定したパスにファイルを書き込みます",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "書き込むファイルのパス",
},
content: {
type: "string",
description: "ファイルの内容",
},
},
required: ["path", "content"],
},
},
{
name: "format_json",
description: "JSON文字列を整形して返します",
inputSchema: {
type: "object",
properties: {
json_string: {
type: "string",
description: "整形するJSON文字列",
},
indent: {
type: "number",
description: "インデントのスペース数(デフォルト: 2)",
},
},
required: ["json_string"],
},
},
],
};
});
// ツールの実行ハンドラー
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
if (name === "read_file") {
const filePath = args?.path as string;
const content = await fs.readFile(filePath, "utf-8");
return {
content: [
{
type: "text",
text: content,
},
],
};
}
if (name === "write_file") {
const filePath = args?.path as string;
const content = args?.content as string;
// ディレクトリが存在しない場合は作成
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, content, "utf-8");
return {
content: [
{
type: "text",
text: `ファイルを正常に書き込みました: ${filePath}`,
},
],
};
}
if (name === "format_json") {
const jsonString = args?.json_string as string;
const indent = (args?.indent as number) ?? 2;
const parsed = JSON.parse(jsonString);
const formatted = JSON.stringify(parsed, null, indent);
return {
content: [
{
type: "text",
text: formatted,
},
],
};
}
throw new Error(`不明なツール: ${name}`);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
content: [
{
type: "text",
text: `エラーが発生しました: ${errorMessage}`,
},
],
isError: true,
};
}
});
// サーバーを起動
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCPサーバーが起動しました");
}
main().catch(console.error);
MCPサーバーの実装:Python編
Pythonでも同様のMCPサーバーを実装できます。
# server.py
import asyncio
import json
import os
from pathlib import Path
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
# MCPサーバーのインスタンスを作成
app = Server("python-file-server")
@app.list_tools()
async def list_tools() -> list[types.Tool]:
"""利用可能なツールのリストを返す"""
return [
types.Tool(
name="read_file",
description="指定したパスのファイルを読み取ります",
inputSchema={
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "読み取るファイルのパス"
}
},
"required": ["path"]
}
),
types.Tool(
name="list_directory",
description="ディレクトリの内容を一覧表示します",
inputSchema={
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "一覧表示するディレクトリのパス"
}
},
"required": ["path"]
}
),
types.Tool(
name="search_files",
description="ファイル内の文字列を検索します",
inputSchema={
"type": "object",
"properties": {
"directory": {
"type": "string",
"description": "検索するディレクトリ"
},
"pattern": {
"type": "string",
"description": "検索する文字列パターン"
},
"file_extension": {
"type": "string",
"description": "対象ファイルの拡張子(例: .py, .js)"
}
},
"required": ["directory", "pattern"]
}
)
]
@app.call_tool()
async def call_tool(
name: str, arguments: dict
) -> list[types.TextContent]:
"""ツールを実行する"""
if name == "read_file":
file_path = arguments["path"]
try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
return [types.TextContent(type="text", text=content)]
except FileNotFoundError:
return [types.TextContent(
type="text",
text=f"エラー: ファイルが見つかりません: {file_path}"
)]
elif name == "list_directory":
dir_path = arguments["path"]
try:
entries = os.listdir(dir_path)
formatted = "\n".join(
f"{'📁' if os.path.isdir(os.path.join(dir_path, e)) else '📄'} {e}"
for e in sorted(entries)
)
return [types.TextContent(type="text", text=formatted)]
except FileNotFoundError:
return [types.TextContent(
type="text",
text=f"エラー: ディレクトリが見つかりません: {dir_path}"
)]
elif name == "search_files":
directory = arguments["directory"]
pattern = arguments["pattern"]
extension = arguments.get("file_extension", "")
results = []
for root, dirs, files in os.walk(directory):
for file in files:
if extension and not file.endswith(extension):
continue
file_path = os.path.join(root, file)
try:
with open(file_path, "r", encoding="utf-8") as f:
for line_num, line in enumerate(f, 1):
if pattern in line:
results.append(
f"{file_path}:{line_num}: {line.rstrip()}"
)
except (UnicodeDecodeError, PermissionError):
continue
if results:
return [types.TextContent(
type="text",
text="\n".join(results)
)]
else:
return [types.TextContent(
type="text",
text=f"'{pattern}' を含むファイルは見つかりませんでした"
)]
else:
raise ValueError(f"不明なツール: {name}")
async def main():
async with stdio_server() as (read_stream, write_stream):
await app.run(
read_stream,
write_stream,
app.create_initialization_options()
)
if __name__ == "__main__":
asyncio.run(main())
Claude DesktopでMCPサーバーを使う
Claude DesktopでカスタムMCPサーバーを使用するには、設定ファイルを編集します。
設定ファイルの場所
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
設定例
{
"mcpServers": {
"my-file-server": {
"command": "node",
"args": ["/path/to/my-mcp-server/dist/index.js"],
"env": {
"NODE_ENV": "production"
}
},
"python-server": {
"command": "python",
"args": ["/path/to/server.py"]
},
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/username/Documents"
]
}
}
}
設定後、Claude Desktopを再起動すると、MCPサーバーが有効になります。
既存のMCPサーバー(公式・コミュニティ製)
Anthropicと開発者コミュニティによって、多数のMCPサーバーが公開されています。
公式MCPサーバー
| サーバー名 | 機能 |
|---|---|
| @modelcontextprotocol/server-filesystem | ローカルファイルシステムへのアクセス |
| @modelcontextprotocol/server-github | GitHub APIとの連携 |
| @modelcontextprotocol/server-postgres | PostgreSQLデータベースへのアクセス |
| @modelcontextprotocol/server-sqlite | SQLiteデータベースへのアクセス |
| @modelcontextprotocol/server-brave-search | Brave Search APIによるWeb検索 |
| @modelcontextprotocol/server-puppeteer | Puppeteerによるブラウザ自動化 |
人気のコミュニティMCPサーバー
- mcp-server-notion:NotionのページとデータベースへのAIアクセス
- mcp-server-slack:SlackチャンネルとメッセージへのAIアクセス
- mcp-server-jira:Jiraチケットの読み書き
- mcp-server-aws:AWSリソースの管理と操作
- mcp-server-docker:Dockerコンテナの管理
実際の活用事例
ケース1:コードレビューの自動化
GitHubのMCPサーバーを使って、AIにプルリクエストを自動レビューさせる仕組みを構築できます。AIはコードの変更差分を読み込み、問題点を指摘し、改善提案を生成します。
# GitHubサーバーのセットアップ
npx @modelcontextprotocol/server-github \
--token $GITHUB_TOKEN
ケース2:データベースへの自然言語クエリ
PostgreSQLのMCPサーバーを使って、自然言語でデータベースに問い合わせることができます。「先月の売上上位10商品を教えて」というプロンプトを送るだけで、AIが適切なSQLを生成して実行し、結果を返します。
JSONレスポンスの確認にはJSONフォーマッターが便利です。
ケース3:ドキュメントの自動生成
ファイルシステムのMCPサーバーを使って、AIがコードベースを読み込み、APIドキュメントやREADMEを自動生成できます。
プロンプト例:
「src/apiディレクトリのすべてのTypeScriptファイルを読んで、
各エンドポイントのAPIドキュメントをMarkdown形式で生成してください」
MCPのセキュリティ考慮事項
MCPサーバーはファイルシステムやデータベースなど、センシティブなリソースへのアクセスを提供できるため、セキュリティには十分注意が必要です。
主要なセキュリティ対策
1. 最小権限の原則 MCPサーバーには、必要最小限の権限だけを与えましょう。ファイルシステムサーバーは、特定のディレクトリだけにアクセスを限定すべきです。
2. 入力バリデーション
// パストラバーサル攻撃を防ぐ
function validatePath(userPath: string, basePath: string): string {
const resolvedPath = path.resolve(basePath, userPath);
if (!resolvedPath.startsWith(basePath)) {
throw new Error("パスが許可された範囲外です");
}
return resolvedPath;
}
3. 認証とアクセス制御 リモートMCPサーバーを公開する場合は、適切な認証機構を実装してください。
4. ログの記録 すべてのツール呼び出しをログに記録し、不正なアクセスを検出できるようにしましょう。
MCPとFunctionCallingの違い
MCPと混同されやすいのが、OpenAIのFunction Calling(現在はTool Useと呼ばれる)です。
| 比較項目 | MCP | Function Calling / Tool Use |
|---|---|---|
| 標準化 | オープンスタンダード | 各プロバイダー独自 |
| ツールの定義場所 | サーバー側 | クライアント側(APIリクエスト時) |
| 再利用性 | 高い(どのMCPクライアントでも使用可能) | 低い(各AIシステム専用) |
| 動的なツール発見 | 対応 | 非対応(事前定義が必要) |
| ステートフル | 対応 | 非対応 |
| 主な用途 | 永続的なツール統合 | 単発のAPIコール |
MCPの将来展望
MCPは2025〜2026年にかけて急速に普及しており、今後さらなる発展が期待されます。
短期的な展望(2026年):
- より多くのIDEとの統合(VS Code、JetBrains)
- エンタープライズ向けセキュリティ機能の強化
- より豊富な公式MCPサーバーの提供
中長期的な展望:
- AIエージェントの「ツールエコシステム」として確立
- クロスAIプラットフォームの標準として採用拡大
- IoTデバイスや物理システムとのMCP統合
まとめ
MCP(Model Context Protocol)は、AIモデルと外部ツールを接続するための革新的な標準プロトコルです。USB-Cが様々なデバイスを接続する共通規格となったように、MCPはAIエコシステムにおける共通コネクターとなりつつあります。
開発者として今からMCPを学んでおくことは、AI開発のトレンドを先取りする上で非常に重要です。簡単なMCPサーバーから始めて、徐々に複雑な統合に挑戦してみてください。
APIレスポンスのデバッグにはJSONフォーマッターを、実装中の正規表現パターンのテストには別途ツールを活用しながら、効率的なMCP開発を進めましょう。
MCPは単なるプロトコルではなく、AIが現実世界のシステムと深く統合される未来への入り口です。今こそ、この新しい標準を習得する最良のタイミングです。