- 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.tsCritical Requirements:
Serverclass from@modelcontextprotocol/sdk/server/index.jsStreamableHTTPServerTransportfor session management- Widget URIs:
ui://widget/{widget-id}.html - Widget MIME type:
text/html+skybridge structuredContentin tool responses_metawithopenai/outputTemplateon 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", // if widget
}
}- 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: { /* sample */ },
},
];- 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;
// Render logic
}
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
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=...
AUTH0_CLIENT_SECRET=...
# Supabase (from database setup)
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)
- Tables have required fields - user_subject indexed - RLS policies 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
# Add auth/database vars if needed- 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 - MCP endpoint: https://{app}.onrender.com/mcp - Tool discovery works - Widgets render
- Configure ChatGPT Connector
- URL: https://{app}.onrender.com/mcp - Test in ChatGPT
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: - "Add another tool?" - "Add a widget?" - "Set up authentication?" - "Set up database?"
Testing Phase: - "Generate golden prompts?" - "Run validation?" - "Run tests?"
Deployment Phase: - "Deploy to Render?" - "Configure ChatGPT connector?"
- Continue Work
Based on user's choice, invoke the appropriate workflow section.
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,
"tested": boolean,
"deployed": boolean,
"deploymentUrl": "string | null",
"goldenPromptsGenerated": boolean,
"lastUpdated": "ISO timestamp"
}Command Reference
# Setup
./setup.sh
# Development
./START.sh --dev # Dev mode with watch
./START.sh --preview # Open preview in browser
./START.sh --stdio # STDIO mode (testing)
./START.sh # Production mode
# Testing
npm run validate # Type checking
curl http://localhost:3000/health
# Deployment
git push origin main # Trigger Render deployGetting Started
When the user invokes any chatgpt-app command:
- Check if
.chatgpt-app/state.jsonexists - If yes → use Resume App workflow
- If no → use Create New App workflow
Always guide users through the natural progression: Concept → Implementation → Testing → Deployment