- MCP Server ToolsUpdated
- Managed MCP with chat()Updated
- Manual MCPUpdated
- MCP Type GenerationUpdated
- MCP Client InputUpdated
- MCP Server Tools: AdvancedNew
- MCP EventsNew
- MCP AppsUpdated
- Serve Tools over HTTPUpdated
- Serve Resources and PromptsUpdated
- Ask for InputUpdated
- Draft Text from a ToolUpdated
- MCP Server TasksUpdated
- MCP Server AuthUpdated
- MCP Server SessionsUpdated
- MCP Server on stdioUpdated
Persistence (Advanced)
- GenerationsUpdated
- Realtime Voice ChatUpdated
- Text-to-SpeechUpdated
- TranscriptionUpdated
- Transcription: AdvancedNew
- Voice CreationUpdated
- Audio RecordingUpdated
- Audio GenerationUpdated
- Image GenerationUpdated
- Image Generation: AdvancedNew
- Video GenerationUpdated
- Video Generation: AdvancedNew
- Live GenerationUpdated
- World GenerationUpdated
- Generation HooksUpdated
- OverviewUpdated
- Quick StartUpdated
- ProvidersUpdated
- HarnessesUpdated
- Harness AuthUpdated
- WorkspaceUpdated
- ToolsUpdated
- PolicyUpdated
- Lifecycle & SnapshotsUpdated
- Portable SnapshotsUpdated
- Keep Files After ReloadUpdated
- Save a Named VersionUpdated
- Branch From a VersionUpdated
- Send a Frozen FileUpdated
- Let the Agent Save and ForkUpdated
- Pick Which Files to KeepUpdated
- What a Snapshot StoresUpdated
- Instance DurabilityUpdated
- Durable RunsUpdated
- EventsUpdated
Sandboxes (Advanced)
- Runtime ContextUpdated
- Bring Your Own KeyUpdated
- Debug LoggingUpdated
- Multimodal ContentUpdated
- Files APIUpdated
- Per-Model Type SafetyUpdated
- Runtime Adapter SwitchingUpdated
- Tree-ShakingUpdated
- Extend AdapterUpdated
- Extend Adapter: AdvancedNew
- Typed Pre-Configured OptionsUpdated
- Test with a Fake ModelUpdated
- Prompt CachingUpdated
- Mid-Conversation ChangesUpdated
- Approval Flow ProcessingUpdated
WebMCP Tools
WebMCP publishes named actions on the page. A browser agent calls an action by name instead of clicking the UI.
You register your TanStack client tools on document.modelContext. The agent finds them there and calls them.
Warning
WebMCP is experimental. Treat it as an extra for browsers that support it. Your page must work without it.
This page sends your tools to WebMCP. To use the WebMCP tools of a page in your own chat, see Page WebMCP Tools in Chat.
Set it up#
1. Install the packages#
npm i @tanstack/ai @tanstack/ai-react zodpnpm add @tanstack/ai @tanstack/ai-react zodyarn add @tanstack/ai @tanstack/ai-react zodbun add @tanstack/ai @tanstack/ai-react zod2. Define a client tool#
Put the tool at module scope. This tool opens a help panel:
// tools.ts
import { toolDefinition } from '@tanstack/ai'
import { z } from 'zod'
export const openHelpPanel = toolDefinition({
name: 'open_help_panel',
description: 'Open the help panel for a topic',
inputSchema: z.object({
topic: z.string(),
}),
outputSchema: z.object({
opened: z.boolean(),
}),
}).client((input) => {
const panel = document.querySelector<HTMLElement>('#help-panel')
if (!panel) {
return { opened: false }
}
panel.dataset.topic = input.topic
panel.showPopover()
return { opened: true }
})
export const webMCPTools = [openHelpPanel]3. Register the tool#
Call the register function for your framework. When the component goes away, the function removes the tools.
Call useRegisterWebMCPTools in a component. Keep the tool array and the options stable, for example at module scope.
import { useRegisterWebMCPTools } from '@tanstack/ai-react'
import { webMCPTools } from './tools'
const webMCPOptions = {
onError(error: unknown) {
console.error('WebMCP registration failed', error)
},
}
export function HelpPage() {
useRegisterWebMCPTools(webMCPTools, webMCPOptions)
return (
<section id="help-panel" popover="auto">
<h2>Help</h2>
</section>
)
}That is all. In a browser with WebMCP, an agent on this page can now find and call open_help_panel. In other browsers, the page works the same as before.
How it works#
- The register function turns each tool into a WebMCP tool. The input schema becomes JSON Schema, so the agent knows what to send.
- The agent calls the tool by name.
- WebMCP runs your .client() function in the page.
- The result goes back to the agent. It does not start or continue a TanStack chat run.
During SSR, in an insecure context, or in a browser without WebMCP, the register function adds no tools. It does not throw, so you can call it everywhere.
Each tool must have:
- A .client() function. WebMCP needs code that it can run.
- A description that is not empty.
- A name of 1 to 128 ASCII letters, numbers, underscores, hyphens, or periods.
- An input schema that accepts an object.
- No needsApproval: true. See Security.
If a tool breaks one of these rules, registration fails and onError gets the error.
Advanced#
Register without a framework#
If your own code owns the lifecycle, use registerWebMCPTools from @tanstack/ai-client. The signal option is required. The tools stay registered until the signal aborts.
import { registerWebMCPTools } from '@tanstack/ai-client'
import { webMCPTools } from './tools'
const registration = new AbortController()
await registerWebMCPTools(webMCPTools, {
signal: registration.signal,
toolOptions: {
open_help_panel: {
title: 'Open help',
annotations: {
readOnlyHint: false,
untrustedContentHint: false,
},
},
},
})
export function disposeWebMCPTools() {
registration.abort()
}Call disposeWebMCPTools() from the teardown code of your application shell. Do not call it on pagehide, because the browser can restore the page from the back/forward cache.
registerWebMCPTools returns a promise. If registration fails, the promise rejects.
Options#
All framework wrappers accept these options. registerWebMCPTools accepts the first two, plus signal.
- toolOptions: a title and annotations for each tool, by tool name.
- context: the value that your handler gets as context. If a client tool declares a context, context and the options argument are required.
- onError: gets a registration failure.
The annotations are hints for the browser agent:
- readOnlyHint: the tool does not change state.
- untrustedContentHint: the tool can return content that your app does not trust.
The annotations do not enforce permissions or approval.
Stable values in React, Preact, and Octane#
In these frameworks, a new tools or options value replaces the registrations. If the contents do not change, keep both values stable. Stable values prevent extra changes to the WebMCP registry.
What your handler gets#
WebMCP calls your client handler directly. The handler gets these values:
- abortSignal: the WebMCP signal for this call. Pass it to browser APIs that you can cancel.
- context: the value from the register options.
- emitCustomEvent: does nothing, because no TanStack stream exists.
- toolCallId: not set, because WebMCP does not give one.
The two signals have different jobs:
- The registration signal removes the tools.
- The execution signal (abortSignal) cancels one call.
Cancellation is cooperative. Your handler must read abortSignal, or pass it to an API that supports cancellation.
Validation#
The register function converts each input schema to JSON Schema for WebMCP.
- Standard Schema (for example Zod): TanStack AI validates the input before your handler runs. It also validates the output before the result goes back to WebMCP.
- Raw JSON Schema: the schema only describes the data. TanStack AI does not validate with it. Validate untrusted input inside the handler, and return a value that matches the output schema.
Tool results must be JSON-serializable. If a result cannot be serialized, WebMCP reports the failure to its caller.
Security#
A tool with needsApproval: true cannot register with WebMCP. WebMCP annotations cannot enforce the TanStack approval flow.
Do not protect a sensitive action with a browser check only. Your server endpoint must enforce these rules:
- Authentication.
- Authorization.
- Rate limits.
- Business rules.
Duplicate tool names#
Tool names must be unique.
- If one call has two tools with the same name, the call fails before it changes the registry.
- If another owner already registered a name, WebMCP rejects that name.
- If registration fails, the register function removes only the tools that this call added.
Upgrade from 0.x#
The 1.0 names of the wrapper functions and their option types are in the 1.0 upgrade guide.