@frontmcp/react

中文文档
1.12.2发布于 2026/11/15Apache-2.0TypeScriptESM + CJS构建来源已验证近 30 天下载 5067

Run a FrontMCP server inside a React app: provider, hooks, components and AI SDK integration

原始使用文档
文档目录16 节
  1. Install
  2. Usage
  3. Entry points
  4. FrontMcpProvider
  5. Hooks
  6. Giving the model a tool from a component
  7. Letting a model show a component
  8. Components
  9. Exposing app state
  10. Registering API operations as tools
  11. Handing the tools to an AI SDK
  12. Letting a model move around the app
  13. Docs
  14. Related packages
  15. Contributing
  16. License

@frontmcp/react

@frontmcp/react runs a FrontMCP server inside a React app. You build the server with create(), in the same process, and FrontMcpProvider connects a client to it. Components call its tools, read its resources and get its prompts with hooks, and can add tools of their own while they're mounted, so a model can fill in a card, move around the app or read its state. Use it to make a React app something an agent can drive. To build the UI a tool shows inside an AI host such as ChatGPT or Claude, use @frontmcp/ui instead.

npm License

Install

npm install @frontmcp/react react react-dom
  • react and react-dom 18 or 19 are peer dependencies.
  • @frontmcp/sdk and @frontmcp/utils come with it, at the same version. @frontmcp/react re-exports what an app needs from the SDK (create, connect and its variants, the decorators and their function forms, the context classes, and z), so you don't import @frontmcp/sdk yourself. npm 7 and later also install its peer @frontmcp/lazy-zod, and zod with it.
  • react-router-dom 7 is an optional peer, needed only for @frontmcp/react/router.
  • In the browser, a bundler that follows the browser export condition, such as Vite, picks the SDK's browser build (Running in a browser). In Node, for tests or server rendering, use Node.js 24 or later.

Usage

A tool, the server, and a component that calls it:

import { create, FrontMcpProvider, Tool, ToolContext, useCallTool, z } from '@frontmcp/react';

@Tool({ name: 'greet', description: 'Greet someone by name', inputSchema: { name: z.string() } })
class GreetTool extends ToolContext {
  async execute({ name }: { name: string }) {
    return { message: `Hello, ${name}!` };
  }
}

const server = await create({ info: { name: 'my-app', version: '1.0.0' }, tools: [GreetTool] });

function Greeter() {
  const [greet, { data, loading, error }] = useCallTool<{ name: string }, { structuredContent?: { message: string } }>(
    'greet',
  );

  return (
    <div>
      <button disabled={loading} onClick={() => greet({ name: 'Ada' })}>
        Greet
      </button>
      {data?.structuredContent && <p>{data.structuredContent.message}</p>}
      {error && <p role="alert">{error.message}</p>}
    </div>
  );
}

export function App() {
  return (
    <FrontMcpProvider server={server}>
      <Greeter />
    </FrontMcpProvider>
  );
}

Clicking the button shows Hello, Ada!. useCallTool() returns [call, state, reset], and data is the MCP result the client got, so the tool's return value is in data.structuredContent. A tool that fails comes back as a result with isError: true in data; error is set only when the call couldn't be made, such as FrontMCP not connected. Decorators need "experimentalDecorators": true in tsconfig.json.

Entry points

ImportWhat's in it
@frontmcp/reactFrontMcpProvider, the hooks, the components, mcpComponent, serverRegistry, DynamicRegistry and bindDynamicTools, the store adapters, and the SDK re-exports listed above.
@frontmcp/react/stateuseStoreResource, useReduxResource, useValtioResource: expose a store from inside a component.
@frontmcp/react/apiuseApiClient, parseOpenApiSpec, createFetchClient: register OpenAPI operations as tools.
@frontmcp/react/aiuseAITools, useTools, createToolCallHandler: hand the server's tools to an AI SDK.
@frontmcp/react/routeruseRouterBridge, createRouterEntries, and the navigate, go_back and route://current entries. Needs react-router-dom 7.

FrontMcpProvider

PropDefaultDescription
serverRequired. The server from create().
name"default"The server's name in serverRegistry, which hooks without a server option use.
serversMore servers, by name. Hooks reach them with { server: 'name' }.
componentsComponents for DynamicRenderer, by URI, like { 'component://Card': Card }.
storesStore adapters to expose as resources and tools (Exposing app state).
dynamicToolAppsThe app that components' tools join, by server name. Only for a server with several apps.
autoConnecttrueConnect on mount. With false, call connect() from useFrontMcp().
onConnectedCalled once the client is connected and the lists are loaded.
onErrorCalled when connecting fails, and when the server refuses a tool a component registers. Without it, a refusal is a warning.

Hooks

Every hook takes { server: 'name' } to use one of the provider's other servers.

