A starter template for building ChatGPT apps with interactive widgets using MCP (Model Context Protocol) on Val Town.
Visit your deployment URL to get the MCP endpoint
Add to ChatGPT:
Test in ChatGPT:
list_messages - Shows all messages in an interactive widgetadd_message - Adds a new message and shows updated listget_message - Shows details for a specific messageTools return discriminated unions that drive widget navigation:
{ kind: "message_list", messages: [...] } // → /list route
{ kind: "message_detail", id: 1, ... } // → /detail/:id route
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.
backend/mcp/server.tsshared/types.tsfrontend/widgets/routes.tsxNavigationSync.tsx to handle new kind