OpenAI
Learn how to create tools with OpenAI widgets for ChatGPT integration
Overview
xmcp provides first-class support for OpenAI's widget system, allowing you to create interactive tools that render rich UI components directly in ChatGPT.
When you define OpenAI metadata in your tools, xmcp automatically splits metadata into tool-specific and resource-specific properties and generates widget resources for your tools.
Quick Start
Scaffold a new OpenAI-ready project:
React Template
The --ui flag scaffolds a project with React support.
Standard Template
The --gpt flag scaffolds a project with template support.
Approaches
xmcp supports three approaches for creating OpenAI widgets:
1. React Components (Recommended)
Return React components directly for interactive, composable widgets:
How it works:
- Install React:
npm install react react-dom - Tool handler returns React component
- Framework renders component to HTML
- Auto-generated resource serves the rendered output
When using React components, tool files must use the .tsx extension (not
.ts).
2. Direct HTML Return
Return HTML directly from your tool handler for simple, static widgets:
How it works:
- Tool handler returns HTML string
- Framework detects
_meta.openaiin metadata - Framework auto-generates a resource at
ui://widget/{toolName}.html - The resource serves your HTML when accessed by ChatGPT
3. Manual Resource Creation (Backwards Compatible)
Create separate tool and resource files for full control:
This approach is backwards compatible but requires manual resource creation. We recommend using React components (approach #1) or direct HTML return (approach #2) instead.
Widget Metadata Reference
OpenAI metadata is defined under the _meta.openai key. The framework automatically splits this metadata into tool-specific and resource-specific properties.
Tool-Specific Metadata
These properties are applied directly to the tool and control its behavior:
toolInvocation
Status messages displayed during tool execution:
invoking- Message shown while the tool is executinginvoked- Message shown after the tool completes
widgetAccessible
Controls whether the widget can communicate back to the tool (default: true):
outputTemplate
URI template for the widget resource. Auto-generated as ui://widget/{toolName}.html if not provided:
resultCanProduceWidget
Indicates whether the tool result can produce a widget (default: true):
Resource-Specific Metadata
These properties are applied to auto-generated widget resources and control how the widget is rendered:
widgetDescription
Human-readable summary of what the widget does:
widgetPrefersBorder
UI rendering hint for whether the widget prefers a border:
widgetCSP
Content Security Policy configuration for external resources:
connect_domains- URLs allowed for fetch, WebSocket, and other connections (maps toconnect-src)resource_domains- URLs allowed for scripts, images, and fonts (maps toscript-src,img-src,font-src)
widgetDomain
Optional dedicated subdomain for the widget:
widgetState
Initial state object passed to the widget:
Complete Example
Here's a complete example with all OpenAI metadata options:
CSP Configuration
CSP Directive Mapping
The widgetCSP configuration maps to standard Content Security Policy directives:
resource_domains→script-src,img-src,font-srcconnect_domains→connect-src
Example configuration:
Generated CSP headers:
Return Values
Your tool handler can return different types of values depending on your approach:
React Component (Recommended)
Return a React component - framework renders and serves it:
HTML String
Return HTML directly - framework auto-generates the resource:
Metadata Only (Backwards Compatible)
Return just metadata - requires manual resource creation:
Content with Metadata
Return structured content with metadata:
Troubleshooting
Widget Not Displaying
Ensure you have:
- Set
widgetAccessible: truein your metadata - Returned valid HTML, React component, or metadata from your tool handler
- Defined
_meta.openaiconfiguration in your tool metadata - Defined CSP domains if loading external resources