Skip to main content

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:

  1. Create a new directory with your project
  2. Generate all necessary files (main.py, requirements.txt, Dockerfile, etc.)
  3. Set up a basic widget
  4. 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

  1. CDN: Load widget from external CDN

    create-chatgpt-app add-widget --type cdn
    
  2. Inline: Simple HTML inline widget

    create-chatgpt-app add-widget --type inline
    
  3. 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:

  1. Widget Definitions: Data structures for your widgets
  2. MCP Protocol Handlers:
    • list_tools(): Register available tools
    • list_resources(): Expose widgets as resources
    • list_resource_templates(): Define resource templates
    • _handle_read_resource(): Serve widget HTML
    • _call_tool_request(): Execute tool logic
  3. Input Validation: Pydantic models for type-safe inputs
  4. FastAPI App: HTTP/SSE transport layer
  5. CORS Configuration: For local development

Customization Points

Edit the generated main.py to:

  1. Add Business Logic: Implement your tool's functionality in _call_tool_request()
  2. Modify Input Schema: Update ToolInput class and TOOL_INPUT_SCHEMA
  3. Customize Widgets: Edit widget HTML, CSS, and JavaScript
  4. Add Middleware: Include authentication, rate limiting, etc.
  5. 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:

  1. template_uri matches between widget and metadata
  2. HTML is valid and includes root element
  3. External CSS/JS URLs are accessible (for CDN widgets)
  4. MIME type is text/html+skybridge
  5. Metadata includes openai/widgetAccessible: true

Input Validation Errors

Verify:

  1. Field names match between schema and Pydantic model
  2. Required fields are marked correctly
  3. Test validation independently:
from main import ToolInput

test_input = {"userQuery": "test"}
result = ToolInput.model_validate(test_input)
print(result)

Server Won't Start

Check:

  1. Port is not already in use: lsof -i :8000 (macOS/Linux)
  2. All dependencies are installed: pip list
  3. Virtual environment is activated
  4. Python version is 3.10+: python --version

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Resources

License

MIT License - see LICENSE file for details

Support

For issues and questions:


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

create_chatgpt_app-0.1.0.tar.gz (19.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

create_chatgpt_app-0.1.0-py3-none-any.whl (19.5 kB view details)

Uploaded Python 3

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

Hashes for create_chatgpt_app-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e08fc2969ad69e3a050db1f9b2411e2a11a9ae2e840840859accae342296b1e7
MD5 3019c991f4cc6cf138d1d4e7b50fdc0a
BLAKE2b-256 aa44147bb0ce2d7fafe3bc804df97696722a8f119e47c01c30c88f19b6a7c387

See more details on using hashes here.

File details

Details for the file create_chatgpt_app-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for create_chatgpt_app-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0d312bf5b4b2ace19b0d5b558eb738997be2935995019deb1cd1b7b894a9aabc
MD5 971f63c970e1d912ed1a525b13981ba8
BLAKE2b-256 a835ef2806808f15866508e1ca0bfd2c03487dba5197af91407cb87b4de110f5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page