A ready-to-use TypeScript/Node.js template for building custom ChatGPT apps with interactive widgets using the MCP (Model Context Protocol) and OpenAI Apps SDK.
Get your app running in ChatGPT in 5 steps:
pnpm installpnpm run build# In a new terminal
ngrok http 8000
# Copy the https URL (e.g., https://abc123.ngrok-free.dev)BASE_URL=https://your-ngrok-url.ngrok-free.dev pnpm run buildcd mcp
pnpm start- Enable developer mode
- Go to Settings > Connectors
- Add your ngrok URL:
https://your-ngrok-url.ngrok-free.dev/mcp - Start chatting! Try: "Show me the best pizzas on a map"
This boilerplate includes 4 example widgets showcasing different UI patterns:
- 📍 Pizza Map - Interactive map with markers
- 🎠 Pizza Carousel - Image carousel widget
- 📔 Pizza Albums - Grid/gallery layout
- 📝 Pizza List - Simple list view
All widgets demonstrate the same MCP + Apps SDK integration pattern, just with different UIs.
Want to build your own ChatGPT app? Just describe what you want!
This starter is optimized for use with AI assistants like Claude or Cursor. Simply describe your app idea, and the AI will guide you through building it.
The AI follows a structured 3-step process:
- Solidify Use Case - The AI asks questions to understand what you want to build
- Define Tools - AI generates the MCP server and tool definitions
- Design Components - AI creates the React widgets and UI
In Claude or Cursor, say:
"I want to build a ChatGPT app that shows [YOUR IDEA HERE]"
Examples:
- "I want to build a ChatGPT app that shows my GitHub starred repos in a gallery"
- "I want to build a ChatGPT app that displays my calendar events on a timeline"
- "I want to build a ChatGPT app that visualizes my Spotify listening history"
The AI will:
- Ask clarifying questions about your use case
- Auto-generate the MCP server code
- Create the React widget components
- Help you test and refine the app
See .claude/prompt-to-app-guide.md for complete instructions on helping users build ChatGPT apps.
When you work with an AI assistant, it will:
- ✅ Create new widget directory in
src/ - ✅ Generate React components with your custom UI
- ✅ Update MCP server with your tool definitions
- ✅ Configure build process
- ✅ Provide testing instructions
├── src/ # Widget source code (React components)
│ ├── example-pizza/ # Map widget
│ ├── example-pizza-carousel/ # Carousel widget
│ ├── example-pizza-list/ # List widget
│ └── example-pizza-albums/ # Gallery widget
├── assets/ # Built widget bundles (HTML/JS/CSS)
├── mcp/ # MCP server
│ └── src/server.ts # Main server file
├── build-all.mts # Build script
└── package.json
- Edit your React component in
src/your-widget/ - Rebuild:
BASE_URL=https://your-ngrok-url.ngrok-free.dev pnpm run build - Restart server:
cd mcp && pnpm start - Test in ChatGPT - invoke the tool again
- Create new directory in
src/(e.g.,src/my-widget/) - Add your React component as
index.jsx - Update
build-all.mts- add totargetsarray - Update
mcp/src/server.ts- add towidgetsarray - Build and test
For faster iteration without ChatGPT:
# Use Vite dev server for hot reload
pnpm run dev
# Or preview built bundles locally
pnpm run build # Default uses http://localhost:4444
pnpm run serve # Serves on :4444The Node server (mcp/src/server.ts) does three things:
- Exposes MCP endpoints at
/mcpfor ChatGPT to connect - Serves static assets (CSS/JS) from the
assets/directory - Returns widget HTML when tools are called
build-all.mts compiles your React widgets into standalone bundles:
- Generates hashed files (e.g.,
example-pizza-2d2b.js) for cache busting - Creates HTML templates that reference the correct assets
- Uses BASE_URL to set where assets load from
User asks ChatGPT → ChatGPT calls MCP tool → Server returns HTML + metadata
→ ChatGPT renders widget in iframe → Widget loads CSS/JS from server
Required for ngrok/production. Sets the base URL for loading widget assets.
- Local dev: Defaults to
http://localhost:4444 - ngrok:
BASE_URL=https://your-ngrok-url.ngrok-free.dev - Production:
BASE_URL=https://your-production-domain.com
Usage:
BASE_URL=https://your-url.com pnpm run buildProblem: HTML references wrong asset URLs
Solution: Rebuild with correct BASE_URL
BASE_URL=https://your-ngrok-url.ngrok-free.dev pnpm run build
cd mcp && pnpm startProblem: Browser blocks cross-origin requests
Solution: This is fixed in the latest code. Make sure you're running the updated server.
Problem: ChatGPT can't reach your server
Solution:
- Check ngrok is running:
ngrok http 8000 - Verify MCP server is running:
cd mcp && pnpm start - Ensure connector URL ends with
/mcp
Problem: Old bundle is cached or ChatGPT isn't refreshing
Solution:
- Rebuild:
BASE_URL=... pnpm run build - Restart server:
cd mcp && pnpm start - Check browser console for any errors or cached assets
- Try a hard refresh in your browser (Cmd+Shift+R on Mac, Ctrl+Shift+R on Windows)
- If still not working: Remove and re-add the connector in ChatGPT settings
- Deploy your server (Heroku, Railway, Render, etc.)
- Build with production URL:
BASE_URL=https://your-app.com pnpm run build
- Upload built assets to your server
- Run the MCP server:
cd mcp && pnpm start - Add connector in ChatGPT:
https://your-app.com/mcp
The Node MCP server serves both API and static assets from the same domain.
For professional, consistent widgets, refer to OpenAI's design guidelines:
- Figma Component Library - Coming soon - See Issue #3 to help add this
- Design Guidelines - Follow ChatGPT's visual language
- Component Patterns - Reusable UI patterns for common interactions
- Mobile-first - ChatGPT is often used on mobile devices
- Accessible - Use semantic HTML, ARIA labels, keyboard navigation
- Fast - Optimize images, minimize bundle size
- Responsive - Test on various screen sizes
- Consistent - Use Tailwind CSS for styling consistency
Update these files to match your app name:
mcp/→ This is your MCP server directory (hosts all your widgets)mcp/src/server.ts→ Update server name and tool namessrc/example-pizza*/→ Rename widget directories or create new onesbuild-all.mts→ Updatetargetsarray with your widget names
Edit mcp/src/server.ts:
- Modify the
widgetsarray - Update tool handlers in
CallToolRequestSchema - Change
structuredContentreturned by tools
Edit React components in src/your-widget/index.jsx:
- Modify JSX/styling
- Add new components
- Update data rendering logic
- MCP Server: Node.js + @modelcontextprotocol/sdk
- UI Framework: React 19
- Styling: Tailwind CSS 4
- Build Tool: Vite 7
- Package Manager: pnpm
Ready to take your app to production? Check out these guides:
For apps that need to:
- Access user-specific data from external APIs
- Validate API keys
- Implement OAuth flows
See TODO-authentication.md for implementation guide.
Improve your ChatGPT integration with better:
- Loading and success messages
- Accessibility features
- Error handling
- Performance hints
See TODO-metadata-optimization.md for optimization guide.
We welcome contributions! Here's how you can help:
Check out our GitHub Issues to see what needs to be done:
- 🔐 Authentication Support - Help implement OAuth and API key auth
- ⚡ Metadata Optimization - Improve loading messages and accessibility
- 🎨 Figma Component Library - Add official design resources
- 📦 Widget Templates - Create templates for common use cases
- 🧪 Testing Guide - Add comprehensive testing examples
- 🚀 Deployment Guides - Platform-specific deployment docs
See GITHUB_ISSUES.md for full details on each issue.
- Find an issue - Check good first issues
- Comment - Let us know you're working on it
- Fork & create a branch - Make your changes
- Test - Ensure everything builds and works
- Submit a PR - Reference the issue in your PR description
git clone https://github.com/meghasharma1/chatgpt-apps-starter
cd chatgpt-apps-starter
pnpm install
pnpm run buildMIT License - see LICENSE for details.