結論から言う:MCPはAIエージェント開発の「配線コスト」を消滅させる標準プロトコルだ。一度MCPサーバーを実装すれば、Claude・ChatGPT・Gemini・Cursorのどれからでも同じツールを呼び出せる。
AIエージェントが複数のツールやデータソースを統合する際、これまで各サービスがバラバラなAPIを実装していた。そのたびに認証・スキーマ・エラー処理を個別に書き直す必要があり、エージェント開発の最大のボトルネックになっていた。
MCP(Model Context Protocol)はその問題を根本から解決する。JSON-RPC 2.0をベースにした統一プロトコルで、2024年11月にAnthropicが公開し、2025年12月にはOpenAI・Blockとともにlinux Foundation傘下AIアライアンス(AAIF)へ寄贈。2026年5月現在、Claude・ChatGPT・Gemini・Cursor・VS Codeが対応し、公開MCPサーバーは10,000以上に達している。
本記事では、MCPの仕様・Python/TypeScriptによるServer・Client実装・主要フレームワークとの比較を体系的に解説する。
MCPとは何か:統一プロトコルが解決する問題
MCP(Model Context Protocol)は、AIモデルと外部ツール・データソースの接続を標準化するオープンプロトコルだ。仕様バージョンは2025-11-25が最新で、modelcontextprotocol.ioで公開されている。
MCPが解決する問題
従来、AIエージェントが外部サービスを使うには:
- サービスごとに異なるAPI仕様を解析する
- 認証方式(APIキー・OAuth・Basic認証)を個別に実装する
- エラーハンドリングとレスポンス形式を統一する処理を書く
- スキーマ定義をLLMが理解できる形式に変換する
MCPはこれを「サーバーがプリミティブを提供し、クライアント(LLM)がそれを発見・呼び出す」という単一パターンに統一した。USB-Cに例えられることが多いが、むしろ「AIのためのHTTP」と考えると分かりやすい。
アーキテクチャ概要
MCPのアーキテクチャは3層構造だ:
- MCP Host:Claude Desktop・Cursor・VS Code などのアプリケーション
- MCP Client:HostとServerの間でJSONメッセージをルーティング
- MCP Server:ツール・リソース・プロンプトを提供するプロセス
通信はJSON-RPC 2.0で行われ、リクエスト・レスポンスとサーバーからのNotificationで構成される。
4つのプリミティブ:Tools・Resources・Prompts・Sampling
MCPが定義するプリミティブは4種類。それぞれ明確な役割がある。
Tools(ツール)
LLMが呼び出せる実行可能な関数。データベース検索・API呼び出し・計算などを担う。Model-controlled(LLMが自律的に呼び出す)が基本。
ツールは以下のJSON Schemaで定義される:
{
"name": "search_database",
"description": "データベースからレコードを検索する",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "検索クエリ文字列"
},
"limit": {
"type": "integer",
"description": "取得件数(デフォルト10)",
"default": 10
}
},
"required": ["query"]
}
}
Resources(リソース)
ファイル・データベース・URLなどの静的データ。Application-controlledで、HostがどのリソースをLLMに渡すかを決定する。URIテンプレートで動的リソースも表現できる。
{
"uri": "file:///workspace/config.json",
"name": "設定ファイル",
"mimeType": "application/json"
}
Prompts(プロンプトテンプレート)
再利用可能なプロンプトとワークフロー定義。ユーザーが明示的に選択して使う。コードレビュー・翻訳・要約といった定型タスクのテンプレートをサーバー側で管理できる。
Sampling(サンプリング)
MCPサーバーがクライアント(LLM)に対してLLM生成を要求できる機能。エージェント連鎖・ループ処理の実装に使われる。セキュリティ上の理由からユーザー承認が必須となっている。
トランスポート層:stdio・SSE・Streamable HTTP
MCPは3つのトランスポート方式をサポートしており、ユースケースによって使い分ける。
| トランスポート | 用途 | 特徴 | ステートフル |
|---|---|---|---|
| stdio | ローカルプロセス | 標準入出力を使用。CLIツール・ローカルサーバー向け | Yes |
| SSE(Server-Sent Events) | レガシーリモート | HTTP GET でストリーミング受信、POST で送信。旧仕様 | Yes |
| Streamable HTTP | スケーラブルリモート | ステートレス対応。HTTP POST に対してSSEまたはJSON返却 | Optional |
Claude Desktop・Cursorのデフォルトはstdio。ChatGPT(ChatGPT Apps SDK)はStreamable HTTPのみサポート。本番環境ではStreamable HTTPが推奨される。
Pythonによるサーバー実装:FastMCP API
Claude Agent SDKとの連携でも使われるPython SDKを使ってMCPサーバーを実装してみよう。
インストール
# Python SDK(FastMCP高レベルAPI含む)
pip install "mcp[cli]"
# または poetry
poetry add mcp
最小構成のサーバー(Tools + Resources)
from mcp.server.fastmcp import FastMCP
from mcp.types import TextContent
# FastMCPインスタンス作成
mcp = FastMCP("my-server")
# --- Tools ---
@mcp.tool()
def add(a: int, b: int) -> int:
"""2つの整数を足し算する"""
return a + b
@mcp.tool()
async def fetch_weather(city: str) -> str:
"""指定した都市の天気情報を取得する"""
import httpx
async with httpx.AsyncClient() as client:
resp = await client.get(
f"https://api.weather.example.com/v1/weather",
params={"q": city, "lang": "ja"},
timeout=10.0
)
data = resp.json()
return f"{city}: {data['description']}, {data['temp']}°C"
# --- Resources ---
@mcp.resource("config://app")
def get_config() -> str:
"""アプリケーション設定を返す"""
return '{"version": "1.0", "env": "production"}'
@mcp.resource("users://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
"""ユーザープロフィールを返す(URIテンプレート)"""
# 実際のDBアクセスに置き換える
return f'{{"id": "{user_id}", "name": "ユーザー{user_id}"}}'
# --- Prompts ---
@mcp.prompt()
def code_review_prompt(code: str, language: str = "Python") -> str:
"""コードレビュープロンプトテンプレート"""
return f"""以下の{language}コードをレビューしてください:
```{language.lower()}
{code}
```
確認ポイント:
1. セキュリティリスク
2. パフォーマンス問題
3. 可読性・保守性
4. ベストプラクティスへの準拠"""
# サーバー起動(stdioトランスポート)
if __name__ == "__main__":
mcp.run()
Streamable HTTPトランスポートで起動
if __name__ == "__main__":
import uvicorn
# Streamable HTTP(本番向け)
mcp.run(transport="http", host="0.0.0.0", port=8000)
# または
# uvicorn.run(mcp.streamable_http_app(), host="0.0.0.0", port=8000)
Pythonクライアントからの呼び出し
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main():
server_params = StdioServerParameters(
command="python",
args=["server.py"],
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# 初期化
await session.initialize()
# 利用可能ツールを一覧取得
tools = await session.list_tools()
print("利用可能ツール:")
for tool in tools.tools:
print(f" - {tool.name}: {tool.description}")
# ツール呼び出し
result = await session.call_tool("add", {"a": 3, "b": 5})
print(f"3 + 5 = {result.content[0].text}")
# リソース取得
resource = await session.read_resource("config://app")
print(f"設定: {resource.contents[0].text}")
asyncio.run(main())
TypeScriptによるサーバー実装
OpenAI Agents SDKはTypeScript版MCPクライアントを内包しており、相互運用が容易だ。TypeScript SDKでMCPサーバーを実装する方法を見ていこう。
インストール
npm install @modelcontextprotocol/sdk zod
# TypeScript開発環境
npm install -D typescript @types/node tsx
TypeScript MCPサーバー(stdioトランスポート)
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
// サーバーインスタンス作成
const server = new Server(
{ name: "typescript-mcp-server", version: "1.0.0" },
{ capabilities: { tools: {}, resources: {} } }
);
// ツール定義
const tools = [
{
name: "search_docs",
description: "ドキュメントを全文検索する",
inputSchema: {
type: "object" as const,
properties: {
query: { type: "string", description: "検索キーワード" },
category: {
type: "string",
enum: ["api", "guide", "tutorial"],
description: "カテゴリフィルター",
},
},
required: ["query"],
},
},
{
name: "generate_code",
description: "指定した仕様からコードスニペットを生成する",
inputSchema: {
type: "object" as const,
properties: {
spec: { type: "string", description: "生成する機能の仕様" },
language: {
type: "string",
enum: ["python", "typescript", "go"],
default: "typescript",
},
},
required: ["spec"],
},
},
];
// ツール一覧ハンドラー
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools,
}));
// ツール実行ハンドラー
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "search_docs": {
const { query, category } = args as {
query: string;
category?: string;
};
// 実際の検索ロジックに置き換える
const results = [
{ title: `${query}に関するドキュメント`, url: `/docs/${query}` },
{ title: `${query} APIリファレンス`, url: `/api/${query}` },
].filter((r) => !category || r.url.includes(category));
return {
content: [
{
type: "text" as const,
text: JSON.stringify(results, null, 2),
},
],
};
}
case "generate_code": {
const { spec, language = "typescript" } = args as {
spec: string;
language?: string;
};
return {
content: [
{
type: "text" as const,
text: `// ${spec}\n// Language: ${language}\n// TODO: 実装`,
},
],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
});
// リソースハンドラー
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [
{
uri: "file:///workspace/README.md",
name: "プロジェクトREADME",
mimeType: "text/markdown",
},
],
}));
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
if (uri === "file:///workspace/README.md") {
return {
contents: [
{
uri,
mimeType: "text/markdown",
text: "# My Project\n\nMCPサーバーの説明",
},
],
};
}
throw new Error(`Unknown resource: ${uri}`);
});
// サーバー起動
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP Server running on stdio");
}
main().catch(console.error);
TypeScript MCPクライアント
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
async function main() {
// stdioトランスポートでサーバーに接続
const transport = new StdioClientTransport({
command: "npx",
args: ["tsx", "server.ts"],
});
const client = new Client(
{ name: "my-client", version: "1.0.0" },
{ capabilities: {} }
);
await client.connect(transport);
// ツール一覧取得
const { tools } = await client.listTools();
console.log("利用可能ツール:", tools.map((t) => t.name));
// ツール呼び出し
const result = await client.callTool({
name: "search_docs",
arguments: { query: "MCP", category: "api" },
});
const content = result.content[0];
if (content.type === "text") {
console.log("検索結果:", content.text);
}
// リソース読み込み
const { contents } = await client.readResource({
uri: "file:///workspace/README.md",
});
console.log("README:", contents[0].text);
await client.close();
}
main().catch(console.error);
主要クライアントとの設定方法
Claude Desktopへの登録(stdio)
~/Library/Application Support/Claude/claude_desktop_config.json(macOS)に追加:
{
"mcpServers": {
"my-python-server": {
"command": "python",
"args": ["/path/to/server.py"],
"env": {
"API_KEY": "your-api-key"
}
},
"my-typescript-server": {
"command": "npx",
"args": ["tsx", "/path/to/server.ts"]
}
}
}
Cursorへの登録
~/.cursor/mcp.json(または設定UI):
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/path/to/server.py"],
"transport": "stdio"
}
}
}
OpenAI Responses APIからの利用
OpenAIは2025年4月からResponses APIでリモートMCPサーバーをネイティブサポートした。toolsパラメータにMCPサーバーURLを渡すだけで接続できる。
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-4o",
tools=[
{
"type": "mcp",
"server_label": "my-mcp-server",
"server_url": "https://my-mcp-server.example.com/mcp",
"require_approval": "never", # 本番では"always"推奨
}
],
input="データベースから最新のユーザー情報を取得して",
)
print(response.output_text)
MCPと他プロトコルの比較
Claude Codeのサブエージェント並列実行でも外部ツール連携が重要になるが、MCPはその標準化レイヤーとして機能する。既存の手法との違いを整理しよう。
| 項目 | MCP | OpenAI Function Calling | LangChain Tools | Anthropic Tools API |
|---|---|---|---|---|
| プロトコル | JSON-RPC 2.0(標準化済み) | OpenAI独自仕様 | Python APIのみ | Anthropic独自仕様 |
| マルチLLM対応 | Claude・ChatGPT・Gemini・Cursor等全対応 | OpenAIモデルのみ | 抽象化あり・実装依存 | Claudeのみ |
| サーバー分離 | サーバーは独立プロセス(再利用可) | クライアント側に関数定義 | エージェントに直接定義 | クライアント側に定義 |
| リソース概念 | あり(ファイル・DB・URLを標準化) | なし | 限定的 | なし |
| Sampling | あり(サーバーからLLM呼び出し) | なし | なし | なし |
| エコシステム | 10,000+サーバー(2026年5月) | プラグイン形式(廃止済み) | 独自ToolセットのみOSS | 小規模 |
| 標準化団体 | Linux Foundation / AAIF(2025年12月) | OpenAI社内 | LangChain Inc | Anthropic社内 |
| ライセンス | MIT | 独自 | MIT | 独自 |
最大の差別化はサーバーの再利用性だ。MCPサーバーは一度実装すれば、Claude・ChatGPT・Cursor・VS Codeのどれからでも同じように使える。Function CallingやTools APIは実装をLLMごとに書き直す必要がある。
MCPエコシステムの現状(2026年5月)
MCPは発表から1年半で急速に普及した。主要な数字をまとめる。
サーバー・SDK規模
- 公開MCPサーバー:10,000以上(GitHub・npm・PyPI合計)
- Python/TypeScript SDKの月間ダウンロード:9,700万回
- 主要公式サーバー:GitHub・Slack・Google Drive・Notion・Postgres・Puppeteer・Brave Search など
対応クライアント(2026年5月時点)
- Claude Desktop / Claude.ai:2024年11月からネイティブサポート
- ChatGPT:2025年9月(Plus/Pro向け、Streamable HTTPのみ)
- Google Gemini:2026年3月(Workspace連携)
- Cursor:エディタに直接統合、stdio/SSE対応
- Windsurf:Cascade AIのMCP統合
- VS Code:GitHub Copilot経由でMCPサポート
- JetBrains AI Assistant:2025年末から
- Zed:拡張形式でMCP統合
ガバナンス
2025年12月、AnthropicはMCP仕様をLinux Foundationの傘下のAI Alliance(AAIF)に寄贈した。OpenAIとBlockも共同創設者として参加。特定ベンダーに依存しない中立的なガバナンスが確立された。
本番運用でのベストプラクティス
セキュリティ設計
MCPサーバーをプロダクションにデプロイする際の注意点:
from mcp.server.fastmcp import FastMCP
from functools import wraps
import hmac, hashlib, os
mcp = FastMCP("secure-server")
# APIキーを環境変数から読み込む
API_KEY = os.environ.get("MCP_API_KEY", "")
def require_auth(func):
"""ツール呼び出し時の認証デコレーター"""
@wraps(func)
async def wrapper(*args, **kwargs):
# 実際にはHTTPヘッダーから取得
# MCPではSamplingリクエストにメタデータを付与可能
return await func(*args, **kwargs)
return wrapper
@mcp.tool()
@require_auth
async def sensitive_operation(query: str) -> str:
"""認証が必要なツール"""
# 入力サニタイズ
sanitized = query.replace(";", "").replace("--", "")[:500]
return f"処理完了: {sanitized}"
# レート制限(サンプル)
from collections import defaultdict
import time
_call_counts: dict[str, list[float]] = defaultdict(list)
@mcp.tool()
def rate_limited_tool(input: str) -> str:
"""レート制限付きツール(1分10回まで)"""
now = time.time()
client_id = "default" # 実際はセッションIDを使用
# 1分以内のコール数を確認
recent = [t for t in _call_counts[client_id] if now - t < 60]
if len(recent) >= 10:
raise RuntimeError("レート制限超過: 1分あたり10回まで")
_call_counts[client_id] = recent + [now]
return f"処理: {input}"
エラーハンドリング
from mcp.server.fastmcp import FastMCP
from mcp.types import TextContent
import logging
logger = logging.getLogger(__name__)
mcp = FastMCP("robust-server")
@mcp.tool()
async def fetch_data(url: str) -> str:
"""エラーハンドリング付きデータ取得"""
import httpx
try:
async with httpx.AsyncClient(timeout=10.0) as client:
resp = await client.get(url)
resp.raise_for_status()
return resp.text[:5000] # 上限設定
except httpx.TimeoutException:
logger.warning(f"タイムアウト: {url}")
return "エラー: リクエストがタイムアウトしました(10秒)"
except httpx.HTTPStatusError as e:
logger.error(f"HTTPエラー {e.response.status_code}: {url}")
return f"エラー: サーバーが {e.response.status_code} を返しました"
except Exception as e:
logger.exception(f"予期しないエラー: {url}")
return f"エラー: {type(e).__name__}"
テスト戦略
import pytest
import asyncio
from mcp import ClientSession
from mcp.client.stdio import stdio_client, StdioServerParameters
@pytest.mark.asyncio
async def test_add_tool():
server_params = StdioServerParameters(
command="python", args=["server.py"]
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("add", {"a": 2, "b": 3})
assert result.content[0].text == "5"
@pytest.mark.asyncio
async def test_tool_list():
server_params = StdioServerParameters(
command="python", args=["server.py"]
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
tool_names = [t.name for t in tools.tools]
assert "add" in tool_names
assert "fetch_weather" in tool_names
AIエージェントとMCPの統合パターン
MCPはエージェントフレームワークとの統合が急速に進んでいる。AIエージェント完全ガイドでも解説している通り、ツール連携はエージェントの核心機能だ。またClaude Codeのサブエージェント並列実行でも、MCPサーバーをツールとして接続するパターンが増えている。
Claude Agent SDKとMCPの組み合わせ
import anthropic
client = anthropic.Anthropic()
# MCPサーバーをAnthropicクライアントから直接使う場合
# (Claude Desktopのconfig経由が一般的だが、Responses相当はAPI経由でも)
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=4096,
tools=[
{
"name": "search_docs",
"description": "ドキュメントを検索する",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
}
],
messages=[
{"role": "user", "content": "MCPの仕様について調べて"}
]
)
よくある落とし穴と対処法
MCPサーバーを本番で運用する際に遭遇しやすい問題:
- stdioバッファリング問題:サーバーが大量データを返す際にバッファが詰まる。
sys.stdout.flush()を明示的に呼ぶか、print(..., flush=True)を使う - セッション切断の検知漏れ:クライアントが突然切断された際の後片付け処理を必ず実装する。FastMCPの
@mcp.on_shutdownを使うと安全 - ツール定義の過剰化:ツール数が多すぎるとLLMのツール選択精度が下がる。20個以上になったらサーバーを分割し、用途別に接続を切り替える
- JSONスキーマの型不一致:LLMが文字列で渡してくる数値をintとして受け取ると型エラーになる。
Union[int, str]でフォールバック処理を入れるか、Pydanticのcoercionを活用する
まとめ:MCPが変えるAIエージェント開発の未来
MCPは「AIのためのUSB規格」として、エージェント開発のコスト構造を根本から変えつつある。
- 開発コスト削減:一度MCPサーバーを作れば、Claude・ChatGPT・Gemini・Cursorで同じツールが動く。プロバイダーごとの実装が不要になる
- エコシステムの恩恵:10,000以上の公開サーバーを即座に使えるため、Slack・GitHub・Notion・Postgres連携を数分で実現できる
- スタンダード化リスクの低減:Linux Foundationへの寄贈により、特定ベンダーによる仕様変更リスクが最小化された
Python FastMCPかTypeScript SDKのどちらかで最初の1サーバーを作ることをすすめたい。既存のAPIラッパーを数十行でMCPサーバーに変換できる。一度体験すると、なぜこのプロトコルが急速に普及しているかが肌感覚でわかるはずだ。
📅 5月開催|Uravation主催 Zoomウェビナー
- 【5/23(土) 14:00-17:00】AI活用入門講座 — ChatGPT・Gemini・Claude・NotebookLM・Manus 全部触る3時間(早割 ¥3,000、5/16締切 / 通常 ¥4,000)
- 【5/24(日)】Claude Code 活用講座【実践編】 — 活用事例50選と業務実装テクニック(早割 ¥3,000)
講師: 株式会社Uravation代表 佐藤傑(X @SuguruKun_ai) / Yusei Tataka
あわせて読みたい:
- Claude Agent SDK完全ガイド:Claudeネイティブのエージェント実装、MCPと組み合わせる定番
- OpenAI Agents SDK完全ガイド:OpenAI公式SDK、MCPもFunction Calling風にラップして使える
- Claude Code Sub-Agents完全ガイド:MCPを使うHost側の代表例、Sub-AgentsからMCP Serverを呼ぶ
- LangGraph完全ガイド:状態機械型エージェントからMCP Serverを呼ぶパターン
- AIエージェント導入完全ガイド:エージェント全体像とMCP導入判断の指針
- AIエージェント観測・評価完全ガイド:LangSmith/Langfuse/RAGAS/DeepEvalで本番品質を可視化
- AIエージェントMemory完全ガイド:Mem0/Zep/Lettaで永続記憶を実装、Core/Archival/Recall 3層モデル
- AI Voiceエージェント7強完全比較:Vapi/Retell/ElevenLabs/Deepgramほか電話AI比較
- AIカスタマーサポート7強完全比較:Decagon/Sierra/Intercom Fin等のCS AI基盤比較
- 士業のAI活用完全ガイド:税理士/社労士/弁護士/司法書士/行政書士の実践プロンプト10選
- Codex×経理 自動化プロンプト10選:経理特化10シーンで最大80%削減
- Codex×Excel自動化プロンプト10選:VBA/Apps Script/Power Query代替
- Codex×業務15選 部署別ガイド:営業/マーケ/人事/法務/経企/情シス/CSの15シーン
参考・出典
- Model Context Protocol 公式仕様(2025-11-25)
https://modelcontextprotocol.io/specification/2025-11-25(参照日: 2026-05-07) - MCP Python SDK(modelcontextprotocol/python-sdk)
https://github.com/modelcontextprotocol/python-sdk(参照日: 2026-05-07) - MCP TypeScript SDK(@modelcontextprotocol/sdk)
https://github.com/modelcontextprotocol/typescript-sdk(参照日: 2026-05-07) - Anthropic MCP発表ブログ(2024年11月)
https://www.anthropic.com/news/model-context-protocol(参照日: 2026-05-07) - OpenAI Responses API MCPサポート発表(2025年4月)
https://openai.com/index/new-tools-for-building-agents/(参照日: 2026-05-07)
関連記事: AIエージェントセキュリティ完全ガイド|OWASP対応 — AIエージェントのセキュリティ実装ガイドです。











