ChatGPT Backend
MCP server, widget registry helpers, and sample tool for the ChatGPT widget backend.
Backend Pairing
Run the widget build script before starting the MCP server so the backend can serve the latest widget HTML bundle.
Overview
The backend block provisions an MCP server with SSE transport, registers the sample add tool, and exposes helper utilities for packaging widget assets. Install it in your backend project to host the ChatGPT widget and deliver structured responses that the frontend renders.
pnpm dlx shadcn@latest add https://utilcn.dev/r/chatgpt-app-backend.jsonbunx --bun shadcn@latest add https://utilcn.dev/r/chatgpt-app-backend.jsonnpx shadcn@latest add https://utilcn.dev/r/chatgpt-app-backend.jsonyarn shadcn@latest add https://utilcn.dev/r/chatgpt-app-backend.jsonProject Files
src/mcp-server.tscreates an HTTP server on port 8000 that exposes/mcpfor SSE sessions and a POST endpoint for messages.src/tools/add.tsregisters theaddtool, validates input with Zod, and returns structured content that maps to the widget props.src/lib/widget-util.tsresolves the built widget HTML, registers MCP resources, and emits metadata required by ChatGPT.
Configure Asset Location
Point the widget helper at the directory that contains the assets generated by the frontend build script:
const ASSETS_DIR = path.resolve(
__dirname,
'..',
'..',
'..',
'web',
'assets',
); // <-- update to wherever your front end `build-chatgpt-widgets.ts` puts your `assets` directoryIf your project places assets in a different folder (for example ../frontend/dist/assets), update ASSETS_DIR to match. The helper looks for ${componentName}.html files and falls back to hashed variations such as add-xxxx.html.
Customise Tools
registerAdd demonstrates how to map tool output to widget props:
server.registerTool('add', { /* metadata */ }, (args) => {
const { a, b } = addInputParser.parse(args);
return {
structuredContent: { a, b, sum: a + b },
_meta: widgetMeta(addWidget),
};
});Reuse registerWidgetResource and widgetMeta for additional widgets. Each widget needs a unique id, templateUri, and descriptive metadata so ChatGPT knows how to render it.
You should create a package.json script to start this up in your environment
Run the MCP Server
# navigate to the mcp-server.ts
bun mcp-server.tsor
pnpm tsx registry/default/chatgpt-app/mcp-server.tsThe server listens on http://localhost:${PORT ?? 8000} and exposes:
GET /mcpfor establishing SSE sessions.POST /mcp/messages?sessionId=...for relaying follow-up requests.
Remember to rebuild the frontend assets whenever the widget changes; otherwise buildWidgetHtml will throw if it cannot locate the HTML template.
You will need to use ngrok to make your local url public to ChatGPT
Related Guides
ChatGPT Widget Frontend
Learn how to build and update the widget assets consumed by this server.