Tool Rendering

Register React renderers for assistant-ui tool calls, tool results, and model data parts.

API Reference

DataRenderers

DataRenderers props
length0

toString() => string

toLocaleString{ (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string; }

pop() => undefined

push(...items: never[]) => number

concat{ (...items: ConcatArray<never>[]): never[]; (...items: ConcatArray<never>[]): never[]; }

join(separator?: string) => string

reverse() => never[]

shift() => undefined

slice(start?: number, end?: number) => never[]

sort(compareFn?: ((a: never, b: never) => number) | undefined) => []

splice{ (start: number, deleteCount?: number): never[]; (start: number, deleteCount: number, ...items: never[]): never[]; }

unshift(...items: never[]) => number

indexOf(searchElement: never, fromIndex?: number) => number

lastIndexOf(searchElement: never, fromIndex?: number) => number

every{ <S>(predicate: (value: never, index: number, array: never[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: never, index: number, array: never[]) => unknown, thisArg?: any): boolean; }

some(predicate: (value: never, index: number, array: never[]) => unknown, thisArg?: any) => boolean

forEach(callbackfn: (value: never, index: number, array: never[]) => void, thisArg?: any) => void

map<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]

filter{ <S>(predicate: (value: never, index: number, array: never[]) => value is S, thisArg?: any): S[]; (predicate: (value: never, index: number, array: never[]) => unknown, thisArg?: any): never[]; }

reduce{ (callbackfn: (previousValue: never, currentValue: never, currentIndex: number, array: never[]) => never): never; (callbackfn: (previousValue: never, currentValue: never, currentIndex: number, array: never[]) => never, initialValue: never): never; <U>(callbackfn: (previousValue: U, currentValue: never, currentIndex: number, array: never[]) => U, initialValue: U): U; }

reduceRight{ (callbackfn: (previousValue: never, currentValue: never, currentIndex: number, array: never[]) => never): never; (callbackfn: (previousValue: never, currentValue: never, currentIndex: number, array: never[]) => never, initialValue: never): never; <U>(callbackfn: (previousValue: U, currentValue: never, currentIndex: number, array: never[]) => U, initialValue: U): U; }

find{ <S>(predicate: (value: never, index: number, obj: never[]) => value is S, thisArg?: any): S | undefined; (predicate: (value: never, index: number, obj: never[]) => unknown, thisArg?: any): undefined; }

findIndex(predicate: (value: never, index: number, obj: never[]) => unknown, thisArg?: any) => number

fill(value: never, start?: number, end?: number) => []

copyWithin(target: number, start: number, end?: number) => []

entries() => ArrayIterator<[number, never]>

keys() => ArrayIterator<number>

values() => ArrayIterator<never>

includes(searchElement: never, fromIndex?: number) => boolean

flatMap<U, This>(callback: (this: This, value: never, index: number, array: never[]) => U | readonly U[], thisArg?: This | undefined) => U[]

flat<A, D>(this: A, depth?: D | undefined) => FlatArray<A, D>[]

at(index: number) => undefined

findLast{ <S>(predicate: (value: never, index: number, array: never[]) => value is S, thisArg?: any): S | undefined; (predicate: (value: never, index: number, array: never[]) => unknown, thisArg?: any): undefined; }

findLastIndex(predicate: (value: never, index: number, array: never[]) => unknown, thisArg?: any) => number

toReversed() => never[]

toSorted(compareFn?: ((a: never, b: never) => number) | undefined) => never[]

toSpliced{ (start: number, deleteCount: number, ...items: never[]): never[]; (start: number, deleteCount?: number): never[]; }

with(index: number, value: never) => never[]

getMcpAppFromToolPart

Returns MCP app metadata for a tool-call part that points at a ui:// resource.

Returns undefined when the part has no MCP app metadata or the metadata does not reference an assistant-ui MCP app resource.

getMcpAppFromToolPart
partToolPartLike

ToolPartLike
mcp?ToolCallMessagePartMcpMetadata

MCP app metadata associated with this tool call, when present.

ToolCallMessagePartMcpMetadata
app?McpAppMetadata

McpAppMetadata
resourceUristring

mimeType?string

visibility?readonly ("model" | "app")[]

serverId?string

Routable server identity emitted by the agent stack when multiple MCP servers back one agent; for

makeAssistantDataUI

Creates a React component that registers a named data-part renderer when rendered.

type AssistantDataUIProps = {
  /** Data part name this renderer handles. */
  name: string;
  /** Component rendered for matching data message parts. */
  render: DataMessagePartComponent<T>;
};

const makeAssistantDataUI: <T = any>(dataUI: AssistantDataUIProps<T>) => AssistantDataUI;

McpAppRenderer

McpAppRenderer props
0McpAppRendererOptions

McpAppRendererOptions
sandbox?McpAppSandboxConfig

Sandbox + container styling. Passes through to SafeContentFrame.

SandboxHostConfig
sandbox?SandboxOption[]

useShadowDom?boolean

enableBrowserCaching?boolean

salt?string

product?string

className?string

style?CSSProperties

unsafeDocumentWrite?boolean

maxHeight?number

Upper bound (in pixels) applied to the widget-driven auto-resize height. Defaults to 800.

hostInfo?McpAppHostInfo

Identifies the host to the widget in the `ui/initialize` response.

McpAppHostInfo
namestring

versionstring

hostContext?McpAppHostContext

Delivered to the widget on initialize and pushed via `notifications/host_context/changed` on change.

McpAppHostContext
theme?"light" | "dark"

displayMode?McpAppDisplayMode

availableDisplayModes?McpAppDisplayMode[]

handlers?Omit< McpAppBridgeHandlers, "callTool" | "readResource" | "listResources" >

Optional widget interaction and lifecycle handlers. Data-plane handlers (`callTool`, `readResource`, `listResources`) always use `host`. Which handlers a widget may call is captured when its frame mounts, so a `forPart` resolver returns the same handler keys for a part on every render even when the implementations change.

Omit
onError?(error: Error) => void

allowedTools?readonly string[]

openLink?(params: { url: string }) => Promise<unknown> | unknown

sendMessage?(params: unknown) => Promise<unknown> | unknown

updateModelContext?(params: unknown) => Promise<unknown> | unknown

requestDisplayMode?(params: { mode: McpAppDisplayMode; }) => Promise<{ mode: McpAppDisplayMode }> | { mode: McpAppDisplayMode }

onSizeChange?(params: { width?: number; height?: number }) => void

onInitialized?() => void

onRequestTeardown?(params: unknown) => void

onLog?(params: unknown) => void

fallback?ReactNode

Rendered when no MCP app is on the part, or while load is in flight / failed (unless overridden).

loadingFallback?ReactNode

Rendered while the resource is loading. Defaults to `fallback`.

errorFallback?ReactNode | ((error: Error) => ReactNode)

Rendered when the resource load rejects. Defaults to `fallback`.

hostResourceElement<McpAppsHost>

Provides the data-plane operations the widget can request (`loadResource`, `callTool`, `readResource`, `listResources`). Use `McpAppsRemoteHost({ url })` for the default HTTP-route convention.

ResourceElement
hook(...args: any[]) => V

argsreadonly unknown[]

key?string | number

deps?readonly unknown[]

forPart?(part: ToolCallMessagePart) => McpAppPartOptions

Resolves the options for one part. Each returned value replaces the thread-wide option of the same name, so a host can give every MCP app its own display mode and answer `requestDisplayMode` for the part that asked. `handlers` is the exception and merges per key. Its keys are capabilities negotiated with the widget rather than data, so replacing the whole bag to add one handler would withdraw the others from that part's widget with nothing to observe it by.

length1

toString() => string

toLocaleString{ (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string; }

pop() => McpAppRendererOptions

push(...items: McpAppRendererOptions[]) => number

concat{ (...items: ConcatArray<McpAppRendererOptions>[]): McpAppRendererOptions[]; (...items: (McpAppRendererOptions | ConcatArray<McpAppRendererOptions>)[]): McpAppRendererOptions[]; }

join(separator?: string) => string

reverse() => McpAppRendererOptions[]

shift() => McpAppRendererOptions

slice(start?: number, end?: number) => McpAppRendererOptions[]

sort(compareFn?: ((a: McpAppRendererOptions, b: McpAppRendererOptions) => number) | undefined) => [options: McpAppRendererOptions]

splice{ (start: number, deleteCount?: number): McpAppRendererOptions[]; (start: number, deleteCount: number, ...items: McpAppRendererOptions[]): McpAppRendererOptions[]; }

unshift(...items: McpAppRendererOptions[]) => number

indexOf(searchElement: McpAppRendererOptions, fromIndex?: number) => number

lastIndexOf(searchElement: McpAppRendererOptions, fromIndex?: number) => number

every{ <S>(predicate: (value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => unknown, thisArg?: any): boolean; }

some(predicate: (value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => unknown, thisArg?: any) => boolean

forEach(callbackfn: (value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => void, thisArg?: any) => void

map<U>(callbackfn: (value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => U, thisArg?: any) => U[]

filter{ <S>(predicate: (value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => value is S, thisArg?: any): S[]; (predicate: (value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => unknown, thisArg?: any): McpAppRendererOptions[]; }

reduce{ (callbackfn: (previousValue: McpAppRendererOptions, currentValue: McpAppRendererOptions, currentIndex: number, array: McpAppRendererOptions[]) => McpAppRendererOptions): McpAppRendererOptions; (callbackfn: (previousValue: McpAppRendererOptions, currentValue: McpAppRendererOptions, currentIndex: number, array: McpAppRendererOptions[]) => McpAppRendererOptions, initialValue: McpAppRendererOptions): McpAppRendererOptions; <U>(callbackfn: (previousValue: U, currentValue: McpAppRendererOptions, currentIndex: number, array: McpAppRendererOptions[]) => U, initialValue: U): U; }

reduceRight{ (callbackfn: (previousValue: McpAppRendererOptions, currentValue: McpAppRendererOptions, currentIndex: number, array: McpAppRendererOptions[]) => McpAppRendererOptions): McpAppRendererOptions; (callbackfn: (previousValue: McpAppRendererOptions, currentValue: McpAppRendererOptions, currentIndex: number, array: McpAppRendererOptions[]) => McpAppRendererOptions, initialValue: McpAppRendererOptions): McpAppRendererOptions; <U>(callbackfn: (previousValue: U, currentValue: McpAppRendererOptions, currentIndex: number, array: McpAppRendererOptions[]) => U, initialValue: U): U; }

find{ <S>(predicate: (value: McpAppRendererOptions, index: number, obj: McpAppRendererOptions[]) => value is S, thisArg?: any): S | undefined; (predicate: (value: McpAppRendererOptions, index: number, obj: McpAppRendererOptions[]) => unknown, thisArg?: any): McpAppRendererOptions | undefined; }

findIndex(predicate: (value: McpAppRendererOptions, index: number, obj: McpAppRendererOptions[]) => unknown, thisArg?: any) => number

fill(value: McpAppRendererOptions, start?: number, end?: number) => [options: McpAppRendererOptions]

copyWithin(target: number, start: number, end?: number) => [options: McpAppRendererOptions]

entries() => ArrayIterator<[number, McpAppRendererOptions]>

keys() => ArrayIterator<number>

values() => ArrayIterator<McpAppRendererOptions>

includes(searchElement: McpAppRendererOptions, fromIndex?: number) => boolean

flatMap<U, This>(callback: (this: This, value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => U | readonly U[], thisArg?: This | undefined) => U[]

flat<A, D>(this: A, depth?: D | undefined) => FlatArray<A, D>[]

at(index: number) => McpAppRendererOptions

findLast{ <S>(predicate: (value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => value is S, thisArg?: any): S | undefined; (predicate: (value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => unknown, thisArg?: any): McpAppRendererOptions | undefined; }

findLastIndex(predicate: (value: McpAppRendererOptions, index: number, array: McpAppRendererOptions[]) => unknown, thisArg?: any) => number

toReversed() => McpAppRendererOptions[]

toSorted(compareFn?: ((a: McpAppRendererOptions, b: McpAppRendererOptions) => number) | undefined) => McpAppRendererOptions[]

toSpliced{ (start: number, deleteCount: number, ...items: McpAppRendererOptions[]): McpAppRendererOptions[]; (start: number, deleteCount?: number): McpAppRendererOptions[]; }

with(index: number, value: McpAppRendererOptions) => McpAppRendererOptions[]

McpAppsRemoteHost

McpAppsRemoteHost props
0McpAppsRemoteHostOptions

McpAppsRemoteHostOptions
urlstring

fetch?typeof fetch

headers?Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>)

length1

toString() => string

toLocaleString{ (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string; }

pop() => McpAppsRemoteHostOptions

push(...items: McpAppsRemoteHostOptions[]) => number

concat{ (...items: ConcatArray<McpAppsRemoteHostOptions>[]): McpAppsRemoteHostOptions[]; (...items: (McpAppsRemoteHostOptions | ConcatArray<McpAppsRemoteHostOptions>)[]): McpAppsRemoteHostOptions[]; }

join(separator?: string) => string

reverse() => McpAppsRemoteHostOptions[]

shift() => McpAppsRemoteHostOptions

slice(start?: number, end?: number) => McpAppsRemoteHostOptions[]

sort(compareFn?: ((a: McpAppsRemoteHostOptions, b: McpAppsRemoteHostOptions) => number) | undefined) => [options: McpAppsRemoteHostOptions]

splice{ (start: number, deleteCount?: number): McpAppsRemoteHostOptions[]; (start: number, deleteCount: number, ...items: McpAppsRemoteHostOptions[]): McpAppsRemoteHostOptions[]; }

unshift(...items: McpAppsRemoteHostOptions[]) => number

indexOf(searchElement: McpAppsRemoteHostOptions, fromIndex?: number) => number

lastIndexOf(searchElement: McpAppsRemoteHostOptions, fromIndex?: number) => number

every{ <S>(predicate: (value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => unknown, thisArg?: any): boolean; }

some(predicate: (value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => unknown, thisArg?: any) => boolean

forEach(callbackfn: (value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => void, thisArg?: any) => void

map<U>(callbackfn: (value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => U, thisArg?: any) => U[]

filter{ <S>(predicate: (value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => value is S, thisArg?: any): S[]; (predicate: (value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => unknown, thisArg?: any): McpAppsRemoteHostOptions[]; }

reduce{ (callbackfn: (previousValue: McpAppsRemoteHostOptions, currentValue: McpAppsRemoteHostOptions, currentIndex: number, array: McpAppsRemoteHostOptions[]) => McpAppsRemoteHostOptions): McpAppsRemoteHostOptions; (callbackfn: (previousValue: McpAppsRemoteHostOptions, currentValue: McpAppsRemoteHostOptions, currentIndex: number, array: McpAppsRemoteHostOptions[]) => McpAppsRemoteHostOptions, initialValue: McpAppsRemoteHostOptions): McpAppsRemoteHostOptions; <U>(callbackfn: (previousValue: U, currentValue: McpAppsRemoteHostOptions, currentIndex: number, array: McpAppsRemoteHostOptions[]) => U, initialValue: U): U; }

reduceRight{ (callbackfn: (previousValue: McpAppsRemoteHostOptions, currentValue: McpAppsRemoteHostOptions, currentIndex: number, array: McpAppsRemoteHostOptions[]) => McpAppsRemoteHostOptions): McpAppsRemoteHostOptions; (callbackfn: (previousValue: McpAppsRemoteHostOptions, currentValue: McpAppsRemoteHostOptions, currentIndex: number, array: McpAppsRemoteHostOptions[]) => McpAppsRemoteHostOptions, initialValue: McpAppsRemoteHostOptions): McpAppsRemoteHostOptions; <U>(callbackfn: (previousValue: U, currentValue: McpAppsRemoteHostOptions, currentIndex: number, array: McpAppsRemoteHostOptions[]) => U, initialValue: U): U; }

find{ <S>(predicate: (value: McpAppsRemoteHostOptions, index: number, obj: McpAppsRemoteHostOptions[]) => value is S, thisArg?: any): S | undefined; (predicate: (value: McpAppsRemoteHostOptions, index: number, obj: McpAppsRemoteHostOptions[]) => unknown, thisArg?: any): McpAppsRemoteHostOptions | undefined; }

findIndex(predicate: (value: McpAppsRemoteHostOptions, index: number, obj: McpAppsRemoteHostOptions[]) => unknown, thisArg?: any) => number

fill(value: McpAppsRemoteHostOptions, start?: number, end?: number) => [options: McpAppsRemoteHostOptions]

copyWithin(target: number, start: number, end?: number) => [options: McpAppsRemoteHostOptions]

entries() => ArrayIterator<[number, McpAppsRemoteHostOptions]>

keys() => ArrayIterator<number>

values() => ArrayIterator<McpAppsRemoteHostOptions>

includes(searchElement: McpAppsRemoteHostOptions, fromIndex?: number) => boolean

flatMap<U, This>(callback: (this: This, value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => U | readonly U[], thisArg?: This | undefined) => U[]

flat<A, D>(this: A, depth?: D | undefined) => FlatArray<A, D>[]

at(index: number) => McpAppsRemoteHostOptions

findLast{ <S>(predicate: (value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => value is S, thisArg?: any): S | undefined; (predicate: (value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => unknown, thisArg?: any): McpAppsRemoteHostOptions | undefined; }

findLastIndex(predicate: (value: McpAppsRemoteHostOptions, index: number, array: McpAppsRemoteHostOptions[]) => unknown, thisArg?: any) => number

toReversed() => McpAppsRemoteHostOptions[]

toSorted(compareFn?: ((a: McpAppsRemoteHostOptions, b: McpAppsRemoteHostOptions) => number) | undefined) => McpAppsRemoteHostOptions[]

toSpliced{ (start: number, deleteCount: number, ...items: McpAppsRemoteHostOptions[]): McpAppsRemoteHostOptions[]; (start: number, deleteCount?: number): McpAppsRemoteHostOptions[]; }

with(index: number, value: McpAppsRemoteHostOptions) => McpAppsRemoteHostOptions[]

useAssistantDataUI

Registers a renderer for named data message parts while the component is mounted.

useAssistantDataUI
dataUIAssistantDataUIProps<any> | null

AssistantDataUIProps<any> | null
namestring

Data part name this renderer handles.

renderDataMessagePartComponent<T>

Component rendered for matching data message parts.

toolApprovalAcceptsText

Whether the request asks for a free-form answer, on its own or alongside its options. Renderers read this to decide whether to offer a text affordance, and the runtime reads it to reject a text response the host cannot record.

const toolApprovalAcceptsText: (approval: { readonly display?: ToolApprovalDisplay; readonly allowFreeform?: boolean; }) => boolean;

makeAssistantToolUI

Warning

Deprecated. Put render/renderText on the matching toolkit entry, or use MessagePrimitive.Parts inline tool render overrides for per-message UI. See https://assistant-ui.com/docs/migrations/toolkit-tools.

Creates a React component that registers a tool-call renderer when rendered.

Use this to package reusable display components for tools whose definitions are registered elsewhere.

type AssistantToolUIProps = {
  /** Name of the tool whose calls should use this renderer. */
  toolName: string;
  /** Component rendered for matching tool-call message parts. */
  render: ToolCallMessagePartComponent<TArgs, TResult>;
  /**
   * How the UI is presented relative to the chain-of-thought trace. Set
   * `"standalone"` to surface it on its own (e.g. human-in-the-loop or
   * generative UI for a backend/MCP tool). Defaults to `"inline"`.
   */
  display?: "standalone" | "inline";
};

const makeAssistantToolUI: <TArgs, TResult>(tool: AssistantToolUIProps<TArgs, TResult>) => AssistantToolUI;

useAssistantToolUI

Warning

Deprecated. Put render/renderText on the matching toolkit entry, or use MessagePrimitive.Parts inline tool render overrides for per-message UI. See https://assistant-ui.com/docs/migrations/toolkit-tools.

Registers a tool-call renderer while the component is mounted.

This only affects rendering. Pair it with Tools or a backend tool registry to expose the actual tool definition to the model.

useAssistantToolUI
toolAssistantToolUIProps<any, any> | null

AssistantToolUIProps<any, any> | null
toolNamestring

Name of the tool whose calls should use this renderer.

renderToolCallMessagePartComponent<TArgs, TResult>

Component rendered for matching tool-call message parts.

display?"standalone" | "inline"

How the UI is presented relative to the chain-of-thought trace. Set `"standalone"` to surface it on its own (e.g. human-in-the-loop or generative UI for a backend/MCP tool). Defaults to `"inline"`.