/** * @fileoverview Consent gate for tool calls whose side effects reach past the * conversation — a deleted notification, an outbound email, a phone call, an * HTTP request fired from someone's phone. Puts the decision in front of the * user via an MCP multi-round-trip input request instead of trusting a model * that may be working from injected instructions. * @module mcp-server/tools/utils/confirm-action */ import { type ContextInputs, type InputRequiredSpec } from '@cyanheads/mcp-ts-core'; /** * - `confirmed` — the user accepted and the payload said so. * - `declined` — the user declined or cancelled, **or** accepted with a * response that did not parse, **or** answered with a response of another * kind. The payload is model-mediated, so an unreadable `confirm` is not * consent. * * There is no "client cannot be asked" outcome. `ctx.requestInput` is present * on every transport and both protocol eras, so the gate always asks: a * 2026-07-28 client fulfils the request itself, and on a 2025-era session the * SDK's legacy shim issues a real `elicitation/create` round trip. A 2025-era * client that declared no `elicitation.form` capability (a bare * `elicitation: {}` counts as declaring it) is refused inside * `ctx.requestInput`, which throws `InvalidRequest` (-32600) with * `data.reason: 'client_capability_missing'` and a recovery hint naming the * capability — so the call fails before the upstream request goes out. The * gate is fail-closed on every transport, Streamable HTTP included. */ export type ConfirmationOutcome = 'confirmed' | 'declined'; /** The multi-round-trip surface `confirmAction` needs — a handler `ctx` satisfies it. */ interface ConfirmationContext { readonly inputs: ContextInputs; readonly requestInput: (spec: InputRequiredSpec) => never; } /** * Ask the user to confirm `message`, and report what they said. * * The first call unwinds the handler: `ctx.requestInput` throws the signal the * handler factory turns into an `input_required` result, and the client * re-invokes the tool with the same arguments once the user has answered. So * every caller must run this *before* the side effect, and everything above it * in the handler runs again on re-entry — keep that stretch free of side * effects of its own. * * No `requestState` rides the round. The gate's guarantee rests on the client * putting the prompt in front of a person and relaying the answer honestly — * a client willing to break that can fabricate an approval outright, so an * unsigned server-state echo would add ceremony and no protection. */ export declare function confirmAction(ctx: ConfirmationContext, message: string): ConfirmationOutcome; export {}; //# sourceMappingURL=confirm-action.d.ts.map