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}):
- Open in Browser opens the URL and transitions the panel to the waiting state (no response sent yet).
- A revealed "I've completed it" action sends
{ action: "accept" }; Cancel sends { action: "cancel" }; optionally a Decline sends { action: "decline" }.
Acceptance criteria
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:
- Detect the
-32042 error on a tools/call (the SDK yields a typed UrlElicitationRequiredError, or a generic McpError with code -32042).
- Surface each carried URL elicitation in order, reusing the same modal + two-step "Open → I've completed it" UI as the request path.
- 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.
- 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).
- 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)
Follow-up from review of #1411.
Problem
In
PendingClientRequestModal's URL-elicitation body, clicking Open in Browser firesonRespond({ action: "accept" })synchronously the momentwindow.open(...)returns — seeElicitationUrlModalBodyinclients/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
ElicitationUrlPanelis already stubbed for (it has anisWaitingprop and a "Waiting for completion..." state, currently hardcodedisWaiting={false}):{ action: "accept" }; Cancel sends{ action: "cancel" }; optionally a Decline sends{ action: "decline" }.Acceptance criteria
accept.ElicitationUrlPanel'sisWaitingstate is wired (no longer hardcoded false).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/createrequest withmode: "url"), the spec defines a second delivery mechanism — the "URL mode with elicitation required error" flow (spec, 2025-11-25). Atools/callcan 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
elicitationspayload is discarded — no URL modal appears. The inspector should handle it:-32042error on atools/call(the SDK yields a typedUrlElicitationRequiredError, or a genericMcpErrorwith code-32042).tools/call(the listed elicitations are the prerequisites for it to succeed). Decline/cancel aborts the call with a clear message.-32042with an empty/absentelicitationslist 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)
tools/callreturning-32042surfaces its URL elicitation(s) in the modal instead of a bare error.-32042with no elicitations surfaces a toast + raw-error modal.notifications/elicitation/completenotification can auto-advance/auto-accept an open URL elicitation.