ChatGPT应用开发工具

一个基于OpenAI Apps SDK (MCP)的完整ChatGPT应用实现,支持通过Privy.io进行OAuth2认证。

  • by Jahnik
  • TypeScript
  • 本地部署
  • 更新于

使用说明

使用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

🚀 快速开始

先决条件

  • 包子 安装
  • 隐私.io 已创建帐户和应用程序
  • OpenSSL(用于生成JWT密钥)

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.openai API

🧪 测试

使用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

  1. 启用开发人员模式:

    • ChatGPT设置→ 应用程序和连接器→ 高级设置
    • 启用“开发人员模式”
  2. 创建连接器:

    • 设置→ 连接器→ 创建
    • 名称:“您的应用程序名称”
    • 描述:“你的应用程序做什么”
    • 连接器URL: https://your-server.com/mcp (或ngrok URL)
  3. 测试OAuth流:

    • 开始新的ChatGPT对话
    • 点击+→ More → 选择您的连接器
    • 您将被重定向到 /authorize
    • 使用Privy登录
    • 授予同意
    • ChatGPT接收OAuth令牌
  4. 测试工具:

    • 询问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流

  1. ChatGPT 将用户重定向到 /authorize?client_id=...&code_challenge=...
  2. 服务器 提供React UI(隐私登录)
  3. 用户 通过Privy进行身份验证
  4. 前端 显示同意屏幕
  5. 用户 批准,服务器生成授权码
  6. 前端 使用代码重定向回ChatGPT
  7. ChatGPT 访问令牌的交换代码 /token
  8. 服务器 验证PKCE,发出JWT
  9. 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。