Max Nardit
← 記事
12 mindev

Claude Code の MCP Tasks と elicitation: 誰も答えないかもしれない質問

Claude Code は長いジョブを MCP サーバーに渡し、あとから状況を確認するようになりました。渡した時点で、ジョブはもうクライアントのものではありません。バックグラウンドに移ったあとは時間制限がなく、終了時のキャンセルもなく、実行中のタスクからの質問にはターミナルの前にいる人しか答えられません。期限と後片付けはサーバー作者の仕事になります。

目次

10 月 23 日、Claude Code チームは MCP Tasks と Elicitations への対応を発表しました。「Tasks let Claude give plugins long-running jobs such as deep research and report back when they're done」、そして elicitation は「let plugins ask users for input mid-task」とのことです。どちらも現在 Claude Code CLI で使え、ほかの Claude 製品にも順次対応する予定です。

MCP Tasks と Elicitations への対応を告知する @ClaudeDevs の投稿、2026 年 10 月 23 日

X の投稿、2026 年 10 月 23 日。論評のために引用。

投稿の言い回しのひとつひとつに、投稿自体は触れていない運用上の事情があります。「report back」とは、Claude Code がサーバーをポーリングするということです。「long-running」とは、クライアント側に時間制限がなく、終了してもキャンセルされないということです。「ask users for input mid-task」は、ターミナルの前に人がいれば機能します。ヘッドレス実行では、タスクからの質問がタスクを終わらせます。

投稿への返信で聞かれていたのも同じことでした。タスクはどれくらい動き続けられるのか、クライアントが切断したらどうなるのか、夜中に質問で止まったタスクには誰が答えるのか。大半は Claude Code の MCP ドキュメントの表に答えがあります。残りを確かめるために、すべてのメッセージを記録する小さな stdio サーバーを書き、Claude Code 2.1.310 をつないで通信を観察しました。条件ごとに 1 回ずつの実行なので、テスト結果は保証ではなく観察として読んでください。

Claude Code は MCP Tasks と elicitation で何をリリースしたのか

新しいのは MCP Tasks で、Claude Code CLI の v2.1.304 (10 月 19 日リリース) からパブリックベータです。elicitation は新機能ではありません。Claude Code は 3 月の v2.1.76 から elicitation ダイアログを表示しており、v2.1.281 で URL モードも加わりました。今回追加されたのは、実行中のタスクの中での elicitation です。

プロトコルでは、tasks は 2025-11-25 リビジョンで実験的なコア機能として登場し、2026-07-28 で io.modelcontextprotocol/tasks 拡張に移されました。ポーリングは tasks/get、回答は tasks/update で行います。

ドキュメントによると、呼び出しがタスクになるのは、サーバーがリビジョン 2026-07-28 で接続され、セッションがフィーチャーフラグを取得し (そのため Bedrock やテレメトリ無効の環境では不可)、呼び出しがサブエージェントではなくメインの会話から来た場合だけです。ターミナルのセッション、Agent SDK、GitHub Actions は条件を満たし、VS Code 拡張、デスクトップアプリ、単発の claude -p "<prompt>" は満たしません。stream-json または SDK のセッションでは CLAUDE_AUTO_BACKGROUND_TASKS=1 が必要で、入力ストリームを開いたままにしておかないと、タスクを待たずに実行が終わります。単発実行ではこの除外を確認できました。tools/call は tasks 拡張なしで届き、サーバーはその場で結果を返すしかありませんでした。

Claude Code で MCP Task はどう動くのか

ポーリングです。つまり「report back」はクライアント側のループです。サーバーは tools/call に結果ではなくタスクハンドルを返し、Claude Code は呼び出しをバックグラウンドに移して、タスクが終わるまでサーバーの pollIntervalMs 間隔で tasks/get で問い合わせます。拡張のプッシュ通知は Claude Code では使われません。

テストサーバーはポーリング間隔として 3 秒を指定し、ロガーの 10 ms の分解能の範囲でそのとおりに問い合わせが来ました。ログから抜粋し、開始からの秒数で示します。

 3.31 IN  tools/call  build_report  capabilities include io.modelcontextprotocol/tasks
 3.31 OUT result: resultType "task", status "working", pollIntervalMs 3000
 3.32 IN  tasks/get   -> working
 6.32 IN  tasks/get   -> working
 9.32 IN  tasks/get   -> working
12.32 IN  tasks/get   -> working
15.32 IN  tasks/get   -> completed, result

ドキュメントでは間隔は 250 ms から 30 秒の範囲に収められ、フィールドがなければ 2 秒です。モデルには、サーバーがタスクを開始し、結果は通知として届くという短いツール結果が渡されます。届いた結果はトランスクリプトではなく Claude に渡ります。Claude が手すきなら自分から拾います。そうでなければ、結果を尋ねるプロンプトをユーザーが入力してください。

