ChatGPT应用SDK演示

一个展示如何使用OpenAI Apps SDK和MCP(模型上下文协议)构建在ChatGPT对话中直接渲染交互式小部件的概念验证项目。

  • by jezweb
  • TypeScript
  • 本地部署
  • 7 星标
  • 更新于
在 GitHub 查看 jezweb/chatgpt-app-sdk

使用说明

JezwebPortfolio-ChatGPT应用程序SDK演示

概念验证ChatGPT应用程序,演示了带有MCP(模型上下文协议)的OpenAI Apps SDK

这个项目展示了如何构建直接在ChatGPT对话中呈现的交互式小部件。作为学习练习,在构建更复杂的应用程序之前了解Apps SDK架构。

这表明了什么

  • MCP服务器:ChatGPT的JSON-RPC 2.0协议实现
  • 交互式小部件:在ChatGPT的iframe沙箱中呈现的React组件
  • 真实数据集成:用于投资组合项目的WordPress REST API
  • 潜在客户捕获:Cloudflare D1数据库存储的联系表单
  • 边缘优先:Cloudflare Workers为小部件资产提供全球CDN

架构概述

┌─────────────────────────────────────────────────────────────────┐
│                         ChatGPT                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  User: "Show me Jezweb's portfolio"                     │    │
│  │                                                          │    │
│  │  ChatGPT calls → show_portfolio tool                    │    │
│  │                                                          │    │
│  │  ┌─────────────────────────────────────────────────┐    │    │
│  │  │          Portfolio Widget (iframe)               │    │    │
│  │  │  ┌─────┐ ┌─────┐ ┌─────┐                        │    │    │
│  │  │  │Card │ │Card │ │Card │  ← React Carousel      │    │    │
│  │  │  └─────┘ └─────┘ └─────┘                        │    │    │
│  │  │       [◀]           [▶]                         │    │    │
│  │  └─────────────────────────────────────────────────┘    │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│              Cloudflare Workers (Edge)                           │
│  ┌──────────────────┐  ┌──────────────────┐                     │
│  │   /mcp endpoint  │  │  /api/contact    │                     │
│  │   (JSON-RPC 2.0) │  │  (Direct API)    │                     │
│  └────────┬─────────┘  └────────┬─────────┘                     │
│           │                     │                                │
│  ┌────────▼─────────────────────▼─────────┐                     │
│  │              Hono Server               │                     │
│  │  • tools/list, tools/call              │                     │
│  │  • resources/list, resources/read      │                     │
│  └────────┬─────────────────────┬─────────┘                     │
│           │                     │                                │
│  ┌────────▼─────────┐  ┌────────▼─────────┐                     │
│  │  WordPress API   │  │   D1 Database    │                     │
│  │  (Portfolio)     │  │   (Leads)        │                     │
│  └──────────────────┘  └──────────────────┘                     │
└─────────────────────────────────────────────────────────────────┘

主要学习内容

1.MCP协议基础

模型上下文协议使用JSON-RPC 2.0。关键方法:

方法 目的
initialize 与协议版本握手
tools/list 用模式宣传可用的工具
tools/call 使用参数执行工具
resources/list 列出可用的小部件资源
resources/read 返回小部件HTML内容

2.小部件集成(至关重要!)

小部件由HTML提供 mimeType: "text/html+skybridge"ChatGPT

  1. 调用您的工具
  2. 从以下位置读取小部件资源 openai/outputTemplate 统一资源标识符
  3. 在iframe沙箱中呈现HTML
  4. 通过以下方式注入数据 window.openai.toolOutput

重要元数据字段:

_meta: {
  "openai/outputTemplate": "ui://widget/portfolio.html",  // Widget URI
  "openai/widgetDescription": "Description for ChatGPT",  // Reduces narration
  "openai/widgetAccessible": true,                        // Widget can call tools
  "openai/resultCanProduceWidget": true,                  // Tool produces widget
  "openai/toolInvocation/invoking": "Loading...",         // Loading text
  "openai/toolInvocation/invoked": "Ready",               // Complete text
}

3.小部件数据访问

ChatGPT通过 structuredContent 作为 window.openai.toolOutput:

// In your widget React component:
useEffect(() => {
  // Direct path (ChatGPT flattens structuredContent)
  const projects = window.openai?.toolOutput?.projects;

  // Listen for updates
  window.addEventListener('openai:set_globals', (event) => {
    const data = event.detail?.globals?.toolOutput;
  });
}, []);

4.布局控制

ChatGPT通过以下方式提供布局约束 window.openai:

// Read constraints
const maxHeight = window.openai?.maxHeight;
const displayMode = window.openai?.displayMode; // 'inline' | 'pip' | 'fullscreen'

// Request more space
await window.openai?.requestDisplayMode({ mode: 'fullscreen' });

5.从小部件调用工具

这太棘手了! window.openai.callTool() 仅适用于生成小部件的工具。对于仅数据操作(如我们的联系人表单),请改用直接API端点:

// DON'T rely on this for non-widget tools:
// await window.openai.callTool('contact_about_project', data);

