[BUG] MCP elicitation: capability is declared but requests are auto-declined ("print mode") in interactive VSCode sessions

Status Open
Reported on v2.1.284
Maintainer reply None cached
Activity 6 comments · opened Sep 29, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

In an interactive VSCode-extension session, Claude Code declares the MCP elicitation capability during initialize, but auto-declines every elicitation/create request without showing any UI. The same session can render permission prompts and AskUserQuestion option dialogs, so it is clearly capable of interactive prompting — only the MCP elicitation path is unwired and silently rejected.

Because the capability is declared, servers cannot detect the situation:

  • ServerSession.check_client_capability(ClientCapabilities(elicitation=...)) returns true
  • ctx.elicit(...) does not raise; it returns a normal non-accept result
  • From the server's perspective this is indistinguishable from a human explicitly declining the dialog

What Should Happen?

Any MCP server that implements a two-phase destructive operation ("show dialog → proceed on accept, abort on decline") dead-ends: the auto-decline is interpreted as a user cancellation, and the operation becomes impossible from Claude Code while working fine from elicitation-capable clients (e.g. Claude Desktop). We had to patch our server to treat decline as "declined or unavailable" and fall back to a confirmation-token flow, which weakens the semantics of a real user decline for every other client.

Error Messages/Logs

Steps to Reproduce

  1. Minimal Python MCP stdio server (FastMCP / mcp SDK) with a tool that calls ctx.elicit(message=..., schema=...).
  2. Register it in .mcp.json, run a Claude Code session from the VSCode extension.
  3. Ask Claude to call the tool.
  4. The tool returns immediately with a non-accept elicitation result; no dialog is shown.

MCP log (~/Library/Caches/claude-cli-nodejs/<project>/mcp-logs-<server>/*.jsonl):

{"debug":"Elicitation request received in print mode: {\"method\":\"elicitation/create\",\"params\":{\"mode\":\"form\", ... }}", ...}

Note the log says "print mode" even though the session is interactive (permission prompts and AskUserQuestion render fine in the very same session).

Claude Model

Opus

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

claude: 2.1.284, vscode extension: 2.1.284

Platform

AWS Bedrock

Operating System

macOS

Terminal/Shell

VS Code integrated terminal

Additional Information

The original issue was erroneously closed by bot: https://github.com/anthropics/claude-code/issues/79174

View original on GitHub ↗

3 Comments

stonianua · 15 days ago

Peer note — elicitation declared but declined as print mode

Thanks for the clear repro and the MCP log line (Elicitation request received in print mode while the same VS Code session still shows permission prompts / AskUserQuestion). That mismatch is the useful signal.

What the log implies

Claude Code’s MCP client is advertising elicitation in initialize (so check_client_capability is true), but the elicitation handler path is still taking the non-interactive / print-mode branch and auto-declining elicitation/create with a normal non-accept result. From the server’s side that is indistinguishable from a human clicking Decline — which is why a two-phase “elicit → proceed” tool dead-ends, and why patching the server to treat decline as “declined or unavailable” weakens real declines for other clients.

Narrow workarounds while the handler is unwired

  1. Do not gate solely on the capability flag. Treat a decline that arrives with no UI / sub-second latency (or with a known print-mode log) as unavailable, and only treat an explicit user decline as cancel — if your SDK exposes any timing/metadata. If it does not, keep a separate confirmation-token (or “type YES”) path for Claude Code until elicitation UI exists.
  2. Prefer tools that use Claude Code’s native prompts for destructive confirmations in this host (permission prompts / AskUserQuestion), and reserve MCP elicitation for clients that actually surface the dialog (e.g. Claude Desktop).
  3. Capture one MCP log line + session kind (VS Code extension vs CLI -p / print) in the report — your log already shows the print-mode branch firing in an interactive extension session, which is the bug to fix on the host side.

What would fix it for server authors

  • Either omit the elicitation capability when the session cannot show UI, or wire elicitation/create to the same interactive prompt path used by AskUserQuestion / permissions in the VS Code extension.
  • Until then, servers cannot safely use “capability advertised ⇒ human will see a dialog.”

No product pitch — just aligning the capability advertisement with the handler so MCP servers can branch correctly.

abhinavallani02-cyber · 15 days ago

Adding a control comparison, which might help pin this on the client.

I maintain may-i, an MCP proxy that gates tool calls behind a human approval sent as elicitation/create (form mode). I ran the same proxy, policy, and wrapped server (@modelcontextprotocol/server-filesystem) with Cursor as the MCP client:

  • Cursor declares elicitation at initialize, and may-i logs elicitation: supported (form).
  • A write_file that hits an ask rule sends elicitation/create. Cursor shows the approval dialog, and the accept comes back about 1.8s later, which is human click time. The audit entry is {"tool":"write_file","verdict":"ask→approved"}.

So the server side and the form schema are fine, and another client handles the identical request correctly. The same request is what gets auto-declined with no UI in the VS Code extension, per the "print mode" log in the original report.

A workaround for other server authors until this is fixed: may-i treats a decline or cancel that arrives faster than a person could click (under 250ms by default) as "client can't ask" and falls back to a terminal prompt. It never falls back to allow (code). That's a heuristic, not a fix. The rmcp report on #79174 measured about 400ms in a headless setup, which would slip past a 250ms threshold. Option 3 from the original report, a distinguishable "not supported" response instead of a synthetic decline, would let servers handle this properly.

tod-uma · 14 days ago

Same behaviour here on a newer build and a different platform, in case that helps narrow it down.

Environment

  • Claude Code CLI 2.1.285, VS Code extension 2.1.285 (linux-arm64, VS Code Remote)
  • First-party Anthropic API (not Bedrock)
  • Python stdio MCP server, negotiated protocol 2026-07-28

What happens

The tool calls a form-mode elicitation/create with a single boolean field:

{"type": "object", "properties": {"confirm": {"type": "boolean", "title": "Confirm", "default": false}}}

In the same interactive session, the normal tool-permission prompt shows up and I approve it (the extension log shows tool_permission_response → behavior: "allow"). Then the elicitation arrives and gets declined without any UI. The webview never sends or receives an elicitation message. I got the same result 4 times in a row, with and without expanding the permission prompt's details, and with message lengths from ~900 to ~2,900 characters:

| Elicitation received → decline returned |
|---|
| 44 ms |
| 7 ms |
| 8 ms |
| 8 ms |

MCP log (~/.cache/claude-cli-nodejs/<project>/mcp-logs-<server>/*.jsonl), trimmed:

[DEBUG] Calling MCP tool: <tool>
[DEBUG] Elicitation request received in print mode: {"method":"elicitation/create","params":{"mode":"form","message":"<redacted>","requestedSchema":{...}}}
[ERROR] Error executing tool <tool>: ... elicitation was decline

About 1 s later, a Notification:elicitation_response hook fires, so the client does emit a response event. It just never asks the user.

The client-side log doesn't record the capabilities the client advertised, so I can't confirm that part myself. But the server did go ahead and send elicitation/create, and all it got back was an ordinary decline, which it can't tell apart from a real one.

---

AI-assistant disclaimer: Drafted by Claude Code (Claude Opus 5.5, claude-opus-5-5) from a conversation with me. May contain inaccuracies or hallucinated details; verify specifics against current sources before relying on them.

Showing cached comments. Read the full discussion on GitHub ↗