> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stateset.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Gate

> An enforcement boundary for MCP tools — the agent never receives an unguarded mutating tool, and no side effect runs without a verified proof.

Every guardrail that depends on an agent *choosing* to check first eventually
meets an agent that doesn't. The Agent Gate removes the choice: it sits between
the agent and an existing MCP server, and forwards a tool call **only after**
NSR has proved that exact call is authorized and the resulting proof verifies.

The model never receives an unguarded mutating tool in the first place.

<Warning>
  `@stateset/agent-gate` is not published to npm yet. The contract below is
  what it enforces; until the package ships, treat this page as the design you
  are integrating against rather than something you can `npx` today.
</Warning>

## The contract

For every guarded `tools/call`, the gateway:

1. Canonicalizes `{actor, tool, resource, arguments, invocation_id}` and computes a SHA-256 `call_id`.
2. Asks NSR to prove the binary goal `can_execute(actor, call_id)`.
3. Requires `decision == "approved"` **and** a self-contained `verifiable_bundle`.
4. Re-checks that bundle through [`/v1/proofs/verify`](/stateset-nsr-decisions#verify-a-proof-without-trusting-us) and confirms its proof goal is that exact `can_execute(actor, call_id)` obligation.
5. Only then forwards the original, unchanged arguments upstream.
6. Attaches a `com.stateset/authorization` receipt — the complete bundle and its SHA-256 hash — to the MCP result metadata.

Denials, refusals, malformed proofs, unavailable authorization, timeouts and
missing bundles **all fail closed**. Only tools listed in `unguardedTools`
bypass the gate; everything else is guarded by default.

<Note>
  Step 4 is the step that matters and the one an obvious implementation gets
  wrong. Checking that *a* valid approval came back is not enough — an approval
  for some other call is still a valid approval. The gate binds the proof to
  the exact obligation, so a proof cannot be moved from one call to another.
  The fresh `invocation_id` nonce closes the same hole across time: an old
  approval cannot be replayed for a later execution of the same tool with the
  same arguments.
</Note>

## Configure

The policy names the upstream MCP server, the agent identity, which argument
carries the resource, and the read-only tools allowed to bypass authorization.

```json theme={null}
{
  "actor": "support-agent",
  "upstream": {
    "command": "npx",
    "args": ["-y", "-p", "@stateset/cli", "stateset-mcp"]
  },
  "unguardedTools": ["get_order"],
  "tools": {
    "issue_refund": {
      "resource": "args.order_id"
    }
  }
}
```

```bash theme={null}
export NSR_API_URL=https://api.nsr.stateset.com
export NSR_API_KEY=nsr_your_key
export NSR_ORG_ID=your_org
export NSR_GATE_POLICY=/absolute/path/to/policy.json
npx -y @stateset/agent-gate
```

<Warning>
  `unguardedTools` is the whole attack surface of this configuration. A tool on
  that list runs with no proof and no receipt, so it must be genuinely
  read-only — not "read-only in the cases we thought about". `get_order` is
  fine; a tool that takes a filter and returns everything matching it is a
  data-exfiltration path, not a read.
</Warning>

## What you get back

A successful call carries its authorization with it. The receipt is the
complete, independently verifiable bundle plus its hash, so an auditor reading
your logs six months later can re-check that the refund was authorized —
without asking NSR, and without trusting it.

That is the difference between a system that logs *that* it checked and one
that can prove *what* it checked.

## Next steps

<CardGroup cols={2}>
  <Card title="Verified decisions" icon="gavel" href="/stateset-nsr-decisions">
    The `can_execute` decision the gate asks for, and the proof it returns.
  </Card>

  <Card title="Proof verification" icon="circle-check" href="/stateset-nsr-decisions#verify-a-proof-without-trusting-us">
    The check in step 4, which you can also run offline.
  </Card>

  <Card title="NSR MCP server" icon="plug" href="/stateset-nsr-mcp">
    Driving NSR itself from an agent.
  </Card>

  <Card title="MCP servers" icon="server" href="/mcp-servers">
    The upstream servers a gate is placed in front of.
  </Card>
</CardGroup>
