Skip to main content
There are three ways to put CTRLRun in front of a consequential action, and only one of them is an adapter. Most readers need the decorator and should not look for an adapter.

The decorator

Wrap the function that acts. Name the action, name the consequence with effect=, and say who is acting with context. The policy beside your code decides.
ApprovalRequired, ActionDenied, DuplicateEffect and AmbiguousEffect are raised as themselves, before the function body runs. Protect a function is the full guide.

The gateway

No agent changes and no server changes. Point the MCP client at the gateway instead of the tool server, and every tools/call is decided, approved, reserved, executed and recorded like a decorated call. Everything else on the wire is relayed untouched.
Tools become actions named mcp.<alias>.<tool>. A tool call has no decorator to carry its effect template, so the template is declared in the policy, and the gateway prints on the line that starts it every action that has none. Put the gateway in front of MCP is the guide.

Adapters

An adapter exists for one reason: so that a human answers where they already answer. When the policy says approve, the request goes out through LangGraph’s interrupt() or the OpenAI Agents SDK’s tool-approval interruption instead of ApprovalRequired being raised past your graph. The adapter returns the answer; one core provider writes the grant through the same calls ctrlrun approve makes. There is never a second place to say yes. You build the Control with your policy, store, identity provider and authority document, and hand it over. An adapter never constructs one and never supplies a principal. Adapters ship on their own version line, adapters-langgraph-1.0 and never a kernel version, because they break when their framework does. A framework with no human-in-the-loop primitive has nothing for an adapter to reuse and does not need one. The decorator already covers it.

Next