Claude Code で MCP Task はどれくらい動き続けられるのか

サーバーがタスクを生かしている限りです。ドキュメントによると、バックグラウンドに移ったタスクには Claude Code 側の時間制限がなく、ttlMs を過ぎても Claude Code はタスクを手放しません。ツール呼び出しの制限が効くのは、サーバーがタスクハンドルを返すまでです。対象は実時間の上限 (デフォルトで約 28 時間) とアイドルタイムアウトで、アイドルタイムアウトはデフォルトで HTTP サーバーが 5 分、stdio が 30 分です。CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT で変更できます。

返信ではこの区別が抜け落ちていました。ある返信はこうです。

a task that sends no progress notification for the idle window gets killed, five minutes for connector servers, thirty for stdio.

これは通常のツール呼び出し、または CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS=0 で Claude に待たせるタスクのルールです。バックグラウンドに移ったタスクにはアイドル制限がありません。

Claude Code が終了または切断したとき、MCP Task はどうなるのか

リモートサーバー上のタスクは動き続け、サーバーに停止を求めるものは何もありません。ドキュメントによると、tasks/cancel が送られるのは、サーバーが接続している間に Claude かユーザーがタスクを止めたときで、終了時には送られません (「not sent on exit」)。終了ダイアログがそのタスクを停止対象として表示していても同じです。しかもキャンセルは依頼にすぎません。拡張はキャンセルを協調的なものとして定めているので、サーバーは作業を最後まで続けてもかまいません。

あとで結果を受け取るには、サーバーの名前と設定を変えずに、同じセッションを対話モードで再開します。新しいセッション、--fork-session、単発の claude -p --resume では古いタスクを追えません。ここで stdio は落とし穴になります。サーバーは Claude Code の子プロセスなので終了と一緒に消えますが、/tasks はそのジョブに「survives exiting this session」と表示します。

サーバーが ID を忘れると、Claude Code は 5 分間問い合わせを続けたあと結果を不明として報告します。ドキュメントは、もう一度呼び出すと作業が繰り返される可能性があると警告しています。ビルドの繰り返しなら数分の損で済みますが、リサーチジョブや外部へのメッセージの繰り返しは、費用が二重にかかる重複です。

夜中にタスクから来た MCP elicitation には誰が答えるのか

誰も答えません。しかも無人の 2 つのモードでは失敗の仕方が違います。テストサーバーに、数秒後に input_required に切り替わり、inputRequests で 2 つのことを尋ねるツールを用意しました。フォームの elicitation (「Include unpublished drafts in the report?」) と roots/list です。

stream-json の claude -p 実行では、input_required を返したポーリングの直後に tasks/cancel リクエストが来ました。ログ上では両方とも同じ 9.57 秒のタイムスタンプです。ドキュメントによると、この場合 Claude Code はユーザーの Elicitation フックも SDK の onElicitation コールバックも実行しません。ほかの場面なら elicitation に自動で答えられるフックも、ヘッドレスのタスクは救えないということです。モデルには、タスクが「asked the user a question that this session cannot show yet」と伝えられ、モデルは失敗を報告しました。

デタッチした tmux ペインの対話セッションでは、フォームが表示されて待ち状態になりました。フォームが開いている間、Claude Code はポーリングを止めていました。8.80 秒から、回答した 48.78 秒まで tasks/get は 1 回もありません。サーバーから見ると、いない人を待っているタスクは、黙り込んだクライアントと区別がつきません。クライアント側では claude agents --json がセッションを waiting、"waitingFor": "input needed" と報告しました。tmux から Claude Code を操作する場合のように、これはオーケストレーターが人に回せるシグナルです。

フォームで承認すると、1 回の tasks/update にフォームと roots の両方の回答が入っていました。Claude Code はフォームの回答をそのままサーバーに送っています。あとで結果について尋ねると、Claude は「never saw the question」「didn't answer it」と答えました。何に同意したのかを Claude が知っていたのは、テストサーバーが結果の中で回答をそのまま返していたからにすぎません。

フォームモードには、繰り返しておく価値のあるルールがもう 1 つあります。ドキュメントは例として「a username and password prompt」を挙げていますが、MCP の elicitation 仕様は、サーバーは「MUST NOT use form mode elicitation to request sensitive information such as passwords, API keys, access tokens, or payment credentials」とし、それらには URL モードを使うよう求めています。Claude Code の URL モードはリンクをシステムの URL ハンドラーに渡し、ドキュメントによると上限は約 8,000 文字、URL の大半がパーセントエスケープなら 4,000 文字程度です。

Claude Code 向けの MCP サーバーに MCP Tasks を実装するには

