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.
aiagenttool callapprovalmcppermissionshuman in the loop
Installation
Pro installs use your private registry token. Add the @geturui-pro registry once — setup guide. The command works after you get Pro.
$npx shadcn@latest add @geturui-pro/tool-approval
Also installs: Button, Animated Badge, Switch
Usage
usage.tsx
1import { ToolApproval } from "@/components/ai/tool-approval";
2
3<ToolApproval
4 tool="github.create_issue"
5 source="GitHub MCP"
6 risk="medium"
7 args={{ repo: "acme/web", title: "Fix flaky test" }}
8 onApprove={async ({ alwaysAllow }) => runTool({ alwaysAllow })}
9 onDeny={() => cancelTool()}
10/>
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.