Claude の能力は、単体の対話インターフェースを大きく超えたところにあります。Model Context Protocol(MCP)とエージェントフレームワークを組み合わせることで、複数の外部システムと連携しながら、複雑なタスクを自律的に実行するシステムを構築できます。
MCPとは何か:基礎から理解する
Model Context Protocol(MCP)は、Anthropicが2024年11月に発表したオープンな標準プロトコルです。AIモデルと外部ツール・データソースをつなぐための共通インターフェースを定義しており、「AIアプリケーションのUSB-C」とも呼ばれます。
MCPが解決する問題
従来のAIシステムでは、外部ツールとの連携のたびに専用のアダプターや統合コードを書く必要がありましました。異なるAIモデルに同じツールを接続しようとすると、モデルごとに実装を書き直す必要があり、保守コストが増大していましました。
MCPはこの問題を解決します。一度MCPサーバーとしてツールを実装すれば、Claude をはじめとする任意のMCP対応クライアントから利用できます。
MCPの構成要素
MCPは3つの主要コンポーネントで構成されています。
MCPホスト(Host): Claude Desktopや Claude Codeのような、AIモデルを実行する環境。ユーザーとのインターフェースを提供し、MCPクライアントとしてサーバーと通信します。
MCPクライアント(Client): ホスト内でMCPサーバーとの接続を管理するコンポーネント。各サーバーとの接続を確立し、リソース・ツール・プロンプトの一覧を取得します。
MCPサーバー(Server): 実際の機能を提供するプログラム。ファイルシステム操作、データベースアクセス、Web検索など、あらゆる機能をMCPサーバーとして実装できます。
MCPが提供する3つのプリミティブ
MCPサーバーは以下の3種類のプリミティブを提供できます。
ツール(Tools): Claudeが呼び出せる関数。ファイルの読み書き、API呼び出し、計算処理などの「アクション」を定義します。ツールはClaudeが判断して呼び出しを決定します。
リソース(Resources): ファイル、データベースレコード、ドキュメントなど、静的・動的なデータへのアクセスを提供します。URIで識別され、コンテキストウィンドウに読み込まれます。
プロンプト(Prompts): よく使うプロンプトテンプレートを再利用可能な形で定義します。ユーザーがスラッシュコマンドで呼び出せるような用途に最適です。
エージェントアーキテクチャの設計パターン
MCPを活用したシステムを設計する前に、エージェントアーキテクチャの主要なパターンを理解しましょう。
シングルエージェントパターン
最もシンプルな構成は、1つのClaudeインスタンスが複数のMCPツールを使いながらタスクを完遂するパターンです。
ユーザー
↓
Claude(オーケストレーター)
├── MCP: ファイルシステム
├── MCP: データベース
├── MCP: Web検索
└── MCP: メール送信
このパターンは、タスクが明確に定義されており、ツール間の調整が比較的単純な場合に適しています。Claude Desktopの通常の使い方が、このシングルエージェントパターンに相当します。
オーケストレーター + サブエージェントパターン
より複雑なタスクでは、親エージェント(オーケストレーター)がタスクを分割し、複数のサブエージェントに割り当てるパターンが効果的です。
ユーザー
↓
オーケストレーター(Claude)
├── サブエージェント1(調査担当)
│ └── MCP: Web検索、Wikipedia
├── サブエージェント2(分析担当)
│ └── MCP: データベース、計算ツール
└── サブエージェント3(出力担当)
└── MCP: ファイル生成、メール送信
Anthropicが2025年に公開した Claude Agent SDK では、このパターンがネイティブにサポートされています。Agent クラスを使って各役割のエージェントを定義し、オーケストレーターが orchestrate() メソッドで全体を制御します。
並列エージェントパターン
独立したタスクを複数のエージェントが同時に処理するパターンです。処理時間の短縮に効果的です。
import asyncio
from anthropic import Anthropic
client = Anthropic()
async def run_agent(task: str, tools: list) -> str:
"""個別エージェントの実行"""
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
tools=tools,
messages=[{"role": "user", "content": task}]
)
return response.content[0].text
async def parallel_workflow(tasks: list[dict]) -> list[str]:
"""複数タスクを並列実行"""
coroutines = [run_agent(t["task"], t["tools"]) for t in tasks]
results = await asyncio.gather(*coroutines)
return results
並列パターンを使う際は、各エージェントが互いに独立していることを確認してください。共有リソースへの競合書き込みは、データ整合性の問題を引き起こします。
チェックポイント付きシーケンシャルパターン
長時間かかるワークフローでは、各ステップの完了後に状態を保存するチェックポイント機構が重要です。途中で失敗しても、最初からやり直す必要がなくなります。
MCPサーバーの実装:実践編
実際にMCPサーバーを実装する方法を学びましょう。ここでは、TypeScript SDK を使って簡単なデータ分析ツールを実装します。
環境セットアップ
mkdir my-mcp-server
cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node ts-node
基本的なMCPサーバーの実装
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "data-analyzer",
version: "1.0.0",
});
// データ集計ツールの定義
server.tool(
"aggregate_data",
"CSVデータを集計して統計情報を返す",
{
data: z.array(z.record(z.string(), z.number())).describe("集計対象のデータ配列"),
column: z.string().describe("集計するカラム名"),
operation: z.enum(["sum", "average", "max", "min"]).describe("集計操作"),
},
async ({ data, column, operation }) => {
const values = data.map(row => row[column]).filter(v => v \!== undefined);
let result: number;
switch (operation) {
case "sum": result = values.reduce((a, b) => a + b, 0); break;
case "average": result = values.reduce((a, b) => a + b, 0) / values.length; break;
case "max": result = Math.max(...values); break;
case "min": result = Math.min(...values); break;
}
return {
content: [{
type: "text",
text: JSON.stringify({ column, operation, result, count: values.length }),
}],
};
}
);
// リソースの定義(テンプレートURI)
server.resource(
"report",
new ResourceTemplate("report://{date}", { list: undefined }),
async (uri, { date }) => ({
contents: [{
uri: uri.href,
text: `${date}のレポートデータ(サンプル)`,
}],
})
);
// STDIOトランスポートで起動
const transport = new StdioServerTransport();
await server.connect(transport);
Claude DesktopへのMCPサーバー登録
実装したサーバーをClaude Desktopで使うには、設定ファイルを編集します。
{
"mcpServers": {
"data-analyzer": {
"command": "node",
"args": ["/path/to/my-mcp-server/dist/index.js"],
"env": {
"NODE_ENV": "production"
}
}
}
}
設定後、Claude Desktopを再起動するとMCPサーバーが認識され、aggregate_data ツールが使えるようになります。
実務ワークフローの設計:3つのユースケース
理論を学んだところで、実際のビジネスシナリオにどう適用するかを見ていきます。
ユースケース1:毎日の情報収集・要約レポート作成
朝、特定のニュースソースや RSS フィードから情報を収集し、要約レポートを作成して Slack に送信する自動化システムです。
必要なMCPツール:
- Web スクレイピングツール(情報収集)
- テキスト要約ツール(Claude APIを内部で使用)
- Slack送信ツール
エージェントワークフロー:
from anthropic import Anthropic
client = Anthropic()
def daily_report_workflow(sources: list[str]) -> str:
"""毎日のレポート生成ワークフロー"""
# Step 1: 各ソースから情報収集(並列)
collection_prompt = f"""
以下のニュースソースから今日の重要な情報を収集してください:
{', '.join(sources)}
各ソースについて:
1. fetch_webpageツールでページを取得
2. 最新5件の記事タイトルと概要を抽出
3. 重要度を1-5で評価
"""
collection_result = client.messages.create(
model="claude-opus-4-6",
max_tokens=8192,
messages=[{"role": "user", "content": collection_prompt}]
)
# Step 2: 収集した情報を分析・要約
summary_prompt = f"""
収集した情報を分析し、今日のエグゼクティブサマリーを作成してください。
収集情報:
{collection_result.content[0].text}
サマリーの要件:
- 最重要トピック3件をトップに
- 各トピックは3行以内で簡潔に
- 業界への影響と推奨アクションを含める
- Slack での読みやすさを考慮したMarkdown形式
"""
summary = client.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
messages=[{"role": "user", "content": summary_prompt}]
)
return summary.content[0].text
ユースケース2:コードレビュー自動化パイプライン
GitHub のプルリクエストを自動的に分析し、コードの品質、セキュリティ上の問題、パフォーマンスへの影響をレポートするシステムです。
エージェントの役割分担:
- コード取得エージェント: GitHub APIでPRの差分を取得
- 品質分析エージェント: コーディング規約の遵守、可読性を評価
- セキュリティ分析エージェント: 潜在的な脆弱性を検出
- パフォーマンス分析エージェント: 計算量、メモリ使用量を評価
- レポート集約エージェント: 各分析結果を統合してコメントを作成
このパターンでは、分析1〜4を並列実行することで、シングルエージェントに比べて処理時間を大幅に短縮できます。
ユースケース3:カスタマーサポートの一次対応自動化
問い合わせメールを受信し、内容を分類、FAQ から回答を生成、必要に応じてエスカレーションを判定するシステムです。
判断ロジックの実装ポイント:
def triage_inquiry(email_content: str) -> dict:
"""問い合わせのトリアージ"""
triage_result = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
system="""あなたはカスタマーサポートのトリアージ専門家です。
問い合わせを以下のカテゴリに分類し、緊急度を判定してください:
- billing: 請求・支払いに関する問題
- technical: 技術的な問題
- general: 一般的な質問
- complaint: クレーム・不満
緊急度: high(即座に人間が対応)/ medium(4時間以内)/ low(24時間以内)
JSON形式で回答してください。""",
messages=[{"role": "user", "content": email_content}]
)
return json.loads(triage_result.content[0].text)
エラー処理と信頼性の向上
本番環境でエージェントワークフローを運用するには、堅牢なエラー処理が不可欠です。
リトライメカニズムの実装
一時的なエラー(ネットワーク障害、レート制限など)に対しては、指数バックオフを使ったリトライが効果的です。
import time
import random
from typing import Callable, TypeVar
T = TypeVar('T')
def with_retry(
func: Callable[[], T],
max_attempts: int = 3,
base_delay: float = 1.0,
max_delay: float = 60.0
) -> T:
"""指数バックオフ + ジッターによるリトライ"""
for attempt in range(max_attempts):
try:
return func()
except Exception as e:
if attempt == max_attempts - 1:
raise # 最後の試行は例外を再スロー
# 指数バックオフ + ランダムジッター
delay = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
print(f"Attempt {attempt + 1} failed: {e}. Retrying in {delay:.1f}s...")
time.sleep(delay)
エラーの分類と対処
エラーには、リトライで回復できるものとできないものがあります。
リトライ可能なエラー:
- HTTP 429(レート制限):
retry-after ヘッダーに従って待機
- HTTP 502/503(一時的なサーバーエラー): 指数バックオフで再試行
- ネットワークタイムアウト: 設定されたリトライ回数まで再試行
リトライ不可なエラー:
- HTTP 401(認証エラー): APIキーを確認
- HTTP 400(不正なリクエスト): リクエストの形式を修正
- コンテキストウィンドウ超過: 入力を分割して再設計
サーキットブレーカーパターン
特定のツールやサービスが連続して失敗する場合、一時的にそのサービスへのアクセスを停止し、システム全体への影響を防ぐサーキットブレーカーパターンが有効です。
ログ管理とオブザーバビリティ
エージェントワークフローの動作を理解し、問題を迅速に発見するには、適切なログ管理が必要です。
構造化ログの実装
import logging
import json
from datetime import datetime
class AgentLogger:
def __init__(self, workflow_id: str):
self.workflow_id = workflow_id
self.logger = logging.getLogger(f"agent.{workflow_id}")
def log_tool_call(self, tool_name: str, input_data: dict, output_data: dict, duration_ms: float):
"""ツール呼び出しのログ"""
self.logger.info(json.dumps({
"timestamp": datetime.utcnow().isoformat(),
"workflow_id": self.workflow_id,
"event": "tool_call",
"tool": tool_name,
"input_tokens": len(str(input_data)),
"output_tokens": len(str(output_data)),
"duration_ms": duration_ms,
}))
def log_agent_decision(self, agent_id: str, decision: str, reasoning: str):
"""エージェントの判断ログ"""
self.logger.info(json.dumps({
"timestamp": datetime.utcnow().isoformat(),
"workflow_id": self.workflow_id,
"event": "agent_decision",
"agent_id": agent_id,
"decision": decision,
"reasoning": reasoning[:500], # 長すぎる場合は切り詰め
}))
追跡すべき主要メトリクス
実運用では以下のメトリクスを継続的に監視することを推奨します。
コスト関連: 1ワークフローあたりのトークン使用量、モデル別のコスト内訳、月次コスト推移。
パフォーマンス関連: エンドツーエンドのレイテンシ、各エージェントの処理時間、ツール呼び出しの平均時間。
信頼性関連: ワークフロー成功率、エラー種別ごとの発生頻度、リトライ率。
コスト最適化の戦略
Claude APIのコストは、主にトークン使用量によって決まります。エージェントワークフローではAPI呼び出しが多くなりがちなので、コスト管理は特に重要です。
モデルの使い分け
すべてのタスクに最高性能のモデルを使う必要はありません。タスクの複雑さに応じてモデルを選択することで、コストを大幅に削減できます。
| タスク種別 | 推奨モデル | 理由 |
|------------|-----------|------|
| 単純な分類・抽出 | claude-haiku-4-5 | 高速・低コスト |
| 中程度の推論 | claude-sonnet-4-6 | バランス |
| 高度な推論・長文生成 | claude-opus-4-6 | 最高品質 |
プロンプトキャッシングの活用
システムプロンプトや共通のコンテキストが繰り返し使われる場合、Anthropicのプロンプトキャッシング機能を使えば、コストを最大90%削減できます。
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
system=[
{
"type": "text",
"text": "(長いシステムプロンプト...)",
"cache_control": {"type": "ephemeral"} # キャッシュを有効化
}
],
messages=[{"role": "user", "content": user_message}]
)
コンテキストウィンドウの効率的な使用
長い会話履歴を持つエージェントでは、古いメッセージを要約して圧縮することで、コンテキストウィンドウを効率的に使えます。
def summarize_history(messages: list, threshold: int = 20) -> list:
"""古いメッセージを要約して圧縮"""
if len(messages) <= threshold:
return messages
old_messages = messages[:-threshold]
recent_messages = messages[-threshold:]
summary_response = client.messages.create(
model="claude-haiku-4-5", # 要約にはHaikuで十分
max_tokens=2048,
messages=[{
"role": "user",
"content": f"以下の会話履歴を簡潔に要約してください:\n\n{json.dumps(old_messages)}"
}]
)
summary = summary_response.content[0].text
return [{"role": "assistant", "content": f"[会話履歴の要約]: {summary}"}] + recent_messages
セキュリティと安全性の考慮
AIエージェントが自律的に行動するシステムでは、セキュリティリスクを適切に管理することが不可欠です。
最小権限の原則
MCPサーバーが持つ権限は、タスクの実行に必要な最小限に絞ります。ファイルシステムへのアクセスが必要な場合でも、特定のディレクトリのみへのアクセスに制限します。
入力サニタイゼーション
ユーザーからの入力をそのままエージェントに渡さないでください。特に、プロンプトインジェクション攻撃(悪意ある入力でエージェントの動作を乗っ取ろうとする攻撃)への対策が必要です。
def sanitize_user_input(user_input: str) -> str:
"""ユーザー入力のサニタイゼーション"""
# 疑わしいパターンを検出
suspicious_patterns = [
"ignore previous instructions",
"system prompt",
"forget everything",
]
lower_input = user_input.lower()
for pattern in suspicious_patterns:
if pattern in lower_input:
raise ValueError(f"Suspicious input detected: {pattern}")
# 長さ制限
if len(user_input) > 10000:
raise ValueError("Input too long")
return user_input
人間による確認ポイントの設計
すべてのアクションをエージェントに自動実行させるのではなく、重要な判断ポイントで人間の確認を要求する設計も重要です。「承認が必要な場合はフラグを立て、それ以外は自動実行」というハイブリッドアプローチが実用的です。
全体を振り返って:実践的なMCPエージェント開発のロードマップ
本記事で解説した内容を振り返り、実際に始める際のロードマップを提示します。
フェーズ1(1〜2週間): MCPの基礎理解と既存サーバーの活用。Claude Desktopに公式MCPサーバーを接続し、実際の業務でどう使えるか探ります。
フェーズ2(2〜4週間): カスタムMCPサーバーの開発。自社のシステムやAPI をMCPサーバーとして実装し、Claudeから呼び出せる状態を作ります。
フェーズ3(1〜2か月): マルチエージェントワークフローの設計と実装。実際のビジネスプロセスをエージェントで自動化し、ログ・コスト管理を含めた本番運用体制を整備します。
MCPとエージェントワークフローは、AIを「使う」から「組み込む」へとシフトするための重要な技術基盤です。まずは小さなユースケースから始め、徐々に複雑なシステムへと発展させていくアプローチをお勧めします。
日々の業務の中で「もし自動化できたら」と感じる場面を見つけたとき、そこにエージェントワークフローの可能性があります。ぜひ、この記事を参考に最初の一歩を踏み出してみてください。