About Oai App Composer
Oai App Composer is an MCP server published by itsnikhil in the Developer Tools category: mCP server: Oai App Composer. It has been installed 0 times through Conduid.
The repository has 7 stars and 0 forks, with the last commit 10 months ago. Six months or more without a commit doesn't mean the server is broken, but check the open issues (0) before depending on it in production.
Install
npx oai-app-composerThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Ask AI
Ask AI about Oai App Composer
Powered by Claude · Grounded in docs
Security checks
- ·README presentNot checked yet.
- ·License declaredNot checked yet.
- ·Tests presentNot checked yet.
- ·Dependencies pinnedNot checked yet.
- ·No dynamic code executionNot checked yet.
- !Scoped permissionsDoesn't declare a permission scope. Assume it can do anything its process can.
README
Component Development Tool
A Storybook-like IDE for developing and testing ChatGPT MCP (Model Context Protocol) components in isolation. Build, preview, and export custom UI components that integrate with ChatGPT Apps SDK.
Features
- 🎨 Component Development: Build React components with hot-reload and live preview
- 📦 Monorepo Structure: Organize components in isolated directories with their own mock data
- 🔍 Mock Data Management: Create and edit multiple mock states using Monaco Editor
- 🎭 Sandboxed Preview: Test components in iframe with ChatGPT-like environment
- 🌐 window.openai API: Full implementation matching ChatGPT's behavior for state management
- 📤 Export: Generate MCP server code (Node.js/Python) for production deployment
- 💾 State Management: Supports both ephemeral UI state and cross-session state patterns
Table of Contents
- Installation
- Quick Start
- Architecture
- Creating Components
- State Management
- Mock Data
- Exporting Components
- Project Structure
- API Reference
Additional Documentation
docs/GETTING_STARTED.md– environment setup and first run walkthroughdocs/COMPONENT_TEMPLATES.md– sample manifest and component blueprintsdocs/CONTRIBUTING.md&docs/AGENTS.md– contribution workflow and agent-specific guidancedocs/PROJECT_SUMMARY.md&docs/ENHANCED_API_SUMMARY.md– architecture overview and API surface
Installation
# Install dependencies
npm install
# Start development server
npm run dev
The tool will start on http://localhost:3000
Quick Start
1. Create Your First Component
- Click "New Component" in the sidebar
- Enter a name and description
- The tool will scaffold a complete component with:
manifest.json- Component metadatacomponent.tsx- React component boilerplatemocks/- Mock data directory with default states
2. Edit Mock Data
- Select your component from the sidebar
- Use the Mock Data Editor on the right to edit JSON data
- Switch between different mock states to test various scenarios
- Changes are persisted automatically
3. Preview Your Component
The component renders in real-time with the selected mock data, exactly as it would appear in ChatGPT.
4. Export for Production
- Click "Export" in the toolbar
- Choose Node.js or Python
- Copy the generated MCP server code
- Deploy to your production environment
Architecture
The tool is built with modern web technologies and follows the ChatGPT Apps SDK architecture:
┌─────────────────────────────────────────────┐
│ Development Tool (Host) │
│ ┌────────────┐ ┌──────────────────────┐ │
│ │ Sidebar │ │ Canvas + Editor │ │
│ │ │ │ │ │
│ │ Component │ │ ┌────────────────┐ │ │
│ │ List │ │ │ Sandboxed │ │ │
│ │ │ │ │ iframe │ │ │
│ │ │ │ │ │ │ │
│ └────────────┘ │ │ window.openai │ │ │
│ │ │ - toolOutput │ │ │
│ │ │ - callTool │ │ │
│ │ │ - getState │ │ │
│ │ │ - setState │ │ │
│ │ └────────────────┘ │ │
│ └──────────────────────┘ │
└─────────────────────────────────────────────┘
Key Components
- Component Registry: Auto-discovers components from
/componentsdirectory - Iframe Bridge: Implements
window.openaiAPI via PostMessage - Widget State Store: IndexedDB-based storage for ephemeral UI state
- Component Builder: Transforms TSX to runnable JavaScript bundle
- File System Service: Manages component files via Vite middleware
Creating Components
Component Structure
Each component lives in its own directory:
components/
my-component/
├── manifest.json # Component metadata
├── component.tsx # React component
└── mocks/
├── default.json # Default mock state
├── empty.json # Empty state
└── loaded.json # Loaded state
manifest.json
{
"name": "My Component",
"description": "A custom widget for ChatGPT",
"version": "1.0.0",
"entry": "component.tsx",
"metadata": {
"prefersBorder": true,
"csp": {
"connect_domains": [],
"resource_domains": []
}
}
}
component.tsx
import { useEffect, useState } from 'react';
import { useToolOutput } from '@/hooks/useOpenAiGlobal';
const DEFAULT_OUTPUT = { title: '', items: [] };
export default function MyComponent() {
const toolOutput = useToolOutput<typeof DEFAULT_OUTPUT>() ?? DEFAULT_OUTPUT;
const [widgetState, setWidgetState] = useState<any>({});
// Load widget state (ephemeral UI state)
useEffect(() => {
if (window.openai?.getWidgetState) {
window.openai.getWidgetState(window.openai.widgetId).then((state) => {
if (state) setWidgetState(state);
});
}
}, []);
// Save widget state when it changes
const updateWidgetState = (newState: any) => {
setWidgetState(newState);
window.openai?.setWidgetState?.(window.openai.widgetId, newState);
};
return (
<div>
<h1>{toolOutput.title || 'My Component'}</h1>
{/* Your component UI */}
</div>
);
}
State Management
The tool implements the ChatGPT Apps SDK state management patterns:
1. Business Data (toolOutput)
Source of truth data from the MCP server, available via window.openai.toolOutput and kept in sync through the openai:set_globals event. The toolkit provides a helper hook:
import { useToolOutput } from '@/hooks/useOpenAiGlobal';
const toolOutput = useToolOutput<MyData>();
2. UI State (Ephemeral)
Ephemeral UI state scoped to the widget instance, persisted in IndexedDB:
const [widgetState, setWidgetState] = useState({ selectedId: null });
// Load state
useEffect(() => {
window.openai.getWidgetState(window.openai.widgetId).then((state) => {
if (state) setWidgetState(state);
});
}, []);
// Save state
const updateState = (newState) => {
setWidgetState(newState);
window.openai.setWidgetState(window.openai.widgetId, newState);
};
3. Cross-Session State
For preferences that persist across sessions, use tool calls:
const savePreferences = async (prefs) => {
const result = await window.openai.callTool('save_preferences', { preferences: prefs });
// Handle result
};
Mock Data
Mock data files are JSON files that represent different states of your component's data:
default.json
{
"_description": "Default state with sample data",
"title": "My Component",
"items": [
{ "id": 1, "name": "Item 1" },
{ "id": 2, "name": "Item 2" }
]
}
empty.json
{
"_description": "Empty state with no data",
"title": "My Component",
"items": []
}
The _description field is optional metadata that doesn't appear in window.openai.toolOutput.
Creating New Mock States
- Click "+ New State" in the Mock Data Editor
- Enter a name (e.g., "error", "loading", "success")
- Edit the JSON data
- Click "Create"
Exporting Components
Generate MCP Server Code
-
Click "Export" in the component toolbar
-
Choose your framework:
- Node.js / TypeScript: Using
@modelcontextprotocol/sdk - Python: Using FastMCP
- Node.js / TypeScript: Using
-
The tool generates complete MCP server code including:
- Resource registration for your component HTML
- Tool definition with proper metadata
- Content Security Policy configuration
- Widget state management hooks
Deployment Steps
- Copy the generated code to your MCP server
- Build your component assets
- Place built files in your server's public directory
- Deploy to production (Heroku, Vercel, Railway, etc.)
- Connect from ChatGPT using your server URL
Reference: OpenAI Apps SDK Deployment Guide
Project Structure
/
├── src/
│ ├── components/ # UI components
│ │ ├── Sidebar.tsx # Component list navigation
│ │ ├── Canvas.tsx # Main preview area
│ │ ├── ComponentFrame.tsx # Sandboxed iframe
│ │ ├── MockDataEditor.tsx # JSON editor
│ │ ├── ComponentCreator.tsx # Component scaffolding
│ │ └── ExportModal.tsx # Export functionality
│ ├── hooks/ # React hooks
│ │ ├── useComponentLoader.ts
│ │ ├── useMockData.ts
│ │ └── useHotReload.ts
│ ├── services/ # Core services
│ │ ├── fileSystem.ts # File operations
│ │ ├── componentRegistry.ts # Component discovery
│ │ ├── componentBuilder.ts # Build pipeline
│ │ ├── iframeBridge.ts # PostMessage communication
│ │ └── widgetStateStore.ts # IndexedDB storage
│ ├── store/
│ │ └── appStore.ts # Zustand global state
│ └── types/
│ ├── component.ts # Component types
│ └── openai.ts # window.openai API types
├── components/ # User components (monorepo)
│ └── example-kanban/ # Example component
└── public/
└── iframe-loader.html # Iframe bootstrap
API Reference
window.openai API
The tool provides a complete implementation of the ChatGPT Apps SDK window.openai API:
window.openai.toolOutput
const toolOutput: Record<string, any>
The structured data from the MCP server tool response.
window.openai.widgetId
const widgetId: string
Unique identifier for the widget instance.
window.openai.callTool(toolName, args)
async function callTool(
toolName: string,
args: Record<string, any>
): Promise<OpenAIToolCallResult>
Call a tool on the MCP server.
window.openai.getWidgetState(widgetId)
async function getWidgetState<T>(widgetId: string): Promise<T | null>
Get persisted UI state for this widget instance.
window.openai.setWidgetState(widgetId, state)
async function setWidgetState<T>(widgetId: string, state: T): Promise<void>
Save UI state for this widget instance.
window.openai.openExternal(url)
function openExternal(url: string): void
Open an external URL (punchout behavior).
File System Service
import { fileSystem } from '@/services/fileSystem';
// Read file
const content = await fileSystem.readFile('path/to/file.txt');
// Write file
await fileSystem.writeFile('path/to/file.txt', 'content');
// Read JSON
const data = await fileSystem.readJSON('path/to/file.json');
// Write JSON
await fileSystem.writeJSON('path/to/file.json', { key: 'value' });
// List directory
const files = await fileSystem.listDirectory('path/to/dir');
// Create directory
await fileSystem.createDirectory('path/to/dir');
Component Registry Service
import { componentRegistry } from '@/services/componentRegistry';
// Load all components
const registry = await componentRegistry.loadRegistry();
// Get specific component
const component = await componentRegistry.getComponent('component-id');
// Refresh registry
await componentRegistry.refresh();
// Add mock state
await componentRegistry.addMockState('component-id', mockState);
// Update mock state
await componentRegistry.updateMockState('component-id', 'state-name', data);
Development
Running Tests
npm run test
Building for Production
npm run build
Linting
npm run lint
Resources
- OpenAI Apps SDK Documentation
- Model Context Protocol Spec
- State Management Guide
- Custom UX Reference
License
MIT
Contributing
Contributions are welcome! Please read the contributing guidelines before submitting PRs.
Built with ❤️ for the ChatGPT developer community
README mirrored from the source repository 4 months ago. The original is authoritative.