A CLI tool to scaffold ChatGPT apps using OpenAI Apps SDK
Project description
ChatGPT App Scaffold
A powerful CLI tool to quickly scaffold ChatGPT apps using the OpenAI Apps SDK and Model Context Protocol (MCP).
Features
- 🚀 Quick Start: Generate a complete ChatGPT app in seconds
- 🎨 Widget Templates: Support for CDN, inline, and local widget types
- 🔧 Extensible: Easy to add new widgets and tools
- 🐳 Docker Ready: Includes Dockerfile and Docker configuration
- ✅ Testing: Pre-configured test structure with pytest
- 📚 Well Documented: Comprehensive README and inline documentation
- 🎯 Interactive CLI: Friendly prompts guide you through setup
Installation
From Source
git clone https://github.com/openai/openai-apps-sdk-examples.git
cd openai-apps-sdk-examples/create-chatgpt-app
pip install -e .
From PyPI (Coming Soon)
pip install create-chatgpt-app
Quick Start
Create a New Project
create-chatgpt-app init my-awesome-app
This will:
- Create a new directory with your project
- Generate all necessary files (main.py, requirements.txt, Dockerfile, etc.)
- Set up a basic widget
- Provide next steps to get started
Interactive Mode
Run without arguments for an interactive experience:
create-chatgpt-app init
You'll be prompted for:
- Project name
- App description
- Initial widget configuration
- Port and host settings
Usage
Initialize a New Project
# Basic usage
create-chatgpt-app init my-app
# With options
create-chatgpt-app init my-app --name "My App" --description "My awesome ChatGPT app"
# Custom port and host
create-chatgpt-app init my-app --port 3000 --host localhost
# Skip Docker files
create-chatgpt-app init my-app --no-docker
# Skip test files
create-chatgpt-app init my-app --no-tests
Add a Widget
Navigate to your project directory and add widgets:
cd my-app
# Interactive mode
create-chatgpt-app add-widget
# With options
create-chatgpt-app add-widget --identifier my-widget --title "My Widget" --type inline
Widget Types
-
CDN: Load widget from external CDN
create-chatgpt-app add-widget --type cdn
-
Inline: Simple HTML inline widget
create-chatgpt-app add-widget --type inline
-
Local: Load from local static files
create-chatgpt-app add-widget --type local
Add a Tool
# Interactive mode
create-chatgpt-app add-tool
# With options
create-chatgpt-app add-tool --identifier my-tool --title "My Tool"
# Tool without widget
create-chatgpt-app add-tool --identifier data-processor --no-widget
List Available Templates
create-chatgpt-app list-templates
Project Structure
After running create-chatgpt-app init my-app, you'll get:
my-app/
├── main.py # Main MCP server implementation
├── requirements.txt # Python dependencies
├── README.md # Project documentation
├── .gitignore # Git ignore patterns
├── Dockerfile # Docker configuration
├── .dockerignore # Docker ignore patterns
└── tests/ # Test directory
├── __init__.py
└── test_main.py # Unit tests
Example: Complete Workflow
# 1. Create a new project
create-chatgpt-app init pizza-finder
# 2. Navigate to the project
cd pizza-finder
# 3. Set up virtual environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# 4. Install dependencies
pip install -r requirements.txt
# 5. Add more widgets
create-chatgpt-app add-widget --identifier pizza-map --title "Pizza Map" --type cdn
# 6. Run the server
python main.py
# 7. Test with MCP Inspector
npm install -g @modelcontextprotocol/inspector
mcp-inspector
# Connect to http://localhost:8000/mcp
Generated Code Structure
Main Components
The generated main.py includes:
- Widget Definitions: Data structures for your widgets
- MCP Protocol Handlers:
list_tools(): Register available toolslist_resources(): Expose widgets as resourceslist_resource_templates(): Define resource templates_handle_read_resource(): Serve widget HTML_call_tool_request(): Execute tool logic
- Input Validation: Pydantic models for type-safe inputs
- FastAPI App: HTTP/SSE transport layer
- CORS Configuration: For local development
Customization Points
Edit the generated main.py to:
- Add Business Logic: Implement your tool's functionality in
_call_tool_request() - Modify Input Schema: Update
ToolInputclass andTOOL_INPUT_SCHEMA - Customize Widgets: Edit widget HTML, CSS, and JavaScript
- Add Middleware: Include authentication, rate limiting, etc.
- Connect to Services: Add database, API calls, file processing
Widget Development
CDN Widget Example
AppWidget(
identifier="my-dashboard",
title="Analytics Dashboard",
template_uri="ui://widget/dashboard.html",
invoking="Loading dashboard",
invoked="Dashboard loaded",
html=(
"<div id=\"dashboard-root\"></div>\n"
"<link rel=\"stylesheet\" href=\"https://cdn.example.com/dashboard.css\">\n"
"<script type=\"module\" src=\"https://cdn.example.com/dashboard.js\"></script>"
),
response_text="Dashboard rendered successfully!",
)
Inline Widget Example
AppWidget(
identifier="simple-card",
title="Info Card",
template_uri="ui://widget/card.html",
invoking="Creating card",
invoked="Card created",
html=(
"<div style='padding: 20px; border: 1px solid #ccc; border-radius: 8px;'>"
" <h2>Hello from MCP!</h2>"
" <p>This is a simple inline widget.</p>"
"</div>"
),
response_text="Info card displayed",
)
Local Widget Example
AppWidget(
identifier="custom-widget",
title="Custom Widget",
template_uri="ui://widget/custom.html",
invoking="Loading widget",
invoked="Widget loaded",
html=(
"<div id=\"custom-root\"></div>\n"
"<link rel=\"stylesheet\" href=\"/static/custom.css\">\n"
"<script type=\"module\" src=\"/static/custom.js\"></script>"
),
response_text="Custom widget rendered!",
)
Testing
The generated project includes a test structure:
# Install test dependencies
pip install pytest pytest-asyncio httpx
# Run tests
pytest
# Run with coverage
pip install pytest-cov
pytest --cov=. --cov-report=html
Docker Support
Build and Run
# Build the image
docker build -t my-app .
# Run the container
docker run -p 8000:8000 my-app
# Run with environment variables
docker run -p 8000:8000 -e PORT=3000 my-app
Docker Compose
Create a docker-compose.yml:
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
environment:
- PORT=8000
- HOST=0.0.0.0
restart: unless-stopped
Run with:
docker-compose up
Advanced Usage
Custom Input Schema
Edit your ToolInput class to add custom fields:
class ToolInput(BaseModel):
"""Schema for tool inputs."""
user_query: str = Field(
...,
alias="userQuery",
description="The user's input query",
)
# Add custom fields
max_results: int = Field(
default=10,
ge=1,
le=100,
description="Maximum number of results"
)
category: str = Field(
default="all",
description="Filter by category"
)
model_config = ConfigDict(populate_by_name=True, extra="forbid")
Adding Database Support
import asyncpg
# Initialize DB pool
DB_POOL = None
async def get_db_pool():
global DB_POOL
if DB_POOL is None:
DB_POOL = await asyncpg.create_pool(
"postgresql://user:pass@localhost/dbname"
)
return DB_POOL
# Use in tool handler
async def _call_tool_request(req: types.CallToolRequest) -> types.ServerResult:
pool = await get_db_pool()
async with pool.acquire() as conn:
results = await conn.fetch("SELECT * FROM items WHERE ...")
# Process results...
External API Integration
import httpx
async def _call_tool_request(req: types.CallToolRequest) -> types.ServerResult:
payload = ToolInput.model_validate(req.params.arguments or {})
async with httpx.AsyncClient() as client:
response = await client.get(
"https://api.example.com/search",
params={"q": payload.user_query}
)
api_data = response.json()
# Return with widget...
Troubleshooting
Widget Not Rendering
Check:
template_urimatches between widget and metadata- HTML is valid and includes root element
- External CSS/JS URLs are accessible (for CDN widgets)
- MIME type is
text/html+skybridge - Metadata includes
openai/widgetAccessible: true
Input Validation Errors
Verify:
- Field names match between schema and Pydantic model
- Required fields are marked correctly
- Test validation independently:
from main import ToolInput
test_input = {"userQuery": "test"}
result = ToolInput.model_validate(test_input)
print(result)
Server Won't Start
Check:
- Port is not already in use:
lsof -i :8000(macOS/Linux) - All dependencies are installed:
pip list - Virtual environment is activated
- Python version is 3.10+:
python --version
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Resources
- OpenAI Apps SDK Examples
- Model Context Protocol Documentation
- FastAPI Documentation
- Pydantic Documentation
- MCP Inspector
License
MIT License - see LICENSE file for details
Support
For issues and questions:
- Open an issue on GitHub
- Check the HOWTO guide
- Review example projects
Made with ❤️ for the ChatGPT developer community
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file create_chatgpt_app-0.1.0.tar.gz.
File metadata
- Download URL: create_chatgpt_app-0.1.0.tar.gz
- Upload date:
- Size: 19.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e08fc2969ad69e3a050db1f9b2411e2a11a9ae2e840840859accae342296b1e7
|
|
| MD5 |
3019c991f4cc6cf138d1d4e7b50fdc0a
|
|
| BLAKE2b-256 |
aa44147bb0ce2d7fafe3bc804df97696722a8f119e47c01c30c88f19b6a7c387
|
File details
Details for the file create_chatgpt_app-0.1.0-py3-none-any.whl.
File metadata
- Download URL: create_chatgpt_app-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d312bf5b4b2ace19b0d5b558eb738997be2935995019deb1cd1b7b894a9aabc
|
|
| MD5 |
971f63c970e1d912ed1a525b13981ba8
|
|
| BLAKE2b-256 |
a835ef2806808f15866508e1ca0bfd2c03487dba5197af91407cb87b4de110f5
|