mcpField
O
OpenAI Apps MCP

OpenAI Apps MCP

github.com/ovachiever开发5644 次安装48 周前更新
代码仓库

关于 OpenAI Apps MCP

用于构建 OpenAI Apps 的开发技能,通过 Cloudflare Workers 上的无状态 MCP 服务扩展 ChatGPT。内容涵盖服务端、工具和组件模式,以及部署时常见问题。

主要功能

  1. 01无状态 MCP 服务模式
  2. 02Cloudflare Workers 配置
  3. 03使用 Zod 验证工具输入
  4. 04ChatGPT 组件资源
  5. 05部署与测试指南

适用场景

  1. 01构建集成 ChatGPT 的应用
  2. 02在 ChatGPT 中呈现交互式组件
  3. 03部署前测试 MCP 端点

MCP 相关

提供实现无状态 MCP 服务的模式,向 ChatGPT 暴露工具和组件资源,并涵盖配置与测试指导。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ovachiever/droid-tings --skill openai-apps-mcp

安装后在 Claude Code 中输入/openai-apps-mcp确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
.claude-plugin/
plugin.json
assets/
example-template.txt
references/
openai-metadata-format.md
example-reference.md
scripts/
example-script.sh
templates/basic/
wrangler.jsonc
vite.config.ts
package.json

详细介绍

使用无状态 MCP 服务构建 OpenAI Apps

状态:已可用于生产环境 最后更新:2025-11-17 依赖项:cloudflare-worker-base、hono-routing(可选,对路由模式很有帮助) 最新版本:@modelcontextprotocol/[email protected]、[email protected]、[email protected]


概览

本技能提供经过生产环境测试的模式,用于构建 OpenAI Apps——通过模型上下文协议(MCP)扩展 ChatGPT 功能的应用。重点介绍使用 Cloudflare Workers 构建的无状态 MCP 服务,适用于 80% 的 OpenAI Apps 使用场景。

什么是 OpenAI Apps?

OpenAI Apps 是集成到 ChatGPT 界面中的扩展,允许用户:

  • 直接在对话中访问第三方服务
  • 显示交互式小组件(地图、轮播图、列表等)
  • 执行可返回结构化 UI 组件的工具
  • 为 ChatGPT 增添特定领域的功能
架构
ChatGPT User
    ↓
ChatGPT (discovers and invokes tools)
    ↓
MCP Server (your Cloudflare Worker)
    ├── Tool handlers (business logic)
    ├── Widget resources (HTML/JS UI)
    └── OpenAI metadata (output templates)
核心组件
  1. MCP 服务 - 通过模型上下文协议公开工具的 HTTP 端点
  2. 工具处理程序 - 处理输入并返回结果的函数
  3. 小组件资源 - 在 ChatGPT iframe 中渲染的 HTML 页面
  4. OpenAI 元数据 - 用于小组件路由和显示的特殊注解

快速入门(10 分钟)

1. 搭建项目脚手架
npm create cloudflare@latest my-openai-app -- --type hello-world --ts --git --deploy false
cd my-openai-app

# Install dependencies
npm install @modelcontextprotocol/[email protected] [email protected] [email protected]
npm install -D @cloudflare/[email protected] [email protected]

为什么这很重要:

  • @modelcontextprotocol/sdk 是官方 MCP 协议实现
  • hono 提供轻量级路由,非常适合 API 端点
  • Vite + CloudFlare 插件支持构建和提供小组件
2. 配置 wrangler.jsonc
{
  "name": "my-openai-app",
  "main": "dist/index.js",
  "compatibility_date": "2025-10-08",
  "compatibility_flags": ["nodejs_compat"],
  "assets": {
    "directory": "dist/client",
    "binding": "ASSETS"
  },
  "observability": {
    "enabled": true
  }
}

重要:

  • MCP SDK 要求启用 nodejs_compat 标志
  • assets.binding: "ASSETS" 必须与 TypeScript 绑定名称一致
  • assets.directory 必须与 Vite 构建输出目录一致
3. 创建 MCP 服务
// src/index.ts
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';

