# Tool Permission Card

> Card that asks a person to approve an agent's tool call — arguments, risk level and an always-allow switch — then springs down into a compact receipt.

- Collection: AI Agents
- Tier: pro
- Docs: https://geturui.com/docs/tool-approval
- Install: `npx shadcn@latest add @geturui-pro/tool-approval`
- Dependencies: motion, lucide-react

## Usage

```tsx
import { ToolApproval } from "@/components/ai/tool-approval";

<ToolApproval
  tool="github.create_issue"
  source="GitHub MCP"
  risk="medium"
  args={{ repo: "acme/web", title: "Fix flaky test" }}
  onApprove={async ({ alwaysAllow }) => runTool({ alwaysAllow })}
  onDeny={() => cancelTool()}
/>
```

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| tool | `string` | — | Tool identifier. |
| args | `unknown` | — | Arguments, shown as highlighted JSON. |
| risk | `"low" | "medium" | "high"` | "medium" | Risk badge; high also tints the border and uses the ember button. |
| description | `string` | — | What the call will do. |
| source | `string` | — | Where the tool lives, e.g. an MCP server. |
| onApprove | `({ alwaysAllow }) => Promise<unknown> | void` | — | Runs with a spinner; rejecting shakes the button and keeps the card open. |
| onDeny | `() => void` | — | Called on deny. |
| decision / onDecisionChange | `"pending" | "approved" | "denied"` | — | Controlled decision state. |
| onReopen | `() => void` | — | Shows a Review button on the receipt that reopens the card. |

## Accessibility

- The card is a labelled region; the receipt is a status message so the outcome is announced.
- Risk is conveyed by icon and word, not colour alone.
- JSON preview is a focusable, scrollable region.
- The always-allow control is a real switch with a visible label.

## Source

Pro item — send `Authorization: Bearer <registry token>` to include the source.