HookReturns
useFrontMcp(name?){ name, server, client, status, error, tools, resources, resourceTemplates, prompts, registry, connect }
useCallTool(name, options?)[call, { data, loading, error, called }, reset]. Options: onSuccess, onError, resetOnToolChange.
useReadResource(uri, options?)Reads on mount: { data, loading, error, refetch }. Without a URI, [read, state] to read on demand.
useGetPrompt(name, options?)[getPrompt, { data, loading, error }]
useListTools(), useListPrompts()The server's tools or prompts, kept current.
useListResources(){ resources, resourceTemplates }
useStoreResource(uri){ data, loading, error, refetch } for a state:// resource, read again whenever the server says it changed.
useDynamicTool(options)Registers a tool while the component is mounted (below).
useDynamicResource(options)Registers a resource, { uri, name, description?, mimeType?, read }, while the component is mounted.
useComponentTree({ rootRef, uri?, ... })Registers a resource (react://component-tree by default) that describes the DOM under rootRef, named by each element's data-component.

Giving the model a tool from a component

import { useDynamicTool, z } from '@frontmcp/react';

export function Cart({ isLoggedIn }: { isLoggedIn: boolean }) {
  useDynamicTool({
    name: 'add_to_cart',
    description: 'Add an item to the shopping cart',
    schema: z.object({ itemId: z.string(), quantity: z.number().optional() }),
    execute: async ({ itemId, quantity }) => {
      addToCart(itemId, quantity ?? 1);
      return { content: [{ type: 'text', text: 'Added to cart' }] };
    },
    enabled: isLoggedIn,
  });

  return <div>Cart</div>;
}

The input is checked against schema before execute runs, and execute gets it typed. A raw JSON Schema in inputSchema works too. The provider registers the tool with the server as a real tool, through server.registerTool(), so its calls run through the server's flow (plugin hooks, authorities, availableWhen) and every client sees it, an in-page agent through @frontmcp/plugin-webmcp included. A name the server already has is refused and reported through the provider's onError.

Letting a model show a component

mcpComponent() wraps a component so that a model can show it: while it's mounted it registers a tool, and the tool's input, checked against schema, becomes the component's props.

import { mcpComponent, z } from '@frontmcp/react';

export const WeatherCard = mcpComponent(
  ({ city, temp }) => (
    <div>
      <h2>{city}</h2>
      <p>{temp}°</p>
    </div>
  ),
  {
    name: 'show_weather',
    description: 'Show the weather for a city',
    schema: z.object({ city: z.string(), temp: z.number() }),
    fallback: <p>Waiting for weather data…</p>,
  },
);

// Render it like any component: <WeatherCard />

Props you pass yourself, like <WeatherCard city="Oslo" />, render right away and are merged over the model's. Call mcpComponent() at module level, not inside a component. The first argument can also be a lazy import wrapped in mcpLazy(() => import('./HeavyChart')), or null with a columns option for a plain table, where the tool takes { rows: [...] }:

export const OrderTable = mcpComponent(null, {
  name: 'show_orders',
  description: 'Show a list of orders',
  schema: z.object({ id: z.string(), product: z.string(), price: z.number() }),
  columns: [
    { key: 'id', header: 'Order ID' },
    { key: 'product', header: 'Product' },
    { key: 'price', header: 'Price', render: (value) => `$${value}` },
  ],
});

Components

ComponentDescription
ToolFormA form generated from a tool's inputSchema. Unstyled, or your own fields with renderField.
PromptFormA form generated from a prompt's arguments.
ResourceViewerShows a read result, { contents }.
OutputDisplayShows a tool or prompt result as text or indented JSON.
DynamicRenderer, ComponentRegistryRender a tree of { type, props?, children? } nodes with components registered by URI.
readDomById, readDomBySelectorRead the page as a resource result, for a resource template.
AgentContent, AgentSearchDeprecated: use mcpComponent().

Exposing app state

Each adapter in the provider's stores becomes a resource with the whole state (state://<name>), a resource per selector (state://<name>/<selector>) and a tool per action (<name>_<action>):

import { createStore, FrontMcpProvider, reduxStore, valtioStore } from '@frontmcp/react';

const stores = [
  reduxStore({
    store: todoStore,
    selectors: { todos: (state) => (state as { todos: unknown[] }).todos },
    actions: { addTodo: (text) => ({ type: 'todos/add', text }) },
  }),
  valtioStore({ proxy: settings, subscribe, paths: { userName: 'user.name' } }),
  createStore({ name: 'counter', getState: getCounter, subscribe: onCounterChange }),
];

export function Root() {
  return (
    <FrontMcpProvider server={server} stores={stores}>
      <App />
    </FrontMcpProvider>
  );
}

reduxStore names its store redux unless you pass name, and dispatches what each action creator returns. valtioStore defaults to valtio; pass it subscribe from valtio/utils. Keep the stores array outside the component. To expose a store only while a component is mounted, use the hooks from @frontmcp/react/state with the same options: useReduxResource(), useValtioResource(), and useStoreResource(), which takes createStore()'s options. That useStoreResource() registers a store; the one from @frontmcp/react reads a state:// resource.

Registering API operations as tools

import { createFetchClient, parseOpenApiSpec, useApiClient } from '@frontmcp/react/api';

const operations = parseOpenApiSpec(openApiDocument);
const client = createFetchClient();

export function ApiTools() {
  useApiClient({ baseUrl: 'https://api.example.com', operations, client });
  return null;
}

Each operation becomes a tool named api_<operationId> (set prefix to change api). client takes any HttpClient, an object with request({ method, url, headers, body? }), so you can use axios or a client that adds auth headers.

Handing the tools to an AI SDK

import { useAITools } from '@frontmcp/react/ai';

export function useOpenAITools() {
  const { tools, callTool, loading } = useAITools('openai');
  return { tools, callTool, ready: !loading && tools !== null };
}

tools is the server's tool list, components' tools included, in the platform's format; callTool(name, args) runs a tool and converts its result. useAITools() takes "openai", "claude", "langchain", "vercel-ai" or "raw". useTools(platform), for "openai", "claude" or "vercel-ai", returns processToolCalls(calls) instead, which runs a batch of the model's tool calls and returns the messages to send back. Outside React, createToolCallHandler(server, platform) gives you the same callTool. Keep API keys on a server of your own.

Letting a model move around the app

Put the router entries into the server, and call useRouterBridge() in a component inside both the router and the provider:

import { BrowserRouter, Route, Routes } from 'react-router-dom';

import { create, FrontMcpProvider } from '@frontmcp/react';
import { createRouterEntries, useRouterBridge } from '@frontmcp/react/router';

const { tools, resources } = createRouterEntries();
const server = await create({ info: { name: 'my-app', version: '1.0.0' }, tools, resources });

function RouterBridge() {
  useRouterBridge();
  return null;
}

export function App() {
  return (
    <BrowserRouter>
      <FrontMcpProvider server={server}>
        <RouterBridge />
        <Routes>
          <Route path="/home" element={<h1>Home</h1>} />
          <Route path="/settings" element={<h1>Settings</h1>} />
        </Routes>
      </FrontMcpProvider>
    </BrowserRouter>
  );
}

The server then has the navigate tool ({ path, replace? }), the go_back tool and the route://current resource. useRouterBridge() only connects React Router to them; without it mounted, they answer Router bridge not connected.

Docs

  • @frontmcp/react reference: the provider, serverRegistry, stores, running in a browser, testing in Node
  • React hooks: every hook, including /state, /api and /ai
  • React components: mcpComponent(), forms, DynamicRenderer, DOM resources, router tools
  • create(): building the server the provider connects to
  • @frontmcp/sdk: the server framework; create(), tools, resources and prompts come from it.
  • @frontmcp/plugin-webmcp: offers the server's tools, components' tools included, to in-browser agents.
  • @frontmcp/ui: React components and hooks for widgets that render inside an AI host.

Contributing

Source: libs/react. Issues and pull requests are welcome; see CONTRIBUTING.md.

License

Apache-2.0. See LICENSE.

版本与发布记录

@frontmcp/react 共发布 98 个版本,首次发布于 2026/03/17;过去 12 个月发布了 98 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.12.2latest2026/11/151 天前
1.12.12026/11/132 天前
1.12.02026/11/114 天前
1.12.0-rc.1rc2026/11/114 天前
1.11.32026/11/106 天前
1.11.22026/11/096 天前

其他发布通道:beta → 1.1.2-beta.1,rc → 1.12.0-rc.1。

关于 @frontmcp/react 的常见问题

@frontmcp/react 是什么?

Run a FrontMCP server inside a React app: provider, hooks, components and AI SDK integration

如何安装 @frontmcp/react?

在项目目录运行 npm install @frontmcp/react,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^18.0.0 || ^19.0.0)、react-dom(^18.0.0 || ^19.0.0)、@frontmcp/sdk(1.12.2)、@frontmcp/utils(1.12.2)、@frontmcp/lazy-zod(1.12.2)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@frontmcp/react 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@frontmcp/react 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@frontmcp/react 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@frontmcp/react 可以商用吗?

@frontmcp/react 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@frontmcp/react 的下载量有多少?

根据 npm 官方下载统计,@frontmcp/react 在 2026/10/16 – 2026/11/14 这 30 天内被下载 5,067 次,日均约 169 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@frontmcp/react 还在维护吗?

最新版本 1.12.2 发布于 2026/11/15(1 天前);至今共发布 98 个版本,其中过去 12 个月发布了 98 个;首次发布于 2026/03/17。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。