Tool Result Rendering
Frontend tools can include a render method that displays custom React components for their results. This creates rich, interactive content directly in the chat interface, going beyond simple text responses.
AI with Custom Tool Rendering
• Tools that render React componentsCustom Rendering with React Components
The render method receives the tool’s return value and renders a React component:
useAIFrontendTool({
name: "create_chart",
description: "Create a data visualization chart",
parameters: z.object({
title: z.string().describe("Title for the chart"),
type: z.enum(["bar", "pie", "line"]).describe("Type of chart"),
data: z.array(z.object({
label: z.string().describe("Label for data point"),
value: z.number().describe("Value for data point"),
})).describe("Data points for the chart"),
}),
execute: async (params) => {
return {
chartId: `chart-${Date.now()}`,
title: params.title,
type: params.type,
data: params.data,
createdAt: new Date().toISOString(),
};
},
render: (result) => (
<ChartComponent
title={result.title}
type={result.type}
data={result.data}
/>
),
});Complete Implementation Example
Here’s a full example showing tools with custom rendering:
"use client";
import React from "react";
import { ChatContainer, useAIFrontendTool } from "ai-chat-bootstrap";
import { z } from "zod";
// Custom Chart Component
function ChartComponent({ data, type, title }: {
data: Array<{ label: string; value: number }>;
type: "bar" | "pie" | "line";
title: string;
}) {
const maxValue = Math.max(...data.map(d => d.value));
return (
<div className="p-4 bg-card rounded-lg border">
<h3 className="text-lg font-semibold mb-4">{title}</h3>
<div className="space-y-3">
{data.map((item, index) => (
<div key={index} className="flex items-center gap-3">
<div className="w-16 text-sm text-muted-foreground">
{item.label}
</div>
<div className="flex-1 bg-muted rounded-full h-6 relative">
<div
className="h-full bg-primary rounded-full transition-all duration-500"
style={{ width: `${(item.value / maxValue) * 100}%` }}
/>
<div className="absolute inset-0 flex items-center justify-center text-xs font-medium">
{item.value}
</div>
</div>
</div>
))}
</div>
</div>
);
}
export function ToolRenderingDemo() {
// Chart creation tool with custom rendering
useAIFrontendTool({
name: "create_chart",
description: "Create a data visualization chart",
parameters: z.object({
title: z.string().describe("Title for the chart"),
type: z.enum(["bar", "pie", "line"]).describe("Type of chart"),
data: z.array(z.object({
label: z.string().describe("Label for data point"),
value: z.number().describe("Value for data point"),
})).describe("Data points for the chart"),
}),
execute: async (params) => {
return {
chartId: `chart-${Date.now()}`,
title: params.title,
type: params.type,
data: params.data,
createdAt: new Date().toISOString(),
};
},
render: (result) => (
<ChartComponent
title={result.title}
type={result.type}
data={result.data}
/>
),
});
return (
<ChatContainer
transport={{ api: "/api/chat" }}
messages={{
systemPrompt:
"You can create charts using the create_chart tool when users request data visualizations.",
}}
header={{ title: "AI with Custom Rendering" }}
ui={{ placeholder: "Ask me to create a chart!" }}
/>
);
}Backend Integration
The backend API route works the same way - tools with render methods are handled automatically:
import { createAzure } from "@ai-sdk/azure";
import { createAIChatHandler } from "ai-chat-bootstrap/server";
const azure = createAzure({
resourceName: process.env.AZURE_RESOURCE_NAME!,
apiKey: process.env.AZURE_API_KEY!,
apiVersion: process.env.AZURE_API_VERSION ?? "preview",
});
const model = azure(process.env.AZURE_DEPLOYMENT_ID!);
export const POST = createAIChatHandler({
model,
});Advanced Features
Conditional Rendering
Render different components based on the result:
render: (result) => {
if (result.type === 'success') {
return <SuccessCard message={result.message} />;
}
if (result.type === 'error') {
return <ErrorCard error={result.error} retry={result.retry} />;
}
return <DefaultCard data={result} />;
}State Management
Tools can interact with external state:
render: (result) => (
<div onClick={() => setSelectedItem(result.id)}>
<ItemCard
item={result}
isSelected={selectedItem === result.id}
/>
</div>
)Event Handling
Components can trigger additional actions:
render: (result) => (
<div className="p-4 bg-card rounded-lg border">
<h3>{result.title}</h3>
<button
onClick={() => {
// Trigger another tool or action
executeAnotherTool(result.id);
}}
className="mt-2 bg-primary text-primary-foreground px-4 py-2 rounded"
>
Process Result
</button>
</div>
)How It Works
- Tool Execution: Tool runs and returns structured data
- Render Invocation: The
rendermethod receives the result - Component Creation: A React component is created and rendered
- Chat Integration: The component appears in the chat message
- Interactivity: Users can interact with the rendered component
- State Updates: Components can trigger further tool executions
MCP Tool Rendering
Custom rendering also works with MCP (Model Context Protocol) tools!
While this page focuses on frontend tools registered with useAIFrontendTool, you can apply the same rendering patterns to tools provided by MCP servers. MCP tools are external services that expose tool capabilities via the Model Context Protocol.
Key Differences for MCP Tools
- Response Format: MCP tools return results in a standardized format with
contentarray - Registration: Use
toolRenderersarray in themcpprop instead ofuseAIFrontendTool - Identification: Match tools using
serverUrl+toolNamefor uniqueness
Quick Example
<ChatContainer
transport={{ api: "/api/chat" }}
mcp={{
enabled: true,
servers: [
{
id: "weather-server",
transport: {
type: "streamable-http",
url: "http://localhost:3030/mcp",
},
},
],
toolRenderers: [
{
serverUrl: "http://localhost:3030/mcp",
toolName: "get_weather",
render: (result) => {
// Parse MCP response format
const data = JSON.parse(result.content[0].text);
return <WeatherCard {...data} />;
},
},
],
}}
/>Learn More
For complete details on MCP tool rendering including:
- MCP response format parsing
- Multiple server configurations
- Tool uniqueness guarantees
- Debugging tips
See the MCP Servers - Custom Tool Rendering section.
API Reference
- Hook: useAIFrontendTool
- Hook: useAIChat
Next
Continue to Sharing Context →