
こんにちは。エンジニアの山下です。
Salesforce から Agentforce 3 が発表され、その目玉機能の1つとして MCP との接続性の強化が予告されました。 AI Agent に対して MCP を用いた機能拡張ができるようになるのはもちろんのこと、各産業向けに構築されたプレビルド MCP の提供やサードパーティ製の MCP の検索ができる AgentExchange の登場についても述べられており、その力の入れ具合が伺えます。また、他のプラットフォームでは Amazon Bedrock Agents からも MCP が利用できるようになるなど、MCP の活用の幅が徐々に広がりつつあるのを感じますね。
そんな MCP 活況の流れの中、MCP の仕様の 最新版 が 2025 年 6 月 18 日に公開されました。セキュリティ考慮事項のアップデートや Structured Tool Output のサポートなど、色々と気になる変更点が含まれているのですが、今回は最新版の仕様で新たに追加された Elicitation という機能について書きたいと思います。
Elicitation は MCP Server からユーザに対して追加の情報収集のためのリクエストを発行する機能で、ざっくり述べると MCP からユーザへの問い返しを行うことができるようになります。
他の変更内容が概ね既存仕様のブラッシュアップに留まる中、Elicitation だけは LLM と MCP の双方向のやり取りという新しい可能性をもたらす機能になっており、非常に興味を惹かれますね。また、Elicitation という名称がビジネスアナリシスの文脈で使用される同用語を想起させることもあり、どの程度の事柄を MCP でカバーしようとしているのかも気になるところです。
というわけで、今回は Elicitation について調べた事柄をまとめたいと思います。
概要
Elicitation は MCP Server からユーザに対して情報の追加入力を要求するための機能です。以下にその動作を表すシーケンスを示します。

大まかな流れは以下の通りです。
- Client から Server に MCP の機能利用のリクエストが送信される
- Server から Client に Elicitation のリクエストが送信される
- Client が Elicitation のリクエストの内容を元に追加入力用の UI を表示する
- ユーザが入力用の UI を使って追加情報を入力する
- Client から Server に Elicitation のレスポンスが送信される
- Server から Client に MCP の機能利用のレスポンスが送信される
要するに MCP の機能利用リクエストを受けた際、MCP Server から必要に応じてユーザに追加の情報入力を要求し、入力が得られたら処理を継続して回答を返す、という流れになります。なお、上記のシーケンス図では 1 で MCP の Tool を呼び出していますが、呼び出す対象に特に制約はなく、Resource や Prompt でも構いません。
追加の入力が必要なパラメータのスキーマは Elicitation のリクエストで以下のような JSON を使って指定します。
{ "type": "object", "properties": { "somethingString": { "type": "string", "title": "Something String", "description": "Something string" }, "somethingNumber": { "type": "number", "title": "Something Number", "description": "Something number" } }, "required": ["somethingString"] }
列挙型や最大値・最小値等もサポートされており、入力パラメータの指定は結構柔軟です。入力スキーマの指定についての詳細は MCP の仕様の こちら に書いてあるので、気になる方は参照してみてください。
ビジネスアナリシスの文脈における Elicitation はシステムに必要な要求や要件を引き出すための問いという結構重めの概念なのですが、概要を見る限り、少なくとも現時点の MCP の Elicitation はそこまで大仰なものではなく、もう少し単純な追加入力要求というイメージになりそうです。
実装してみる
実際の Elicitation の動作を確認してみたいので、Elicitation を使ったサンプルを実装してみましょう。MCP TypeScript SDK には既に Elicitation を実装するための関数が用意されているので、今回はそちらを使用します。
実装するのは Echo 機能を持つ簡単な MCP Server です。ただし、Echo に使用する文字列は入力パラメータではなく Elicitation で追加入力として受け取ります。
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js" import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js" const server = new McpServer({ name: "demo-server", version: "1.0.0" }) server.registerTool("echo", { title: "Echo with elicitation", description: "Echo the input", inputSchema: {} }, async ({}) => { const result = await server.server.elicitInput({ message: "Please input something string:", requestedSchema: { type: "object", properties: { input: { type: "string", title: "Input", description: "Please input something string:" } }, required: ["input"] } }) if (result?.action !== "accept" || typeof(result?.content?.input) !== "string") { console.log(result) return { content: [{ type: "text", text: "Invalid input" }] } } return { content: [{ type: "text", text: result.content?.input }] } } ) const transport = new StdioServerTransport() await server.connect(transport)
実際に Elicitation を実行しているのは elicitInput() を呼んでいる箇所です。この関数を呼ぶだけで Elicitation の一連の動作を行うことができます。簡単でよいですね。
では実際に動かしてみます。上記の MCP Server を立てて MCP Inspector で Echo ツールを実行すると、以下の追加入力用のフォームが表示されます。

