The MRTR mechanic is the part I'd want a strong opinion on before wiring anything real behind it. If the server already did something before returning input_required -- reserved a slot, hit a paid API, written a provisional record -- then retrying the whole request with a new ID after the client gathers input means the server has to treat "reconstitute from requestState" as authoritative for what already happened, not just for what's still needed. That's fine when the tool is stateless up to the input gate, but it looks like a real footgun for anything where the first pass causes a side effect before it can know it needs input. Does the spec say anything about idempotency keys for that case, or is it left entirely to the tool author?
Mihai_LeanZero
Atlassian consultant and Forge developer at LeanZero. We do Data Center to Cloud migrations and build Forge apps, and I write up what I learn at leanzero.net.
Good catch Mihai_LeanZero . I went back through the MRTR spec, and it doesn't give you a built-in idempotency key for this.
The spec does give you replay protection around requestState: bind it to the authenticated principal, give it a short TTL, and tie it to the originating request. But it explicitly says that still doesn't guarantee single use. If you need exactly-once behavior, the server has to enforce that itself.
There's another edge case too: the client isn't required to retry after input_required. So if the first pass already reserves something or calls a paid API, you can end up with either a duplicate on retry or an orphan if the retry never happens.
I'd keep the first pass side-effect free where possible. If that's not possible, create a short-lived reservation/idempotency ID, carry it through requestState, and have the retry reconcile against that reservation instead of performing the action again.
And yeah, idempotentHint doesn't solve this. It's useful metadata, but it's still only a hint, not an enforcement mechanism.
Good to have that confirmed against the actual spec text rather than guessed. The orphan case is the one I hadn't considered — I was assuming a client that gives up mid-gather just leaves a stale reservation sitting there, but you're right that the spec doesn't obligate the client to retry at all, so "the retry never happens" is a real outcome, not an edge case. That pushes the reservation/idempotency ID you're describing toward needing its own TTL and cleanup independent of the request's own lifecycle, otherwise a tool author gets reservations that outlive any client that could ever reconcile them.
The MRTR mechanic is the part I'd want a strong opinion on before wiring anything real behind it. If the server already did something before returning input_required -- reserved a slot, hit a paid API, written a provisional record -- then retrying the whole request with a new ID after the client gathers input means the server has to treat "reconstitute from requestState" as authoritative for what already happened, not just for what's still needed. That's fine when the tool is stateless up to the input gate, but it looks like a real footgun for anything where the first pass causes a side effect before it can know it needs input. Does the spec say anything about idempotency keys for that case, or is it left entirely to the tool author?