4. A denied approval
This is a protocol event, not a user-interface convention
In MCP 2026-07-28 the server does not call the client.
Server-initiated requests were replaced by Multi Round-Trip Requests
(SEP-2322): the server returns a result whose
resultType is "input_required", carrying an
inputRequests map and an opaque requestState. The client then
re-issues the original request, with a new JSON-RPC id,
carrying inputResponses. Both round trips are in the traces below with
their two different mcp.request.id values.
The same mid-flight-input pattern is carried by the official
Tasks extension (io.modelcontextprotocol/tasks), which
moved out of core in this revision: there the pause is against a durable handle that
survives a dropped connection, polled with tasks/get and answered with
tasks/update. This demonstration implements the in-core MRTR mechanism and
not the Tasks extension; the compliance list on the contracts screen says so.
Two host-side rules make the gate mean something. The approval is bound
to a fingerprint of the exact arguments, so changing the part number or the quantity
after approval invalidates it — possession of a requestState is not
authorisation, it is a name. And a denial is returned as a tool execution error, so the
planner sees it, cannot mistake it for a transient failure, and has an explicit
instruction not to work around it.
Denied
Granted, for comparison
pipeline/agent.py injects an explicit host instruction and the
authority matrix still refuses the second attempt, which is the only version of this
that survives a planner that wants to be helpful.
Demo4/pipeline/.