type Bindings = {
  ASSETS: Fetcher;
};

const app = new Hono<{ Bindings: Bindings }>();

// CORS - must allow ChatGPT
app.use('/mcp/*', cors({
  origin: 'https://chatgpt.com',
  credentials: true,
  allowMethods: ['GET', 'POST', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization']
}));

// Create MCP server
const mcpServer = new Server(
  { name: 'my-openai-app', version: '1.0.0' },
  { capabilities: { tools: {}, resources: {} } }
);

// Register a simple tool
mcpServer.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: 'hello_world',
    description: 'Use this when the user wants to see a hello world message',
    inputSchema: {
      type: 'object',
      properties: {
        name: { type: 'string', description: 'Name to greet' }
      },
      required: ['name']
    },
    annotations: {
      openai: {
        outputTemplate: 'ui://widget/hello.html'
      }
    }
  }]
}));

mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === 'hello_world') {
    const { name } = request.params.arguments as { name: string };
    return {
      content: [{ type: 'text', text: `Hello, ${name}!` }],
      _meta: { initialData: { name } }
    };
  }
  throw new Error(`Unknown tool: ${request.params.name}`);
});

// MCP endpoint
app.post('/mcp', async (c) => {
  const body = await c.req.json();
  const response = await mcpServer.handleRequest(body);
  return c.json(response);
});

// Serve widgets
app.get('/widgets/*', async (c) => c.env.ASSETS.fetch(c.req.raw));

export default app;

5 步设置流程

步骤 1:搭建项目脚手架

使用 Cloudflare 官方脚手架:

npm create cloudflare@latest my-openai-app -- --type hello-world --ts --git --deploy false

要点:

  • 创建使用 TypeScript 的 Workers 项目
  • 包含 wrangler.jsonc
  • 初始化 git 仓库
步骤 2:安装依赖项
npm install @modelcontextprotocol/[email protected] [email protected] [email protected]
npm install -D @cloudflare/[email protected] [email protected]

各软件包的作用:

  • @modelcontextprotocol/sdk - 官方 MCP 协议(Anthropic)
  • hono - 快速、轻量的路由框架
  • zod - 对工具输入进行运行时类型验证
  • @cloudflare/vite-plugin - 用于 Workers 和静态资源的构建工具
  • vite - 前端构建工具
步骤 3:配置构建系统

创建 vite.config.ts:

import { defineConfig } from 'vite';
import { cloudflareDevProxyVitePlugin as cloudflare } from '@cloudflare/vite-plugin';

export default defineConfig({
  plugins: [
    cloudflare({
      configPath: 'wrangler.jsonc',
      persist: { path: '.wrangler/state' }
    })
  ],
  build: {
    outDir: 'dist',
    rollupOptions: {
      input: {
        worker: './src/index.ts'
      },
      output: {
        entryFileNames: (chunkInfo) => {
          if (chunkInfo.name === 'worker') return 'index.js';
          return 'client/[name]-[hash].js';
        }
      }
    }
  }
});

为什么这很重要:

  • 同时构建 Worker 代码和静态资源
  • 为 Workers 和 ASSETS 绑定生成正确的输出结构
  • 使用内容哈希实现缓存失效
步骤 4:创建小组件 HTML
mkdir -p src/widgets

创建 src/widgets/hello.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Hello Widget</title>
  <style>
    body {
      margin: 0;
      padding: 20px;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      background: var(--background);
      color: var(--foreground);
    }
    .greeting {
      font-size: 24px;
      font-weight: 600;
    }
  </style>
</head>
<body>
  <div class="greeting" id="greeting">Loading...</div>

  <script>
    // Access initial data from tool handler
    if (window.openai && window.openai.getInitialData) {
      const data = window.openai.getInitialData();
      document.getElementById('greeting').textContent = `Hello, ${data.name}! 👋`;
    }
  </script>
</body>
</html>

应避免的事项:

  • 不要使用第三方 CDN 脚本(CSP 可能会阻止)
  • 不要使用自定义字体(请使用系统字体)
  • 未配置 CORS 时不要调用外部 API
