View the source code for this module on GitHub: https://github.com/mcp-use/mcp-use/blob/main/libraries/typescript/packages/mcp-use/src/react/useWidget.ts
useWidget abstracts over two data providers, selected automatically:
- MCP Apps bridge (SEP-1865
postMessage), the primary runtime for hosted widget iframes including ChatGPT. The hook connects viaui/initializeand listens forui/notifications/tool-input,ui/notifications/tool-input-partial,ui/notifications/tool-result, andui/notifications/host-context-changed. - URL params fallback (
mcpUseParams), used during local development (themcp-use devinspector) wheretoolInputandtoolOutputare injected via the query string. There is no live streaming in this mode.
content text array) separately from what the widget sees (structuredContent mapped to props). This lets a tool return rich structured data for rendering without polluting the model’s context.
All exports come from mcp-use/react:
Hooks
useWidget
The primary hook for building MCP Apps widgets. Returns props, persisted state, host context (theme, display mode, locale, layout), host actions (call a tool, send a message, open a link, request a display mode), and streaming and availability flags.TProps, TState, TOutput, TMetadata, TToolInput. The single runtime argument, defaultProps, seeds props before any tool data arrives.
props is merged from toolInput (base) and structuredContent (overlay). When the widget is exposed as a tool, props equals toolInput while pending and structuredContent once done. When the widget is returned by another tool, props equals structuredContent and toolInput holds the parent tool’s arguments.
Type Parameters
ParametersShape ofprops, mapped fromstructuredContentin the tool result (or fromtoolInputwhile pending).Shape of the persisted widgetstateread and written viasetState.Shape ofoutput, the rawstructuredContentfield from the tool result.Shape ofmetadata, the_metaobject from the tool result.Shape oftoolInput, the arguments the model passed to the tool.
ReturnsOptional initial props used as the merge base beforetoolInputorstructuredContentarrives. When omitted, the base is an empty object.
UseWidgetResult<TProps, TState, TOutput, TMetadata, TToolInput>, a discriminated union on isPending. While isPending is true, props is Partial<TProps>; once isPending is false, props is the full TProps.
SignatureMerged widget props.Partial<TProps>whileisPendingistrue, then the fullTPropsonce the tool result arrives. Defaults todefaultProps(or{}).The arguments the model passed when calling the tool, delivered viaui/notifications/tool-input. Defaults to{}when unavailable.ThestructuredContentfield from the tool result. Widget-only data the LLM never sees.nullwhile the tool is still executing.The_metaobject from the tool result (timestamps, cache headers, API version, etc.). Not in the model’s context.nullwhile pending, and alwaysnullon the URL params fallback.Persisted widget state the model can read on future turns.nulluntilsetStateis first called. The internal model-context key is stripped from the returned value.Update the persisted widget state. Accepts a new value or a functional updater(prev) => next. Sendsui/update-model-contextso the LLM sees the new state next turn. Rapid updates before the next user message are deduplicated by the host.The host’s color-scheme preference,"light"or"dark". Defaults to"light". Changes arrive viaui/notifications/host-context-changed.Current rendering context:"inline","fullscreen", or"pip". Defaults to"inline". On mobile,"pip"is coerced to"fullscreen"by the host.Safe-area inset boundaries (in pixels) for OS chrome (notch, home indicator, system bars). Defaults to{ insets: { top: 0, bottom: 0, left: 0, right: 0 } }. FromHostContext.safeAreaInsets.Maximum height the widget container can grow to, in pixels. Defaults to600. FromHostContext.containerDimensions.maxHeight.Maximum width the widget container can grow to, in pixels. FromHostContext.containerDimensions.maxWidth.undefinedwhen unbounded or unavailable (no default is applied).Device type and input-capability flags. Defaults to{ device: { type: "desktop" }, capabilities: { hover: true, touch: false } }. Derived fromHostContext.platformandHostContext.deviceCapabilities.The user’s BCP 47 language and region tag (for example"en-US"). Defaults toWIDGET_DEFAULTS.LOCALE. FromHostContext.locale.The user’s IANA timezone (for example"America/New_York"). FromHostContext.timeZone. Falls back to the browser timezone (Intl.DateTimeFormat().resolvedOptions().timeZone), or"UTC"when nowindowis present.Base URL of the MCP server running inside the sandbox, derived fromwindow.__mcpPublicUrlwith the/mcp-use/publicsuffix removed.""when unavailable.Call any tool registered on the MCP server (including app-only tools). Sendstools/callvia the host and returns a normalizedCallToolResponse.Add a user-role message to the conversation and trigger a new model turn. A plain string is wrapped as a singletextblock; an array ofMessageContentBlockis sent as-is. Sendsui/message.Ask the host to open a URL in the user’s browser or a new tab viaui/open-link. The host may deny the request; errors are logged, not thrown.Request a display-mode change viaui/request-display-mode. The host returns the actual granted mode, which may differ from the requested one.truewhen the MCP AppspostMessagebridge has connected.falsewhile connecting or on the URL params fallback (where it is alwaysfalse).truewhile the tool is still executing; becomesfalseonceui/notifications/tool-resultis received. Whiletrue,propsisPartial<TProps>. On the URL params fallback it istrueuntiltoolOutputis present.Partial tool arguments streamed in real time while the LLM is still generating them, viaui/notifications/tool-input-partial. A best-effort parse of incomplete JSON (auto-closed brackets), so fields may be missing or change.nullon the URL params fallback.truewhilepartialToolInputis non-null and the completetoolInputhas not yet arrived. Alwaysfalseon the URL params fallback.Name and version of the MCP Apps host from theui/initializehandshake.undefinedoutside a supported MCP Apps host.Capabilities advertised by the host duringui/initialize(SEP-1865HostCapabilities).undefinedoutside a supported host or when none were sent.Raw host context from the MCP Apps bridge. Includes standardized host style variables athostContext.styles.variableswhen provided.undefinedoutside a supported host.
new MCPServer({ ... }):
useWidgetProps
Convenience wrapper arounduseWidget that returns only the widget props. Equivalent to calling useWidget(defaultProps) and reading the props field.
Type Parameters
ParametersShape of the returned props.
ReturnsOptional initial props used as the merge base, forwarded touseWidget.
SignatureThe merged widget props. Fields may beundefinedwhile the tool is still executing.
useWidgetState
Convenience wrapper arounduseWidget that returns persisted state as a [state, setState] tuple, similar to useState but persisted and visible to the model. When defaultState is provided and the current state is null, the hook initializes it once the widget runtime is available (isAvailable === true).
Type Parameters
ParametersShape of the persisted state.
ReturnsOptional initial state. Applied viasetStateonly when the current state isnulland the runtime is available.
Signaturereturnsreadonly [TState | null, (state: TState | ((prev: TState | null) => TState)) => Promise<void>]A readonly tuple of the current state (nulluntil set) and thesetStateupdater. The updater accepts a value or a functional updater and persists viaui/update-model-context.
useWidgetTheme
Convenience wrapper arounduseWidget that returns only the current theme value.
Returns
SignatureThe host’s color-scheme preference,"light"or"dark". Defaults to"light".
Types
UseWidgetResult
The return type ofuseWidget. A discriminated union on isPending over a shared base of fields.
When isPending is true, props is typed as Partial<TProps> (fields may be undefined). When isPending is false, props is typed as the full TProps (all required fields present). Guarding on isPending narrows the type, so after an if (isPending) return ... guard, props field access is safe without optional chaining.
Every field is described in the useWidget Returns section above.
Type Parameters
SignatureShape ofprops.Shape ofstate.Shape ofoutput.Shape ofmetadata.Shape oftoolInput.
API
Type definition for thewindow.openai extension API exposed by the ChatGPT Apps SDK host. useWidget wraps these methods (for example callTool, sendFollowUpMessage, openExternal, requestDisplayMode, setState) so widget code does not call window.openai directly. The interface is parameterized by WidgetState.
Type Parameters
MembersShape of the persisted widget state passed tosetWidgetState.
SignatureCall a tool on your MCP server and return the full response.Trigger a follow-up turn in the conversation.Open an external link, redirect the web page, or open a mobile app.Transition the app between inline, fullscreen, and pip. The host may reject the request, and on mobile pip is always coerced to fullscreen.Persist widget state that will be shown to the model.Notify OpenAI about intrinsic height changes for auto-sizing.Upload a file to the host. Optional: only present when the OpenAI extension exposes file APIs. Detect availability withuseFiles().isSupported.Get a temporary download URL for a previously uploaded file. Optional: only present when the OpenAI extension exposes file APIs.
DisplayMode
The rendering context of a widget."inline" embeds the widget in the host’s content flow, "fullscreen" occupies the full screen or window, and "pip" is a floating picture-in-picture overlay. On mobile, "pip" requests are coerced to "fullscreen" by the host.
Signature
SafeArea
Host-provided safe-area boundaries for a widget. Wraps aSafeAreaInsets value under an insets key. Apply the insets as padding or margin so interactive elements are not hidden behind OS chrome.
Members
SignatureThe four-sided inset measurements, in pixels.
SafeAreaInsets
Pixel inset measurements for each side of the viewport, describing the space consumed by OS chrome (notch, home indicator, rounded corners, system bars). MembersSignatureInset from the top edge, in pixels.Inset from the bottom edge, in pixels.Inset from the left edge, in pixels.Inset from the right edge, in pixels.
Theme
The host’s color-scheme preference.useWidget defaults this to "light" when no host context is available.
Signature
DeviceType
The device class reported by the host, used asUserAgent.device.type. The MCP Apps bridge maps host platforms to "mobile" or "desktop"; "tablet" and "unknown" are valid members of the type.
Signature
UserAgent
Device type and input-capability flags reported by the host. Usedevice.type to adapt layout density and capabilities.hover / capabilities.touch to decide whether to show hover-only UI or touch-friendly hit targets.
Members
SignatureThe reported device class.Input capabilities: whether the device supports hover and whether it supports touch.
OpenAiGlobals
Type definition for the global state values exposed onwindow.openai by the ChatGPT Apps SDK host (theme, layout, locale, and tool state). useWidget reads equivalent values from the MCP Apps host context, so widget code does not access these globals directly. The interface is parameterized by the tool input, output, response-metadata, and widget-state shapes.
Type Parameters
MembersShape of the tool input arguments.Shape of the tool output.Shape of the tool response metadata.Shape of the persisted widget state.
SignatureCurrent color-scheme preference.Device type and input-capability flags.The user’s BCP 47 locale tag.Maximum container height, in pixels.Current display mode.Safe-area insets for the current layout.The arguments the model passed to the tool.The tool output, ornullwhile pending.The tool response metadata, ornullwhile pending.The persisted widget state, ornullwhen unset.
Widget lifecycle
Widgets render before the tool finishes executing:- First render (
isPending === true): the widget mounts immediately,propsisPartial<TProps>, andoutputandmetadataarenull. Render a loading state here. - After the tool completes (
isPending === false):propsis the fullTProps, andoutputandmetadataare populated. The widget re-renders with full data.
mcp-use dev inspector or MCP Apps clients that send ui/notifications/tool-input-partial), an optional phase occurs between (1) and (2): the widget receives partialToolInput in real time while isStreaming is true, then transitions to full props. On the URL params fallback, partialToolInput stays null and isStreaming stays false.
Default values
When host values are unavailable,useWidget returns these safe defaults:
theme:"light"displayMode:"inline"safeArea:{ insets: { top: 0, bottom: 0, left: 0, right: 0 } }maxHeight:600userAgent:{ device: { type: "desktop" }, capabilities: { hover: true, touch: false } }locale:WIDGET_DEFAULTS.LOCALEtimeZone: browser timezone, or"UTC"when nowindowprops:defaultPropswhen provided, otherwise{}output:nullmetadata:nullstate:nullmaxWidth: no default (staysundefinedwhen unavailable)
Related
McpUseProviderfor unified widget setup including auto-sizing.WidgetControlsfor debug and view controls.ThemeProviderfor theme management.ErrorBoundaryfor widget error handling.