Reference implementation of ChatGPT Apps using Svelte 5. Shows how to build custom widgets with the Apps SDK.
Two tools (hotel search + room search), one widget with conditional rendering, all static data.
# Install dependencies
yarn install && cd server && yarn install && cd ..
# Build widget
yarn build
# Start MCP server
cd server && yarn devServer runs on http://localhost:3000/mcp. Connect it to ChatGPT, then ask: "Search for hotels in Cape Town"
Uses Svelte 5 runes to listen to window.openai.toolOutput and route based on type:
<script lang="ts">
let toolOutput = $state<any>(null);
onMount(() => {
window.addEventListener('openai:set_globals', handleSetGlobal);
});
</script>
{#if toolOutput?.type === 'hotel_search'}
<HotelSearch data={toolOutput} />
{:else if toolOutput?.type === 'room_search'}
<RoomSearch data={toolOutput} />
{/if}Read the full guide: Building ChatGPT Apps with Svelte 5
Single source of truth for tools and widget metadata. Defines two TypeScript interfaces:
interface WidgetConfig {
widget: {
uri: string;
name: string;
description: string;
mimeType: "text/html+skybridge";
meta: {
"openai/widgetDescription": string;
"openai/widgetPrefersBorder": boolean;
"openai/outputTemplate": string;
"openai/widgetAccessible": boolean;
"openai/resultCanProduceWidget": boolean;
};
};
tools: ToolConfig[];
}
interface ToolConfig {
name: string;
description: string;
outputType: string; // Custom field for widget routing
meta: {
"openai/toolInvocation/invoking": string;
"openai/toolInvocation/invoked": string;
};
}Server imports this config to generate MCP tool definitions and widget responses. Change tool names, descriptions, or widget URIs all in one place.