步骤 5:部署并测试
# Build
npm run build

# Deploy to Cloudflare
npx wrangler deploy

# Test with MCP Inspector
npx @modelcontextprotocol/inspector https://my-openai-app.workers.dev/mcp

关键规则

务必做到

✅ 将 CORS 设置为允许 https://chatgpt.com ✅ 小组件使用资源 URI 模式 ui://widget/ ✅ HTML 资源的 MIME 类型设置为 text/html+skybridge ✅ 在工具响应中包含 _meta.initialData 以初始化小组件 ✅ 使用以操作为导向的工具描述(“在……时使用此工具”) ✅ 使用 Zod 模式验证工具输入 ✅ 部署到 ChatGPT 之前,使用 MCP Inspector 进行测试

绝不要

❌ 使用自定义 MIME 类型(必须是 text/html+skybridge) ❌ 忘记配置 CORS(ChatGPT 将无法连接) ❌ 使用不带 ui://widget/ 前缀的资源 URI ❌ 将小组件打包进 Worker 代码(请使用 ASSETS 绑定) ❌ 跳过输入验证(工具接收的数据不可信) ❌ 使用 SSE 时不配置心跳(Workers 上会在 100s 后超时) ❌ 未先在 MCP Inspector 中测试就部署


已知问题预防

本技能可预防已记录的 8 个问题:

问题 #1:CORS 策略阻止 MCP 端点

错误:Access to fetch at 'https://my-app.workers.dev/mcp' from origin 'https://chatgpt.com' has been blocked by CORS policy

来源:未配置 CORS 时常见的浏览器控制台错误

原因:ChatGPT 会向你的 MCP 服务发起跨域请求。如果没有 CORS 标头,浏览器会阻止这些请求。

预防措施:

