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/model-context.tsx
ModelContext and modelContext let your widget push contextual descriptions to the AI model so it can reason about what the user is currently seeing, without requiring an explicit tool call or storing it in developer-managed state.
Both APIs feed into a single hierarchical context string. On every change the tree is serialized into an indented markdown-like list and pushed to the host via ui/update-model-context (MCP Apps) or setWidgetState (ChatGPT Apps SDK). Updates are batched automatically with queueMicrotask, so rapid mount and unmount cycles within a single render produce a single host notification.
ModelContext
Declarative React component that registers a context annotation for as long as it is mounted. Participates in a parent-child tree based on nesting in JSX.content in a hierarchical tree that is serialized into an indented string and pushed to the host via ui/update-model-context (MCP Apps).
The component re-registers automatically when content changes, so it reflects interactive state. The registration runs inside a useEffect and is cleaned up on unmount, which removes the node from the tree. Only non-empty content is registered: if content.trim() is empty, no node is created.
- Supports empty children: a self-closing
<ModelContext content="..." />registers a leaf annotation and rendersnull. - Nested
<ModelContext>components become child nodes in the tree. When children are provided, the component wraps them in a context provider so descendants attach to this node as their parent. - Multiple siblings at the same level produce a flat list at that depth. Siblings are sorted deterministically by their internal id.
ReturnsThe text describing what the user is currently seeing. Required. Whitespace-only values register no node.Optional. When provided, this component acts as a scope boundary: nested<ModelContext>components become children in the serialized tree. When omitted ornull, the component rendersnull(a leaf annotation).
SignatureRendersnullwhen no children are passed. When children are provided, renders the children wrapped in an internal parent-id context provider so descendants nest under this node.
Basic usage
A self-closing tag registers a leaf annotation. No children are needed.Nesting
<ModelContext> components nest hierarchically. A component wrapped in another’s children becomes a child node in the serialized tree.
Siblings
Multiple<ModelContext> at the same level are siblings. They produce a flat list at that depth.
Dynamic content
The component re-registers automatically whencontent changes. Use this to reflect interactive state.
modelContext
Module-level imperative API. Works anywhere: event handlers, plain functions, code outside React. Entries registered via this API are always root-level nodes (no parent in the tree).Unlike
<ModelContext>, entries set via modelContext.set() are not automatically cleaned up when a component unmounts. Always call modelContext.remove(key) in cleanup logic, or use <ModelContext> when you need automatic lifecycle management.modelContext.set
Register or update a named context entry. Thekey acts as a stable identifier: calling set with the same key overwrites the previous content. The entry is registered as a root-level node (parent is null) and the host is notified on the next batched flush.
Parameters
ReturnsStable identifier for the entry. Reusing a key overwrites the previous value.The description the model should see for this entry.
Signature
modelContext.remove
Remove a previously registered context entry by key. Removing a key that is not present is a no-op. The host is notified on the next batched flush. ParametersReturnsThe key of the entry to remove.
Signature
modelContext.clear
Remove all context entries, both component-based (<ModelContext>) and imperative (modelContext.set). Useful for cleanup on unmount of a top-level widget. The host is notified on the next batched flush.
Returns
Signature
Usage
modelContext.set from a useEffect when you want lifecycle-aware imperative updates.
How the tree is serialized
All mounted<ModelContext> nodes and modelContext.set() entries are collected in a single global registry. On every change the tree is serialized into an indented markdown-like list. Empty (whitespace-only) content is skipped, and siblings at each depth are sorted deterministically.
- MCP Apps:
ui/update-model-contextwithstructuredContent.__model_context. - ChatGPT Apps SDK:
setWidgetStatewith__model_contextmerged into the state object.
queueMicrotask, so rapid mount and unmount cycles within a single render produce a single host notification. If no host handler is registered yet (for example, the widget has not mounted), updates are silently dropped and re-flow when the component tree registers a node on the next mount.
Integration with useWidget state
<ModelContext> and setState from useWidget are independent. Use them for different purposes.
| API | Purpose |
|---|---|
setState | Explicit developer-managed state (cart items, form values, filters). The developer decides what to include. |
<ModelContext> / modelContext.set() | Declarative annotations about what the user is currently seeing. Set it and forget it: the framework handles the rest. |
__model_context key is automatically filtered from the state value returned by useWidget, so it never appears in your code.
Full example
This widget pairs the declarative component with the imperative API. The server registers a tool whose widget keeps the model aware of UI state.Related
useWidget()for accessing widget props and state.<McpUseProvider />for the widget root provider.