Claude Code MCP Elicitation入門——MCPサーバーが実行中にユーザー入力を求める新機能
Claude Code v2.1.76で追加されたMCP Elicitation機能を徹底解説。MCPサーバーがタスク実行中に構造化された入力をインタラクティブに要求する仕組み、Elicitation/ElicitationResultフック、実装パターンまで実践的に紹介します。

はじめに
MCPサーバーを使ってClaude Codeにカスタムツールを持たせる開発スタイルが定着してきました。しかし、これまでのMCPツール呼び出しは「入力を渡す → 結果を返す」の一方通行であり、ツール実行中にユーザーへ追加の確認や選択を求めることができませんでした。
| 状況 | 困りごと |
|---|---|
| データベースMCPでの操作 | 実行前に「本当にDROP TABLEしますか?」の確認ができない |
| デプロイMCPサーバー | 環境(staging/production)の選択を途中で求められない |
| API連携ツール | OAuthの同意画面をMCPフロー内で表示できない |
つまり、MCPツールは「渡されたパラメータで処理を完遂する」ことしかできず、実行途中でのインタラクションが欠如していたのです。
Claude Code v2.1.76(2026年3月14日リリース)で追加されたMCP Elicitationは、この制約を取り払う新機能です。MCPサーバーがツール実行の途中でクライアントを通じてユーザーに構造化された入力を要求し、その応答に基づいて処理を継続できるようになりました。
この記事を読み終わると、以下ができるようになります:
- MCP Elicitationの仕組みと用途を理解できる
- Elicitationに対応したMCPサーバーを実装できる
- Elicitation/ElicitationResult Hooksでカスタマイズできる
- 安全なツール実行フローを設計できる
MCP Elicitationとは
双方向インタラクションの実現
従来のMCPツール呼び出しは、Claudeがパラメータを渡し、サーバーが結果を返す単方向のフローでした。Elicitationはこのフローに「問い合わせ → 応答」のステップを挟みます。
MCPサーバーはツール処理の途中でElicitation要求を発行し、Claude Codeがそれをダイアログとしてユーザーに表示します。ユーザーが入力した結果はElicitationResultとしてサーバーに戻り、処理が継続されます。
入力の構造化
Elicitation要求では、JSON Schemaベースのフォーム定義を送信できます。単なるテキスト入力だけでなく、列挙型の選択(enum)、真偽値(boolean)、数値(number)など、型安全な入力をユーザーに求められます。
これにより、MCPサーバーは「正しい型・正しい形式のデータ」を受け取ることが保証され、バリデーションエラーのリスクを低減できます。
主な特徴
| 特徴 | 詳細 |
|---|---|
| 構造化入力 | JSON Schemaで入力フォームを定義 |
| 型安全 | string/boolean/number/enumに対応 |
| キャンセル可能 | ユーザーは入力を拒否・キャンセルできる |
| Hooks連携 | Elicitation/ElicitationResultフックで拡張可能 |
| 複数回の問い合わせ | 1つのツール実行中に複数回のElicitationが可能 |
ユースケース
Elicitationが威力を発揮するのは、ツール実行前に人間の判断が必要な場面です。
1. 危険な操作の確認
データベース操作ツールで、DROP文やTRUNCATE文を実行する前に最終確認を求めます。誤操作によるデータ消失を防ぐガードレールとして機能します。
// 例: DELETE操作前に確認を求める
const result = await server.elicit({
message: `テーブル "${tableName}" のレコードを${count}件削除します。本当に実行しますか?`,
requestedSchema: {
type: "object",
properties: {
confirm: {
type: "boolean",
description: "削除を実行する"
}
},
required: ["confirm"]
}
});
2. パラメータ選択
デプロイ先環境の選択やビルド構成の指定など、実行時にユーザーが選択すべきパラメータがある場合に使います。
3. 認証フロー
OAuthの同意画面やAPIキーの入力など、認証に関する操作をMCPフロー内で完結させられます。URLリダイレクト型のElicitationを使えば、外部の認証ページへユーザーを案内することも可能です。
4. 入力補完
ツール実行に必要な情報が不足している場合、不足分だけをユーザーに追加入力してもらえます。Claudeがパラメータを推測して間違えるリスクを回避でき、確実なデータで処理を進められます。
ハンズオン: Elicitation対応MCPサーバーを実装する
実際にElicitationを活用したデプロイツールのMCPサーバーを作ってみましょう。
事前準備
mkdir elicitation-demo && cd elicitation-demo
yarn init -y
yarn add @modelcontextprotocol/sdk zod
yarn add -D typescript @types/node
tsconfig.jsonを作成します。
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
package.jsonに以下を追加します。
{
"type": "module",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
}
}
サーバー実装
// src/index.ts
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: "deploy-server",
version: "1.0.0",
});
// デプロイツール — Elicitationで環境選択と最終確認を行う
server.tool(
"deploy",
"アプリケーションをデプロイする(環境選択と確認あり)",
{
branch: z.string().describe("デプロイするブランチ名"),
},
async ({ branch }, { sendElicitationRequest }) => {
// ステップ1: デプロイ先環境をユーザーに選択させる
const envResult = await sendElicitationRequest({
message: `ブランチ "${branch}" のデプロイ先を選択してください`,
requestedSchema: {
type: "object" as const,
properties: {
environment: {
type: "string",
enum: ["staging", "production"],
description: "デプロイ先環境",
},
},
required: ["environment"],
},
});
// ユーザーがキャンセルした場合
if (envResult.action === "reject" || envResult.action === "dismiss") {
return {
content: [{ type: "text", text: "デプロイをキャンセルしました" }],
};
}
const environment = envResult.content?.environment as string;
// ステップ2: production の場合は追加の最終確認を求める
if (environment === "production") {
const confirmResult = await sendElicitationRequest({
message: `⚠️ 本番環境へのデプロイです。ブランチ "${branch}" を production にデプロイしますか?`,
requestedSchema: {
type: "object" as const,
properties: {
confirm: {
type: "boolean",
description: "本番デプロイを実行する",
},
reason: {
type: "string",
description: "デプロイ理由(任意)",
},
},
required: ["confirm"],
},
});
if (
confirmResult.action === "reject" ||
confirmResult.action === "dismiss" ||
!confirmResult.content?.confirm
) {
return {
content: [
{ type: "text", text: "本番デプロイをキャンセルしました" },
],
};
}
}
// ステップ3: デプロイ実行(実際の処理をここに記述)
const timestamp = new Date().toISOString();
return {
content: [
{
type: "text",
text: [
`デプロイが完了しました`,
`- 環境: ${environment}`,
`- ブランチ: ${branch}`,
`- 時刻: ${timestamp}`,
].join("\n"),
},
],
};
}
);
// サーバー起動
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Deploy MCP Server with Elicitation started");
}
main().catch(console.error);
ポイント解説
上記の実装で注目すべき点を整理します。
| ポイント | 説明 |
|---|---|
sendElicitationRequest | ツールハンドラの第2引数から取得できるElicitation送信関数 |
requestedSchema | JSON Schema形式で入力フォームを定義 |
envResult.action | "accept" / "reject" / "dismiss" でユーザーの応答を判定 |
envResult.content | ユーザーが入力した値をオブジェクトとして取得 |
| 複数回のElicitation | 1つのツール内でsendElicitationRequestを複数回呼び出し可能 |
本番環境へのデプロイ時には2段階の確認(環境選択 → 最終確認)を挟むことで、誤操作のリスクを最小化しています。
ビルドと登録
# ビルド
yarn build
# Claude Codeに登録
claude mcp add deploy-server node dist/index.js
動作確認として、Claude Codeで以下のように指示してみましょう。
mainブランチをデプロイして
ダイアログが表示され、環境の選択と確認が求められるはずです。
Elicitation Hooks
Claude Code HooksにElicitationとElicitationResultの2つの新しいイベントが追加されました。これにより、Elicitationのリクエストとレスポンスの前後にカスタム処理を差し込めます。
| フック | タイミング | 用途 |
|---|---|---|
Elicitation | Elicitation要求がユーザーに表示される前 | ログ記録、通知、バリデーション |
ElicitationResult | ユーザーが応答した後 | 監査ログ、後続処理のトリガー |
設定例
.claude/settings.jsonにフックを追加します。
{
"hooks": {
"Elicitation": [
{
"matcher": "deploy-server",
"type": "command",
"command": "echo \"$(date): Elicitation requested from deploy-server\" >> ~/.claude/elicitation.log"
}
],
"ElicitationResult": [
{
"matcher": "deploy-server",
"type": "command",
"command": "echo \"$(date): User responded to elicitation\" >> ~/.claude/elicitation.log"
}
]
}
}
活用パターン
Elicitation Hooksの実用的な活用パターンをいくつか紹介します。
監査ログの記録: 誰がいつどのElicitationに応答したかを記録し、コンプライアンス要件を満たします。
{
"hooks": {
"ElicitationResult": [
{
"matcher": "",
"type": "command",
"command": "jq -n --arg server \"$MCP_SERVER_NAME\" --arg time \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" '{server: $server, timestamp: $time}' >> ~/.claude/audit.jsonl"
}
]
}
}
Slack通知: 本番環境への操作が承認された際にSlackチャンネルに通知を送信します。
{
"hooks": {
"ElicitationResult": [
{
"matcher": "deploy-server",
"type": "http",
"url": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL",
"method": "POST",
"headers": { "Content-Type": "application/json" },
"body": "{\"text\": \"本番デプロイが承認されました\"}"
}
]
}
}
既存のMCPパターンとの比較
Elicitationの位置づけを、他のMCPインタラクションパターンと比較して整理します。
| パターン | 説明 | インタラクション |
|---|---|---|
| 通常のツール | 入力 → 実行 → 結果 | 一方向 |
| Elicitation | 入力 → 確認要求 → 応答 → 実行 | 双方向 |
| Channels | 外部 → プッシュ → 処理 | プッシュ型 |
通常のツールは「Claudeが判断してパラメータを渡し、結果を受け取る」だけですが、Elicitationではツール側がユーザーに直接問い合わせることができます。この違いにより、「Claudeの推測ではなくユーザーの明示的な意思決定」を処理に組み込めるようになります。
Channelsは外部からClaude Codeセッションにイベントをプッシュする仕組みであり、Elicitationとは方向が異なります。ElicitationはあくまでMCPツール実行中のサーバー → ユーザー方向の問い合わせです。
設計上のベストプラクティス
Elicitation対応のMCPサーバーを設計する際に押さえておきたいポイントを整理します。
| 原則 | 詳細 |
|---|---|
| 最小限の問い合わせ | ユーザーの作業を中断する回数は最小限にする |
| 明確なメッセージ | 何を選択・入力すべきか一目で分かる文言にする |
| デフォルト値 | 安全な方向のデフォルト値を設定する |
| キャンセルハンドリング | ユーザーがキャンセルした場合のフォールバック処理を必ず実装する |
| 段階的な確認 | 危険度が高い操作ほど確認ステップを増やす |
特に重要なのはキャンセルハンドリングです。sendElicitationRequestのレスポンスにはrejectとdismissの2種類のキャンセルがあるため、どちらのケースも適切に処理する必要があります。
まとめ
MCP Elicitationは、MCPツールの実行モデルを「一方向の呼び出し」から「双方向のインタラクション」に拡張する機能です。
| 課題 | Elicitationによる解決 |
|---|---|
| 危険な操作を止められない | 実行前に構造化された確認ダイアログを表示 |
| パラメータの推測ミス | ユーザーに直接選択を委ねる |
| 認証フローの断絶 | MCPフロー内でOAuth等の認証を完結 |
| 監査証跡の欠如 | Elicitation Hooksでログ・通知を自動化 |
次のアクションとしておすすめ:
- 既存のMCPサーバーにElicitationを追加する — 破壊的な操作を行うツールに確認ダイアログを差し込む
- Elicitation Hooksで監査ログを設定する — チーム運用では操作の記録が重要
- 段階的な確認フローを設計する — 危険度に応じてElicitationの回数と内容を調整する
- カスタムMCPサーバー開発入門を参照する — MCPサーバーの基礎から学びたい方はこちらから
Elicitationの導入により、MCPサーバーは「自律的に実行するだけのツール」から「必要な場面で人間の判断を仰げるインテリジェントなツール」へと進化します。安全性と利便性の両立を目指す方は、ぜひ取り入れてみてください。
参考リンク:
関連記事: