MCP Roots
The roots a client has granted its servers — the closest thing MCP has to a permission boundary, and invisible in most clients. A root covering a whole home directory is drawn as a warning rather than as another grey row.
src/components/ui/mcp-roots.tsxAbout
From the component's own source, where it was written.
The roots a client has granted its MCP servers.
Roots are how an MCP client says "you may look here and nowhere else", and they are the closest thing the protocol has to a permission boundary. They are also invisible in most clients, which means nobody notices when one is a great deal wider than intended.
So this leans on making a wide grant *look* wide. A root at /, ~ or a home directory covers everything a person owns, and it is rendered as a warning rather than as another grey row — the same reasoning as SandboxPolicy, applied to the protocol's own mechanism.
Per-server scoping is shown when present. A root granted to every server is a different fact from one granted to a single trusted server, and a flat list of paths cannot tell them apart.
Install
npx astralyx-ui add mcp-roots
Usage
import { McpRoots } from '@/components/ui/mcp-roots'
<McpRoots roots={roots} onAdd={add} onRemove={remove} />Composer
Change the props and the source below follows.
Roots
astralyx
file:///Users/ada/work/astralyx
filesystem, gitScratch
file:///tmp/agent-scratch
all serversHome
file:///Users/ada
filesystemCovers everything you own
<McpRoots
roots={roots}
onAdd={add}
onRemove={remove}
/>Examples
One root wider than intended
<McpRoots roots={roots} onRemove={remove} />API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
McpRoots
The roots a client has granted its MCP servers.
Extends Omit<ComponentProps<'div'>, 'children'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| roots | McpRoot[] | required | Rendered as “servers can see nothing”, rather than as an empty box that could mean either thing. |
| onAdd | () => void | — | — |
| onRemove | (uri: string) => void | — | — |
| addLabel | string | 'Add a root' | — |
| removeLabel | string | 'Remove' | — |
| allServersLabel | string | 'all servers' | — |
| readOnlyLabel | string | 'read-only' | — |
| broadLabel | string | 'Covers everything you own' | — |
| emptyLabel | string | 'No roots granted — servers can see nothing on this machine.' | — |
| label | string | 'Roots' | — |
Functions
| Function | Signature | Description |
|---|---|---|
| isBroadRoot | (uri: string) => boolean | — |
Types
McpRoot
| Field | Type | Description |
|---|---|---|
| uri | string | A file:// URI, as the protocol specifies. |
| name? | string | — |
| servers? | string[] | Server ids this root is exposed to. Empty or absent means all of them. |
| readOnly? | boolean | Read-only grant. |
Behaviour
| Topic | Detail | Description |
|---|---|---|
| broad detection | isBroadRoot | /, a bare ~, and /Users/<name> or /home/<name> cover everything a person owns. Exported so a save handler can check before granting. |
| scoping | shown per root | A root granted to every server is a different fact from one granted to a single trusted server, and a flat path list cannot tell them apart. |