Summary
Retire the in-band preview → confirm/apply double-confirm pattern on write tools. Gate mutations the standard MCP way instead: destructiveHint tool annotations + the client's own call-approval flow (with context.elicit() reserved for cases that genuinely need a server-driven confirmation step). Execute the write on the first call and return the result immediately.
Why
Using the double-confirm pattern in practice causes recurring friction:
- It's not what agents are used to. Most MCP servers don't gate writes behind a
preview/confirm argument, so agents don't reliably drive the two-step handshake — they call once, get a preview, and either stop or re-call inconsistently.
- The agent doesn't get the result right away. The first call withholds the actual outcome (it returns a preview), forcing a second round-trip. That extra hop is where a lot of the inconsistency and "did it actually apply?" confusion comes from.
- It creates duplicate/ambiguous confirmation paths. We've already hit concrete bugs from this — e.g. card-button apply vs. agent-chat confirmation diverging, and agents re-running preview after an apply already succeeded.
This is the same cleanup just done in xpo-fitness-member-mcp: booking tools now execute immediately, gated only by destructiveHint + client approval, with the confirm arg removed. It's noticeably smoother in practice.
Proposed direction
- Remove the
preview/confirm parameter as a gate from write tools; have them apply directly and return the applied result.
- Rely on
destructiveHint (+ idempotentHint/readOnlyHint as appropriate) so clients prompt for approval before the call.
- Where a genuine server-side confirmation or quote is truly needed, use
context.elicit() rather than a stateful two-call handshake.
- If a preview/quote is still valuable for some tools, keep it as an explicit, optional read-only affordance (e.g. a separate dry-run/quote) — not a mandatory gate in front of every mutation.
Related / prior art
Scope note
This is a design/behavior change across all write tools and their Prefab UI cards; worth confirming the migration path (and whether any tool legitimately needs elicit()) before ripping the pattern out wholesale.
Summary
Retire the in-band preview → confirm/apply double-confirm pattern on write tools. Gate mutations the standard MCP way instead:
destructiveHinttool annotations + the client's own call-approval flow (withcontext.elicit()reserved for cases that genuinely need a server-driven confirmation step). Execute the write on the first call and return the result immediately.Why
Using the double-confirm pattern in practice causes recurring friction:
preview/confirmargument, so agents don't reliably drive the two-step handshake — they call once, get a preview, and either stop or re-call inconsistently.This is the same cleanup just done in
xpo-fitness-member-mcp: booking tools now execute immediately, gated only bydestructiveHint+ client approval, with theconfirmarg removed. It's noticeably smoother in practice.Proposed direction
preview/confirmparameter as a gate from write tools; have them apply directly and return the applied result.destructiveHint(+idempotentHint/readOnlyHintas appropriate) so clients prompt for approval before the call.context.elicit()rather than a stateful two-call handshake.Related / prior art
context.elicit()vsdestructiveHint) (closed — this revisits that decision with practical evidence)confirm→previewacross write toolsScope note
This is a design/behavior change across all write tools and their Prefab UI cards; worth confirming the migration path (and whether any tool legitimately needs
elicit()) before ripping the pattern out wholesale.