useCallTool
The useCallTool function allows you to call additional MCP tools from your view. It wraps the window.openai.callTool function while providing a more convenient state management and typed API.
Make sure your tool _meta["openai/widgetAccessible"] property is set to true to make it accessible from views - more info on component-initiated tool calls.
Basic usage
Section titled “Basic usage”import { useCallTool } from "@usefractal/frac/web";import { useState } from "react";
function BookTableView() { const { callTool, isPending, isSuccess, data } = useCallTool< { time: string; people: number }, { structuredContent: { tableNumber: string } } >("bookTable");
return ( <div> <button disabled={isPending} onClick={() => callTool({ time: "12:00", people: 2 })} > Book Table </button> {isSuccess && <p>Table booked: {data.structuredContent.tableNumber}</p>} </div> );}Parameters
Section titled “Parameters”const { data, error, isError, isIdle, isPending, isSuccess, status, callTool, callToolAsync,} = useCallTool<ToolArgs, ToolResponse>(name);
callTool(toolArgs, { onError, onSettled, onSuccess,});
await callToolAsync(toolArgs);name: string;Required
The name of the tool to call. This must match the name of a tool registered on your MCP server.
Type Parameters
Section titled “Type Parameters”ToolArgs
Section titled “ToolArgs”ToolArgs extends CallToolArgs = nullThe type of arguments your tool accepts. Defaults to null for tools that don’t require arguments.
- If your tool has no arguments, you can omit this type parameter or set it to
null. - If your tool requires arguments, define the shape as a
Record<string, unknown>.
ToolResponse
Section titled “ToolResponse”ToolResponse extends Partial< { structuredContent: Record<string, unknown>; meta: Record<string, unknown> }> = {}The type of the response returned by your tool. This allows you to specify the exact shape of both the structuredContent and meta fields of your tool’s response.
Returns
Section titled “Returns”callTool
Section titled “callTool”callTool: (toolArgs?: ToolArgs, sideEffects?: SideEffects) => voidThe mutation function you can call to trigger the tool. Optionally pass side-effect callbacks.
toolArgs: ToolArgs- Optional if
ToolArgsisnull - The arguments to pass to the tool
- Optional if
sideEffects: SideEffects- Optional
- The side-effect callbacks to execute when the tool call is successful, encounters an error, or is settled:
onSuccess: (data: ToolResponse, toolArgs: ToolArgs) => void- Optional
- This function will fire when the tool call is successful and will be passed the tool’s response
onError: (error: unknown, toolArgs: ToolArgs) => void- Optional
- This function will fire if the tool call encounters an error
onSettled: (data: ToolResponse | undefined, error: unknown | undefined, toolArgs: ToolArgs) => void- Optional
- This function will fire when the tool call is either successful or encounters an error
callToolAsync
Section titled “callToolAsync”callToolAsync: (toolArgs?: ToolArgs) => Promise<ToolResponse>;Similar to callTool but returns a promise which can be awaited.
status
Section titled “status”status: "idle" | "pending" | "success" | "error";idle- Initial status prior to the tool call executingpending- The tool call is currently executingsuccess- The last tool call was successfulerror- The last tool call resulted in an error
isIdle, isPending, isSuccess, isError
Section titled “isIdle, isPending, isSuccess, isError”isIdle: boolean;isPending: boolean;isSuccess: boolean;isError: boolean;Boolean variables derived from status for convenience.
data: ToolResponse | undefined;- The successfully resolved data from the last tool call. Only available when the status is
success. - Contains the default
CallToolResponseshape merged with yourToolResponsetype:
type CallToolResponse = { /** content, isError and result shape is not configurable and shared across all tools */ content: { type: "text"; text: string }[]; isError: boolean; result: string; /** structuredContent and meta are shaped according to your ToolResponse type parameter */ structuredContent: Record<string, unknown>; meta: Record<string, unknown>;};error: unknown | undefined;- Only available when the status is
error. - The error object if the last tool call encountered an error
Examples
Section titled “Examples”With Side Effects
Section titled “With Side Effects”Handle success, error, and settled states with callbacks:
import { useCallTool } from "@usefractal/frac/web";
function SubmitForm() { const { callTool, isPending } = useCallTool<{ email: string }>("subscribe");
const handleSubmit = (email: string) => { callTool( { email }, { onSuccess: (data) => { console.log("Subscribed successfully!", data); }, onError: (error) => { console.error("Subscription failed:", error); }, onSettled: (data, error) => { console.log("Request completed", { data, error }); }, } ); };
return ( <button disabled={isPending} onClick={() => handleSubmit("user@example.com")} > Subscribe </button> );}Tools without arguments
Section titled “Tools without arguments”You can pass side effect options as the first argument to the callTool function if it doesn’t require any arguments.
import { useCallTool } from "@usefractal/frac/web";
function RefreshButton() { const { callTool, isPending } = useCallTool("refresh");
return ( <button disabled={isPending} onClick={() => callTool({ onSuccess: () => { console.log("Refreshed"); }, }) } > {isPending ? "Refreshing..." : "Refresh"} </button> );}Async/Await Pattern
Section titled “Async/Await Pattern”Use callToolAsync for async/await syntax:
import { useCallTool } from "@usefractal/frac/web";
function AsyncExample() { const { callToolAsync, isPending, isError, error } = useCallTool< { id: string }, { structuredContent: { name: string; price: number } } >("getProduct");
const handleClick = async () => { try { const response = await callToolAsync({ id: "123" }); console.log("Product:", response.structuredContent.name); } catch (err) { console.error("Failed to fetch product:", err); } };
return ( <div> <button disabled={isPending} onClick={handleClick}> Fetch Product </button> {isError && <p>Error: {String(error)}</p>} </div> );}Typed Response
Section titled “Typed Response”Leverage TypeScript to get full type safety on the response:
import { useCallTool } from "@usefractal/frac/web";
type WeatherArgs = { city: string; units?: "metric" | "imperial";};
type WeatherResponse = { structuredContent: { temperature: number; conditions: string; humidity: number; };};
function WeatherView() { const { callTool, data, isPending, isSuccess } = useCallTool< WeatherArgs, WeatherResponse >("getWeather");
return ( <div> <button disabled={isPending} onClick={() => callTool({ city: "Paris", units: "metric" })} > Get Weather </button>
{isSuccess && ( <div> <p>Temperature: {data.structuredContent.temperature}°C</p> <p>Conditions: {data.structuredContent.conditions}</p> <p>Humidity: {data.structuredContent.humidity}%</p> </div> )} </div> );}