// DO use direct API:
await fetch('https://your-worker.workers.dev/api/contact', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(data),
});

6.CORS配置

Widget沙盒有着不同寻常的起源。对小部件可访问的端点使用许可CORS:

app.use('/api/*', cors({
  origin: '*',  // Widget sandbox can have null/blob origins
  allowMethods: ['GET', 'POST', 'OPTIONS'],
  allowHeaders: ['Content-Type'],
}));

7.小部件资产服务

从与MCP服务器相同的源提供CSS/JS,以避免CSP问题:

<!-- Widget HTML returned by resources/read -->
<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://your-worker.workers.dev/widgets/styles.css">
</head>
<body>
  <div id="root"></div>
  <script src="https://your-worker.workers.dev/widgets/portfolio.js"></script>
</body>
</html>

技术栈

层 技术
运行时 Cloudflare Workers+静态资产
前端 React 19+Vite 7+顺风v4
UI组件 shadcn/UI+根UI
后端 Hono 4
数据库 Cloudflare D1+Drizzle ORM
验证 Zod
数据源 WordPress REST API

项目结构

chatgpt-app-sdk/
├── src/
│   ├── client/              # React frontend (dev UI)
│   │   ├── components/ui/   # shadcn/ui components
│   │   └── types/           # TypeScript types
│   ├── server/              # Hono backend
│   │   ├── routes/mcp.ts    # MCP endpoint handler
│   │   ├── tools/           # Tool implementations
│   │   │   ├── portfolio.ts # show_portfolio tool
│   │   │   └── contact.ts   # contact_about_project tool
│   │   └── index.ts         # Server entry
│   ├── lib/
│   │   ├── mcp/             # MCP protocol (types, server)
│   │   ├── db/              # Drizzle schema
│   │   └── wordpress/       # WordPress API client
│   └── widgets/             # Widget entry points
│       └── PortfolioWidget.tsx
├── docs/                    # Architecture docs
├── wrangler.jsonc           # Cloudflare config
├── vite.config.ts           # Main Vite config
└── vite.widget.config.ts    # Widget bundle config

发展

先决条件

  • Node.js 18+和pnpm
  • Cloudflare帐户
  • 牧马人CLI

设置

# Clone and install
git clone https://github.com/jezweb/chatgpt-app-sdk.git
cd chatgpt-app-sdk
pnpm install

# Create D1 database
npx wrangler d1 create chatgpt-portfolio-db

# Update wrangler.jsonc with database ID

# Run migrations
pnpm db:generate
npx wrangler d1 execute chatgpt-portfolio-db --local --file=drizzle/0000_*.sql

# Start dev server
pnpm dev

构建和部署

# Build for production (includes widget bundle)
CLOUDFLARE_ENV=production pnpm build

# Deploy to Cloudflare
npx wrangler deploy

测试MCP端点

# List tools
curl -X POST https://your-worker.workers.dev/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

# Call show_portfolio
curl -X POST https://your-worker.workers.dev/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"show_portfolio","arguments":{}}}'

Gotchas&解决方案

1.小部件未渲染

问题:小部件在ChatGPT中显示空白或错误。 解决方案:检查 mimeType: "text/html+skybridge" 在资源/读取响应中。

2.数据未加载

问题: window.openai.toolOutput 未定义。 解决方案:使用事件侦听器 openai:set_globals 因为数据可能会在小部件之后加载。

3.联系表400错误

问题: window.openai.callTool() 非小部件工具返回400。 解决方案:使用直接API端点,而不是MCP调用工具。

4.外键错误

问题:由于FK约束,数据库插入失败。 解决方案:如果使用外部ID(例如WordPress帖子ID),请删除FK引用。

5.CSP冻结资产

问题:CSS/JS被内容安全策略阻止。 解决方案:为与MCP服务器来自同一来源的资产提供服务。

6.ChatGPT过度叙述

问题:ChatGPT在小部件下方添加冗余文本。 解决方案:添加 openai/widgetDescription 元数据和简化工具响应文本。

开发时间表

阶段 描述 状态
1 项目设置(Vite+Cloudflare) ✅
2 数据库设置(D1+细雨) ✅
3 MCP服务器(JSON-RPC 2.0) ✅
4 投资组合小部件(React旋转木马) ✅
5 小部件MCP集成 ✅
6 联系表格 ✅
7 造型和波兰语 ✅
8 内容哈希 ⏸️
9 生产部署 ✅
10 文件 ✅

资源

未来想法

这个POC为许多可能性打开了大门:

  • 带购物车的电子商务产品浏览器
  • 实时仪表板小部件
  • 具有多步流程的交互式表单
  • 地图/基于位置的界面
  • 带注释的文档查看器
  • 日程安排/预订小部件

许可证

MIT许可证-将其用作您自己的ChatGPT应用程序的模板!

作者

杰里米·道斯 (耶稣)

  • 网站:https://www.jezweb.com.au
  • 电子邮件:jeremy@jezweb.net
  • github: @jweb

内置于 克劳德代码 AI助手