multiAI Summary Pending

chatgpt-app-builder

Build ChatGPT Apps using the Apps SDK and MCP. Use when users want to: (1) Evaluate if their product should become a ChatGPT App (2) Design and implement MCP servers with widgets (3) Test apps locally and in ChatGPT (4) Prepare for App Store submission Triggers: "ChatGPT app", "Apps SDK", "build for ChatGPT", "ChatGPT integration", "MCP server for ChatGPT", "submit to ChatGPT"

231 stars

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/chatgpt-app-builder/SKILL.md --create-dirs "https://raw.githubusercontent.com/aiskillstore/marketplace/main/skills/bayramannakov/chatgpt-app-builder/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/chatgpt-app-builder/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How chatgpt-app-builder Compares

Feature / Agentchatgpt-app-builderStandard Approach
Platform SupportmultiLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Build ChatGPT Apps using the Apps SDK and MCP. Use when users want to: (1) Evaluate if their product should become a ChatGPT App (2) Design and implement MCP servers with widgets (3) Test apps locally and in ChatGPT (4) Prepare for App Store submission Triggers: "ChatGPT app", "Apps SDK", "build for ChatGPT", "ChatGPT integration", "MCP server for ChatGPT", "submit to ChatGPT"

Which AI agents support this skill?

This skill is compatible with multi.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# ChatGPT App Builder

Build production-ready ChatGPT Apps from concept to App Store submission.

## Quick Start

```
New app?           → Start at Phase 1 (Fit Evaluation)
Have app-spec.md?  → Start at Phase 3 (Implementation)
App built?         → Start at Phase 4 (Testing)
Ready to ship?     → Start at Phase 5 (Deployment)
```

---

## Phase 1: Fit Evaluation

**Goal**: Determine if a ChatGPT App is right for this product.

### Step 1: Gather Context
Ask the user:
1. What does your product do?
2. Who are your users?
3. What API/data does it expose?
4. What actions can users take?

### Step 2: Apply Know/Do/Show Framework
Evaluate against three value pillars (see [fit_evaluation.md](references/fit_evaluation.md)):

| Pillar | Question | Strong Signal |
|--------|----------|---------------|
| **Know** | Does it provide data ChatGPT lacks? | Live prices, user-specific data, internal metrics |
| **Do** | Can it take real actions? | Create, update, delete, send, schedule |
| **Show** | Can it display better than text? | Lists, charts, maps, media galleries |

**Minimum requirement**: At least one pillar must be strong.

### Step 3: Check Blockers
Review [fit_evaluation.md](references/fit_evaluation.md) for:
- Prohibited categories (gambling, adult, crypto speculation)
- Data restrictions (no PCI, PHI, SSN, API keys)
- Age requirements (13+ audience)

### Step 4: Create Golden Prompt Set
Draft prompts for discovery testing:
- **5 direct prompts**: Explicitly name your product ("Show my TaskFlow tasks")
- **5 indirect prompts**: Describe intent without naming ("What should I work on?")
- **3 negative prompts**: Similar but shouldn't trigger ("Create a reminder")

### Step 5: Write app-spec.md
Create the specification file:

```markdown
# [Product Name] ChatGPT App Spec

## Product Context
- Name: [Product name]
- API Base: [API URL]
- Auth: [Bearer token / OAuth / None]

## Value Proposition
- Know: [What data does it provide?]
- Do: [What actions can it take?]
- Show: [What UI is needed?]

## Golden Prompts
### Direct (should trigger)
1. ...

### Indirect (should trigger)
1. ...

### Negative (should NOT trigger)
1. ...
```

**Output**: `app-spec.md` in project directory

---

## Phase 2: App Design

**Goal**: Define complete technical specification.

### Step 1: Define Tools (2-5)
Follow one-job-per-tool principle. See [chatgpt_app_best_practices.md](references/chatgpt_app_best_practices.md).

For each tool, specify:
```yaml
name: service_verb_noun  # e.g., taskflow_get_tasks
title: Human Readable Name
description: Use this when the user wants to... [be specific]
annotations:
  readOnlyHint: true/false
  destructiveHint: true/false
  openWorldHint: true/false
inputSchema:
  param1: type (required/optional)
  param2: enum["a", "b", "c"]
outputStructure:
  content: [text summary for model]
  structuredContent: {machine-readable data}
  _meta: {widget-only data}
```

### Step 2: Decide Widget Needs
Does the app need custom UI?

| Use Case | Widget Needed? | Component Type |
|----------|----------------|----------------|
| Task list with checkboxes | Yes | List with actions |
| Data display only | Maybe | Could use text |
| Maps, charts, media | Yes | Specialized |
| Multi-step workflow | Yes | Stateful widget |

