はじめに
Anthropicが開発したModel Context Protocol (MCP) は、LLM(大規模言語モデル)が外部データソースに標準化された方法でアクセスできるようにするオープンプロトコルです。
MCPを利用すると、ローカルファイル、データベース、APIなどの外部データをLLMの推論に活用できるようになりますが、これは機密性の高いデータがLLMのコンテキストとして渡されることを意味します。そのため、セキュリティとデータプライバシーの観点から慎重な設計が求められます。
本記事では、MCPを安全に利用するためのデータ分離とアクセス制御の基本原則を解説します。
1. データ分離の原則:コンテキストを安全に保つ
MCPでは外部データをLLMのコンテキストとして提供しますが、異なるユーザーやセッションのデータが混在しないよう、論理的な分離が不可欠です。
1.1. セッション/ユーザーごとの厳格な分離
マルチユーザー環境では、あるユーザーの機密データが他のユーザーに漏洩するリスク(コンテキストリーク)を防ぐ必要があります。
実装のポイント:
- セッション管理の徹底: 各MCPサーバー接続に一意のセッションIDを割り当て、リクエストごとに検証します
- データスコープの制限: MCPサーバー側で、認証されたユーザー/セッションがアクセス可能なリソースのみを返すようフィルタリングします
- メモリ管理: LLMホスト側では、セッション終了時にコンテキストウィンドウや一時ファイルを適切にクリアします
注意点:
MCPはステートレスなプロトコルですが、実装時にはセッション状態を適切に管理する必要があります。特に、長時間実行されるMCPサーバープロセスでは、セッション間でのデータ漏洩に注意が必要です。
1.2. データの機密性による分離(分類とラベリング)
すべてのデータを同じように扱うのではなく、機密性に応じた取り扱いが重要です。
実装のポイント:
- データ分類: リソースに「公開」「内部限定」「機密」「個人情報」などのラベルを付与します
-
メタデータ活用: MCPのリソース定義に
annotations
フィールドを使ってセキュリティレベルを記述します - 条件付きアクセス: MCPサーバー側で、ユーザーの権限レベルに応じて返すリソースを動的に変更します
実装例:
// MCPサーバー側でのリソース分類
server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
const userRole = await getUserRole(request.sessionId);
const resources = [
{
uri: "file:///public/docs.txt",
name: "公開ドキュメント",
annotations: { securityLevel: "public" }
},
{
uri: "db://customer/data",
name: "顧客情報",
annotations: { securityLevel: "confidential" }
}
];
// ユーザー権限に基づいてフィルタリング
return {
resources: resources.filter(r =>
canAccess(userRole, r.annotations.securityLevel)
)
};
});
2. アクセス制御の基本:誰が、何を、どう使うかを決める
データ分離が「データの隔離」を担保するなら、アクセス制御は「誰に権限を与えるか」を定義します。
2.1. 最小権限の原則(Principle of Least Privilege)
LLMやToolが必要とする最低限のデータのみにアクセスを許可します。
実装のポイント:
- リソースベースのアクセス制御: MCPサーバーごとに異なる権限を設定します(例:読み取り専用サーバー、書き込み可能サーバー)
- スコープの制限: データベース接続では、特定のテーブルやカラムのみにアクセスを制限します
- 時間制限: 一時的なタスクには、期限付きの認証トークンを使用します
Claude Desktopでの設定例:
{
"mcpServers": {
"public-docs": {
"command": "mcp-server-filesystem",
"args": ["--readonly", "/public/docs"]
},
"customer-db": {
"command": "mcp-server-database",
"args": ["--connection", "postgres://readonly@localhost/crm"],
"env": {
"DB_READ_ONLY": "true"
}
}
}
}
2.2. 認証と認可の実装
MCPサーバーへのアクセス自体を適切に制御します。
実装レベル:
- プロセスレベルの分離: MCPサーバーは通常、ローカルプロセスとして実行されます。OSレベルの権限管理を活用しましょう
- API認証: 外部データソース(API、データベース)への接続には適切な認証情報を使用します
- ユーザーコンテキストの伝播: MCPサーバーが複数ユーザーをサポートする場合、各リクエストにユーザー識別子を含めます
外部API接続の実装例:
// 環境変数から安全に認証情報を取得
const API_KEY = process.env.EXTERNAL_API_KEY;
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "fetch-customer-data") {
// ユーザー権限の検証
if (!await hasPermission(request.sessionId, "customer:read")) {
throw new Error("Insufficient permissions");
}
// 外部APIへの認証済みリクエスト
const response = await fetch("https://api.example.com/customers", {
headers: {
"Authorization": `Bearer ${API_KEY}`,
"X-User-Context": request.sessionId
}
});
return { content: [{ type: "text", text: await response.text() }] };
}
});
2.3. 環境変数と秘密情報の管理
重要な注意点:
- APIキーやデータベースパスワードをコード内にハードコードしない
- 環境変数や専用の秘密管理システム(AWS Secrets Manager、HashiCorp Vaultなど)を使用する
-
.env
ファイルは絶対にGitにコミットしない
3. ログと監査:透明性の確保
セキュリティインシデントの検知や、コンプライアンス要件への対応のため、すべてのアクセスを記録可能にします。
3.1. アクセスログの記録
記録すべき情報:
- タイムスタンプ
- ユーザー/セッションID
- アクセスされたリソース(URI)
- 実行されたTool
- アクセス結果(成功/失敗)
実装例:
// ロギングミドルウェア
async function logAccess(sessionId: string, resource: string, action: string) {
const logEntry = {
timestamp: new Date().toISOString(),
sessionId: sessionId,
resource: resource,
action: action,
sourceIP: getClientIP()
};
// 構造化ログとして出力
console.log(JSON.stringify(logEntry));
// または専用のログシステムへ送信
await logService.send(logEntry);
}
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
await logAccess(request.sessionId, request.params.uri, "read");
// リソース読み取り処理...
});
3.2. 監査とアラート
- 異常検知: 通常と異なるアクセスパターン(大量のデータ取得、深夜のアクセスなど)を検知する
- 定期的なレビュー: アクセスログを定期的にレビューし、不正利用がないか確認する
- コンプライアンス: GDPR、HIPAAなどの規制要件に応じた監査証跡を保持する
4. MCPセキュリティのベストプラクティス
4.1. セキュアな設計チェックリスト
- MCPサーバーは最小権限で実行される
- 機密データへのアクセスには適切な認証が実装されている
- セッション間でのデータ分離が保証されている
- すべてのアクセスがログに記録されている
- 秘密情報(APIキー、パスワード)は安全に管理されている
- エラーメッセージから機密情報が漏洩しない
4.2. 定期的なセキュリティレビュー
- MCPサーバーの依存関係を最新に保つ
- アクセスログを定期的に監査する
- 権限設定を定期的に見直す
- セキュリティテストを実施する
まとめ
MCPは強力なプロトコルですが、その力を安全に活用するには、適切なセキュリティ設計が不可欠です。
重要なポイント:
- データ分離: セッション/ユーザーごとにデータを厳格に分離する
- 最小権限: 必要最低限のアクセス権のみを付与する
- 認証・認可: 適切な認証メカニズムを実装する
- 監査: すべてのアクセスを記録し、定期的にレビューする
これらの原則を守ることで、MCPの利便性とセキュリティを両立した、信頼できるLLMアプリケーションを構築できます。
参考リンク
注意: MCPはAnthropicが開発した比較的新しいプロトコルです。最新の情報については、公式ドキュメントを参照してください。