# First denial in 60 seconds

Reading about permission boundaries proves nothing. Watching your own agent
get told **no** — by a grant, not by a prompt — is the whole product in one
moment. This page gets you there in about a minute, then shows the second
moment: pulling the plug from outside the process.

## 1. Watch a denial happen (~30 seconds, zero setup)

```sh
npx -y @grantor/mcp demo
```

This wraps a bundled toy MCP server behind a grant for **one** tool
(`search`), while the server also exposes `delete_everything`. A scripted
agent calls both. The granted call is served. The other one produces this:

```
┌─ DENIED ───────────────────────────────────────────────────┐
│  requested      delete_everything                          │
│  grant allows   search                                     │
│  refused as     CapabilityDenied — no effective grant …    │
│                                                            │
│  Denied by the grant, not by a prompt —                    │
│  the server never saw the call.                            │
│  revoke everything:   grantor-mcp revoke --child …         │
└────────────────────────────────────────────────────────────┘
```

Only the agent is scripted. The enforcement is the real thing: a real
grant minted by the broker, the real wrap relay, and a live on-chain
revocation read. The denied request is answered by the broker itself —
the wrapped server never receives it, so there is no prompt, system
message, or clever jailbreak on the other side to talk past.

## 2. Now your own server (~30 seconds more)

You don't modify the server. First see what it exposes:

```sh
npx -y @grantor/mcp tools -- npx -y @modelcontextprotocol/server-filesystem /tmp
```

This lists the server's tools, marks the write-shaped ones, and prints a
ready-to-paste wrap command granting only the read-like names — a **name
heuristic, stated as such**: review the suggestion before trusting it.
Then run the suggestion, or write your own grant:

```sh
npx -y @grantor/mcp wrap --tools read_file,list_directory --max-uses 50 --ttl-secs 3600 -- \
  npx -y @modelcontextprotocol/server-filesystem /tmp
```

Point your agent at the wrapped command instead of the bare server — in a
Claude Code / MCP client config, the wrap line simply replaces the server
line:

```json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@grantor/mcp", "wrap",
               "--tools", "read_file,list_directory",
               "--max-uses", "50", "--ttl-secs", "3600",
               "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    }
  }
}
```

The first time the agent reaches for `write_file`, you get your denial —
in your own session, on your own server.

## 3. The second moment: revoke from outside the process

A boundary you can set is good. A boundary you can *pull* while the agent
is mid-flight is the part credentials can't do. The wrap's startup log and
every DENIED box name the child id; revoke it:

```sh
npx -y @grantor/mcp revoke --child <child-id>
```

The revocation is an on-chain epoch bump — the next call the agent makes,
**including the previously allowed ones**, is denied with `EpochRevoked`.
The agent's process was never touched; its authority just stopped existing,
from outside, with a receipt anyone can verify on a public chain.

## What you just used

The wrap is the [permission broker](mcp-broker.md)'s enforcing mode: named
tools, a use budget, an expiry, delegation that can only narrow, and
on-chain revocation — the same [capability model](capabilities.md) that
runs everything here. The demo's sandbox rides the public mainnet tenant;
production use is [your own tenant](getting-started.md), and everything
above is the same commands with your own config.
