Agent components are React components that register MCP tools automatically. Agents interact with these components by calling tools — pushing data into the UI or receiving UI state.
mcpComponent
The recommended way to create agent-driven components. mcpComponent() is a factory that wraps a React component + zod schema into an MCP-registered component with full type safety.
import { mcpComponent } from '@frontmcp/react';
import { z } from 'zod';
const WeatherCard = mcpComponent(
({ city, temp }) => (
<div className="weather-card">
<h2>{city}</h2>
<p>{temp}°</p>
</div>
),
{
name: 'show_weather',
description: 'Display weather data for a city',
schema: z.object({
city: z.string(),
temp: z.number(),
}),
fallback: <p>Waiting for weather data...</p>,
},
);
// Use it like a normal component
function App() {
return <WeatherCard />;
}
How It Works
- On mount,
mcpComponent registers an MCP tool with the given name and zod schema
- Input is validated against the zod schema before reaching your component
- Before any agent invocation, the
fallback is rendered
- When an agent calls the tool, the validated data is passed as typed props
- The tool returns a success response to the agent
Options
| Option | Type | Default | Description |
|---|
name | string | — | Required. MCP tool name agents will call |
description | string | name | Tool description for agents |
schema | z.ZodObject | — | Required. Zod schema for type-safe input |
fallback | ReactNode | null | Shown before first invocation |
server | string | — | Target a named server |
columns | McpColumnDef[] | — | Table mode column definitions |
Static Properties
The returned component has a .toolName property:
const WeatherCard = mcpComponent(WeatherCardImpl, { name: 'show_weather', schema });
console.log(WeatherCard.toolName); // 'show_weather'
Patterns
Wrapping Existing Components
import { WeatherCardImpl } from './WeatherCard';
const WeatherCard = mcpComponent(WeatherCardImpl, {
name: 'show_weather',
description: 'Display weather data',
schema: z.object({ city: z.string(), temp: z.number() }),
fallback: <Skeleton />,
});
Inline Components
const MetricsCard = mcpComponent(
({ cpu, memory }) => (
<div>
<span>CPU: {cpu}%</span>
<span>Memory: {memory}%</span>
</div>
),
{
name: 'show_metrics',
schema: z.object({ cpu: z.number(), memory: z.number() }),
},
);
Lazy Loading
const HeavyChart = mcpComponent(
() => import('./HeavyChart'),
{
name: 'show_chart',
schema: z.object({ data: z.array(z.number()), label: z.string() }),
fallback: <p>Loading chart...</p>,
},
);
Use multiple mcpComponent instances to build agent-controlled dashboards:
function AgentDashboard() {
return (
<div className="grid grid-cols-2 gap-4">
<MetricsCard />
<WeatherCard />
<OrderTable />
</div>
);
}
Direct Props
The returned component accepts partial props directly, which merge with agent-provided data:
<WeatherCard city="Default City" />
Table Mode
When component is null and columns is provided, mcpComponent renders a default <table>. The tool schema is automatically wrapped in { rows: z.array(schema) }.
import { mcpComponent } from '@frontmcp/react';
import { z } from 'zod';
const OrderTable = mcpComponent(null, {
name: 'show_orders',
description: 'Display order data as a table',
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: (v) => `$${v}` },
],
});
McpColumnDef
| Field | Type | Description |
|---|
key | string | Property key in the row object |
header | string | Column header text |
render | (value) => ReactNode | Optional custom cell renderer |
How Table Mode Works
- The agent calls the tool with
{ rows: [...] }
- Each row is validated against the zod schema
- The table renders with the specified columns
- Custom
render functions allow formatting (e.g., currency, dates)
Legacy Components
AgentContent
AgentContent is deprecated. Use mcpComponent() instead for type-safe schemas.
A component that registers itself as an MCP tool using raw JSON Schema.
import { AgentContent } from '@frontmcp/react';
<AgentContent
name="show_weather"
description="Display weather data"
inputSchema={{
type: 'object',
properties: {
city: { type: 'string' },
temp: { type: 'number' },
},
}}
render={(data) => (
<div>
<h2>{String(data.city)}</h2>
<p>{String(data.temp)}°</p>
</div>
)}
fallback={<p>Waiting for weather data...</p>}
/>
AgentSearch
AgentSearch is deprecated. Use mcpComponent() with the columns option for table-based result rendering.
A headless search component that registers an MCP tool for search execution.
import { AgentSearch } from '@frontmcp/react';
<AgentSearch
toolName="product_search"
description="Search products"
placeholder="Search..."
onResults={(results) => setSearchResults(results)}
/>
Migration Guide
AgentContent → mcpComponent:
// Before
<AgentContent
name="show_weather"
description="Display weather"
inputSchema={{ type: 'object', properties: { city: { type: 'string' } } }}
render={(data) => <div>{String(data.city)}</div>}
fallback={<p>Loading...</p>}
/>
// After
const WeatherCard = mcpComponent(
({ city }) => <div>{city}</div>,
{
name: 'show_weather',
description: 'Display weather',
schema: z.object({ city: z.string() }),
fallback: <p>Loading...</p>,
},
);
// Then use: <WeatherCard />
AgentSearch → mcpComponent table mode:
// Before
<AgentSearch
toolName="product_search"
description="Search products"
onResults={(results) => setResults(results)}
/>
// After
const ProductTable = mcpComponent(null, {
name: 'product_search',
description: 'Search products',
schema: z.object({ name: z.string(), price: z.number() }),
columns: [
{ key: 'name', header: 'Product' },
{ key: 'price', header: 'Price', render: (v) => `$${v}` },
],
});
// Then use: <ProductTable />