
React Mcp
- 2k installs
- 20 repo stars
- Updated August 2, 2026
- assistant-ui/skills
react-mcp provides documented workflows for Lets end users add, authenticate, and manage MCP servers from the browser in assistant-ui apps with @assistant-ui/react-mcp. Use when building user-managed MCP
About
The react-mcp skill lets end users add authenticate and manage MCP servers from the browser in assistant-ui apps with assistant-ui react-mcp Use when building user-managed MCP server UIs mounting McpManagerResource via useAui mcp declaring presets with defineConnector dropping in McpConfigDialog or composing McpManagerPrimitive Root Connectors CustomServers AddCustomTrigger McpServerPrimitive Root Name Icon Status ConnectButton DisconnectButton OAuthLink RemoveButton Error and McpAddFo assistant-ui React MCP Always consult assistant-ui com llms txt https www assistant-ui com llms txt for the latest API Let end users add authenticate and manage MCP servers from the browser with assistant-ui react-mcp The connected servers tools are merged into the chat runtime automatically Contents References references Routes vs tools routes-vs-tools Mount the manager mount-the-manager Drop-in dialog drop-in-dialog Compose from primitives compose-from-primitives OAuth connect flow oauth-connect-flow Custom storage custom-storage Imperative API imperative-api Common Gotchas common-gotchas Related Skills related-skills References references setup md references setup md McpManagerResource defineConn.
- [./references/setup.md](./references/setup.md) -- McpManagerResource, defineConnector, storage, useAui({ mcp })
- [./references/ui.md](./references/ui.md) -- McpManagerPrimitive / McpServerPrimitive / McpConfigDialog
- [./references/oauth.md](./references/oauth.md) -- OAuth connect flow and auth modes
- The server must reach the `connected` state; check `McpServerPrimitive.Status` or `s.mcpServer.connectionState`.
- Tool names are prefixed `serverId__toolName`; reference that exact name in tool UI.
React Mcp by the numbers
- 1,963 all-time installs (skills.sh)
- +210 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #243 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
react-mcp capabilities & compatibility
- Capabilities
- [./references/setup.md](./references/setup.md) · [./references/ui.md](./references/ui.md) mcpm · [./references/oauth.md](./references/oauth.md) · the server must reach the `connected` state; che · tool names are prefixed `serverid__toolname`; re
- Use cases
- documentation
What react-mcp says it does
The connected servers' tools are merged into the chat runtime automatically.
Each server's tools are namespaced as `serverId__toolName` and exposed to the chat runtime with no extra wiring.
npx skills add https://github.com/assistant-ui/skills --skill react-mcpAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2k |
|---|---|
| repo stars | ★ 20 |
| Last updated | August 2, 2026 |
| Repository | assistant-ui/skills ↗ |
How do I use react-mcp for the task described in its SKILL.md triggers?
Lets end users add, authenticate, and manage MCP servers from the browser in assistant-ui apps with @assistant-ui/react-mcp. Use when building user-managed MCP server UIs: mounting McpManagerResource.
Who is it for?
Teams invoking react-mcp when the user request matches documented triggers and prerequisites.
Skip if: Skip when cached docs are missing, the request is a negative trigger, or another sibling skill owns the workflow.
When should I use this skill?
Lets end users add, authenticate, and manage MCP servers from the browser in assistant-ui apps with @assistant-ui/react-mcp. Use when building user-managed MCP server UIs: mounting McpManagerResource via useAui({ mcp }),
What you get
Step-by-step guidance grounded in react-mcp documentation and reference files.
- mcp manager provider config
- oauth callback route
- connector and custom server UI
By the numbers
- Documents 3 MCP auth modes: none, bearer, and oauth
- Default oauthRedirectUri is ${window.location.origin}/mcp/callback
- Connection states include connected, connecting, authRequired, authPending, error, disconnected
Files
assistant-ui React MCP
Always consult [assistant-ui.com/llms.txt](https://www.assistant-ui.com/llms.txt) for the latest API.
Let end users add, authenticate, and manage MCP servers from the browser with @assistant-ui/react-mcp. The connected servers' tools are merged into the chat runtime automatically.
Contents
- References | Routes vs tools | Mount the manager | Drop-in dialog | Compose from primitives | OAuth connect flow | Custom storage | Imperative API | Common Gotchas | Related Skills
References
- ./references/setup.md -- McpManagerResource, defineConnector, storage, useAui({ mcp })
- ./references/ui.md -- McpManagerPrimitive / McpServerPrimitive / McpConfigDialog
- ./references/oauth.md -- OAuth connect flow and auth modes
Routes vs tools
This skill is for user-managed MCP servers: the end user picks and authenticates servers at runtime in the browser. Each server's tools are namespaced as serverId__toolName and exposed to the chat runtime with no extra wiring.
For developer-defined tools (frontend makeAssistantTool, backend AI SDK tool(), custom tool-call UI), use the tools skill instead. The two compose: a chat built with useChatRuntime can use both app tools and user-connected MCP tools at once.
Mount the manager
McpManagerResource({ connectors }) builds the mcp scope; pass it to useAui and wrap the app in AuiProvider. Connectors are presets declared with defineConnector.
"use client";
import { AuiProvider, useAui } from "@assistant-ui/react";
import { McpManagerResource, defineConnector } from "@assistant-ui/react-mcp";
const connectors = [
defineConnector({
id: "linear",
name: "Linear",
url: "https://mcp.linear.app",
auth: { type: "oauth", scopes: ["read"] },
icon: "/icons/linear.svg",
}),
defineConnector({
id: "weather",
name: "Weather",
url: "https://mcp.example.com/weather",
auth: { type: "none" },
}),
];
export function Providers({ children }: { children: React.ReactNode }) {
const aui = useAui({ mcp: McpManagerResource({ connectors }) });
return <AuiProvider value={aui}>{children}</AuiProvider>;
}Defaults: storage is McpLocalStorage(), oauthRedirectUri is ${window.location.origin}/mcp/callback, and autoConnect is true.
Drop-in dialog
McpConfigDialog is the shadcn dialog that lists connectors and custom servers with inline auth controls and an add form. Drop it anywhere under the provider.
import { McpConfigDialog } from "@/components/assistant-ui/mcp-config";
export default function Page() {
return (
<header className="flex items-center justify-between">
<h1>My app</h1>
<McpConfigDialog />
</header>
);
}Pass children to override the default trigger: <McpConfigDialog><Button>Servers</Button></McpConfigDialog>.
Compose from primitives
McpManagerPrimitive iterates servers; nested McpServerPrimitive.* reads each item's scope automatically. Conditional buttons render only when the connection state matches.
"use client";
import { McpManagerPrimitive, McpServerPrimitive } from "@assistant-ui/react-mcp";
const ServerCard = () => (
<McpServerPrimitive.Root>
<McpServerPrimitive.Icon />
<McpServerPrimitive.Name />
<McpServerPrimitive.Status />
<McpServerPrimitive.ConnectButton>Connect</McpServerPrimitive.ConnectButton>
<McpServerPrimitive.DisconnectButton>Disconnect</McpServerPrimitive.DisconnectButton>
<McpServerPrimitive.OAuthLink>Authorize</McpServerPrimitive.OAuthLink>
<McpServerPrimitive.RemoveButton>Remove</McpServerPrimitive.RemoveButton>
<McpServerPrimitive.Error />
</McpServerPrimitive.Root>
);
export default function McpPage() {
return (
<McpManagerPrimitive.Root>
<h2>Connectors</h2>
<McpManagerPrimitive.Connectors>{() => <ServerCard />}</McpManagerPrimitive.Connectors>
<h2>Your servers</h2>
<McpManagerPrimitive.CustomServers>{() => <ServerCard />}</McpManagerPrimitive.CustomServers>
<McpManagerPrimitive.AddCustomTrigger>Add custom server</McpManagerPrimitive.AddCustomTrigger>
</McpManagerPrimitive.Root>
);
}RemoveButton is hidden on connectors (presets cannot be removed). Omit AddCustomTrigger and CustomServers to disable user-added servers. Build the add form with McpAddFormPrimitive (Root, NameField, UrlField, AuthSelect, AuthFields, Error, Submit, Cancel); see ui.md.
OAuth connect flow
auth is one of { type: "none" }, { type: "bearer", token? }, or { type: "oauth", scopes?, ... }. For OAuth, add a callback route at the configured oauthRedirectUri and render McpOAuthCallback inside the same provider so it can finish the handshake.
"use client";
import { McpOAuthCallback } from "@assistant-ui/react-mcp";
import { useRouter } from "next/navigation";
import { Providers } from "../../providers";
export default function Callback() {
const router = useRouter();
return (
<Providers>
<McpOAuthCallback onComplete={() => router.replace("/mcp")} />
</Providers>
);
}See oauth.md for the full auth-mode shapes and connection-state values (connected, connecting, authRequired, authPending, error, disconnected).
Custom storage
Replace the default McpLocalStorage() to persist custom servers and auth state on a backend (use McpMemoryStorage() for SSR/tests).
import { McpManagerResource, McpCustomStorage } from "@assistant-ui/react-mcp";
const aui = useAui({
mcp: McpManagerResource({
connectors,
storage: McpCustomStorage({
loadCustomServers: async () => fetch("/api/mcp/servers").then((r) => r.json()),
saveCustomServers: async (records) =>
fetch("/api/mcp/servers", { method: "PUT", body: JSON.stringify(records) }),
loadAuthState: async (id) =>
fetch(`/api/mcp/auth/${id}`).then((r) => (r.ok ? r.json() : null)),
saveAuthState: async (id, state) =>
fetch(`/api/mcp/auth/${id}`, { method: "PUT", body: JSON.stringify(state) }),
clearAuthState: async (id) => fetch(`/api/mcp/auth/${id}`, { method: "DELETE" }),
}),
}),
});Imperative API
Inside event handlers, drive the manager through useAui().mcp().
const aui = useAui();
await aui.mcp().addCustomServer({ name, url, auth: { type: "bearer", token } });
await aui.mcp().server({ id }).connect();
await aui.mcp().server({ id }).callTool("echo", { text: "hi" });Read reactive state with useAuiState, scoped under s.mcp (manager) and s.mcpServer (current item inside a McpServerPrimitive subtree):
const isHydrated = useAuiState((s) => s.mcp.isHydrated);
const connectionState = useAuiState((s) => s.mcpServer.connectionState);Common Gotchas
Tools not appearing in chat
- The server must reach the
connectedstate; checkMcpServerPrimitive.Statusors.mcpServer.connectionState. - Tool names are prefixed
serverId__toolName; reference that exact name in tool UI.
OAuth never completes
- The callback route path must match
oauthRedirectUri(default/mcp/callback). McpOAuthCallbackmust be rendered inside the same provider as the manager.
Servers not persisting / SSR errors
- Default
McpLocalStorage()needs the browser; useMcpMemoryStorage()orMcpCustomStorage(...)on the server.
Custom server cannot be removed
RemoveButtonhides on connector presets by design; only user-added servers are removable.
Transport
- Only StreamableHTTP is supported; resources, prompts, sampling, and auto-reconnect are not yet wired.
Related Skills
- tools -- developer-defined frontend/backend tools and custom tool-call UI (
makeAssistantTool, AI SDKtool(),makeAssistantToolUI); the complement to user-managed MCP servers. - setup -- scaffold with the
mcptemplate (npx assistant-ui@latest create -t mcp) and pick a runtime. - runtime -- the chat runtime (
useChatRuntime) that MCP tools are merged into.
MCP OAuth and Auth Modes
Let end users connect and authenticate MCP servers from the browser with @assistant-ui/react-mcp. Auth modes are none, bearer, and oauth (PKCE + DCR).
Contents
- Auth modes
- Connectors and the manager resource
- OAuth connect flow
- OAuth callback route
- Server connect UI
- Imperative connect and auth
- Reading connection state
- Token storage
Auth modes
Each connector or custom server carries an auth config. Three shapes:
// no auth header
{ type: "none" }
// Authorization: Bearer …
{ type: "bearer", token: "…" }
// PKCE + DCR + refresh; every field below the type is optional
{
type: "oauth",
scopes: ["read"],
authorizationEndpoint: "…", // overrides RFC 8414 discovery
tokenEndpoint: "…",
registrationEndpoint: "…",
clientId: "…", // skip DCR with a static client
clientSecret: "…",
}With oauth and no endpoint overrides, the client discovers metadata (RFC 8414), dynamically registers (DCR, RFC 7591), runs PKCE, exchanges the code, and refreshes tokens on 401. Set clientId (and clientSecret) to skip DCR with a pre-registered client.
Connectors and the manager resource
OAuth connectors are declared with defineConnector({ ..., auth: { type: "oauth", scopes } }) and mounted via McpManagerResource on the aui instance. The oauthRedirectUri option defaults to "${window.location.origin}/mcp/callback". See ./setup.md for the full defineConnector / McpManagerResource / provider setup.
OAuth connect flow
1. The user triggers a connect on an oauth server (button or imperative call). 2. The client runs discovery/DCR/PKCE and opens the authorization URL. 3. The provider redirects back to oauthRedirectUri with ?state=…&code=…. The server id is encoded in the OAuth state param, so one callback route resolves any server. 4. The callback route completes the exchange; autoConnect then connects the server.
Set the redirect URI explicitly when not using the default route:
McpManagerResource({
connectors,
oauthRedirectUri: `${window.location.origin}/auth/mcp`,
});OAuth callback route
Render McpOAuthCallback at the redirect path. It reads code and state from the URL and calls completeAuth on the right server. Wrap it in the same Providers so the manager resource is in scope.
// app/mcp/callback/page.tsx
"use client";
import { McpOAuthCallback } from "@assistant-ui/react-mcp";
import { useRouter } from "next/navigation";
import { Providers } from "../../providers";
export default function Callback() {
const router = useRouter();
return (
<Providers>
<McpOAuthCallback onComplete={() => router.replace("/mcp")} />
</Providers>
);
}McpOAuthCallback takes onComplete: () => void, fired after the token exchange resolves.
Server connect UI
McpServerPrimitive action buttons render only when the server's state matches, so no manual gating is needed: ConnectButton when connectable, OAuthLink when authorization is required, DisconnectButton when connected.
"use client";
import {
McpManagerPrimitive,
McpServerPrimitive,
} from "@assistant-ui/react-mcp";
const ServerCard = () => (
<McpServerPrimitive.Root>
<McpServerPrimitive.Icon />
<McpServerPrimitive.Name />
<McpServerPrimitive.Status />
<McpServerPrimitive.ConnectButton>Connect</McpServerPrimitive.ConnectButton>
<McpServerPrimitive.DisconnectButton>Disconnect</McpServerPrimitive.DisconnectButton>
<McpServerPrimitive.OAuthLink>Authorize ↗</McpServerPrimitive.OAuthLink>
<McpServerPrimitive.RemoveButton>Remove</McpServerPrimitive.RemoveButton>
<McpServerPrimitive.Error />
</McpServerPrimitive.Root>
);
export default function McpPage() {
return (
<McpManagerPrimitive.Root>
<h2>Connectors</h2>
<McpManagerPrimitive.Connectors>
{() => <ServerCard />}
</McpManagerPrimitive.Connectors>
<h2>Your servers</h2>
<McpManagerPrimitive.CustomServers>
{() => <ServerCard />}
</McpManagerPrimitive.CustomServers>
<McpManagerPrimitive.AddCustomTrigger>
Add custom server
</McpManagerPrimitive.AddCustomTrigger>
</McpManagerPrimitive.Root>
);
}Imperative connect and auth
aui.mcp().server({ id }).connect(), called from an event handler, triggers the OAuth flow when the server needs it. See ./setup.md for the full imperative API (addCustomServer, connect, callTool).
Reading connection state
Read state with useAuiState from @assistant-ui/store. The mcpServer.* selectors require an McpServerByIdProvider in scope, which the manager iteration primitives supply automatically.
import { useAuiState } from "@assistant-ui/store";
const isHydrated = useAuiState((s) => s.mcp.isHydrated);
const connectionState = useAuiState((s) => s.mcpServer.connectionState);
const name = useAuiState((s) => s.mcpServer.name);
const icon = useAuiState((s) => s.mcpServer.icon ?? null);
const error = useAuiState((s) => s.mcpServer.lastError?.message ?? null);Token storage
OAuth tokens persist through the manager's storage. McpLocalStorage (the default) keeps them in plain text and is XSS-exposed; for anything beyond local prototyping use McpCustomStorage against an HTTP-only-cookie-backed endpoint. See ./setup.md for the storage backends and a full McpCustomStorage example.
MCP manager setup
Mount user-managed MCP servers on the aui instance with @assistant-ui/react-mcp. Connectors are presets, storage persists servers and tokens, and aui.mcp() drives the manager imperatively.
Contents
Imports
import { AuiProvider, useAui } from "@assistant-ui/react";
import {
McpManagerResource,
defineConnector,
McpLocalStorage,
McpMemoryStorage,
McpCustomStorage,
} from "@assistant-ui/react-mcp";defineConnector
A connector is an app-declared preset the end user can connect to. id, name, url, and auth are required; icon is optional. Auth is one of { type: "none" }, { type: "bearer", token? }, or { type: "oauth", scopes?, ... } (see oauth.md for the full shapes).
const connectors = [
defineConnector({
id: "linear",
name: "Linear",
url: "https://mcp.linear.app",
auth: { type: "oauth", scopes: ["read"] },
icon: "/icons/linear.svg",
}),
defineConnector({
id: "weather",
name: "Weather",
url: "https://mcp.example.com/weather",
auth: { type: "none" },
}),
];McpManagerResource
McpManagerResource(options) builds the mcp scope you pass to useAui. Options and their defaults:
connectors: the array fromdefineConnector(...).storage:McpLocalStorage()by default; persists under theaui-mcp:prefix inwindow.localStorage.oauthRedirectUri:"${window.location.origin}/mcp/callback"by default.autoConnect:trueby default; connects on mount when usable auth is already persisted.
McpManagerResource({
connectors,
storage: McpLocalStorage(),
oauthRedirectUri: `${window.location.origin}/auth/mcp`,
autoConnect: true,
});Mount on the provider
Pass the resource to useAui({ mcp }) and wrap the app in AuiProvider. Connected servers' tools merge into the chat runtime automatically, namespaced serverId__toolName.
"use client";
import { AuiProvider, useAui } from "@assistant-ui/react";
import { McpManagerResource, defineConnector } from "@assistant-ui/react-mcp";
const connectors = [
defineConnector({
id: "linear",
name: "Linear",
url: "https://mcp.linear.app",
auth: { type: "oauth", scopes: ["read"] },
}),
];
export function Providers({ children }: { children: React.ReactNode }) {
const aui = useAui({ mcp: McpManagerResource({ connectors }) });
return <AuiProvider value={aui}>{children}</AuiProvider>;
}Storage
Three built-in storage backends control where custom servers and OAuth tokens persist:
McpLocalStorage(): default;window.localStorageunder theaui-mcp:prefix. Browser only.McpMemoryStorage(): in-process Map; use for SSR or tests wherelocalStorageis absent.McpCustomStorage({...}): bring your own load/save handlers (for example a backend endpoint).
McpLocalStorage keeps tokens in plain text and is XSS-exposed; for anything past local prototyping, back McpCustomStorage with an HTTP-only-cookie endpoint.
McpManagerResource({ connectors, storage: McpMemoryStorage() });McpCustomStorage
Supply async handlers for custom-server records and per-server auth state. loadAuthState returns the stored state or null; saveAuthState and clearAuthState are keyed by server id.
const aui = useAui({
mcp: McpManagerResource({
connectors,
storage: McpCustomStorage({
loadCustomServers: async () =>
fetch("/api/mcp/servers").then((r) => r.json()),
saveCustomServers: async (records) =>
fetch("/api/mcp/servers", {
method: "PUT",
body: JSON.stringify(records),
}),
loadAuthState: async (id) =>
fetch(`/api/mcp/auth/${id}`).then((r) => (r.ok ? r.json() : null)),
saveAuthState: async (id, state) =>
fetch(`/api/mcp/auth/${id}`, {
method: "PUT",
body: JSON.stringify(state),
}),
clearAuthState: async (id) =>
fetch(`/api/mcp/auth/${id}`, { method: "DELETE" }),
}),
}),
});Imperative API
Drive the manager through useAui().mcp() from inside event handlers, never during render. addCustomServer registers a user server with its own auth; server({ id }) scopes to one server for connect and callTool.
const aui = useAui();
// inside an event handler:
await aui.mcp().addCustomServer({ name, url, auth: { type: "bearer", token } });
await aui.mcp().server({ id }).connect();
const result = await aui.mcp().server({ id }).callTool("echo", { text: "hi" });Read reactive state with useAuiState from @assistant-ui/store, scoped under s.mcp (manager) and s.mcpServer (current item inside a McpServerPrimitive subtree).
import { useAuiState } from "@assistant-ui/store";
const isHydrated = useAuiState((s) => s.mcp.isHydrated);
const connectionState = useAuiState((s) => s.mcpServer.connectionState);MCP config UI
Headless primitives for letting end users add and authenticate MCP servers from the browser, plus the McpConfigDialog shadcn registry component built on them.
The primitives ship from @assistant-ui/react-mcp. Per-server card and form state is read with useAuiState from @assistant-ui/store. Install the prebuilt dialog with the CLI (https://r.assistant-ui.com/mcp-config.json) to get a ready styled version under @/components/assistant-ui/mcp-config that you can edit.
Contents
- Imports
- McpManagerPrimitive
- McpServerPrimitive
- McpAddFormPrimitive
- MCPConnectionState
- Reading server state
- McpConfigDialog
Imports
import { useAuiState } from "@assistant-ui/store";
import {
McpAddFormPrimitive,
McpManagerPrimitive,
McpServerPrimitive,
type MCPConnectionState,
} from "@assistant-ui/react-mcp";McpManagerPrimitive
Wraps the manager state and iterates over the two server collections. The iteration parts take a render-prop child () => <ServerCard />; each rendered card reads its own server from context.
| Part | Props | Description |
|---|---|---|
.Root | Manager context provider; wrap the whole UI | |
.Connectors | App-defined connectors; child is () => ReactNode | |
.CustomServers | User-added servers; child is () => ReactNode | |
.AddCustomTrigger | asChild | Reveals the add form |
<McpManagerPrimitive.Root>
<section>
<h3>Connectors</h3>
<McpManagerPrimitive.Connectors>
{() => <ServerCard />}
</McpManagerPrimitive.Connectors>
</section>
<section>
<h3>Custom servers</h3>
<McpManagerPrimitive.CustomServers>
{() => <ServerCard />}
</McpManagerPrimitive.CustomServers>
<McpManagerPrimitive.AddCustomTrigger asChild>
<Button>Add server</Button>
</McpManagerPrimitive.AddCustomTrigger>
</section>
</McpManagerPrimitive.Root>McpServerPrimitive
Renders a single server (the one provided by the surrounding .Connectors / .CustomServers iteration). The connect, authorize, and disconnect actions render conditionally based on the server's connection state, so include all three and let the primitive decide which is active.
| Part | Props | Description |
|---|---|---|
.Root | className | Card container; exposes data-connection-state (e.g. data-[connection-state=error]) |
.Name | Renders the server name | |
.ConnectButton | asChild | Connects a server that uses no OAuth |
.OAuthLink | className | Starts the OAuth flow (renders as a link) |
.DisconnectButton | asChild | Disconnects a connected server |
.RemoveButton | asChild | Removes the server from the manager |
const ServerCard: FC = () => (
<McpServerPrimitive.Root
className={cn(
"rounded-lg border p-3",
"data-[connection-state=error]:border-destructive/40",
)}
>
<McpServerPrimitive.Name />
<McpServerPrimitive.ConnectButton asChild>
<Button size="sm">Connect</Button>
</McpServerPrimitive.ConnectButton>
<McpServerPrimitive.OAuthLink className={cn(buttonVariants({ size: "sm" }))}>
Authorize
</McpServerPrimitive.OAuthLink>
<McpServerPrimitive.DisconnectButton asChild>
<Button size="sm" variant="outline">Disconnect</Button>
</McpServerPrimitive.DisconnectButton>
<McpServerPrimitive.RemoveButton asChild>
<Button variant="ghost" size="icon"><Trash2Icon className="size-4" /></Button>
</McpServerPrimitive.RemoveButton>
</McpServerPrimitive.Root>
);McpAddFormPrimitive
The form for adding a custom server. .Root owns the form state and fires onSubmitted after a successful add and onCancel when dismissed; both are handy for closing the form. .AuthSelect chooses the auth scheme and .AuthFields renders whatever inputs that scheme needs (for example a bearer token field).
| Part | Props | Description |
|---|---|---|
.Root | onSubmitted, onCancel | Form provider and submit handler |
.NameField | asChild | Server name input |
.UrlField | asChild | Server URL input |
.AuthSelect | className | Auth scheme <select> |
.AuthFields | Inputs required by the selected scheme | |
.Error | className | Validation / submit error text |
.Submit | asChild | Submits the form |
.Cancel | asChild | Cancels and fires onCancel |
const AddServerForm: FC<{ onClose: () => void }> = ({ onClose }) => (
<McpAddFormPrimitive.Root onSubmitted={onClose} onCancel={onClose}>
<McpAddFormPrimitive.NameField asChild>
<Input placeholder="My MCP server" />
</McpAddFormPrimitive.NameField>
<McpAddFormPrimitive.UrlField asChild>
<Input placeholder="https://example.com/mcp" />
</McpAddFormPrimitive.UrlField>
<McpAddFormPrimitive.AuthSelect className="h-9 w-full rounded-md border px-2 text-sm" />
<McpAddFormPrimitive.AuthFields />
<McpAddFormPrimitive.Error className="text-destructive text-xs" />
<McpAddFormPrimitive.Cancel asChild>
<Button type="button" variant="ghost" size="sm">Cancel</Button>
</McpAddFormPrimitive.Cancel>
<McpAddFormPrimitive.Submit asChild>
<Button type="submit" size="sm">Add server</Button>
</McpAddFormPrimitive.Submit>
</McpAddFormPrimitive.Root>
);MCPConnectionState
Union of the six states a server can be in; useful for mapping status to a label or badge variant.
type MCPConnectionState =
| "connected"
| "connecting"
| "authRequired"
| "authPending"
| "error"
| "disconnected";Reading server state
Inside a McpServerPrimitive.Root (or any .Connectors / .CustomServers child) read the current server from the store via s.mcpServer.
const icon = useAuiState((s) => s.mcpServer.icon ?? null);
const name = useAuiState((s) => s.mcpServer.name);
const status = useAuiState((s) => s.mcpServer.connectionState);
const message = useAuiState((s) => s.mcpServer.lastError?.message ?? null);McpConfigDialog
The registry component is a shadcn dialog that lists connectors and custom servers with inline auth controls and an add form, composing every primitive above. Its only prop is children, which overrides the default trigger button.
export namespace McpConfigDialog {
export type Props = { children?: ReactNode };
}import { McpConfigDialog } from "@/components/assistant-ui/mcp-config";
// default trigger ("MCP servers" button)
<McpConfigDialog />
// custom trigger
<McpConfigDialog>
<Button variant="ghost">Servers</Button>
</McpConfigDialog>The dialog reads connectors and custom servers from the MCP manager resource on the runtime, so render it inside the same provider tree as your AuiProvider. See setup.md for mounting McpManagerResource.
Related skills
How it compares
Use react-mcp for end-user MCP connector UIs; use the assistant-ui tools skill for developer-defined frontend and backend tools.
FAQ
What does react-mcp do?
Lets end users add, authenticate, and manage MCP servers from the browser in assistant-ui apps with @assistant-ui/react-mcp. Use when building user-managed MCP server UIs: mounting McpManagerResource via useAui({ mcp }),
When should I use react-mcp?
Lets end users add, authenticate, and manage MCP servers from the browser in assistant-ui apps with @assistant-ui/react-mcp. Use when building user-managed MCP server UIs: mounting McpManagerResource via useAui({ mcp }),
What are common prerequisites?
--- name: react-mcp description: "Lets end users add, authenticate, and manage MCP servers from the browser in assistant-ui apps with @assistant-ui/react-mcp.