[BUG] URL-mode elicitation broken: client capability dropped from {form,url} to {} (~2.1.108); server elicitation/create mode:"url" rejected with -32602

Resolved 💬 2 comments Opened Jun 19, 2026 by WubbbaLubbbaDubDub Closed Jun 23, 2026

Preflight Checklist

  • [x] I have searched existing issues — this regression is also tracked in #48164. This is a consolidated, root-caused report (minimal repro + likely cause + reference implementation); happy for it to be linked/merged there.
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

Claude Code no longer supports MCP URL-mode elicitation (elicitation/create with mode: "url", per the 2025-11-25 spec). This is a regression in the advertised client capability:

  • v2.1.87 advertised "elicitation": { "form": {}, "url": {} } — but silently answered url-mode requests with {"action":"cancel"} (the URL was never shown to the user).
  • ~v2.1.108 onward narrowed the capability to "elicitation": {}, which per the spec means form-mode only. URL-mode requests now hard-fail with -32602 "Client does not support URL-mode elicitation requests".

Net effect: url-mode elicitation has never worked end-to-end, and the capability is now dropped entirely. This blocks every server-initiated out-of-band flow — OAuth/3LO, credential entry, and human-in-the-loop confirmation.

What Should Happen?

Per the 2025-11-25 spec, Claude Code should:

  1. Advertise "elicitation": { "form": {}, "url": {} } at initialize.
  2. On a mode: "url" elicitation/create, show the user the full URL with consent controls, open it out-of-band (browser), and return accept/decline/cancel accordingly.
  3. Support the URLElicitationRequiredError (-32042) retry path: run the required url-elicitation(s), then retry the original tools/call.

Steps to Reproduce

  1. Save this minimal stdio MCP server as url_elicit_server.py:
#!/usr/bin/env python3
"""Minimal stdio MCP server that sends a URL-mode elicitation after initialize."""
import json, sys

def send(msg):
    sys.stdout.write(json.dumps(msg) + "\n"); sys.stdout.flush()

for line in sys.stdin:
    line = line.strip()
    if not line:
        continue
    msg = json.loads(line)
    method, mid = msg.get("method"), msg.get("id")
    if method == "initialize":
        send({"jsonrpc":"2.0","id":mid,"result":{
            "protocolVersion":"2025-11-25",
            "capabilities":{"tools":{}},
            "serverInfo":{"name":"url-elicit-test","version":"1.0.0"}}})
    elif method == "notifications/initialized":
        send({"jsonrpc":"2.0","id":1,"method":"elicitation/create","params":{
            "mode":"url",
            "elicitationId":"550e8400-e29b-41d4-a716-446655440000",
            "url":"https://example.com/authorize",
            "message":"Please authorize to continue."}})
    elif method == "tools/list":
        send({"jsonrpc":"2.0","id":mid,"result":{"tools":[]}})
    elif "result" in msg or "error" in msg:
        sys.stderr.write("CLIENT RESPONSE: " + json.dumps(msg) + "\n"); sys.stderr.flush()
  1. Register it in ~/.claude.json (use an absolute path):
{ "mcpServers": { "url-elicit-test": { "type": "stdio", "command": "python3", "args": ["/ABS/PATH/url_elicit_server.py"] } } }
  1. Run claude --debug.
  2. Observe in the debug output: (a) the client's initialize capabilities show "elicitation": {} (no url), and (b) the client's response to the server's mode:"url" elicitation/create is -32602 "Client does not support URL-mode elicitation requests". The URL is never shown to the user.

Error Messages/Logs

# Current build — capability advertised at initialize:
{"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{"roots":{},"elicitation":{}}, ... }}

# Client response to the server's mode:"url" elicitation/create:
{"jsonrpc":"2.0","id":1,"error":{"code":-32602,"message":"MCP error -32602: Client does not support URL-mode elicitation requests"}}

# For comparison, v2.1.87 advertised url-mode but silently cancelled (URL never shown):
{"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{"roots":{},"elicitation":{"form":{},"url":{}}},"clientInfo":{"name":"claude-code","version":"2.1.87"}}}
# -> elicitation response: {"result":{"action":"cancel"},"jsonrpc":"2.0","id":1}

Claude Model

Not applicable — transport/capability-layer behavior, independent of the model.

Is this a regression?

Yes — url mode was advertised in 2.1.87 and dropped at ~2.1.108.

Last Working Version

2.1.87 (last version to advertise url; note even there the url flow returned cancel without showing the URL).

Claude Code Version

2.1.108 (where the capability was dropped to {}, per the wire captures in #48164); reported still unresolved on later versions, while the docs continue to advertise the feature.

Platform

Anthropic API (per #48164 — behavior is protocol-level, not platform-specific).

Operating System

macOS (per #48164 — transport-layer; not OS-specific).

Terminal/Shell

N/A — protocol-level (stdio MCP server), independent of the terminal.

Additional Information

Likely root cause (and why a fix is now safe). The {form,url}{} narrowing lines up with older MCP servers crashing on the new capability keys: the Java MCP SDK ≤ 0.17.1 modeled ClientCapabilities.Elicitation as an empty record and threw UnrecognizedPropertyException: Unrecognized field "form" during initialize (see #35389 and open-metadata/OpenMetadata#26454). That was fixed server-side in Java SDK ≥ 0.18.0, so narrowing the client capability to {} is no longer necessary and can be reverted to { "form": {}, "url": {} }.

Reference implementation. VS Code's Copilot MCP client ships url-mode end-to-end and is a close blueprint:

  • capability decl → src/vs/workbench/contrib/mcp/common/mcpServerRequestHandler.ts (elicitation: { form: {}, url: {} })
  • url handling → src/vs/workbench/contrib/mcp/browser/mcpElicitationService.ts (_elicitUrl → opener service)
  • -32042 retry → src/vs/workbench/contrib/mcp/common/mcpServer.ts

Why it matters. URL-mode is the spec-native way to do human-in-the-loop confirmation and out-of-band auth without secrets passing through the client or model context. For MCP gateways/proxies it's required to deliver require-confirmation as a single blocking, resumable step (via -32042) and to drive upstream OAuth/3LO for proxied servers. Recent commenters on #48164 are independently asking for the same.

Docs contradiction. code.claude.com/docs/en/mcp states Claude Code supports url-mode ("opens a browser URL for authentication or approval"), but the client rejects it. Please either implement it or correct the docs.

Related: #48164 (same regression), #35353 (VS Code extension variant), #35389 (Java SDK crash = the trigger).

/cc @localden

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