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:

Return React components directly for interactive, composable widgets:

src/tools/counter.tsx

How it works:

  1. Install React: npm install react react-dom
  2. Tool handler returns React component
  3. Framework renders component to HTML
  4. 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:

src/tools/get-map.ts

How it works:

  1. Tool handler returns HTML string
  2. Framework detects _meta.openai in metadata
  3. Framework auto-generates a resource at ui://widget/{toolName}.html
  4. The resource serves your HTML when accessed by ChatGPT

3. Manual Resource Creation (Backwards Compatible)

Create separate tool and resource files for full control:

src/tools/get-map.ts
src/resources/(ui)/widget/map.ts

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 executing
  • invoked - 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 to connect-src)
  • resource_domains - URLs allowed for scripts, images, and fonts (maps to script-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:

src/tools/analytics-dashboard.ts

CSP Configuration

CSP Directive Mapping

The widgetCSP configuration maps to standard Content Security Policy directives:

  • resource_domainsscript-src, img-src, font-src
  • connect_domainsconnect-src

Example configuration:

Generated CSP headers:

Return Values

Your tool handler can return different types of values depending on your approach:

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: true in your metadata
  • Returned valid HTML, React component, or metadata from your tool handler
  • Defined _meta.openai configuration in your tool metadata
  • Defined CSP domains if loading external resources

On this page

One framework to rule them all

    OpenAI | xmcp Documentation