適当な文字列を入力して Submit するとツールの実行結果が表示されます。以下は追加入力に Hello, World! という文字列を指定した場合の画面です。

いい感じですね。実装も容易で動作もシンプルなので言うことなしです。
制約事項
Elicitation の大まかな動作イメージが掴めたところで、もう少し細かい内容に踏み込んで見ていきましょう。
上で見た通り、Elicitation は極めてシンプルな機能ではありますが、一方で無視できない制約事項がいくつかあります。厄介なことに、まだ若い機能故にそれらの制約事項の多くは仕様や MCP SDK のドキュメントに明記されておらず、開発者自身がその動作を確認して独自に知見を得るしかないというのが現状です。
ここでは開発者の皆さんの労が減ることを願って、筆者が実際に転んで試していて気づいた Elicitation の制約事項についてまとめたいと思います。
Elicitation による入力待機中にタイムアウトが発生する
Elicitation の流れをおさらいすると、
- Client から Server に MCP の機能利用のリクエストが送信される
- Server から Client に Elicitation のリクエストが送信される
- Client から Server に Elicitation のレスポンスが送信される
- Server から Client に MCP の機能利用のレスポンスが送信される
という入れ子構造になっているのでした。
ところで、この Elicitation のリクエストには Server Sent Event (SSE) 等の経路が利用され、MCP の機能利用リクエストと並行する形で同リクエストが走ります。従って、実は Elicitation を利用した場合でも MCP の機能利用リクエストは終端されず、単に Elicitation の完了までレスポンスの送信を控える形になります。
勘の良い方は気づいたかもしれませんが、この構成には致命的な構造的欠陥があります。MCP の機能利用リクエストは Elicitation の完了を待機するわけですが、Client 側のタイムアウトのカウントはこの間も継続します。従って、Elicitation による追加入力の取得が長引くと、MCP の機能利用リクエストがタイムアウトします。
図にすると以下のような状況ですね。

