🚀 Remix 3 MCP 演示项目
本项目展示了如何构建交互式的 MCP(模型上下文协议)小部件,这些小部件可在 Cloudflare Workers 上运行,并能嵌入到像 ChatGPT 这样的 AI 聊天界面中。它展示了将 MCP 与现代 Web 技术相结合的强大能力,能在 AI 对话中创造丰富、有状态的交互体验。
🎥 演示视频
观看计算器小部件在 ChatGPT 中的实际运行效果,其中还包含隐藏的《创:战纪》彩蛋:
https://github.com/user-attachments/assets/5df110d8-f40b-4c6a-8820-c2dbf3ff79c8
在 X/Twitter 上观看演示
🔍 演示原理
架构概述
本演示实现了一个计算器小部件,作为可由 AI 助手调用的 MCP 工具。该架构包含以下几个关键组件:
- MCP 服务器:一个实现了模型上下文协议的 Cloudflare 持久对象。
- 小部件系统:使用 Remix 3 构建的交互式 UI 组件,可嵌入到 AI 聊天中。
- 双向通信:小部件既能从 AI 接收初始状态,也能向 AI 发送消息。
- 静态资源:从 Cloudflare 的 CDN 提供的小部件捆绑包。
计算器小部件
这是一个功能完备、设计精美的计算器,其复古未来主义的美学风格灵感源自《创:战纪》。以下是它的独特之处:
初始状态配置
当 AI 助手调用计算器工具时,它可以传递初始状态参数:
display:初始显示值
previousValue:已输入的值(例如,“我想给一个数加 5”)
operation:待执行的操作(+、-、*、/)
waitingForNewValue:计算器是否准备好接收新输入
errorState:是否以错误状态启动
这意味着 AI 可以根据用户的请求预先配置计算器。例如,如果用户说“我想给某个数加 5”,AI 可以使用 previousValue: 5、operation: '+' 和 waitingForNewValue: true 来调用计算器。
交互式 UI
计算器小部件是一个完全交互式的 Remix 应用程序,具备以下特点:
- 使用 JSX/TSX 和 CSS-in-JS 样式进行渲染。
- 支持键盘快捷键(Enter、Escape、数字键、运算符等)。
- 具有《创:战纪》风格的初始化序列和动画加载消息。
- 用户交互时实时更新。
- 使用 Remix 3 的实验性 DOM 渲染器进行高效更新。
彩蛋:主控程序
计算器中有一个隐藏功能:当计算结果等于 1982(即原版《创:战纪》电影上映的年份)时,计算器会向 AI 助手发送一条 MCP 提示消息,指示它采用《创:战纪》中的主控程序(MCP)角色。
这展示了小部件通过向 AI 发送消息动态影响对话的能力。
技术实现
使用持久对象的 MCP 服务器
MathMCP 类继承自 McpAgent,并使用 Cloudflare 的持久对象来维护状态:
export class MathMCP extends McpAgent<Env, State, Props> {
server = new McpServer(
{
name: 'MathMCP',
version: '1.0.0',
},
{
instructions: `Use this server to solve math problems reliably and accurately.`,
},
)
async init() {
await registerTools(this)
await registerWidgets(this)
}
}
服务器注册了两种类型的功能:
- 工具:一个在服务器端执行算术运算的
do_math 工具。
- 小部件:可嵌入聊天中的交互式 UI 资源。
小部件注册
小部件既作为 MCP 资源(用于 HTML/JS 捆绑包)又作为 MCP 工具(用于调用)进行注册。注册内容包括:
- 输入模式:Zod 模式,定义小部件接受的参数。
- 输出模式:Zod 模式,定义小部件可以返回的内容。
- HTML 捆绑包:包含脚本引用的渲染后的 HTML。
- OpenAI 元数据:特殊元数据,告知 ChatGPT 如何显示小部件。
agent.server.registerResource(name, uri, {}, async () => ({
contents: [
createUIResource({
content: {
type: 'rawHtml',
htmlString: await widget.getHtml(),
},
metadata: {
'openai/widgetDescription': widget.description,
'openai/widgetCSP': {
connect_domains: [],
resource_domains: [baseUrl],
},
},
}).resource,
],
}))
独立构建过程
该项目使用两个独立的构建过程:
- 小部件构建(Vite):将计算器 UI 构建为独立的 JavaScript 捆绑包。
- 输入:
worker/widgets/calculator/index.tsx
- 输出:
dist/public/widgets/calculator.js
- 格式:包含所有依赖项的 ES 模块
- Worker 构建(Wrangler):构建带有 MCP 服务器的 Cloudflare Worker。
- 输入:
worker/index.tsx
- 输出:部署到 Cloudflare 的 Worker 捆绑包
- 包含:MCP 协议处理程序、工具注册、小部件服务
通信协议
小部件使用 postMessage 与父框架(AI 聊天界面)进行通信:
- 初始化:小部件挂载时发送
ui-lifecycle-iframe-ready。
- 渲染数据:小部件接收包含初始状态的
ui-lifecycle-iframe-render-data。
- 工具调用:小部件可以通过发送
tool 消息调用其他 MCP 工具。
- 提示:小部件可以使用
prompt 消息向 AI 发送新提示。
- 链接:小部件可以使用
link 消息打开链接。
sendMcpMessage('prompt', { prompt: MCP_PROMPT })
const renderData = await waitForRenderData(renderDataSchema)
用户体验
当用户在 ChatGPT 中与这个 MCP 服务器交互时,会发生以下情况:
- 用户询问:“我能使用计算器吗?”
- ChatGPT 通过 MCP 调用
calculator 工具。
- 服务器响应:
- 文本内容:“计算器已渲染”
- UI 资源:包含初始状态的计算器 HTML
- 结构化内容:当前计算器状态
- ChatGPT 在 iframe 中渲染计算器小部件。
- 小部件加载,显示《创:战纪》风格的初始化序列,然后显示计算器。
- 用户与计算器交互(点击按钮或使用键盘)。
- 如果计算结果为 1982,小部件向 ChatGPT 发送提示。
- ChatGPT 采用 MCP 角色并相应回复。
🏃♂️ 本地运行
前提条件
- Node.js(v18 或更高版本)
- npm 或 yarn
- 一个 Cloudflare 账户(用于部署)
本地开发
- 克隆项目并安装依赖
npm install
- 启动开发服务器
npm run dev
这将同时运行两个进程:
- 小部件构建的监听模式(Vite)
- 带有本地持久对象的 Worker(Wrangler)
- 测试计算器小部件
访问
http://localhost:8787/__dev/widgets 以单独查看计算器小部件。
- 连接到 MCP 检查器
使用 MCP 检查器测试 MCP 服务器:
npm run inspect
然后在检查器中连接到 http://localhost:8787/mcp。
部署
- 生产环境构建
npm run build
- 部署到 Cloudflare
npm run deploy
- 在 ChatGPT 中使用
部署完成后,你可以通过提供部署 URL +
/mcp 端点将此 MCP 服务器添加到 ChatGPT 中。
项目结构
├── worker/
│ ├── index.tsx # 主 Worker 入口点
│ ├── tools.ts # MCP 工具定义 (do_math)
│ ├── widgets.tsx # 小部件注册系统
│ ├── utils.ts # CORS 和实用函数
│ └── widgets/
│ ├── utils.ts # 小部件通信实用工具
│ └── calculator/
│ ├── index.tsx # 计算器 UI 组件
│ ├── calculator.ts # 计算器业务逻辑
│ └── mcp-prompt.ts # MCP 彩蛋提示
├── dist/
│ └── public/
│ └── widgets/
│ └── calculator.js # 构建后的计算器捆绑包
├── vite.config.widgets.ts # 小部件构建的 Vite 配置
└── wrangler.jsonc # Cloudflare Workers 配置
关键技术
环境与配置
wrangler.jsonc 配置了以下内容:
- 持久对象绑定 (
MATH_MCP_OBJECT)
- 用于提供小部件捆绑包的资产绑定
- MCP SDK 的 Node.js 兼容性
- 生产环境监控的可观测性
开发提示
- 小部件开发:小部件代码的更改将自动热重载。
- Worker 更改:Wrangler 会在文件更改时重启 Worker。
- 类型安全:运行
npm run typecheck 验证 TypeScript。
- 代码检查:运行
npm run lint 检查代码风格。
🙏 致谢
本演示展示了前沿的 Web 技术,包括实验性的 Remix 3 功能、MCP 小部件和 Cloudflare 的边缘计算平台。计算器的设计向《创:战纪》的美学风格致敬,具有独特的橙色光芒和复古未来主义风格。