Agent SDK
Client tools
Use the Agent SDK clientTools prop to let the agent refresh data, navigate the UI, and update the current page from inside your app.
clientTools lets the agent run browser-side functions inside the host app.
This is how an embedded agent goes beyond chat and starts interacting with your UI directly.
Use client tools for actions like:
- refreshing the page's data after an MCP mutation
- prefilling a form
- navigating to a different view
- selecting a record in the current screen
- opening a local modal or drawer
The prop shape#
The Agent SDK config accepts a clientTools map:
type ClientToolDefinition = {
description: string;
parameters: Record<
string,
{
type: string;
description: string;
required?: boolean;
enum?: string[];
}
>;
execute: (params: Record<string, unknown>) => Promise<unknown>;
requireConfirmation?: boolean;
};
type ClientToolsMap = Record<string, ClientToolDefinition>;Pass it directly to EmcyChat:
<EmcyChat
apiKey="emcy_sk_xxxx"
agentId="ag_xxxxx"
clientTools={clientTools}
/>Todo sample example#
The Todo sample app exposes two browser-side tools:
const clientTools: ClientToolsMap = {
fillQuickAddForm: {
description: "Pre-fill the quick-add input.",
parameters: {
title: {
type: "string",
description: "Task title.",
required: true,
},
},
execute: async ({ title }) => {
const nextTitle = String(title ?? "").trim();
if (!nextTitle) {
return { success: false, error: "Title required." };
}
setDraft(nextTitle);
return { success: true, title: nextTitle };
},
},
refreshTodoData: {
description: "Refresh the todo list.",
parameters: {},
execute: async () => refreshTodos(),
},
};That gives the agent two important capabilities:
- it can stage work in the local UI without calling the server
- it can keep the host page in sync after a real MCP-side mutation
When to use client tools vs MCP tools#
Use MCP tools when the action should happen on the server side or against a real backend API.
Use client tools when the action should happen in the browser or affect only the current UI state.
Good split:
-
MCP tool:
createTodo -
client tool:
refreshTodoData -
MCP tool:
getCustomer -
client tool:
navigateToCustomerDetails
Use prompt and context to teach the handoff#
The SDK will expose your clientTools, but you should still tell the agent when to use them.
Two good places:
- the agent
System Prompt - the per-turn
contextprop
Example:
<EmcyChat
context={{
hostRefreshInstruction:
"After any server-side todo mutation, call the refreshTodoData client tool before you answer so the host page reflects the latest data.",
}}
clientTools={clientTools}
/>That is a strong pattern for embedded agents: server truth comes from MCP, but visible UI completion comes from clientTools.
Best practices#
- keep client tool names explicit and verb-first
- describe what the tool changes in the UI
- return structured results from
execute - expose only actions that are safe for the current page
- keep the set small so the agent is not choosing from unnecessary browser actions
If a tool is destructive or easy to misuse, set requireConfirmation.