これは Elicitation の機能設計における最も微妙な点の1つで、このために MCP の機能利用リクエストのタイムアウトの期限を大きめに取りたいという要望が生じますが、そもそも MCP Server から MCP Client のタイムアウト設定に干渉する術はなく、打てる手立ては基本的にありません。また、MCP Client からしても MCP Server のどの機能が Elicitation を使用するのかわからないため、こちらの側からも打てる手立てがないというのが現状です。
この制約に対する回答は現時点では特にないため、素直にもう少し仕様のブラッシュアップを待つのが正解というのが率直な印象です。
Streamable HTTP での利用にはセッション管理が必要
先の Echo MCP の実装は StdioServerTransport を使用した標準入出力方式になっていましたが、Elicitation はもちろん Streamable HTTP でも実装可能です。ただし、Streamable HTTP を利用する際はセッション管理が必須で、セッション管理なしの場合は Elicitation を利用できません。
この制約は Streamable HTTP が SSE を利用して Elicitation のやり取りが行うことにより生じます。具体的には、Streamable HTTP では以下の流れで Elicitation が行われます。
- Client から Server に SSE の通信経路確保用の GET リクエストが送信される
- Client から Server に MCP の機能利用の POST リクエストが送信される
- Server から Client に 1 の SSE の経路で Elicitation リクエストが送信される
- Client から Server に 1 の SSE の経路で Elicitation レスポンスが送信される
- Server から Client に MCP の機能利用のレスポンスが送信される
要するに、Elicitation を行うには上記の 1 と 2 による2つの HTTP リクエストを関連付ける必要があり、これによりセッション管理が必要になるというわけです。
参考までに、Streamable HTTP で実装した Echo MCP は以下になります。
import express from "express" import { randomUUID } from "node:crypto" import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js" import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js" import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js" const server = new McpServer({ name: "demo-server", version: "1.0.0" }) server.registerTool("echo", { title: "Echo with elicitation", description: "Echo the input", inputSchema: {} }, async ({}) => { const result = await server.server.elicitInput({ message: "Please input something string:", requestedSchema: { type: "object", properties: { input: { type: "string", title: "Input", description: "Please input something string:" } }, required: ["input"] } }) if (result?.action !== "accept" || typeof(result?.content?.input) !== "string") { console.log(result) return { content: [{ type: "text", text: "Invalid input" }] } } return { content: [{ type: "text", text: result.content?.input }] } } ) const app = express() app.use(express.json()) const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {} const buildInvalidRequestResponse = () => { return { jsonrpc: '2.0', error: { code: -32000, message: 'Bad Request: No valid session ID provided', }, id: null, } } app.post('/mcp', async (req, res) => { const sessionId = req.headers['mcp-session-id'] as string | undefined let transport: StreamableHTTPServerTransport if (sessionId && transports[sessionId]) { transport = transports[sessionId] } else if (!sessionId && isInitializeRequest(req.body)) { transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (sessionId) => { transports[sessionId] = transport }, }) transport.onclose = () => { if (transport.sessionId) { delete transports[transport.sessionId] } } await server.connect(transport) } else { res.status(400).json(buildInvalidRequestResponse()) return } await transport.handleRequest(req, res, req.body) }) const handleSessionRequest = async (req: express.Request, res: express.Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined if (!sessionId || !transports[sessionId]) { res.status(400).send('Invalid or missing session ID') return } const transport = transports[sessionId] await transport.handleRequest(req, res) } app.get('/mcp', handleSessionRequest) app.delete('/mcp', handleSessionRequest) app.listen(3001)
なお、このセッション管理に関する制約は MCP の仕様にも SDK のドキュメントにも何故か記載がありません。さらに厄介なことに、セッション管理なしの Streamable HTTP で Elicitation を実装した場合、MCP TypeScript SDK では特に明示的なエラーは発生せず、単に接続がタイムアウトするような実装になっており、実際の動作からも仕様についてのヒントを得るのが難しくなっています。
Streamable HTTP で実装する場合は割と引っかかりがちな罠なので注意しましょう。俺のようにはなるな。
多重リクエストができない
現状、1度の MCP の機能利用リクエストの中で複数回の Elicitation リクエストを発行することはできないようです。
仕様にはリクエスト回数についての記載はなく、かつ Elicitation の Pull Request では複数回のリクエストも容認されているような書き振りが散見されるので、微妙に整合しない感じはあるのですが、MCP TypeScript SDK で試したところ動作しなかったので制約として記載しています。実際に試すと2回目の Elicitation リクエストのタイミングでスタックしてタイムアウトになってしまうようなので、単に SDK のバグかもしれません。
この制約により、ユーザに複数回の質問を行うことができないため、例えば図形の面積を計算する MCP の実装に対して、最初に図形の種類(円や矩形など)を質問し、次に各図形のプロパティ(円の半径や矩形の縦横長など)を質問するといった戦略は採れなくなります。
このような場合、代わりに MCP の機能利用リクエストの際に入力パラメータで図形の種類までは聞いておくか、図形の種類とプロパティを以下のように一括で訊いてしまうかの2択になりそうです。
const result = await server.server.elicitInput({ message: "Please input the type of shape and the properties", requestedSchema: { type: "object", properties: { type: { type: "string", title: "Type", description: "Please choose a type of shape", enum: ["circle", "rectangle"], enumNames: ["Circle", "Rectangle"] }, radius: { type: "number", title: "Radius", description: "Please input the radius of the circle. This parameter is required when the type is circle." }, width: { type: "number", title: "Width", description: "Please input the width of the rectangle. This parameter is required when the type is rectangle." }, height: { type: "number", title: "Height", description: "Please input the height of the rectangle. This parameter is required when the type is rectangle." }, }, required: ["type"] } })
上記のように一括で訊いてしまうと、入力欄の視認性が悪くなったり、バリデーションが複雑になったりといった点が気になるので、利用できるシーンが限られそうな感じはします。
機密情報のやり取りをしてはならない
Elicitation で機密性の高い情報のやり取りをしてはならないという旨が珍しく仕様に明記されています。
これは言わずもがな、セキュリティ上の懸念のために設けられた制約です。Elicitation をはじめとする MCP の機能で取得した情報は Client によって常に LLM のコンテキストに転記される可能性があり、このようなセキュリティ上の違反行為はプロトコルの規約で非推奨としても抑止できないことが多いことから、最初から機密情報は取り扱わないことにしておいた方がいいと判断されたようです。
実際、Elicitation の Pull Request では同内容についての議論が交わされており、プロトコルを定める側にも独特の気苦労があることが伺えます。
どんなユースケースに適しているか
意外と制約が多い印象はありますが、Elicitation が全く新しい可能性をもたらす機能という点に変わりはないので、どんなユースケースでの利用が期待できるのかは把握しておきたいところです。
Elicitation の Pull Request には以下の5つのユースケースが挙げられており、検討のヒントとなりそうです。
- Confirmation of critical actions
- Redirecting user to a sign-in flow
- Clarification of ambiguous requests
- Progressive form filling
- Contextual information gathering
ただし、これらのユースケースはあくまで Pull Request 作成時点で想定されていたものであり、リリースされた Elicitation の仕様とは明らかに整合しないものもいくつか存在します。
以下、これらのユースケースそれぞれがリリース後の Elicitation の仕様に適合しているかどうかを検討してみます。
1. Confirmation of critical actions
最初に挙げられているのは重要なアクションの確認というユースケースです。S3 などのストレージサービスからファイル削除を行う際に「本当に削除してもよいですか?」と確認するような目的のもので、これは普通にありそうですね。
MCP Client になり得る Cursor 等の AI Editor には MCP 利用時にユーザから実行内容の承認を得る機能が搭載されていることも多く、これが本ユースケースと競合しそうではありますが、この手の機能は全アクションに一律で適用されてしまうケースが多いため、日常的な作業の手間を考えると自動承認に設定されがちです。そうなると、一部の重要なアクションに追加確認のための Elicitation を搭載するというのはあり得そうな気がします。
このユースケースであれば先ほど見た制約群の影響を受けることもなさそうなので、有望な用途になりそうです。
2. Redirecting user to a sign-in flow
2つ目に認証処理へのユーザの誘導が挙げられていますが、これは明らかにリリース時点の Elicitation の仕様では実現不可能です。
そもそも Elicitation では機密情報を取り扱えないという前提があるため、各種認証のためのクレデンシャルはもちろんのこと、認証の結果として得られるトークン等も取り扱うことはできません。この前提を遵守しながら認証処理において何らかの補助的役割を果たすのは極めて困難であり、またそのような苦労を背負うくらいなら最初から MCP の OAuth 関連の仕様を利用した方がよい結果が得られそうです。
このユースケースの記載は Elicitation での機密情報の取り扱いが容認されていた頃の名残であり、セキュリティ上の懸念により機密情報の取り扱いが禁止された時点で実現可能性は消えたと考えてよさそうです。
3. Clarification of ambiguous requests
3つ目は曖昧なリクエストを明確にするための問い返しとなっています。
個人的には、そもそもリクエストの時点で曖昧さが残るような機能設計はそれ自体ダメでは、という思いがあるので、やや歓迎しづらいユースケースです。ただし、以下のような状況では Elicitation を利用するメリットがあるような気がしています。
- ユーザの選択肢が動的に決定される場合
- 一部の状況においてのみ追加の情報が必要になる場合
例えば、会議室の予約を行う MCP を開発するとします。この MCP を「入力パラメータで部屋と日時を指定して予約を取る」という設計で実装することも可能ですが、その場合、事前にどの会議室がどの時間に空いているのかをユーザが確認しなければなりません。そのような設計にするよりは「この時間の範囲で予約をしたい」という緩い条件指定のみを入力パラメータとして指定し、Elicitation で予約可能な部屋と日時の候補を列挙型で返す設計の方が親切かもしれません。これが 1 の内容で、リソースの状況次第で選択肢が変わる場合は Elicitation を利用する価値がありそうです。
また、ある会議室は区画分けがされており、その会議室を予約する場合にはどの区画を使用するかも含めて指定しなければならないとします。この場合は Elicitation で追加質問するのが実装的にも自然でしょう。これが 2 に当たる内容です。
実際のところ、ユースケースとして多そうなのは 1 でしょうか。2 では Elicitation を多用するとロジックの複雑化を招きそうなので、使いどころに悩みそうな気はします。
4. Progressive form filling
こちらは段階的なフォーム入力ということで、複数ターンにまたがるやり取りが想定されていそうです。特に入力パラメータの数が多い場合は、一度に大量の入力を要求すると UX が悪化するため、段階的に入力を要求することによる恩恵が大きそうです。
しかし、筆者が試した限りでは複数回の Elicitation はそもそも動作せず、現状では追加の情報収集ができるのは1回のみのため、この状況ではパラメータの入力負荷を下げる効果はやや期待しづらいような気がします。
また、入力負荷を下げる以外の恩恵が段階的入力にあるかというと、あまりなさそうな気がしています。少なくとも筆者にはこのユースケースが輝く状況が想像できませんでした。少なくとも複数回の Elicitation ができるようになるまでは、こちらのユースケースは頭の片隅に置いておくくらいで良いかなという印象です。
5. Contextual information gathering
最後に挙げられているのが文脈情報の収集なのですが、あまりにも抽象的すぎてイメージが湧きませんでした。こちらについては具体的な想定があるというよりは、いわゆる「その他全般」的なカテゴリを表すために置かれているのかなと思いました。
その他
MCP TypeScript SDK には Elicitation の実装例として予約システムの MCP が挙げられています。ここでは指定した条件で予約ができなかった場合、他の候補日を入力するようにユーザに促す目的で Elicitation が使用されています。
いわゆる例外ハンドリング的な文脈での Elicitation の利用ということになりそうですが、これは結構使いどころが難しそうですね。指定した条件で予約が取れなかった場合に他の候補日を挙げたいかどうかはユーザの状況に依存しそうなので、単に予約できないことを示すに留めるという方針も全然ありという気がします。
要求の処理に失敗した場合に取るべき次のステップが明らかな状況でのみ採用できるユースケースなので、あまり汎用性はなさそうですね。こちらも頭の片隅に入れておくくらいで良さそうです。
まとめると、ユースケースとして有望そうなのは、
- 重要なアクションの実行の承認
- リソース予約等における選択肢となる候補の表示
- 限定的な条件下でのみ必要な追加情報の収集
といったところになりそうですね。
まとめ
というわけで、今回は MCP の Elicitation についてまとめました。
個人的には LLM によるコンサル的な問い返しは今後の業務において重要な役割を果たしていきそうだと考えており、Elicitation が気になったのはそういった背景によるのですが、MCP は割と静的な事柄を対象とするプロトコルということもあり、筆者の期待とは少し違った内容という印象でした。
とはいえ、面白い可能性を発掘できそうな機能という点は間違いないので、今後の発展に期待したいところです。今はやや使いづらさが目立ちますが、今後の改訂でこのあたりも解消されていくとよいですね。
以上です。最後までお読みいただき、ありがとうございました。