A starter template for building ChatGPT apps with interactive widgets using MCP (Model Context Protocol) on Val Town.
- Backend: Hono + MCP Lite + Drizzle ORM + SQLite + Cloudinary
 - Widget: React 19 + TanStack Router + OpenAI App SDK
 
Before using the OpenCloset functionality, add these environment variables in Val Town:
CLOUDINARY_CLOUD_NAME- Your Cloudinary cloud nameCLOUDINARY_API_KEY- Your Cloudinary API keyCLOUDINARY_API_SECRET- Your Cloudinary API secretCLOUDINARY_UPLOAD_PRESET- (Optional) Unsigned upload preset for easier setup
- 
Visit your deployment URL to get the MCP endpoint
 - 
Add to ChatGPT:
- Open ChatGPT settings β Apps & Connectors -> Create (you will need developer mode enabled)
 - Add MCP server with your endpoint URL
 
 - 
Test in ChatGPT:
- "List all messages"
 - "Add a message: Hello!"
 - "Show me message #1"
 - "Show me a counter widget"
 - "Show me a todo list"
 - "Show me the weather"
 - "Show me an item card"
 - "Show me multiple wardrobe items"
 - "Show me an outfit"
 - Upload clothing photos and say "Add these to my closet as tops"
 - "Suggest an outfit from my closet"
 - "Show me all my closet items"
 
 
list_messages- Shows all messages in an interactive widgetadd_message- Adds a new message and shows updated listget_message- Shows details for a specific message
show_counter- Display an interactive counter with increment/decrement buttonsincrement_counter- Increment the counter by the step amountdecrement_counter- Decrement the counter by the step amountreset_counter- Reset the counter to zero
show_todos- Display an interactive todo list with progress tracking
show_weather- Display current weather information for a location
show_item_card- Display a single wardrobe item cardshow_multi_item_card- Display multiple wardrobe items in a gridshow_outfit_card- Display a complete outfit with top and bottom pieces
opencloset.capture_items- Upload and categorize clothing photos to your closetopencloset.suggest_outfit- Get outfit suggestions from your saved itemsopencloset.list_items- View all items in your closet (with optional category filter)
The project includes several React widget components:
- CounterWidget (
/counter) - Interactive counter with +/- buttons and reset - TodoWidget (
/todo) - Todo list with completion tracking and progress bar - WeatherWidget (
/weather) - Weather display with temperature, conditions, and stats - DemoWidget (
/demo) - Showcase page displaying all three widgets together - ItemCard - Individual wardrobe item display component
 - MultiItemCard - Grid display for multiple wardrobe items
 - OutfitCard - Complete outfit display with top and bottom pieces
 
Tools return discriminated unions that drive widget navigation:
{ kind: "message_list", messages: [...] }      // β /list route
{ kind: "message_detail", id: 1, ... }         // β /detail/:id route
{ kind: "counter", count: 5, step: 1 }         // β /counter route
{ kind: "todo_list", todos: [...] }            // β /todo route
{ kind: "weather", location: "NYC", ... }      // β /weather route
{ kind: "item_card", item: {...} }             // β Individual ItemCard component
{ kind: "multi_item_card", items: [...] }      // β Individual MultiItemCard component
{ kind: "outfit_card", top: {...}, bottom: {...} } // β Individual OutfitCard component
The widget automatically navigates based on the kind field.
Messages are automatically scoped using the openai/subject field that ChatGPT includes in request metadata. This provides authless data isolation - each subject gets its own message board.
The scoping happens in tool handlers:
const subject = ctx.request.params._meta?.["openai/subject"];
const messages = await getMessages(subject);
The exact semantics of openai/subject are determined by ChatGPT.
- Add tool in 
backend/mcp/server.ts - Define output schema in 
shared/types.ts - Create widget component in 
frontend/widgets/components/ - Add route in 
frontend/widgets/routes.tsx - Update 
NavigationSync.tsxto handle newkind 
For detailed information about the OpenCloset digital wardrobe functionality, see:
- OPENCLOSET.md - Complete implementation guide
 - TESTING.md - Testing instructions for all widgets
 - TROUBLESHOOTING.md - Fix common Cloudinary setup issues