Claude Media
MCP elicitationが自動辞退される不具合 — VS Code拡張の現状

MCP elicitationが自動辞退される不具合 — VS Code拡張の現状

VS Code拡張の対話セッションで、MCPのelicitationがダイアログなしで辞退される報告です。症状、サーバー作者の回避策、利用者側の切り分けをまとめます。

Claude CodeのVS Code拡張で、MCPサーバーが送ったelicitationの要求が、ダイアログを出さないまま辞退として返される報告があります。claude-codeのissue #98256に寄せられた内容で、ログには「print mode」という文字列が残ります。同じセッションで許可プロンプトは表示されるのに、elicitationだけが通りません。

この記事は、報告された症状、サーバー作者が取れる回避策、利用者が手元で切り分ける手順をまとめたものです。issueは10月10日時点でopenで、報告のあったバージョンはv2.1.284とv2.1.285です。

何が起きているのか

elicitationは、MCPサーバーがツール実行の途中でユーザーに追加入力を求める仕組みです。通常はClaude Codeが対話ダイアログを出し、ユーザーの応答をサーバーへ返します。仕組みの詳細はMCPのElicitation、フォームとURLで何が違うかにあります。

issueの報告では、次の3点が同時に起きています。

  • サーバーがelicitationのformモードで要求を送る
  • ダイアログは一度も表示されず、ツールは非acceptの結果で即座に戻る
  • MCPログにElicitation request received in print modeという行が残る

同じセッションで、ツールの許可プロンプトやAskUserQuestionのダイアログは表示されています。対話はできる状態なのに、elicitationの経路だけが非対話の分岐に入っている、というのが報告者の見立てです。

症状

報告された症状の要点

  • 対象

    VS Code拡張の対話セッションで、MCPのelicitationが辞退される。

  • 見え方

    UIは出ず、サーバーには通常の辞退と同じ形で結果が返る。

  • 手がかり

    MCPログのElicitation request received in print mode。

報告された環境と、辞退までの時間

issueには2人の環境が載っています。原報告はmacOSとAWS Bedrockの組み合わせで、後からの追加報告はLinux上のVS Code RemoteとファーストパーティのAnthropic APIです。プラットフォームが違っても同じ挙動だった点が、この報告の重みになっています。

項目原報告追加報告
Claude Code / 拡張原報告v2.1.284追加報告v2.1.285
OS原報告macOS追加報告linux-arm64(VS Code Remote)
接続先原報告AWS Bedrock追加報告Anthropic API
要求の形原報告form(ctx.elicit)追加報告form(boolean項目1つ)
ダイアログ原報告出ない追加報告出ない

追加報告には、要求を受けてから辞退を返すまでの時間が4回分載っています。44ミリ秒、7ミリ秒、8ミリ秒、8ミリ秒です。人がダイアログを読んでボタンを押す速さではありません。メッセージ長を約900字から約2,900字まで変えても結果は同じでした。

もう一つ興味深い記述があります。約1秒後にNotificationフックのelicitation_responseが発火していたそうです。応答イベント自体はクライアントから出ているのに、ユーザーには尋ねていない、という状態です。

サーバーから見ると、本物の辞退と区別できない

原報告の核心は、capabilityを宣言していることです。サーバー側のSDKでクライアント能力を確認すると、elicitationは使えると返ります。ctx.elicit(...)も例外を投げず、ふつうの非accept結果を返します。

つまり「宣言があれば人間がダイアログを見る」という前提が崩れます。破壊的な操作を「ダイアログを出して、acceptなら実行、declineなら中止」の2段階で作ったサーバーは、行き止まりになります。Claude Desktopのようにダイアログを出すクライアントでは動くのに、Claude Codeではどうしても実行できません。

報告者は自分のサーバーを、declineを「辞退された、または使えない」とみなして確認トークン方式にフォールバックするよう直したそうです。ただし、この対処は他のクライアントでの本物の辞退の意味を弱めます。

他のクライアントでは同じ要求が通っている

別のコメントで、MCPプロキシのmay-iを使った対照実験が報告されています。同じプロキシ、同じポリシー、同じラップ対象のサーバー(@modelcontextprotocol/server-filesystem)をCursorから使うと、elicitationのダイアログが表示され、約1.8秒後にacceptが返りました。人がクリックする時間です。

この結果から、サーバーの実装やフォームのスキーマに原因があるとは考えにくくなります。同じ形式の要求が、あるクライアントでは処理され、VS Code拡張では辞退されているからです。

ドキュメントの記述との食い違い

Claude Codeのドキュメントは、elicitationのダイアログは「サーバーが要求したときに自動で表示される」と書いています。設定は不要です。ダイアログを出さずに応答させたい場合はElicitationフックを使う、という案内もあります。

一方、非対話実行の説明では、--permission-prompts noneを付けたclaude -pでは、Elicitationフックが答えなかったelicitationはキャンセルされると書かれています。この場合に返るのはcancelです。issueで観測されているのはdecline相当の結果なので、-pの仕様をそのまま当てはめた説明にはなりません。報告者が混乱の原因として指しているのは、対話セッションなのに非対話の分岐へ入っている点です。

サーバー作者向けの回避策

