Tool results have separate audiences
An MCP tool result can carry model-visible text and widget-only data at the same time.| Field | Model sees it? | Widget sees it? | Use it for |
|---|---|---|---|
content | Yes | Yes | A short answer or summary for the conversation |
structuredContent | No | Yes, as props | Data the widget renders |
_meta | No | Yes, as metadata | Extra widget data that should not be model-visible |
mcp-use, widget({ props, output, metadata }) maps these fields for you:
output text. The widget reads props and metadata through useWidget(), so it can show details like when the result was generated without adding that detail to the model context.
Keep model text short
Useoutput to tell the model what happened, not to duplicate the full widget payload.
Use props for rendering data
Useprops for data the widget needs to render.
props is partial while isPending is true. Check isPending before reading required fields.
Use state for user choices
UsesetState for user choices that should survive widget re-renders and be available to future model turns.
Use ModelContext for what is visible
Use<ModelContext> when the model should know what part of the widget the user is currently seeing.
<ModelContext> is lifecycle-aware. When the component unmounts, that context is removed.
Use modelContext.set() for imperative events that do not map cleanly to JSX:
Choose the right channel
| Need | Use |
|---|---|
| The model needs a concise result | output: text(...) |
| The widget needs render data | props |
| The widget needs hidden auxiliary data | metadata |
| The model should know user selections on future turns | setState |
| The model should know what UI is visible now | <ModelContext> |
| Data must persist across conversations or users | Your backend |
Next steps
- Use Build widgets for the server and React setup.
- Use Interactivity for buttons, tool calls, and follow-up messages.
- Use the
ModelContextAPI reference for full lifecycle behavior.