使用说明
使用OAuth2+MCP+Privy的ChatGPT应用程序
使用OpenAI Apps SDK(MCP)的完整ChatGPT应用程序实现,通过Privy.io进行OAuth2身份验证。
🏗️ 建筑
- 后端:Express+MCP服务器(Types/Bun)
- OAuth用户界面:React+Privy+React路由器
- 小部件:React组件(在ChatGPT中呈现)
- 认证:OAuth2与PKCE+Privy.io
- 包管理器:Bun
📁 项目结构
mcp2/
├── src/
│ ├── server/ # Express + MCP server
│ │ ├── oauth/ # OAuth2 endpoints
│ │ ├── mcp/ # MCP tools & resources
│ │ ├── api/ # Backend API integration
│ │ └── middleware/ # Auth middleware
│ ├── client/ # OAuth authorization UI
│ └── widgets/ # ChatGPT widget components
├── dist/
│ ├── client/ # Built OAuth UI
│ ├── widgets/ # Built widget bundles
│ └── server/ # Compiled server
└── package.json
🚀 快速开始
先决条件
1.安装Bun
curl -fsSL https://bun.sh/install | bash
2.安装依赖项
bun install
3.生成JWT密钥
# Generate RSA key pair for JWT signing
openssl genrsa -out private-key.pem 2048
openssl rsa -in private-key.pem -pubout -out public-key.pem
# Base64 encode for .env
echo "JWT_PRIVATE_KEY=$(cat private-key.pem | base64)"
echo "JWT_PUBLIC_KEY=$(cat public-key.pem | base64)"
# Clean up PEM files
rm private-key.pem public-key.pem
4.配置环境
cp .env.example .env
# Edit .env with your values:
# - PRIVY_APP_ID (from Privy dashboard)
# - PRIVY_APP_SECRET (from Privy dashboard)
# - JWT_PRIVATE_KEY (from step 3)
# - JWT_PUBLIC_KEY (from step 3)
# - BACKEND_API_URL (your existing backend)
5.构建和运行
重要:必须在启动服务器之前构建小部件!
# First time: Build widgets (required!)
bun run build:widgets
# Then start development server
bun run dev
服务器将在以下时间启动 http://localhost:3002
🔧 发展
了解小部件构建过程
⚠️ 关键点: bun run dev 做 非 自动构建小部件。你必须分别构建它们!
有三种开发工作流程:
选项1:手动构建(建议用于首次设置)
# 1. Build widgets once
bun run build:widgets
# 2. Start server with auto-reload
bun run dev
# 3. Rebuild widgets manually when you change widget code
bun run build:widgets
选项2:监视模式(建议用于活动小部件开发)
# Terminal 1: Build widgets in watch mode (auto-rebuilds on changes)
bun run dev:widgets
# Terminal 2: Run server with auto-reload
bun run dev
选项3:运行一切(最方便)
# Runs both server AND widget watch mode simultaneously
bun run dev:all
其他开发命令
# Type check
bun run type-check
# Run tests
bun run test
# Build everything for production
bun run build
项目配置
服务器: src/server/index.ts
- OAuth端点:
/authorize,/token,/.well-known/* - MCP端点:
/mcp - 健康检查:
/health
OAuth用户界面: src/client/src/App.tsx
- 使用Privy登录的授权页面
- 同意屏幕
- 采用Vite+React+React路由器构建
小部件: src/widgets/src/
- ListView:带有操作的交互式列表
- 作为独立捆绑包构建
- 通过以下方式进行沟通
window.openaiAPI
🧪 测试
使用MCP检查员进行测试
# Terminal 1: Run server
bun run dev
# Terminal 2: Run MCP Inspector
bunx @modelcontextprotocol/inspector http://localhost:3002/mcp
使用ngrok进行测试
# Expose local server
ngrok http 3002
# Copy the HTTPS URL (e.g., https://abc123.ngrok.app)
# Use this URL in ChatGPT Settings → Connectors
连接到ChatGPT
-
启用开发人员模式:
- ChatGPT设置→ 应用程序和连接器→ 高级设置
- 启用“开发人员模式”
-
创建连接器:
- 设置→ 连接器→ 创建
- 名称:“您的应用程序名称”
- 描述:“你的应用程序做什么”
- 连接器URL:
https://your-server.com/mcp(或ngrok URL)
-
测试OAuth流:
- 开始新的ChatGPT对话
- 点击+→ More → 选择您的连接器
- 您将被重定向到
/authorize - 使用Privy登录
- 授予同意
- ChatGPT接收OAuth令牌
-
测试工具:
- 询问ChatGPT:“显示我的项目”
- 这
get-items工具将被调用 - 小部件将在ChatGPT中呈现
📦 生产建设
# Build everything
bun run build
# Run production server
bun run start
# Or preview locally
bun run preview
Docker部署
# Build image
docker build -t chatgpt-app .
# Run container
docker run -p 3000:3000 --env-file .env chatgpt-app
部署到Fly.io
# Install flyctl
curl -L https://fly.io/install.sh | sh
# Create app
fly launch
# Set secrets
fly secrets set PRIVY_APP_ID=xxx
fly secrets set PRIVY_APP_SECRET=xxx
fly secrets set JWT_PRIVATE_KEY=xxx
fly secrets set JWT_PUBLIC_KEY=xxx
fly secrets set BACKEND_API_URL=xxx
# Deploy
fly deploy
🔐 OAuth2流
- ChatGPT 将用户重定向到
/authorize?client_id=...&code_challenge=... - 服务器 提供React UI(隐私登录)
- 用户 通过Privy进行身份验证
- 前端 显示同意屏幕
- 用户 批准,服务器生成授权码
- 前端 使用代码重定向回ChatGPT
- ChatGPT 访问令牌的交换代码
/token - 服务器 验证PKCE,发出JWT
- ChatGPT 使用JWT
/mcp请求:
🎨 添加新工具
1.在中定义工具 src/server/mcp/tools.ts
{
name: 'my-new-tool',
description: 'What the tool does',
inputSchema: {
type: 'object',
properties: {
param: { type: 'string' }
},
required: ['param']
}
}
2.实现处理程序
async function handleMyNewTool(args: any, auth: any) {
// Validate auth
// Call backend API
// Return structured response
}
3.小部件链接(可选)
_meta: {
'openai/outputTemplate': 'ui://widget/my-widget.html',
}
🎨 添加新小部件
1.创建小部件组件
mkdir -p src/widgets/src/MyWidget
2.构建小部件
// src/widgets/src/MyWidget/index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { MyWidget } from './MyWidget';
const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(<MyWidget />);
3.配置Vite
// Update src/widgets/vite.config.ts
build: {
lib: {
entry: {
'my-widget': 'src/MyWidget/index.tsx'
}
}
}
4.注册资源
// src/server/mcp/resources.ts
await registerMyWidget(server, widgetPath);
📚 环境变量
| 变量 | 描述 | 必填 |
|---|---|---|
PRIVY_APP_ID |
您的Privy应用程序ID | ✅ |
PRIVY_APP_SECRET |
您的Privy应用程序机密 | ✅ |
VITE_PRIVY_APP_ID |
Privy应用程序ID(用于前端) | ✅ |
JWT_PRIVATE_KEY |
Base64编码RSA私钥 | ✅ |
JWT_PUBLIC_KEY |
Base64编码RSA公钥 | ✅ |
SERVER_BASE_URL |
您的服务器URL | ✅ |
BACKEND_API_URL |
您现有的后端URL | ✅ |
PORT |
服务器端口(默认值:3000) | ❌ |
NODE_ENV |
环境(开发/生产) | ❌ |
🐛 故障排除
小部件未加载
# Build widgets first
bun run build:widgets
# Restart server
bun run dev
OAuth流失败
- 检查
SERVER_BASE_URL匹配您的实际URL - 验证Privy应用程序ID是否正确
- 检查JWT密钥是否正确进行base64编码
- 确保重定向URI已在ChatGPT中注册
令牌验证失败
- 验证JWT密钥是否正确(公共/私有对)
- 检查令牌尚未过期(默认1小时)
- 确保
aud索赔与您的服务器URL匹配
MCP检查器无法连接
# Ensure server is running
bun run dev
# Try:
bunx @modelcontextprotocol/inspector http://localhost:3002/mcp
📖 资源
📝 许可证
麻省理工学院
🤝 贡献
欢迎投稿!请打开问题或PR。