issueのコメントに出ている考え方は3つあります。

  1. capabilityの宣言だけで、人間に届くと決めつけない
  2. 辞退が人間の操作として不自然に速く返ったときは「使えない」と扱い、別の確認経路へ移る
  3. 破壊的な確認は、ホスト側のネイティブな許可プロンプトに任せる

2番目の実例が、may-iが採っている方式です。辞退またはキャンセルが250ミリ秒未満(既定値)で返ってきたら「クライアントは尋ねられない」と判断して、端末のプロンプトに切り替えます。許可側へのフォールバックは行いません。

# 疑似コード: 辞退が速すぎるときは「確認できなかった」とみなす
t0 = time.monotonic()
result = await ctx.elicit(message="本当に削除しますか", schema=Confirm)
elapsed = time.monotonic() - t0
 
if result.action == "accept":
    proceed()
elif elapsed < 0.25:
    # 人間が押せる速さではない。許可はせず、別の確認経路へ
    require_confirmation_token()
else:
    abort("ユーザーが辞退しました")

ただし、これは経験則であって解決策ではありません。コメント内でも、別の報告(rmcp)では約400ミリ秒かかった例があり、250ミリ秒の閾値をすり抜けることが指摘されています。追加報告の7〜44ミリ秒とも合わせると、時間で判定する方式は環境によって外れます。

根本的な解決として挙がっているのは、2つの案です。VS Code拡張でUIを出せないなら能力を宣言しない。あるいはelicitation/createを、許可プロンプトやAskUserQuestionと同じ対話経路につなぐ。どちらも、クライアント側の修正が必要です。

利用者が手元で切り分ける手順

自分の環境で同じ現象かどうかは、MCPのログで確かめられます。ログの場所は、issueによるとmacOSでは~/Library/Caches/claude-cli-nodejs/<project>/mcp-logs-<server>/以下、Linuxでは~/.cache/claude-cli-nodejs/<project>/mcp-logs-<server>/以下です。

# macOS: print mode で辞退されたログ行を探す
grep -l "Elicitation request received in print mode" \
  ~/Library/Caches/claude-cli-nodejs/*/mcp-logs-*/*.jsonl
 
# Linux
grep -l "Elicitation request received in print mode" \
  ~/.cache/claude-cli-nodejs/*/mcp-logs-*/*.jsonl

該当する行があり、その時刻にダイアログが出ていなければ、報告と同じ症状です。Elicitationフックで要求の内容を記録しておくと、サーバー名・モード・スキーマも残せます。フックの設定はElicitation/ElicitationResultフックでMCP入力要求を横取りする、フック全般はClaude Code Hooks完全ガイドにあります。

{
  "hooks": {
    "Elicitation": [
      {
        "hooks": [{ "type": "command", "command": "~/.claude/hooks/log-elicitation.sh" }]
      }
    ]
  }
}

スクリプトは入力を読んでファイルへ追記し、exit 0で終えるだけの記録専用にします。応答を返さなければ、通常のダイアログに処理が渡ります。

フックの扱いには注意があります。issueには、辞退の分岐に入る前にフックが発火するかどうかの記述がありません。ドキュメントでは、Elicitationフックが答えるとダイアログは表示されず、デバッグログにElicitation resolved by hookという行が残ると説明されています。claude --debugで起動して、この行が出るかどうかを見れば、フックが経路の手前に入れているかが分かります。

フックでacceptを自動返答する方法は、確認の目的を損ないます。破壊的操作の確認を、人間の代わりにスクリプトが承諾するからです。フォームに入れるのが機械的な値(プロジェクトキーなど)に限られる場合だけ、現実的な選択肢になります。

修正の状況

issueはopenのままで、最後のコメントは10月1日です。そのコメントは、10件以上のupvoteか14日以内のコメントがないと自動でcloseされる、というstale botの注意書きでした。元のissue #79174は、botによって誤ってcloseされたものだと原報告に書かれています。

Claude Codeのchangelogは、10月8日付のv2.1.295まで公開されています。そこにelicitationの辞退に関する修正の項目はありません。したがって、アップデートで直ったかどうかを自分のログで確かめる運用になります。

影響を受けるのは誰か

影響が出るのは、次の条件が重なる構成です。

  • VS Code拡張からClaude Codeを使っている
  • MCPサーバーがelicitationを確認手段に使っている
  • 辞退を「ユーザーが断った」と解釈して中止する実装になっている

elicitationを使わないMCPサーバーや、ターミナルでCLIを直接使う運用には、報告された範囲では当てはまりません。ただしissueにはCLIとの比較結果がないため、CLIで同じ要求が通るかは、自分の環境で試すのが確実です。

自作のMCPサーバーで確認フローを組むなら、辞退だけを中止の根拠にしない設計が現実的です。確認トークンのように、elicitationが使えなくても完結する経路を用意しておけば、クライアントが修正された後もそのまま動きます。

まとめ

VS Code拡張でのMCP elicitationの自動辞退は、2人の報告で再現条件が揃い、他のクライアントとの対照も取られています。サーバーからは本物の辞退と見分けがつかないため、確認フローを作る側が先に備える必要があります。利用者側は、MCPログのprint modeの行で自分の環境の症状を切り分けられます。

VS Code拡張の基本的な使い方はClaude Code VS Code拡張機能の使い方にまとめています。

この記事を共有:XはてブLinkedIn