See [widget_development.md](references/widget_development.md) for patterns.

### Step 3: Plan Authentication
If accessing user-specific data or write operations, auth is required.

See [oauth_integration.md](references/oauth_integration.md) for:
- Well-known endpoint setup
- Provider-specific guides (Auth0, Stytch)
- Tool-level securitySchemes

### Step 4: Update app-spec.md
Add technical specification:

```markdown
## Tools

### 1. service_get_items
- **Annotations**: readOnlyHint: true
- **Input**: { status?: "active" | "completed", limit?: number }
- **Output**:
  - content: "Found N items"
  - structuredContent: { items: [...] }
  - _meta: { fullData: [...] }

### 2. service_create_item
- **Annotations**: openWorldHint: true
- **Input**: { title: string, description?: string }
- **Output**: { id, title, created_at }

## Widget
- Type: List with action buttons
- Display modes: inline, fullscreen
- State: { selectedId, filter }

## Authentication
- Required: Yes
- Provider: Auth0
- Scopes: read:items, write:items
```

**Output**: Updated `app-spec.md` with full technical spec

---

## Phase 3: Implementation

**Goal**: Generate complete working project.

### Step 1: Initialize Project
Copy from assets and customize:

```bash
# Project structure
myapp-chatgpt/
├── package.json
├── tsconfig.json
├── src/
│   ├── index.ts          # MCP server entry
│   ├── tools/            # Tool handlers
│   ├── widget/           # Widget source
│   └── types/            # TypeScript types
└── scripts/
    └── build-widget.ts   # Widget bundler
```

See [node_chatgpt_app.md](references/node_chatgpt_app.md) for complete patterns.

### Step 2: Implement MCP Server
Key components (from assets/server/):

1. **HTTP server with SSE transport** (required for ChatGPT Apps):
```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";

// GET /mcp - SSE stream connection
// POST /mcp/messages - Message handling
```

2. **Tool definitions with JSON Schema**:
```typescript
const tools: Tool[] = [{
  name: "service_get_items",
  title: "Get Items",
  description: "Use this when the user wants to see items...",
  inputSchema: { type: "object", properties: {...} },
  _meta: {
    "openai/outputTemplate": "ui://widget/app.html",
    "openai/widgetAccessible": true
  },
  annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
}];
```

3. **Handler registration**:
```typescript
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  // Handle tool calls...
  return {
    content: [{ type: "text", text: `Found ${items.length} items` }],
    structuredContent: { items: items.slice(0, 10) },
    _meta: { fullItems: items }
  };
});
```

### Step 3: Implement Widget
Key patterns (from assets/widget/):

```typescript
// Access data
const output = window.openai.toolOutput;
const meta = window.openai.toolResponseMetadata;

// Invoke tools
await window.openai.callTool("service_action", { id: "123" });

// Persist state
window.openai.setWidgetState({ selectedId: "123" });

// Layout control
window.openai.notifyIntrinsicHeight(400);
await window.openai.requestDisplayMode({ mode: "fullscreen" });
```

See [widget_development.md](references/widget_development.md) for React hooks and patterns.

### Step 4: Build
```bash
npm install
npm run build  # Compiles server + bundles widget
```

### Step 5: Implementation Checklist

Before moving to testing, verify:

