The inspector fully emulates the
window.openai API used by OpenAI Apps SDK widgets. This allows you to develop and test widgets locally before deploying to ChatGPT. For the official API reference, see the OpenAI Apps SDK documentation.Overview
What are ChatGPT Apps?
ChatGPT Apps are custom applications that extend ChatGPT’s capabilities using:- MCP Servers: Provide tools and resources
- OpenAI Apps SDK: Create interactive widgets and components
- Tool Integration: Connect ChatGPT to external services
How the Inspector Helps
The inspector provides:- Tool Testing: Execute tools independently of ChatGPT
- Widget Rendering: Preview OpenAI Apps SDK widgets
- Interactive Debugging: Test widget interactions
- Real-time Feedback: See tool calls and responses
- Dev Mode Support: Hot reload for widget development
window.openai API Emulation
The inspector provides a complete emulation of thewindow.openai API that widgets use to interact with ChatGPT. This API is automatically injected into widget iframes, allowing your components to work identically in the inspector and in ChatGPT.
API Overview
Thewindow.openai object provides:
- Global Properties: Theme, display mode, tool data, widget state
- Methods: Tool calls, follow-up messages, display mode requests
- Events: Global change notifications via
openai:set_globalsevents
Global Properties
These properties are available onwindow.openai and update reactively:
toolInput
The input parameters passed to the tool that triggered this widget.
toolOutput
The structured output from the tool execution. This is the primary data source for your widget.
toolResponseMetadata
Additional metadata from the tool response (currently null in inspector).
widgetState
Persistent state for this widget instance. State is scoped to the specific widget and conversation message.
Widget state persists in browser localStorage and is rehydrated when the widget loads. State is scoped to the widget instance and doesn’t travel across different widgets or conversation turns.
displayMode
Current display mode: "inline", "pip", or "fullscreen".
theme
Current theme: "light" or "dark". Automatically syncs with inspector theme.
maxHeight
Maximum height available for the widget container (in pixels).
locale
User’s locale setting.
safeArea
Safe area insets for mobile devices.
userAgent
User agent information including device type and capabilities.
API Methods
callTool(name, params)
Call an MCP tool directly from the widget. Returns a Promise with the tool result.
- Sends
postMessageto parent (inspector) - Inspector executes tool via MCP connection
- Result is formatted to match OpenAI’s expected format
- MCP
contentsarray is converted to OpenAIcontentformat - 30-second timeout for tool calls
sendFollowUpMessage(args)
Send a follow-up message to ChatGPT as if the user typed it.
- Dispatches custom event
mcp-inspector:widget-followup - Message appears in Chat tab
- Can be used to continue conversation from widget interactions
setWidgetState(state)
Persist widget state across interactions. State is visible to ChatGPT and can influence future tool calls.
- Stores state in browser localStorage
- Keyed by widget instance ID
- State is rehydrated on widget load
- Sent to parent via
postMessagefor inspector awareness
Keep widget state under 4k tokens for performance. State is sent to ChatGPT and can influence model behavior.
requestDisplayMode(options)
Request a different display mode for the widget.
"inline"- Default embedded view"pip"- Picture-in-Picture floating window"fullscreen"- Full browser window
- Uses native Fullscreen API when available
- Falls back to CSS-based fullscreen
- On mobile, PiP may be coerced to fullscreen
- Updates
displayModeproperty and dispatches events
openExternal(payload)
Open an external link in a new window/tab.
- Uses
window.open()with security flags - Opens in new tab with
noopener,noreferrer
Events
openai:set_globals
Custom event dispatched when any global property changes. React components can listen to this for reactive updates.
- Initial widget load
- Display mode changes
- Theme changes
- Any global property update from parent
React Helper Hooks
The inspector’s API emulation is compatible with React hooks that useuseSyncExternalStore to subscribe to global changes. Here’s an example pattern:
Implementation Details
API Injection
Thewindow.openai API is injected into widget iframes via server-side HTML generation:
- Widget HTML is fetched from MCP server
- Inspector injects API script before widget content
- API object is attached to
window.openaiandwindow.webplus(for compatibility) - Initial globals event is dispatched
- Message listeners are set up for parent communication
Communication Protocol
Widget-to-inspector communication usespostMessage:
Widget → Inspector:
openai:callTool- Tool execution requestsopenai:sendFollowup- Follow-up messagesopenai:requestDisplayMode- Display mode changesopenai:setWidgetState- State updates
openai:callTool:response- Tool call resultsopenai:globalsChanged- Global property updatesopenai:displayModeChanged- Display mode changes (legacy)
State Persistence
Widget state is persisted in browser localStorage:- Key format:
mcp-inspector-widget-state-${toolId} - Storage: Browser localStorage (scoped to inspector domain)
- Lifetime: Persists across page reloads
- Scope: Per widget instance
Tool Result Formatting
MCP tool results are automatically converted to OpenAI’s expected format: MCP Format:Compatibility
The inspector maintains compatibility with:- OpenAI Apps SDK: Full API compatibility
- Legacy APIs:
sendFollowupTurn(aliased tosendFollowUpMessage) - React Router: URL normalization for routing
- Multiple display modes: Inline, PiP, Fullscreen
Differences from ChatGPT
While the inspector provides full API compatibility, there are some differences:- User Agent: Inspector provides mock user agent data
- Safe Area: Defaults to zero insets (not mobile-specific)
- Locale: Defaults to “en-US” (not user-specific)
- Tool Results: Converted from MCP format to OpenAI format
- Follow-ups: Appear in inspector Chat tab instead of ChatGPT
Testing Your Widget
To test widget compatibility:- Develop locally with inspector
- Test all API methods in your widget
- Verify state persistence across interactions
- Test display mode transitions
- Verify tool calls work correctly
- Check theme adaptation
- Test in ChatGPT for final verification
Official Documentation
For the complete OpenAI Apps SDK API reference, see:- OpenAI Apps SDK - Build a custom UX - Official API documentation
- OpenAI Apps SDK Reference - Complete API reference
Connecting Your ChatGPT App
Setting Up Your MCP Server
Your ChatGPT App needs an MCP server that exposes tools and optionally widgets:Connecting via Inspector
- Start your MCP server
- Open the inspector (local or hosted)
- Connect to your server URL:
- Local:
http://localhost:3000/mcp - Remote:
https://your-server.com/mcp
- Local:
- Server appears in Connected Servers list
Authentication Setup
If your ChatGPT App requires authentication:- Configure OAuth in connection settings
- Or add custom headers with API keys
- Complete authentication flow
- Inspector stores credentials securely
Testing Tools
Executing Tools
Test your ChatGPT App tools directly:- Navigate to Tools tab
- Find your tool in the list
- Click to select it
- Enter test parameters
- Click Execute
- View results in real-time
Viewing Tool Results
Tool results show:- Text Output: Plain text responses
- Structured Data: JSON responses
- Widget References: Links to OpenAI Apps SDK widgets
- Metadata: Tool execution metadata
Testing with Different Parameters
Test edge cases and variations:- Execute tool with different parameters
- Save successful requests for replay
- Test error handling
- Verify parameter validation
Use saved requests to quickly test the same tool with different parameters.
Widget/Component Testing
OpenAI Apps SDK Widget Support
The inspector fully supports OpenAI Apps SDK widgets:- Widget Rendering: Interactive widget display
- Dev Mode: Hot reload during development
- Display Modes: Inline, Picture-in-Picture, Fullscreen
- CSP Handling: Content Security Policy support
Rendering Widgets
When a tool returns a widget reference:- Tool executes successfully
- Inspector detects widget URI in metadata
- Widget automatically loads and renders
- Interactive components become available
- Looks for
openai/outputTemplatein tool metadata - Fetches widget resource from MCP server
- Renders in dedicated widget container
Dev Mode for Widgets
Enable hot reload for widget development:- Set widget metadata with dev flag:
- Inspector uses dev server URL
- Changes reload automatically
- Console logs visible in inspector
Widget Display Modes
Widgets support three display modes: Inline:- Default mode
- Embedded in result panel
- Scrollable content
- Floating window
- Stays visible while scrolling
- Resizable and draggable
- Full browser window
- Maximum visibility
- Exit with ESC or close button
- Widget can request mode changes
- Inspector handles transitions
- State persists during session
Widget CSP Handling
Content Security Policy is automatically handled:- CSP metadata from tool results
- Applied to widget iframe
- Secure sandbox environment
- Script execution allowed
Interactive Widget Features
Tool Calls from Widgets
Widgets can call MCP tools:- Widget uses
window.openai.callTool() - Inspector intercepts the call
- Executes tool via MCP connection
- Returns result to widget
- Widget updates with response
Follow-up Messages
Widgets can send follow-up messages to ChatGPT:- Widget calls
window.openai.sendFollowup() - Inspector captures the message
- Message appears in Chat tab
- ChatGPT processes the follow-up
- Conversation continues
- User interactions in widget
- Dynamic conversation flow
- Context-aware responses
Widget State Management
Widget state is managed automatically:- Tool Input: Parameters passed to tool
- Tool Output: Results from tool execution
- Widget Data: Resource content for widget
- Display State: Current display mode
Console Logging from Widgets
View widget console output:- Widget console logs appear in inspector
- Access via console panel in widget container
- Filter by log level
- Debug widget issues
- Real-time log streaming
- Log level filtering
- Error highlighting
- Stack trace display
Debugging Workflow
Step-by-Step Process
-
Connect to Server
- Add your MCP server in inspector
- Verify connection status
-
Test Tools
- Execute each tool independently
- Verify parameters and responses
- Check for errors
-
Test Widgets
- Execute tools that return widgets
- Verify widget rendering
- Test widget interactions
-
Test Integration
- Use Chat tab with LLM
- Verify tool calls from ChatGPT
- Check widget rendering in context
-
Debug Issues
- Check console logs
- Review tool results
- Verify widget metadata
- Test error scenarios
Common Issues and Solutions
Widget Not Rendering:- Check
openai/outputTemplatein metadata - Verify widget resource exists
- Check CSP settings
- Review console for errors
- Verify tool name matches
- Check parameter schema
- Review authentication
- Check server logs
- Verify
window.openaiAPI availability - Check widget iframe sandbox
- Review console for errors
- Test in different display modes
Testing Widget Interactions
- Render Widget: Execute tool to load widget
- Interact: Click buttons, fill forms in widget
- Monitor: Watch console for tool calls
- Verify: Check tool results and widget updates
- Iterate: Fix issues and retest
Verifying Tool Outputs
- Preview Mode: See formatted widget output
- JSON Mode: View raw tool response
- Metadata: Check widget references
- Structure: Verify data format
Best Practices
Development vs Production Widgets
Development:- Use dev mode for hot reload
- Enable console logging
- Test in all display modes
- Verify error handling
- Disable dev mode
- Minimize console output
- Test CSP restrictions
- Verify performance
Testing Widget Responsiveness
- Test in different display modes
- Verify mobile layouts
- Check resize behavior
- Test PiP mode transitions
Handling Widget Errors
- Implement error boundaries
- Show user-friendly messages
- Log errors to console
- Provide fallback UI
Performance Considerations
- Optimize widget loading
- Minimize initial bundle size
- Lazy load components
- Cache widget resources
Related Documentation
- Overview - Saved requests and preview mode
- Connection Settings - Advanced configuration
- Getting Started - Basic inspector usage