| name | chatgpt-app:validate |
| description | Run validation suite on your ChatGPT App to check schemas, annotations, widgets, and UX compliance. |
Validate ChatGPT App
You are helping the user validate their ChatGPT App before testing and deployment.
Validation Checks
1. Required Files Check (RUN FIRST)
Check that ALL mandatory files exist:
ls package.json tsconfig.server.json setup.sh START.sh .env.example server/index.ts
Expected file structure:
{app-name}/
├── package.json
├── tsconfig.server.json
├── setup.sh
├── START.sh
├── .env.example
├── .gitignore
└── server/
└── index.ts
If ANY of the above are missing, report as CRITICAL ERROR.
2. Server Implementation Check
Verify server/index.ts uses correct patterns:
MUST have:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
MUST NOT have:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
Session management MUST exist:
const transports = new Map<string, StreamableHTTPServerTransport>();
3. Widget Configuration Check
Verify widgets array structure:
const widgets: WidgetConfig[] = [
{
id: "widget-id",
name: "Widget Name",
description: "What it displays",
templateUri: "ui://widget/widget-id.html",
invoking: "Loading...",
invoked: "Ready",
mockData: { },
},
];
4. Tool Response Check
Widget tools MUST return:
return {
content: [{ type: "text", text: JSON.stringify(result) }],
structuredContent: result,
_meta: {
"openai/outputTemplate": widget.templateUri,
"openai/toolInvocation/invoked": widget.invoked,
},
};
5. Resource Handler Check
Verify ReadResource returns correct format:
return {
contents: [{
uri,
mimeType: "text/html+skybridge",
text: generateWidgetHtml(widget.id),
}],
_meta: {
"openai/serialization": "markdown-encoded-html",
"openai/csp": { ... },
},
};
6. Widget HTML Check
Verify generateWidgetHtml includes:
window.PREVIEW_DATA support for local preview
window.openai.toolOutput data access
openai:set_globals event listener
- Polling fallback with setInterval
rendered flag to prevent re-renders
7. Endpoint Check
Verify these endpoints exist:
GET /health - Health check
GET /preview - Widget preview index
GET /preview/:widgetId - Individual widget preview
ALL /mcp - MCP protocol handler
DELETE /mcp - Session cleanup
8. Package.json Scripts Check
{
"scripts": {
"build": "npm run build:server",
"build:server": "tsc -p tsconfig.server.json",
"start": "HTTP_MODE=true node dist/server/index.js",
"dev": "HTTP_MODE=true NODE_ENV=development tsx watch --clear-screen=false server/index.ts"
}
}
MUST NOT have: dev:web, build:web, concurrently
9. Annotation Validation
- Query tools have
readOnlyHint: true
- Delete tools have
destructiveHint: true
- External API tools have
openWorldHint: true
10. Database Validation (if enabled)
- All migrations are valid SQL
- Tables have
user_subject column
- Indexes exist for user queries
Workflow
- Run file existence checks
- Read and analyze server/index.ts
- Verify patterns match requirements
- Collect errors and warnings
- Display results
Results Format
## Validation Results
### File Structure ✓
All required files present.
### Server Implementation ✓
Using correct Server class with session management.
### Widget Configuration ✓
2 widgets properly configured.
### Tool Responses ✓
All widget tools return structuredContent.
---
**Overall: PASS**
Common Errors
| Error | Fix |
|---|
| Uses McpServer | Change to Server from @modelcontextprotocol/sdk/server/index.js |
| Missing session management | Add Map<string, StreamableHTTPServerTransport> |
| Wrong widget URI | Use ui://widget/{id}.html format |
| Wrong MIME type | Use text/html+skybridge |
| Missing structuredContent | Add to tool response for widget data |
| Has web/ folder | Remove - widgets are inline in server/index.ts |