@GPTApp Decorator
@GPTApp vs @UIApp: Use
@GPTApp for ChatGPT Apps with OpenAI-specific metadata (widget controls, CSP, invocation messages). For general MCP apps, use @UIApp.@GPTApp decorator links an MCP tool to a React UI component compliant with the ChatGPT Apps SDK. When applied to a tool method, it automatically:
- Adds
_meta.ui.resourceUrito the tool definition - Adds OpenAI-specific metadata (widgetAccessible, widgetDescription, etc.)
- Registers a resource that renders the component to HTML with
text/html+skybridgemimeType - Enables ChatGPT to display your widget with proper security and behavior controls
Installation
Usage
API Reference
@GPTApp(options)
Decorator function that links a tool to a UI component for ChatGPT Apps.Configuration options
GPTAppOptions
React component or path to component file (relative to service file)
- Use component reference for direct SSR rendering
- Use path string (e.g.,
'./WeatherCard') for CLI build - avoids importing browser code in server
Custom resource URI. Auto-generated if not provided.Default format:
ui://{className}/{methodName}Example: ui://weather/getWeatherHTML document title for the rendered UI
Additional CSS styles to inject into the HTML document
OpenAI-Specific Options
Allow widget to call tools via
window.openai.callTool.Maps to _meta["openai/widgetAccessible"]Tool visibility:
'public': Visible to both model and widget'private': Hidden from model but callable by widget
_meta["openai/visibility"]Widget prefers border around iframe.Maps to
_meta["openai/widgetPrefersBorder"]Widget domain for API allowlists.Maps to
_meta["openai/widgetDomain"]Widget description shown to the model.Maps to
_meta["openai/widgetDescription"]Content Security Policy configuration for the widget.Maps to
_meta["openai/widgetCSP"]Field names that should be treated as file uploads.Maps to
_meta["openai/fileParams"]Messages shown during tool invocation.Maps to
_meta["openai/toolInvocation"]Examples
Basic Widget
Private Tool (Widget-Only)
Custom Invocation Messages
Content Security Policy
File Upload Support
Widget with Border
Path-based Component (CLI)
Helper Functions
getGPTAppMetadata()
Get GPTApp metadata from a method.Returns
GPTApp options if decorator was applied, undefined otherwise
getGPTAppUri()
Get the resource URI from a method.Returns
Resource URI if decorator was applied, undefined otherwise
How It Works
1. Metadata Storage
The decorator stores metadata usingreflect-metadata:
2. Tool Metadata Enhancement
The decorator adds OpenAI-specific metadata to the tool definition:3. Dual Format Support
The decorator provides both:- New nested format (preferred by ext-apps 0.2.2+):
_meta.ui.* - Legacy flat format (backwards compatibility):
_meta["openai/*"]
4. Resource Registration
A resource is automatically registered that:- Renders the React component to HTML
- Injects the tool result as context
- Returns HTML with
text/html+skybridgemimeType - Includes OpenAI widget integration scripts
5. ChatGPT Integration
When the tool is called in ChatGPT:- ChatGPT sees the
ui.resourceUriin tool metadata - Fetches the resource HTML
- Displays the widget in an iframe
- Applies CSP and security policies
- Enables widget-to-tool communication if
widgetAccessible: true
URI Format
By default, URIs follow the pattern:WeatherService.getWeather→ui://weather/getWeatherKanbanService.showBoard→ui://kanban/showBoardUserService.getProfile→ui://user/getProfile
- Is converted to lowercase
- Has the
Servicesuffix removed (if present)
Integration with @Tool
The@GPTApp decorator works seamlessly with @Tool from @leanmcp/core:
@Tool decorator automatically detects the UI metadata added by @GPTApp and includes it in the tool definition.
Best Practices
1. Widget Security
Always specify CSP domains for widgets that make network requests:2. Private Tools for Helpers
Usevisibility: 'private' for tools that should only be called by widgets:
3. Helpful Invocation Messages
Provide clear status messages:4. Type Safety
Use TypeScript interfaces for tool results:5. Component Separation
Keep UI components in separate files:Troubleshooting
Widget not displaying in ChatGPT
- Check that
reflect-metadatais imported at app entry point - Verify the resource URI is correct in tool metadata
- Ensure the component is exported properly
- Check that mimeType is
text/html+skybridge
widgetAccessible not working
- Verify
widgetAccessible: trueis set - Check that
window.openai.callToolis available in the widget - Ensure the widget is running in ChatGPT environment
CSP violations
- Add required domains to
csp.connect_domainsorcsp.resource_domains - Check browser console for CSP error messages
- Test in ChatGPT environment (CSP may not apply in local dev)
TypeScript errors
Make sureexperimentalDecorators and emitDecoratorMetadata are enabled:
See Also
- @UIApp Decorator - General MCP UI decorator (without OpenAI-specific features)
- React Components - Available UI components
- @Tool Decorator - Core tool decorator
- ChatGPT Apps SDK - OpenAI documentation