#### Widget Requirements
- [ ] Uses Apps SDK UI design tokens (see [apps_sdk_ui_tokens.md](references/apps_sdk_ui_tokens.md))
- [ ] Implements dark mode with CSS variable architecture
- [ ] Uses LoadingDots pattern for loading states (see [widget_ui_patterns.md](references/widget_ui_patterns.md))
- [ ] Calls `notifyIntrinsicHeight()` after all DOM changes
- [ ] Includes copy button feedback for copyable content
- [ ] Has show more/less for long lists (>3 items)
- [ ] Works on mobile (test at 375px width)
- [ ] Loading UI guards against re-initialization (see [widget_loading_patterns.md](references/widget_loading_patterns.md))
- [ ] SVG animations use `.style` property, not `setAttribute()` (see [widget_development.md](references/widget_development.md#common-widget-gotchas))

#### Security Requirements
- [ ] All user input is validated (see [security_patterns.md](references/security_patterns.md))
- [ ] HTML output uses safe DOM methods (textContent, createElement)
- [ ] External image URLs are proxied with domain whitelist and size limits (200KB)
- [ ] Rate limiting is implemented per session with LRU eviction

#### Server Requirements
- [ ] `/.well-known/openai-apps-challenge` endpoint returns challenge token
- [ ] `/privacy` endpoint returns HTML privacy policy
- [ ] `/terms` endpoint returns HTML terms of service
- [ ] `/mcp` endpoint handles SSE connections
- [ ] `/health` or `/` returns health check JSON
- [ ] CORS configured for ChatGPT domains only
- [ ] Security headers set on all responses
- [ ] **Session routing uses direct lookup by sessionId** (CRITICAL - see [troubleshooting.md](references/troubleshooting.md#critical-multi-connection-session-routing))
- [ ] Response size under 300KB total (remove duplicates, limit images)

#### Production Readiness (if deploying to production)
- [ ] OAuth tokens stored in database, not in-memory (see [oauth_integration.md](references/oauth_integration.md#production-considerations-token-storage))
- [ ] Mutation tools include idempotency checks (see [chatgpt_app_best_practices.md](references/chatgpt_app_best_practices.md#idempotency-keys))
- [ ] Disambiguation pattern for multi-match scenarios (see [chatgpt_app_best_practices.md](references/chatgpt_app_best_practices.md#disambiguation-pattern))
- [ ] Confirmation receipts for all mutations (see [chatgpt_app_best_practices.md](references/chatgpt_app_best_practices.md#confirmation-receipts))

**Output**: Complete project in working directory

---

## Phase 4: Testing

**Goal**: Verify the app works correctly.

### Step 1: Local Testing with MCP Inspector
```bash
# Terminal 1: Start server
npm run dev
# Server runs at http://localhost:8000

# Terminal 2: Run inspector
npx @modelcontextprotocol/inspector@latest http://localhost:8000/mcp
```

Verify:
- [ ] All tools appear in inspector
- [ ] Tool calls return expected structure
- [ ] Widget renders without errors

### Step 2: Create HTTPS Tunnel
```bash
ngrok http 8000
# Copy the https://xxx.ngrok.app URL
```

### Step 3: Create ChatGPT Connector
1. Go to ChatGPT → Settings → Connectors
2. Enable Developer Mode (Settings → Apps & Connectors → Advanced)
3. Create new connector:
   - Name: Your app name
   - Description: From app-spec.md
   - URL: `https://xxx.ngrok.app/mcp`
4. Click Create and verify tools appear

### Step 4: Test Golden Prompts
In a new ChatGPT conversation:
1. Enable your connector (+ button → More → select connector)
2. Test each golden prompt from app-spec.md
3. Verify:
   - [ ] Direct prompts trigger correctly
   - [ ] Indirect prompts trigger correctly
   - [ ] Negative prompts do NOT trigger
   - [ ] Widget renders properly
   - [ ] Actions work (if applicable)

### Step 5: Iterate
If issues found:
1. Fix code
2. Rebuild: `npm run build`
3. Refresh connector in ChatGPT settings
4. Re-test

See [troubleshooting.md](references/troubleshooting.md) for common issues and solutions.

**Output**: Working app tested in ChatGPT

---

## Phase 5: Deployment & Submission

**Goal**: Ship to production and App Store.

### Step 1: Deploy to Production
Generate deployment configs from assets/deploy/:

**Fly.io** (recommended):
```bash
fly launch
fly deploy
```

**Vercel/Cloudflare**: Ensure streaming HTTP support.

### Step 2: Update Connector
1. Replace ngrok URL with production URL
2. Verify connection in ChatGPT settings

### Step 3: Pre-Submission Checklist
See [submission_requirements.md](references/submission_requirements.md):

**Required**:
- [ ] Organization verified on OpenAI Platform
- [ ] All tools have clear descriptions
- [ ] Annotations correct (readOnlyHint, destructiveHint, openWorldHint)
- [ ] No prohibited content/commerce
- [ ] No restricted data collection
- [ ] Widget renders on mobile
- [ ] Test credentials with sample data prepared

**If auth required**:
- [ ] Well-known endpoints accessible
- [ ] Test account credentials documented
- [ ] OAuth flow completes successfully

### Step 4: Submit
1. Go to platform.openai.com/apps-manage
2. Enter MCP server URL
3. Add OAuth metadata (if applicable)
4. Complete submission form
5. Submit for review

### Step 5: Post-Submission
- Monitor email for review status
- Address any reviewer feedback
- Click Publish after approval

**Output**: App live in ChatGPT App Store

---

## External Resources

- [OpenAI Apps SDK Docs](https://developers.openai.com/apps-sdk)
- [Apps SDK Examples](https://github.com/openai/openai-apps-sdk-examples)
- [Apps SDK UI Kit](https://openai.github.io/apps-sdk-ui)
- [MCP Protocol Spec](https://modelcontextprotocol.io)