| name | chatgpt-apps |
| description | Complete ChatGPT Apps builder - Create, design, implement, test, and deploy ChatGPT Apps with MCP servers, widgets, auth, database integration, and automated deployment |
| homepage | https://github.com/hollaugo/prompt-circle-claude-plugins |
| user-invocable | true |
ChatGPT Apps Builder
Complete workflow for building, testing, and deploying ChatGPT Apps from concept to production.
Commands
/chatgpt-apps new - Create a new ChatGPT App
/chatgpt-apps add-tool - Add an MCP tool to your app
/chatgpt-apps add-widget - Add a widget to your app
/chatgpt-apps add-auth - Configure authentication
/chatgpt-apps add-database - Set up database
/chatgpt-apps validate - Validate your app
/chatgpt-apps test - Run tests
/chatgpt-apps deploy - Deploy to production
/chatgpt-apps resume - Resume working on an app
Table of Contents
- Create New App
- Add MCP Tool
- Add Widget
- Add Authentication
- Add Database
- Generate Golden Prompts
- Validate App
- Test App
- Deploy App
- Resume App
1. Create New App
Purpose: Create a new ChatGPT App from concept to working code.
Workflow
Phase 1: Conceptualization
-
Ask for the app idea
"What ChatGPT App would you like to build? Describe what it does and the problem it solves."
-
Analyze against UX Principles
- Conversational Leverage: What can users accomplish through natural language?
- Native Fit: How does this integrate with ChatGPT's conversational flow?
- Composability: Can tools work independently and combine with other apps?
-
Check for Anti-Patterns
- Static website content display
- Complex multi-step workflows requiring external tabs
- Duplicating ChatGPT's native capabilities
- Ads or upsells
-
Define Use Cases
Create 3-5 primary use cases with user stories.
Phase 2: Design
-
Tool Topology
- Query tools (readOnlyHint: true)
- Mutation tools (destructiveHint: false)
- Destructive tools (destructiveHint: true)
- Widget tools (return UI with _meta)
- External API tools (openWorldHint: true)
-
Widget Design
For each widget:
id - unique identifier (kebab-case)
name - display name
description - what it shows
mockData - sample data for preview
-
Data Model
Design entities and relationships.
-
Auth Requirements
- Single-user (no auth needed)
- Multi-user (Auth0 or Supabase Auth)
Phase 3: Implementation
Generate complete application with this structure:
{app-name}/
โโโ package.json
โโโ tsconfig.server.json
โโโ setup.sh
โโโ START.sh
โโโ .env.example
โโโ .gitignore
โโโ server/
โโโ index.ts
Critical Requirements:
Server class from @modelcontextprotocol/sdk/server/index.js
StreamableHTTPServerTransport for session management
- Widget URIs:
ui://widget/{widget-id}.html
- Widget MIME type:
text/html+skybridge
structuredContent in tool responses
_meta with openai/outputTemplate on tools
Phase 4: Testing
- Run setup:
./setup.sh
- Start dev:
./START.sh --dev
- Preview widgets:
http://localhost:3000/preview
- Test MCP connection
Phase 5: Deployment
- Generate Dockerfile and render.yaml
- Deploy to Render
- Configure ChatGPT connector
2. Add MCP Tool
Purpose: Add a new MCP tool to your ChatGPT App.
Workflow
-
Gather Information
- What does this tool do?
- What inputs does it need?
- What does it return?
-
Classify Tool Type
- Query (readOnlyHint: true) - Fetches data
- Mutation (destructiveHint: false) - Creates/updates data
- Destructive (destructiveHint: true) - Deletes data
- Widget - Returns UI content
- External (openWorldHint: true) - Calls external APIs
-
Design Input Schema
Create Zod schema with appropriate types and descriptions.
-
Generate Tool Handler
Use chatgpt-mcp-generator agent to create:
- Tool handler in
server/tools/
- Zod schema export
- Type exports
- Database queries (if needed)
-
Register Tool
Update server/index.ts with metadata:
{
name: "my-tool",
_meta: {
"openai/toolInvocation/invoking": "Loading...",
"openai/toolInvocation/invoked": "Done",
"openai/outputTemplate": "ui://widget/my-widget.html",
}
}
-
Update State
Add tool to .chatgpt-app/state.json.
Tool Naming
Use kebab-case: list-items, create-task, show-recipe-detail
Annotations Guide
| Scenario | readOnlyHint | destructiveHint | openWorldHint |
|---|
| List/Get | true | false | false |
| Create/Update | false | false | false |
| Delete | false | true | false |
| External API | varies | varies | true |
3. Add Widget
Purpose: Add inline HTML widgets with HTML/CSS/JS and Apps SDK integration.
5 Widget Patterns
- Card Grid - Multiple items in grid
- Stats Dashboard - Key metrics display
- Table - Tabular data
- Bar Chart - Simple visualizations
- Detail Widget - Single item details
Workflow
-
Gather Information
- Widget purpose and data
- Visual design (cards, table, chart, etc.)
- Interactivity needs
-
Define Data Shape
Document expected structure with TypeScript interface.
-
Add Widget Config
const widgets: WidgetConfig[] = [
{
id: "my-widget",
name: "My Widget",
description: "Displays data",
templateUri: "ui://widget/my-widget.html",
invoking: "Loading...",
invoked: "Ready",
mockData: { },
},
];
-
Add Widget HTML
Generate HTML with:
- Preview mode support (
window.PREVIEW_DATA)
- OpenAI Apps SDK integration (
window.openai.toolOutput)
- Event listeners (
openai:set_globals)
- Polling fallback (100ms, 10s timeout)
-
Create/Update Tool
Link tool to widget via widgetId.
-
Test Widget
Preview at /preview/{widget-id} with mock data.
Widget HTML Structure
(function() {
let rendered = false;
function render(data) {
if (rendered || !data) return;
rendered = true;
}
function tryRender() {
if (window.PREVIEW_DATA) { render(window.PREVIEW_DATA); return; }
if (window.openai?.toolOutput) { render(window.openai.toolOutput); }
}
window.addEventListener('openai:set_globals', tryRender);
const poll = setInterval(() => {
if (window.openai?.toolOutput || window.PREVIEW_DATA) {
tryRender();
clearInterval(poll);
}
}, 100);
setTimeout(() => clearInterval(poll), 10000);
tryRender();
})();
4. Add Authentication
Purpose: Configure authentication using Auth0 or Supabase Auth.
When to Add
- Multiple users
- Persistent private data per user
- User-specific API credentials
Providers
Auth0:
- Enterprise-grade
- OAuth 2.1, PKCE flow
- Social logins (Google, GitHub, etc.)
Supabase Auth:
- Simpler setup
- Email/password default
- Integrates with Supabase database
Workflow
-
Choose Provider
Ask user preference based on needs.
-
Guide Setup
- Auth0: Create application, configure callback URLs, get credentials
- Supabase: Already configured with database setup
-
Generate Auth Code
Use chatgpt-auth-generator agent to create:
- Session management middleware
- User subject extraction
- Token validation
-
Update Server
Add auth middleware to protect routes.
-
Update Environment
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=...
AUTH0_CLIENT_SECRET=...
SUPABASE_URL=...
SUPABASE_ANON_KEY=...
-
Test
Verify login flow and user isolation.
5. Add Database
Purpose: Configure PostgreSQL database using Supabase.
When to Add
- Persistent user data
- Multi-entity relationships
- Query/filter capabilities
Workflow
-
Check Supabase Setup
Verify account and project exist.
-
Gather Credentials
- Project URL
- Anon key (public)
- Service role key (server-side)
-
Define Entities
For each entity, specify:
- Fields and types
- Relationships
- Indexes
-
Generate Schema
Use chatgpt-database-generator agent to create SQL with:
id (UUID primary key)
user_subject (varchar, indexed)
created_at (timestamptz)
updated_at (timestamptz)
- RLS policies for user isolation
-
Setup Connection Pool
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
);
-
Apply Migrations
Run SQL in Supabase dashboard or via migration tool.
Query Pattern
Always filter by user_subject:
const { data } = await supabase
.from('tasks')
.select('*')
.eq('user_subject', userSubject);
6. Generate Golden Prompts
Purpose: Generate test prompts to validate ChatGPT correctly invokes tools.
Why Important
- Measure precision/recall
- Enable iteration
- Post-launch monitoring
3 Categories
-
Direct Prompts - Explicit tool invocation
- "Show me my task list"
- "Create a new task called..."
-
Indirect Prompts - Outcome-based, ChatGPT should infer tool
- "What do I need to do today?"
- "Help me organize my work"
-
Negative Prompts - Should NOT trigger tool
- "What is a task?"
- "Tell me about project management"
Workflow
-
Analyze Tools
Review each tool's purpose and inputs.
-
Generate Prompts
For each tool, create:
- 5+ direct prompts
- 5+ indirect prompts
- 3+ negative prompts
- 2+ edge case prompts
-
Best Practices
- Tool descriptions start with "Use this when..."
- State limitations clearly
- Include examples in descriptions
-
Save Output
Write to .chatgpt-app/golden-prompts.json:
{
"toolName": {
"direct": ["prompt1", "prompt2"],
"indirect": ["prompt1", "prompt2"],
"negative": ["prompt1", "prompt2"],
"edge": ["prompt1", "prompt2"]
}
}
7. Validate App
Purpose: Validation suite before deployment.
10 Validation Checks
-
Required Files
- package.json
- tsconfig.server.json
- setup.sh (executable)
- START.sh (executable)
- server/index.ts
- .env.example
-
Server Implementation
- Uses
Server from MCP SDK
- Has
StreamableHTTPServerTransport
- Session management with Map
- Correct request handlers
-
Widget Configuration
widgets array exists
- Each has id, name, description, templateUri, mockData
- URIs match pattern
ui://widget/{id}.html
-
Tool Response Format
- Returns
structuredContent (not just content)
- Widget tools have
_meta with openai/outputTemplate
-
Resource Handler Format
- MIME type:
text/html+skybridge
- Returns
_meta with serialization and CSP
-
Widget HTML Structure
- Preview mode support
- Event listeners for Apps SDK
- Polling fallback
- Render guard
-
Endpoint Existence
/health - Health check
/preview - Widget index
/preview/:widgetId - Widget preview
/mcp - MCP endpoint
-
Package.json Scripts
- Has
build:server
- Has
start with HTTP_MODE=true
- Has
dev with watch mode
- NO web build scripts (web/, ui/, client/)
-
Annotation Validation
- readOnlyHint set correctly
- destructiveHint for delete operations
- openWorldHint for external APIs
-
Database Validation (if enabled)
Common Errors
| Error | Fix |
|---|
| Missing structuredContent | Add to tool response |
| Wrong widget URI | Use ui://widget/{id}.html |
| No session management | Add Map<string, Transport> |
| Missing _meta | Add to tool definition and response |
| Wrong MIME type | Use text/html+skybridge |
Critical: Check file existence FIRST before other validations!
8. Test App
Purpose: Run automated tests using MCP Inspector and golden prompts.
4 Test Categories
-
MCP Protocol
- Server starts without errors
- Handles initialize
- Lists tools correctly
- Lists resources correctly
-
Schema Validation
- Tool schemas are valid Zod
- Required fields marked
- Types match implementation
-
Widget Tests
- All widgets render in preview mode
- Mock data loads correctly
- No console errors
-
Golden Prompt Tests
- Direct prompts trigger correct tools
- Indirect prompts work as expected
- Negative prompts don't trigger tools
Workflow
-
Start Server in Test Mode
HTTP_MODE=true NODE_ENV=test npm run dev
-
Run MCP Inspector
Test protocol compliance:
- Initialize connection
- List tools
- Call each tool with valid inputs
- Check responses
-
Schema Validation
Verify schemas compile and match implementation.
-
Golden Prompt Tests
Use ChatGPT to test prompts:
- Record which tool was called
- Compare to expected tool
- Calculate precision/recall
-
Generate Report
{
"passed": 42,
"failed": 3,
"categories": {
"mcp": "โ
",
"schema": "โ
",
"widgets": "โ
",
"prompts": "โ ๏ธ 3 failures"
},
"timing": "2.3s"
}
Fixing Failures
For each failure, explain:
- What failed
- Why it failed
- How to fix (with code example)
9. Deploy App
Purpose: Deploy ChatGPT App to Render with PostgreSQL and health checks.
Prerequisites
- โ
Validation passed
- โ
Tests passed
- โ
Git repository clean
- โ
Environment variables ready
Workflow
-
Pre-flight Check
- Run validation
- Run tests
- Check database connection (if enabled)
-
Generate render.yaml
services:
- type: web
name: {app-name}
runtime: docker
plan: free
healthCheckPath: /health
envVars:
- key: PORT
value: 3000
- key: HTTP_MODE
value: true
- key: NODE_ENV
value: production
- key: WIDGET_DOMAIN
generateValue: true
-
Generate Dockerfile
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
EXPOSE 3000
CMD ["node", "dist/server/index.js"]
-
Deploy
Option A: Automated (if Render MCP available)
Use Render MCP agent to deploy.
Option B: Manual
- Push to GitHub
- Connect repo in Render dashboard
- Set environment variables
- Deploy
-
Verify Deployment
- Health check:
https://{app}.onrender.com/health
10. Resume App
Purpose: Resume building an in-progress ChatGPT App.
Workflow
-
Load State
Read .chatgpt-app/state.json:
{
"appName": "My Task Manager",
"phase": "Implementation",
"tools": ["list-tasks", "create-task"],
"widgets": ["task-list"],
"auth": false,
"database": true,
"validated": false,
"deployed": false
}
-
Display Progress
Show current status:
- App name
- Current phase
- Completed items (tools, widgets)
- Pending items (auth, validation, deployment)
-
Offer Next Steps
Based on phase:
Concept Phase:
- "Let's design the tools and widgets"
- "Shall we start implementation?"
Implementation Phase:
Best Practices
- Always save state after each major step
- Validate before moving forward (especially before deployment)
- Use agents for code generation (chatgpt-mcp-generator, chatgpt-auth-generator, etc.)
- Test at every phase (preview widgets, test tools, run golden prompts)
- Keep it conversational - guide the user naturally through the workflow
- Explain trade-offs when offering choices (Auth0 vs Supabase, etc.)
- Show examples when introducing new concepts
State Management
The .chatgpt-app/state.json file tracks progress:
{
"appName": "string",
"description": "string",
"phase": "Concept" | "Implementation" | "Testing" | "Deployment",
"tools": ["tool-name"],
"widgets": ["widget-id"],
"auth": {
"enabled": boolean,
"provider": "auth0" | "supabase" | null
},
"database": {
"enabled": boolean,
"entities": ["entity-name"]
},
"validated": boolean,
boolean
boolean
boolean
Command Reference
./setup.sh
./START.sh --dev
./START.sh --preview
./START.sh --stdio
./START.sh
npm run validate
curl http://localhost:3000/health
git push origin main
Getting Started
When the user invokes any chatgpt-app command:
- Check if
.chatgpt-app/state.json exists
- If yes โ use Resume App workflow
- If no โ use Create New App workflow
Always guide users through the natural progression:
Concept โ Implementation โ Testing โ Deployment