An agent platform handing out OAuth scopes is granting a permission it cannot
recall, cannot bound and cannot attribute to a person. A grant has an expiry, a
ceiling and a named human. When the tools an agent reaches are ones you did not
write, that difference stops being philosophical.
export ROTASCALE_URL="https://rotagrant.internal.example"export ROTASCALE_API_KEY="rsk_..."export ROTASCALE_MCP_TRANSPORT="stdio" # or the HTTP transportrotascale-mcp
Every tool call is authorised before it reaches your handler. A refusal is
returned to the caller as an MCP error carrying the outcome and the reason, not
as a generic failure, so the agent on the other end can tell “not permitted”
from “out of allowance” and stop retrying the second one.
A server exposing ten tools is not one authority. A read tool and a tool that
moves money should not sit behind the same bound, and putting them there is the
mistake this package exists to prevent.Grants resolve per tool. A tool with no grant configured is refused rather than
allowed, which is the correct default and the opposite of what most gateway
software does.
Content returned by an MCP tool is untrusted unless you say otherwise. That is
the right default here more than anywhere: the premise of an open tool ecosystem
is that you did not write the thing on the other end.Where a tool result feeds an action that requires a clean context, gate 5
refuses it and the record names the tool and the step. See
Clean context.