/** * `replay_request` — validate a drafted recipe before proving: confirm its * selectors extract the target(s), and (with `withoutSecrets`) that the * endpoint is auth-bound. Authored once as a plain {@link RegisteredTool}; the * backend does the actual replay (MCP re-runs locally, cloud re-issues in the * TEE pod). */ import { objectSchema, type ResolveBackend } from '../../../authoring/util.ts' import { defineTool, type RegisteredTool } from '../../../tools/registry.ts' export function replayTool(resolveBackend: ResolveBackend): RegisteredTool { return defineTool>( { name: 'replay_request', description: 'Validate the drafted recipe before proving — confirm its selectors ' + 'extract the target value. Returns diagnostics; run before ' + 'proving. Set `withoutSecrets: true` for the AUTH-BOUND check: it ' + 're-issues the request with NO secrets/cookies (an anonymous ' + 'visitor). If the values still extract (valid:true), the endpoint ' + 'is PUBLIC and the proof would not bind to the user — reject it ' + 'and find an auth-bound request instead.', inputSchema: objectSchema( { draftId: { type: 'string' }, withoutSecrets: { type: 'boolean' }, }, ['draftId'], ), }, async(args) => { const backend = resolveBackend(args) const draft = backend.drafts.get(String(args.draftId)) if(!draft) { throw new Error(`no draft ${String(args.draftId)}`) } return backend.replay(draft, { withoutSecrets: Boolean(args.withoutSecrets), }) }, ) }