Openai应用模板(todo APP)
构建、预览和发布一个ChatGPT应用程序,该应用程序呈现一个响应式的React小部件,并与模型上下文协议(MCP)服务器通信——所有这些都来自一个存储库。
- 单文件小部件交付 –每个小部件都捆绑在
dist/.html使用内联JS+CSS,因此ChatGPT可以通过以下方式嵌入它ui://widget/.... - 电池包括MCP服务器 –公开SSE+POST端点,通告工具/资源,并返回结构化todo数据和小部件元数据。
- 本地首个DX –带有HMR、Tailwind风格、React 19、TypeScript和反映ChatGPT的助手钩子的Vite开发服务器
window.openai运行时。
使用此模板作为任何需要交互式UI和ChatGPT代理可以调用的工具的小型应用程序的起点。
______________________________________________________________________
一览
| 工件 | 技术 | 目的 |
|---|---|---|
src/widgets/todo.tsx | React+hooks | 交互式todo小部件,可以在与代理同步的同时乐观地更新本地状态 |
server.ts | 节点+ @modelcontextprotocol/sdk | 最小化MCP服务器暴露 todo list, add_todo, toggle_todo, delete_todo,以及小部件资源 |
build.ts | Vite+esbuild | 发现小部件条目,将其捆绑在一起,并生成准备好的内联HTML文件 ui://widget/... |
dev.ts | Vite loader | 允许您通过以下方式热重新加载任何小部件 http://localhost:5173?entry= |
______________________________________________________________________
先决条件
- Node.js 18+
- npm(或者pnpm/yarn,如果你调整脚本的话)
- (可选) 吸烟 或类似的隧道,与ChatGPT共享MCP服务器
安装依赖项:
npm install______________________________________________________________________
快速开始
- 构建小部件包
npm run build
# → dist/todo.html (inline CSS + JS)- 运行MCP服务器
npm start
# SSE GET http://localhost:8000/mcp
# POST POST http://localhost:8000/mcp/messages?sessionId=...- 在本地预览小部件(可选)
npm run dev
# open http://localhost:5173?entry=todo- 暴露于ChatGPT(可选)
ngrok http 8000
# use https://.ngrok-free.app/mcp as the connector URL______________________________________________________________________
开发流程
小部件迭代
- 小工具位于
src/widgets/.tsx。每个文件都应该调用createRoot并自行安装__WIDGET_ROOT_ID__. npm run dev使用HMR启动Vite。引导到http://localhost:5173?entry=加载该小部件。- 挂钩下
src/hooks提供键入访问权限window.openai全局:
- useWidgetProps 提取结构化工具输出(toolOutput.todoList 在这种情况下)。 - useWidgetState 通过以下方式使本地小部件状态与ChatGPT主机保持同步 window.openai.setWidgetState. - useCallTool, useRequestDisplayMode等包装MCP API。
- todo小部件显示
theme,safeArea.insets,displayMode,以及maxHeight因此,它可以匹配ChatGPT的亮/暗调色板,尊重安全区域,并根据PiP、内联或全屏布局调整自身大小,而无需您进行额外工作。
ChatGPT的构建
npm run build自动发现中的每个文件src/widgets(或嵌套index.tsx目录中的文件)并发出dist/.html.- 每个HTML文件内联:
1. 共享顺风风格 src/styles/main.css 1. 退路 window.todoData 独立预览块 1. 缩小的小部件包
- 构建脚本保持输出自包含,因此ChatGPT可以获取
ui://widget/.html没有额外的资产。
MCP服务器
server.ts电线向上@modelcontextprotocol/sdk带着一个SSEServerTransport:
- GET /mcp 启动SSE会话。 - POST /mcp/messages?sessionId= 流工具消息/响应。
- 默认情况下附带的工具:
| 名称 | 描述 | 参数 |
|---|---|---|
list_todos | 返回当前待办事项列表 | none |
add_todo_item | 插入新待办事项 | { title } |
toggle_todo_item | 翻转完成状态 | { todoId } |
delete_todo_item | 删除待办事项 | { todoId } |
- 所有工具响应包括:
- structuredContent.todoList (反映小部件数据契约) - _meta.openai/* 描述符,以便ChatGPT知道如何呈现小部件
- 服务器在内存中保存了一个简单的
globalTodoState.当你从演示毕业时,把它换成一个真正的数据库或API。
______________________________________________________________________
连接到ChatGPT应用程序
- 启用 开发者模式 在ChatGPT中→ 设置→ _连接器_.
- 创建新的“模型上下文协议”连接器。
- 将MCP URL指向您的服务器(本地隧道或部署的主机):
https://.ngrok-free.app/mcp- 在ChatGPT对话中,询问类似“显示我的待办事项列表”或“在我的待办事务中添加“审核PR”之类的问题。ChatGPT将调用相应的工具,小部件将使用
ui://服务器公开的资源。
______________________________________________________________________
项目结构
openai-apps-template/
├─ src/
│ ├─ widgets/
│ │ └─ todo/
│ │ ├─ index.tsx # Widget entry point (self-mounting)
│ │ └─ components/
│ │ ├─ NewTodo.tsx # Input row for creating todos
│ │ └─ TodoItem.tsx # Presentational list item
│ ├─ hooks/ # window.openai + MCP helpers
│ ├─ styles/main.css # Tailwind layer shared by widgets
│ └─ utils/ # UI utilities (media queries, etc.)
├─ build.ts # Inline widget bundler
├─ dev.ts # Vite preview loader (?entry=)
├─ server.ts # MCP SSE server + todo tools
├─ dist/ # Generated ui:// HTML widgets
├─ package.json
└─ README.md______________________________________________________________________
脚本和配置
| 命令 | 描述 |
|---|---|
npm run build | 将每个小部件捆绑到 dist/*.html |
npm start | 启动MCP服务器(默认为端口 8000) |
npm run start:all | 构建小部件,然后启动服务器 |
npm run dev | 用于小部件HMR预览的Vite开发服务器 |
环境变量:
PORT–覆盖MCP服务器端口(默认8000).
______________________________________________________________________
扩展模板
- 添加另一个小部件:drop
src/widgets/notes.tsx,确保其安装到__WIDGET_ROOT_ID__,跑npm run build,然后将其作为新的资源/工具公开server.ts. - 保存待办事项数据:替换
globalTodoState使用数据库调用或REST客户端。小部件需要的唯一合同是{ todoList: TodoList },在哪里TodoList只不过{ title: string; todos: TodoItem[] }. - 增强UI状态:使用
useWidgetState乐观的更新;它已经将状态镜像回ChatGPT,因此主机在代理轮之间保持同步。 - 添加更多工具:在中注册描述符
server.ts(ListToolsRequestSchema处理程序)并在内部实现行为CallToolRequest处理程序。
______________________________________________________________________
故障排除
- 小部件显示过时数据 –确保MCP响应包括新鲜
structuredContent.todoList和_meta.openai/outputTemplate。只有当主机发送新的结构化数据时,小部件才会重新同步。 - “未找到构建”错误 –运行
npm run build开始前npm start所以dist/todo.html存在。 - ChatGPT中没有小部件 –验证连接器是否允许渲染小部件(
openai/widgetAccessible: true)而且ui://widget/.html资源通过以下方式列出ListResources. - CORS或隧道问题 –服务器启用
Access-Control-Allow-Origin: *,但你的隧道必须同时向前GET /mcp和POST /mcp/messages.
______________________________________________________________________
运输愉快!如果添加新的小部件、存储适配器或部署方案,则会出现未解决的问题或PR。