app.use('/mcp/*', cors({
  origin: 'https://chatgpt.com',  // Must allow ChatGPT specifically
  credentials: true,
  allowMethods: ['GET', 'POST', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization']
}));
问题 #2:小组件返回 404 Not Found

错误:小组件 URL 出现 Failed to load resource: the server responded with a status of 404 (Not Found)

来源:OpenAI Apps SDK 对 ui://widget/ 前缀的要求

原因:资源 URI 必须遵循特定格式。前缀错误会导致 ChatGPT 无法解析小组件。

预防措施:

// ✅ Correct
annotations: {
  openai: {
    outputTemplate: 'ui://widget/map.html'
  }
}

// ❌ Wrong - will 404
outputTemplate: 'resource://map.html'
outputTemplate: '/widgets/map.html'
问题 #3:小组件显示为纯文本

错误:显示的是 HTML 源代码,而非渲染后的小组件

来源:OpenAI Apps SDK 对 MIME 类型的要求

原因:ChatGPT 需要特定的 MIME 类型 text/html+skybridge 才能渲染小组件。标准的 text/html 无法正常工作。

预防措施:

server.setRequestHandler(ListResourcesRequestSchema, async () => ({
  resources: [{
    uri: 'ui://widget/map.html',
    mimeType: 'text/html+skybridge'  // Must use +skybridge
  }]
}));
问题 #4:ASSETS 绑定未定义

错误:访问 c.env.ASSETS 时出现 TypeError: Cannot read property 'fetch' of undefined

来源:wrangler.jsonc 或 TypeScript 类型配置错误

原因:wrangler.jsonc 中的 ASSETS 绑定名称必须与 TypeScript 绑定接口一致。

预防措施:

// wrangler.jsonc
{
  "assets": {
    "directory": "dist/client",
    "binding": "ASSETS"  // Must match TypeScript
  }
}
// src/index.ts
type Bindings = {
  ASSETS: Fetcher;  // Must match wrangler.jsonc binding name
};
问题 #5:SSE 连接在 100 秒后断开

错误:SSE 流意外关闭,工具停止响应

来源:Cloudflare Workers 在没有数据发送时的 SSE 超时

原因:Workers 会在 100 秒无活动后关闭 SSE 连接。必须发送心跳事件。

预防措施:

import { streamSSE } from 'hono/streaming';

app.get('/mcp/stream', (c) => {
  return streamSSE(c, async (stream) => {
    // Send heartbeat every 30 seconds
    const heartbeat = setInterval(async () => {
      await stream.writeSSE({
        data: JSON.stringify({ type: 'heartbeat' }),
        event: 'ping'
      });
    }, 30000);

    // Clean up on close
    stream.onAbort(() => clearInterval(heartbeat));
  });
});
问题 #6:ChatGPT 不会推荐工具

错误:工具已注册,但从未出现在 ChatGPT 的推荐中

来源:OpenAI 工具发现机制要求描述以操作为导向

原因:泛泛的描述无法匹配用户意图模式。ChatGPT 会根据描述判断何时调用工具。

预防措施:

// ✅ Good - action-oriented
description: 'Use this when the user wants to see a location on a map'

// ❌ Bad - generic
description: 'Shows a map'

// ✅ Good - specific use case
description: 'Use this when the user asks about weather in a specific city'

// ❌ Bad - vague
description: 'Gets weather data'
问题 #7:小组件无法访问初始数据

错误:小组件中的 window.openai.getInitialData() 返回 undefined

来源:工具响应中缺少 _meta.initialData

原因:必须通过 _meta 字段显式传递数据。常规响应内容不会传递给小组件。

预防措施:

// Tool handler
return {
  content: [{
    type: 'text',
    text: 'Here is your map'
  }],
  _meta: {
    initialData: {  // This object reaches window.openai.getInitialData()
      location: 'San Francisco',
      zoom: 12
    }
  }
};
问题 #8:CSP 阻止小组件脚本

错误:Refused to load the script because it violates the following Content Security Policy directive

来源:ChatGPT 针对小组件 iframe 的内容安全策略

原因:出于安全考虑,第三方 CDN 的外部脚本会被阻止。

预防措施:


<script>
  console.log('Widget loaded');
</script>


<script src="/widgets/lib.js"></script>


<script src="https://cdn.example.com/library.js"></script>



配置文件参考

wrangler.jsonc(完整示例)
{
  "name": "my-openai-app",
  "main": "dist/index.js",
  "compatibility_date": "2025-10-08",
  "compatibility_flags": ["nodejs_compat"],
  "assets": {
    "directory": "dist/client",
    "binding": "ASSETS"
  },
  "observability": {
    "enabled": true
  },
  "vars": {
    "ENVIRONMENT": "production"
  }
}

这些设置的作用:

  • nodejs_compat - MCP SDK 所需(使用 Node.js API)
  • assets.directory - Vite 输出小组件 HTML 文件的位置
  • assets.binding: "ASSETS" - 在代码中访问静态资源的方式
  • observability - 启用日志记录和跟踪以便调试
vite.config.ts(完整示例)
import { defineConfig } from 'vite';
import { cloudflareDevProxyVitePlugin as cloudflare } from '@cloudflare/vite-plugin';

export default defineConfig({
  plugins: [
    cloudflare({
      configPath: 'wrangler.jsonc',
      persist: { path: '.wrangler/state' }
    })
  ],
  build: {
    outDir: 'dist',
    rollupOptions: {
      input: {
        worker: './src/index.ts',
        // Widget entry points
        hello: './src/widgets/hello.html',
        map: './src/widgets/map.html'
      },
      output: {
        entryFileNames: (chunkInfo) => {
          if (chunkInfo.name === 'worker') return 'index.js';
          return 'client/[name]-[hash].js';
        },
        assetFileNames: 'client/[name]-[hash][extname]'
      }
    }
  }
});

这些设置的作用:

  • 多个输入入口(worker 和小组件)
  • 为 worker(index.js)和客户端资源(client/)分别设置输出
  • 使用内容哈希防止缓存问题([hash])

常见模式

模式 1:纯文本工具

返回文本而不包含小组件的工具:

mcpServer.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: 'get_weather',
    description: 'Use this when the user asks about current weather in a city',
    inputSchema: {
      type: 'object',
      properties: {
        city: { type: 'string', description: 'City name' }
      },
      required: ['city']
    }
    // No annotations - returns plain text
  }]
}));

mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === 'get_weather') {
    const { city } = request.params.arguments as { city: string };

    // In production, call weather API
    const weather = await fetchWeather(city);

    return {
      content: [{
        type: 'text',
        text: `Weather in ${city}: ${weather.description}, ${weather.temp}°F`
      }]
    };
  }
});

适用场景:不需要可视化呈现的简单数据检索

模式 2:列表小组件

显示项目列表的工具:

// Tool registration
{
  name: 'search_products',
  description: 'Use this when the user wants to search for products',
  inputSchema: {
    type: 'object',
    properties: {
      query: { type: 'string' }
    }
  },
  annotations: {
    openai: {
      outputTemplate: 'ui://widget/product-list.html'
    }
  }
}

// Tool handler
const products = await searchProducts(query);
return {
  content: [{
    type: 'text',
    text: `Found ${products.length} products`
  }],
  _meta: {
    initialData: {
      products: products.map(p => ({
        id: p.id,
        name: p.name,
        price: p.price,
        image: p.image
      }))
    }
  }
};

<div id="products"></div>
<script>
const data = window.openai.getInitialData();
const container = document.getElementById('products');

data.products.forEach(product => {
  const item = document.createElement('div');
  item.className = 'product-item';
  item.innerHTML = `
    <img src="${product.image}" alt="${product.name}">
    <h3>${product.name}</h3>
    <p>$${product.price}</p>
  `;
  container.appendChild(item);
});
</script>

适用场景:显示项目集合(搜索结果、推荐内容等)

模式 3:带工具回调的交互式小组件

可以触发其他工具的小组件:

// Register multiple related tools
{
  name: 'show_tasks',
  description: 'Use this when user wants to see their task list',
  annotations: {
    openai: {
      outputTemplate: 'ui://widget/tasks.html'
    }
  }
},
{
  name: 'complete_task',
  description: 'Mark a task as completed',
  inputSchema: {
    type: 'object',
    properties: {
      taskId: { type: 'number' }
    }
  }
}

<div id="tasks"></div>
<script>
const data = window.openai.getInitialData();

data.tasks.forEach(task => {
  const taskEl = document.createElement('div');
  taskEl.innerHTML = `
    <span>${task.title}</span>
    <button onclick="completeTask(${task.id})">Complete</button>
  `;
  document.getElementById('tasks').appendChild(taskEl);
});

function completeTask(taskId) {
  if (window.openai && window.openai.callTool) {
    window.openai.callTool({
      name: 'complete_task',
      arguments: { taskId }
    });
  }
}
</script>

适用场景:需要触发后续操作的交互式小组件


使用捆绑资源

脚本(scripts/)

运行 ./scripts/scaffold-openai-app.sh 以生成完整的入门项目:

chmod +x ./scripts/scaffold-openai-app.sh
./scripts/scaffold-openai-app.sh my-new-app

cd my-new-app
npm install
npm run dev
参考资料(references/)
  • references/mcp-protocol-basics.md - MCP SDK 使用模式
  • references/openai-metadata-format.md - 所有 OpenAI 专用注解字段
  • references/widget-patterns.md - Widget HTML 示例和最佳实践
  • references/optional-agents-upgrade.md - 何时以及如何添加有状态功能

Claude 应在以下情况下加载这些资料:需要查阅详细的 API 参考或了解本 SKILL.md 之外的高级模式时

模板(templates/)
  • templates/basic/ - 最小化的无状态 MCP 服务
  • templates/with-react/ - 基于 React 的 Widget,使用 Vite 构建

用法:复制整个模板目录,作为新项目的起点


高级主题

使用 Zod 进行输入验证
import { z } from 'zod';

const CreateTaskInputSchema = z.object({
  title: z.string().min(1).max(200),
  dueDate: z.string().datetime().optional(),
  priority: z.enum(['low', 'medium', 'high']).default('medium')
});

// Convert Zod schema to JSON Schema for MCP
const jsonSchema = zodToJsonSchema(CreateTaskInputSchema);

// Use in tool registration
{
  name: 'create_task',
  inputSchema: jsonSchema,
  // ...
}

