react-mcp
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseassistant-ui React MCP
assistant-ui React MCP
Always consult assistant-ui.com/llms.txt for the latest API.
Let end users add, authenticate, and manage MCP servers from the browser with . The connected servers' tools are merged into the chat runtime automatically.
@assistant-ui/react-mcp请始终查阅assistant-ui.com/llms.txt获取最新API。
借助,让终端用户能在浏览器中添加、验证和管理MCP服务器。已连接服务器的工具会自动合并到聊天运行时中。
@assistant-ui/react-mcpContents
目录
References
参考文档
- ./references/setup.md -- McpManagerResource, defineConnector, storage, useAui({ mcp })
- ./references/ui.md -- McpManagerPrimitive / McpServerPrimitive / McpConfigDialog
- ./references/oauth.md -- OAuth connect flow and auth modes
- ./references/setup.md -- McpManagerResource、defineConnector、存储、useAui({ mcp })
- ./references/ui.md -- McpManagerPrimitive / McpServerPrimitive / McpConfigDialog
- ./references/oauth.md -- OAuth连接流程与认证模式
Routes vs tools
路由 vs 工具
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 and exposed to the chat runtime with no extra wiring.
serverId__toolNameFor developer-defined tools (frontend , backend AI SDK , custom tool-call UI), use the tools skill instead. The two compose: a chat built with can use both app tools and user-connected MCP tools at once.
makeAssistantTooltool()useChatRuntime本技能适用于用户管理的MCP服务器:终端用户可在浏览器运行时选择并验证服务器。每个服务器的工具会以为命名空间,无需额外配置即可暴露给聊天运行时。
serverId__toolName对于开发者定义的工具(前端、后端AI SDK 、自定义工具调用UI),请改用工具技能。两者可组合使用:基于构建的聊天应用可同时使用应用工具和用户连接的MCP工具。
makeAssistantTooltool()useChatRuntimeMount the manager
挂载管理器
McpManagerResource({ connectors })mcpuseAuiAuiProviderdefineConnectortsx
"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: is , is , and is .
storageMcpLocalStorage()oauthRedirectUri${window.location.origin}/mcp/callbackautoConnecttrueMcpManagerResource({ connectors })mcpuseAuiAuiProviderdefineConnectortsx
"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>;
}默认配置:为,为,为。
storageMcpLocalStorage()oauthRedirectUri${window.location.origin}/mcp/callbackautoConnecttrueDrop-in dialog
嵌入对话框
McpConfigDialogtsx
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 to override the default trigger: .
children<McpConfigDialog><Button>Servers</Button></McpConfigDialog>McpConfigDialogtsx
import { McpConfigDialog } from "@/components/assistant-ui/mcp-config";
export default function Page() {
return (
<header className="flex items-center justify-between">
<h1>我的应用</h1>
<McpConfigDialog />
</header>
);
}传入可覆盖默认触发器:。
children<McpConfigDialog><Button>服务器</Button></McpConfigDialog>Compose from primitives
基于原语组合
McpManagerPrimitiveMcpServerPrimitive.*tsx
"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>
);
}RemoveButtonAddCustomTriggerCustomServersMcpAddFormPrimitiveRootNameFieldUrlFieldAuthSelectAuthFieldsErrorSubmitCancelMcpManagerPrimitiveMcpServerPrimitive.*tsx
"use client";
import { McpManagerPrimitive, McpServerPrimitive } from "@assistant-ui/react-mcp";
const ServerCard = () => (
<McpServerPrimitive.Root>
<McpServerPrimitive.Icon />
<McpServerPrimitive.Name />
<McpServerPrimitive.Status />
<McpServerPrimitive.ConnectButton>连接</McpServerPrimitive.ConnectButton>
<McpServerPrimitive.DisconnectButton>断开连接</McpServerPrimitive.DisconnectButton>
<McpServerPrimitive.OAuthLink>授权</McpServerPrimitive.OAuthLink>
<McpServerPrimitive.RemoveButton>移除</McpServerPrimitive.RemoveButton>
<McpServerPrimitive.Error />
</McpServerPrimitive.Root>
);
export default function McpPage() {
return (
<McpManagerPrimitive.Root>
<h2>连接器</h2>
<McpManagerPrimitive.Connectors>{() => <ServerCard />}</McpManagerPrimitive.Connectors>
<h2>你的服务器</h2>
<McpManagerPrimitive.CustomServers>{() => <ServerCard />}</McpManagerPrimitive.CustomServers>
<McpManagerPrimitive.AddCustomTrigger>添加自定义服务器</McpManagerPrimitive.AddCustomTrigger>
</McpManagerPrimitive.Root>
);
}RemoveButtonAddCustomTriggerCustomServersMcpAddFormPrimitiveRootNameFieldUrlFieldAuthSelectAuthFieldsErrorSubmitCancelOAuth connect flow
OAuth连接流程
auth{ type: "none" }{ type: "bearer", token? }{ type: "oauth", scopes?, ... }oauthRedirectUriMcpOAuthCallbacktsx
"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 (, , , , , ).
connectedconnectingauthRequiredauthPendingerrordisconnectedauth{ type: "none" }{ type: "bearer", token? }{ type: "oauth", scopes?, ... }oauthRedirectUriMcpOAuthCallbacktsx
"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>
);
}完整的认证模式结构和连接状态值(、、、、、)请见oauth.md。
connectedconnectingauthRequiredauthPendingerrordisconnectedCustom storage
自定义存储
Replace the default to persist custom servers and auth state on a backend (use for SSR/tests).
McpLocalStorage()McpMemoryStorage()ts
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" }),
}),
}),
});替换默认的,可在后端持久化自定义服务器和认证状态(SSR/测试场景使用)。
McpLocalStorage()McpMemoryStorage()ts
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
命令式API
Inside event handlers, drive the manager through .
useAui().mcp()ts
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 , scoped under (manager) and (current item inside a subtree):
useAuiStates.mcps.mcpServerMcpServerPrimitivets
const isHydrated = useAuiState((s) => s.mcp.isHydrated);
const connectionState = useAuiState((s) => s.mcpServer.connectionState);在事件处理器中,可通过驱动管理器。
useAui().mcp()ts
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" });使用读取响应式状态,作用域为(管理器)和(子树内的当前项):
useAuiStates.mcps.mcpServerMcpServerPrimitivets
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 state; check
connectedorMcpServerPrimitive.Status.s.mcpServer.connectionState - Tool names are prefixed ; reference that exact name in tool UI.
serverId__toolName
OAuth never completes
- The callback route path must match (default
oauthRedirectUri)./mcp/callback - must be rendered inside the same provider as the manager.
McpOAuthCallback
Servers not persisting / SSR errors
- Default needs the browser; use
McpLocalStorage()orMcpMemoryStorage()on the server.McpCustomStorage(...)
Custom server cannot be removed
- hides on connector presets by design; only user-added servers are removable.
RemoveButton
Transport
- Only StreamableHTTP is supported; resources, prompts, sampling, and auto-reconnect are not yet wired.
聊天中未显示工具
- 服务器必须达到状态;请检查
connected或McpServerPrimitive.Status。s.mcpServer.connectionState - 工具名称前缀为;在工具UI中需引用此完整名称。
serverId__toolName
OAuth流程无法完成
- 回调路由路径必须与匹配(默认值为
oauthRedirectUri)。/mcp/callback - 必须与管理器在同一个Provider内渲染。
McpOAuthCallback
服务器无法持久化 / SSR报错
- 默认的依赖浏览器环境;在服务器端请使用
McpLocalStorage()或McpMemoryStorage()。McpCustomStorage(...)
无法移除自定义服务器
- 默认在连接器预设上隐藏;仅用户添加的服务器可被移除。
RemoveButton
传输
- 仅支持StreamableHTTP;资源、提示词、采样和自动重连功能暂未实现。
Related Skills
相关技能
- tools -- developer-defined frontend/backend tools and custom tool-call UI (, AI SDK
makeAssistantTool,tool()); the complement to user-managed MCP servers.makeAssistantToolUI - setup -- scaffold with the template (
mcp) and pick a runtime.npx assistant-ui@latest create -t mcp - runtime -- the chat runtime () that MCP tools are merged into.
useChatRuntime
- 工具 -- 开发者定义的前端/后端工具及自定义工具调用UI(、AI SDK
makeAssistantTool、tool());与用户管理的MCP服务器互为补充。makeAssistantToolUI - 初始化 -- 使用模板快速搭建项目(
mcp)并选择运行时。npx assistant-ui@latest create -t mcp - 运行时 -- MCP工具会合并到其中的聊天运行时()。
useChatRuntime