Skip to content

URL elicitation: error path handling + replace accept-on-open with explicit completion  #1415

Description

@cliffhall

Follow-up from review of #1411.

Problem

In PendingClientRequestModal's URL-elicitation body, clicking Open in Browser fires onRespond({ action: "accept" }) synchronously the moment window.open(...) returns — see ElicitationUrlModalBody in clients/web/src/components/groups/PendingClientRequestModal/PendingClientRequestModal.tsx.

The inspector cannot observe completion of an external flow, so this is optimistic: the user may close the tab without finishing, yet the originating tool call has already been told the elicitation was accepted. That commits a claim that may not have happened.

Proposal

Adopt the two-step flow the ElicitationUrlPanel is already stubbed for (it has an isWaiting prop and a "Waiting for completion..." state, currently hardcoded isWaiting={false}):

  1. Open in Browser opens the URL and transitions the panel to the waiting state (no response sent yet).
  2. A revealed "I've completed it" action sends { action: "accept" }; Cancel sends { action: "cancel" }; optionally a Decline sends { action: "decline" }.

Acceptance criteria

  • Opening the URL does not by itself resolve the elicitation.
  • The user explicitly confirms completion to send accept.
  • ElicitationUrlPanel's isWaiting state is wired (no longer hardcoded false).
  • Tests cover open → waiting → complete and open → cancel.

Notes

A code comment documenting the current accept-on-open semantic was added in #1411 and points here; remove it when this lands.


Additional requirement: error-path URL elicitation (-32042)

Beyond the request-path flow above (server sends an elicitation/create request with mode: "url"), the spec defines a second delivery mechanism — the "URL mode with elicitation required error" flow (spec, 2025-11-25). A tools/call can come back as a JSON-RPC error -32042 (URLElicitationRequiredError) carrying the URL elicitations the user must complete before the call can succeed:

{
  "error": {
    "code": -32042,
    "message": "This request requires browser-based authorization.",
    "data": { "elicitations": [
      { "mode": "url", "url": "https://…", "message": "", "elicitationId": "" }
    ]}
  }
}

Today this surfaces as a generic failed tool call and the elicitations payload is discarded — no URL modal appears. The inspector should handle it:

  1. Detect the -32042 error on a tools/call (the SDK yields a typed UrlElicitationRequiredError, or a generic McpError with code -32042).
  2. Surface each carried URL elicitation in order, reusing the same modal + two-step "Open → I've completed it" UI as the request path.
  3. Once all are accepted, retry the original tools/call (the listed elicitations are the prerequisites for it to succeed). Decline/cancel aborts the call with a clear message.
  4. Loop guard: if a retry's error re-requests a URL the user already completed during the same call, completing it again can't make progress — abort with a toast naming the repeated URL instead of re-prompting (an endless loop otherwise).
  5. Non-spec no-list case: a -32042 with an empty/absent elicitations list has nothing to open — surface a short toast linking to a modal with the raw error body, rather than a bare error.

Acceptance criteria (error path)

  • A tools/call returning -32042 surfaces its URL elicitation(s) in the modal instead of a bare error.
  • Elicitations are processed in order; the original call is retried only after all are accepted.
  • Decline/cancel of a required elicitation aborts the call with a clear reason.
  • A repeated URL (already completed this call) aborts with a "same URL" toast rather than looping; the retry count is bounded.
  • A -32042 with no elicitations surfaces a toast + raw-error modal.
  • The optional notifications/elicitation/complete notification can auto-advance/auto-accept an open URL elicitation.
  • Tests cover: error → surface → retry-on-accept, multi-elicitation ordering, cancel-aborts, repeated-URL loop abort, and the no-list case.

Metadata

Metadata

Assignees

Labels

v2Issues and PRs for v2

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions