Confirmations
confirm(), MRTR input_required, ctx.ask, and execute after accept.
Destructive or sensitive tools declare confirmation outside execute.
export default defineTool({
description: "Delete rows matching a query",
input: z.object({ query: z.string() }),
async confirm({ query }) {
const plan = planDelete(query);
return {
message: `Delete ${plan.rows} rows matching ${query}?`,
preview: plan,
};
},
async execute({ query }) {
const plan = planDelete(query);
return result(plan, `Deleted ${plan.rows} rows.`);
},
});MRTR
confirm maps to resultType: "input_required" (MRTR).
- Text-only hosts see
message - UI hosts may render
previewfrom the MRTRstructuredContent executeruns once, after accept- The mutation does not run on the first call and does not replay
ctx.ask
For mid-flight fields, use a continuation inside execute:
async execute(input, ctx) {
const { note } = await ctx.ask(z.object({
note: z.string().describe("Why are you deleting these rows?"),
}));
return applyDelete(input.query, note);
}ctx.ask re-enters execute on a new request with inputResponses. Do not mutate before ask.
Prefer confirm for yes/no gates. Raw ctx.inputRequired remains an escape hatch.
Never View-only
A View must not be the only confirm path for a side effect. MRTR works in terminal hosts. Views can show previews, not replace the gate.