// Validate in handler
mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === 'create_task') {
    try {
      const validated = CreateTaskInputSchema.parse(request.params.arguments);
      // validated is typed and validated
    } catch (error) {
      if (error instanceof z.ZodError) {
        return {
          content: [{
            type: 'text',
            text: `Invalid input: ${error.errors.map(e => e.message).join(', ')}`
          }],
          isError: true
        };
      }
    }
  }
});
环境变量和密钥
# Set secrets via Wrangler
wrangler secret put API_KEY

# Access in code
type Bindings = {
  ASSETS: Fetcher;
  API_KEY: string;  // Secret binding
};

// In handler
const apiKey = c.env.API_KEY;
使用 Vite 构建 React Widget
// vite.config.ts - add React plugin
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react(),
    cloudflare({ /* ... */ })
  ],
  // ...
});
// src/widgets/TaskList.tsx
import { useState, useEffect } from 'react';

export function TaskList() {
  const [tasks, setTasks] = useState([]);

  useEffect(() => {
    if (window.openai) {
      const data = window.openai.getInitialData();
      setTasks(data.tasks);
    }
  }, []);

  return (
    <div>
      {tasks.map(task => (
        <div key={task.id}>{task.title}</div>
      ))}
    </div>
  );
}

依赖项

必需:

可选:


官方文档


软件包版本(已于 2025-11-17 验证)

{
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.21.0",
    "hono": "^4.10.2",
    "zod": "^3.25.76"
  },
  "devDependencies": {
    "@cloudflare/vite-plugin": "^1.13.13",
    "@cloudflare/workers-types": "^4.20250531.0",
    "@vitejs/plugin-react": "^4.3.4",
    "vite": "^7.1.9",
    "wrangler": "^4.42.2"
  }
}

生产环境示例

此技能基于以下模式:


故障排除

问题:MCP Inspector 显示“Connection refused”

解决方案:确保开发服务正在正确的端口上运行,并且已配置 /mcp 端点:

npm run dev  # Should show port (usually 8787)
npx @modelcontextprotocol/inspector http://localhost:8787/mcp
问题:Widget 在 ChatGPT 中显示空白页面

解决方案:检查浏览器控制台中的错误。常见原因:

  1. CSP 阻止外部脚本——使用 Vite 将其打包
  2. 缺少 window.openai 检查——Widget 在 API 就绪前加载
  3. 缺少 CORS 标头——将其添加到 /mcp/* 路由
问题:工具已注册,但从未被调用

解决方案:改进工具描述,使其更具行动导向:

// ✅ Good
description: 'Use this when the user wants to see weather forecast for a specific city'

// ❌ Bad
description: 'Weather tool'

完整设置清单

  • 使用 npm create cloudflare 搭建项目脚手架
  • 安装依赖(@modelcontextprotocol/sdk、hono、zod)
  • 配置 wrangler.jsonc 中的 ASSETS 绑定
  • 使用 CloudFlare 插件配置 vite.config.ts
  • 为 /mcp/* 路由添加 CORS 中间件
  • 至少向 MCP 服务注册一个工具
  • 为工具编写面向操作的描述
  • 在 src/widgets/ 中创建 Widget HTML
  • 使用 ui://widget/ URI 模式注册资源
  • 将 MIME 类型设置为 text/html+skybridge
  • 工具处理程序为 Widget 返回 _meta.initialData
  • 开发服务器运行正常,无错误(npm run dev)
  • MCP Inspector 成功连接
  • 生产构建成功(npm run build)
  • 部署到 Cloudflare Workers(npx wrangler deploy)
  • 在 ChatGPT 开发者模式下完成测试

有问题?遇到故障?

  1. 查看 references/openai-metadata-format.md,了解所有注释字段
  2. 检查设置流程中的所有步骤
  3. 查看 MCP 官方文档:https://modelcontextprotocol.io/
  4. 确保 CORS 配置允许 https://chatgpt.com
  5. 在尝试使用 ChatGPT 前,先使用 MCP Inspector 测试

评论

支持 Markdown