拡張を宣言し、リクエストが求めたときだけタスクハンドルを返し、タスク ID にはどの接続からでも答えられるようにしておきます。サーバーは server/discover の capabilities で extensions に io.modelcontextprotocol/tasks を載せます。リビジョン 2026-07-28 では各リクエストが _meta にクライアントの capabilities を持ち、タスクになりうる tools/call には同じ拡張が含まれます。ドキュメントによると、拡張を含まない呼び出しにタスクを返すと、Claude には Unsupported result type 'task' for tools/call が返ります。

ハンドルは tools/call の JSON-RPC の結果です。ドキュメントのサーバー作者向けセクションから引用します。

json
{
  "resultType": "task",
  "taskId": "build-7f3a9c2e",
  "status": "working",
  "statusMessage": "Compiling, 40 of 212 files done",
  "createdAt": "2026-10-22T14:03:07Z",
  "lastUpdatedAt": "2026-10-22T14:03:07Z",
  "ttlMs": null,
  "pollIntervalMs": 5000
}

その後、tasks/get は "resultType": "complete" と、ハンドルと同じ必須フィールドを返し、completed なら result、failed なら error を付けます。tasks/update は回答を、tasks/cancel は停止の要求を受け取ります。tasks/result、tasks/list、notifications/tasks は Claude Code では無視されます。HTTP サーバーでは、リクエストごとのタイマー (60 秒、サーバーのツールタイムアウト、MCP_TIMEOUT のうち最大の値) 以内にハンドルを返し、それから作業に取りかかります。

Tasks がサーバーに求めるのは、消えない ID です。リビジョン 2026-07-28 でプロトコルのセッションは廃止され、呼び出しをまたぐ状態が必要なサーバーは自分でハンドルを発行します。API カタログと比較した読み取り専用の MCP エンドポイントのようなステートレスなサーバーは、1 回のリクエストより長く残るストレージなしには Tasks を提供できません。

MCP Tasks は長いジョブのライフサイクルをサーバー作者に渡す

4 つの挙動を並べてみます。呼び出しがバックグラウンドに移ると、Claude Code は時間を計らなくなります。終了時にキャンセルしません。質問が開いている間はポーリングを止めます。そしてターミナルに誰もいなければ、人に尋ねる代わりにサーバーにキャンセルを求めます。これが設計どおりなのか、パブリックベータの現状なのかはわかりません。いずれにしても、今の時点での結論は同じです。ジョブの期限、後片付け、重複の責任はサーバー作者にあり、しかもそのツールは多くの場合、クライアントが見張ってくれる前提で書かれています。

だから今週やるべきことはサーバー側にあります。input_required には独自のタイムアウトを設けてください。テストではフォームが開いている間ずっとクライアントが沈黙し、夜中のフォームは一晩中開いたままになるからです。ツールを 2 回呼ばれても安全にするか、状態確認用のツールを用意してください。「outcome unknown」は再試行を誘います。質問することになりそうな内容は、先にツールの引数として受け取っておいてください。ヘッドレスの呼び出し元は待たずにタスクを終わらせるからです。そしてシークレットはフォームに入れないことです。

テストで頭に残っている光景は tmux ペインです。読む人のいないフォームが開いたままで、3 秒ごとにクライアントから連絡を受けていたサーバーには、もう何も届かない。遅い人間といない人間を、サーバーは見分けられません。

01 / ディスカッション

コメント欄はありません。議論は X で行っています。

Max Nardit@mnardit

02 / ほかの記事

  1. Claude アプリで auto mode が標準に: チェックが止めるもの、89% の調査が測ったもの

    Anthropic の調査は、その設計については正直です。疲れたテスターに、仕込んだ危険なコマンドを 1 つ見せただけです。誤検知率も実運用での見逃し率も示しておらず、クラウドセッションには戻る先の Manual モードがありません。

  2. Claude Code の料金 2026:同じ作業に Pro、Max、API はいくら請求するか

    プランの料金は定額で、トークン単価も公開されています。そのため比較はただの計算に見えますが、そう単純ではありません。Claude Code は支払い方によって会話のキャッシュの仕方を変えます。そしてサブスクリプションの利用量をドル換算するのに多くの人が使うツールは、実際に使っていたキャッシュで計算するため、乗り換えた後に使うことになるキャッシュの料金は出てきません。

  3. Claude Code のフック:誘導には強く、関門としては弱い

    フックはモデルが同意するかどうかに関係なく実行されます。そのためフォーマットのような雑用や、エージェントを望むルートへ誘導する用途には向いています。関門としては見た目より弱く、指定したツールしか検査せず、チェック自体が壊れるとブロックを明示的に有効にしない限り呼び出しは通り、構成によっては、フックがブロックした呼び出しを mod が承認できてしまいます。