CopilotKit MCP Apps 实战:让交互式 HTML 应用直接渲染在聊天界面中

发布时间:2026/9/10 12:10:38
CopilotKit MCP Apps 实战:让交互式 HTML 应用直接渲染在聊天界面中 CopilotKit MCP Apps 实战让交互式 HTML 应用直接渲染在聊天界面中【免费下载链接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit导读MCP AppsModel Context Protocol Applications对应规范 SEP-1865是 MCP 生态中一项让工具结果直接以 HTML/JS 应用形态渲染在对话界面的能力。本仓库的 examples/showcases/mcp-apps 演示项目将 CopilotKit 前端、AG-UI Runtime 与一个 Express MCP SDK 服务端串联起来在一个聊天侧边栏中同时承载机票预订、酒店预订、投资模拟器和看板管理四款交互式应用。读完本文你将掌握如何用_meta[ui/resourceUri]把工具与 UI 资源绑定、如何用MCPAppsMiddleware在 AG-UI 运行时中接管 UI 化工具调用以及如何让 iframe 内应用通过 JSON-RPC over postMessage 反向调用 MCP 工具。一、什么是 MCP Apps从“工具返回文本”到“工具返回应用”传统 MCP 工具调用链中服务端返回的是结构化文本或 JSON前端只能以聊天气泡形式展示。MCP Apps 扩展SEP-1865改变了这一点由 MCP 服务器托管的 HTML/JS 应用可以在沙箱 iframe 中渲染用户直接在聊天侧边栏里与这些应用交互交互产生的操作又通过 JSON-RPC 反向调用 MCP 工具。在 examples/showcases/mcp-apps/CLAUDE.md 中这套机制被拆成四个核心要点机制说明MCP Apps ExtensionSEP-1865由 MCP 服务器提供 HTML/JS 应用前端在 iframe 中渲染Tool-to-UI 链接工具元数据_meta[ui/resourceUri]将工具调用与 UI 资源 URI 关联双向通信UI 通过 postMessage 发送 JSON-RPC 请求调用 MCP 工具MCPAppsMiddlewareAG-UI 中间件拦截带 UI 资源的工具调用并完成资源注入这套机制的价值在于Agent 不再只是回答而是能交付一个可操作的界面——选座位、订房间、拖卡片、执行交易全部发生在用户与 AI 对话的上下文里。二、整体架构与一次完整请求的流转2.1 三端架构从 examples/showcases/mcp-apps/CLAUDE.md 的架构图可以看到完整链路由三部分组成Frontend (Next.js) CopilotKit Runtime MCP Server ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ CopilotSidebar │ ──SSE──▶│ BuiltInAgent │──HTTP──▶│ Express :3001 │ │ │ │ MCPApps │ │ │ │ ┌─────────────┐ │ │ Middleware │ │ Tools: │ │ │ MCP App │ │ │ │ │ - search-flights│ │ │ iframe │◀──────────│ Emits Activity │ │ - search-hotels │ │ └─────────────┘ │ │ Snapshots │ │ - create-portfolio│ └─────────────────┘ └─────────────────┘ │ - create-board │ │ helper tools │ │ │ │ Resources: │ │ - flights-app │ │ - hotels-app │ │ - trading-app │ │ - kanban-app │ └─────────────────┘2.2 请求流转用户在聊天中发出自然语言请求例如Book a flight from JFK to LAXCopilotKit Runtime 中的 Agent 决定调用带 UI 资源的 MCP 工具MCPAppsMiddleware拦截该调用从 MCP 服务器拉取对应的 HTML 资源CopilotKit 前端将 HTML 渲染到沙箱 iframe 中侧边栏内用户与 iframe 应用交互iframe 内的应用通过 postMessage 以 JSON-RPC 形式反向调用 MCP 工具选座位、下单等工具结果通过ui/notifications/tool-result通知回到应用驱动 UI 更新。三、四个演示应用一览原文档将四个应用概括如下均遵循一个主工具触发 UI 若干辅助工具支撑交互的模式App主工具辅助工具UI 特性Fitness Coachworkout-generatorlog-exercise-complete,adjust-workout计时器、训练卡片、进度条Recipe Chefgenerate-recipeadjust-servings配料清单、步骤、营养信息Investment Simulatorcreate-portfolioexecute-trade,refresh-prices持仓、CSS 图表、交易弹窗Kanban Boardcreate-boardadd-card,update-card,delete-card,move-card拖拽卡片、列、详情弹窗注意原文档描述的这 4 个应用版本与当前仓库已演化后的mcp-server目录略有出入。仓库当前版本将演示重心调整为Airline Bookingsearch-flights、Hotel Bookingsearch-hotels、Investment Simulatorcreate-portfolio与Kanban Boardcreate-board四款应用见 examples/showcases/mcp-apps/README.md 与 server.ts其中机票、酒店预订还扩展出了完整的多步骤向导工具链select-flight/select-seats/book-flight、select-hotel/select-room/book-hotel。本文以仓库当前实现为准展开。四、本地运行两个终端、两个端口原文档给出的启动方式如下它假设工作目录在examples/showcases/mcp-apps# 终端 1MCP Server cd mcp-server npm run dev # 终端 2Next.js 前端 npm run dev前端http://localhost:3000MCP Serverhttp://localhost:3001MCP 端点实际为http://localhost:3001/mcp4.1 完整的首次启动流程结合 examples/showcases/mcp-apps/README.md 的 Quick Start完整的依赖安装与环境准备如下# 1. 在 mcp-apps 目录安装前端依赖 npm install # 2. 安装 MCP Server 依赖 cd mcp-server npm install cd .. # 3. 在 mcp-apps 目录创建 .env.local 并配置 LLM 密钥 # OPENAI_API_KEYsk-...4.2 构建 MCP App 的 HTML 产物MCP 服务器通过loadHtml()从apps/dist/*.html读取 UI 页面server.ts。这些 HTML 由 Vite 打包生成开发与生产目录有差异时loadHtml会自动判断__dirname是否以dist结尾来定位资源路径若产物未构建会返回一个占位 HTML 并提示运行npm run build:appcd mcp-server npm run build:app # 使用 Vite 将 apps/*.html 打包为自包含的 dist 产物4.3 环境变量与模型选择前端 API 路由 route.ts 中的determineModel()会根据环境变量自动选择模型环境变量使用模型OPENAI_API_KEY优先openai/gpt-5.2ANTHROPIC_API_KEYanthropic/claude-sonnet-4.5GOOGLE_API_KEYgoogle/gemini-2.5-pro均未设置回退openai/gpt-5.2MCP 服务器地址通过MCP_SERVER_URL配置默认http://localhost:3001/mcproute.ts。生产环境部署后将MCP_SERVER_URL指向已部署的 MCP 服务器即可仓库中同时提供了面向 Railway 的 railway.toml 与 Dockerfile。五、前端接线Provider、Sidebar 与 Agent 运行5.1 页面结构page.tsx 是演示首页核心结构为export default function MCPAppsDemo() { return ( CopilotKitProvider runtimeUrl/api/copilotkit AppLayout / /CopilotKitProvider ); }CopilotKitProvider的runtimeUrl指向同仓库的 Next.js API 路由/api/copilotkit桌面端渲染CopilotSidebar defaultOpen{true} width50%移动端自动降级为CopilotPopup通过useMediaQuery((min-width: 768px))判断页面顶部是一组应用卡片每张卡片带示例 prompt 按钮点击后调用sendMessage把提示词注入聊天并触发 Agent 运行const sendMessage useCallback(async (message: string) { config?.setModalOpen(true); agent.addMessage({ id: randomUUID(), role: user, content: message }); await copilotkit.runAgent({ agent }); }, [agent, copilotkit, config]);这里的agent来自useAgent({ agentId: DEFAULT_AGENT_ID })DEFAULT_AGENT_ID由copilotkit/shared提供。5.2 API 路由BuiltInAgent MCPAppsMiddlewareroute.ts 是前后端接线的关键文件它使用copilotkit/runtime/v2的BuiltInAgent创建了一个多应用助手人格含四款应用的参数说明与示例提示词并挂载 MCP Apps 中间件const agent new BuiltInAgent({ model: determineModel(), prompt: You are an AI assistant with access to 4 interactive apps that render in the chat. ..., }).use( new MCPAppsMiddleware({ mcpServers: [ { type: http, url: process.env.MCP_SERVER_URL || http://localhost:3001/mcp, }, ], }), ); const runtime new CopilotRuntime({ agents: { default: agent }, runner: new InMemoryAgentRunner(), }); const app createCopilotEndpoint({ runtime, basePath: /api/copilotkit, });最后通过hono/vercel的handle()导出GET/POST供 Next.js 路由使用。需要注意MCPAppsMiddleware的mcpServers配置中目前不支持includeTools/excludeTools这类 per-server 工具策略键——运行时中的 mcp-apps-servers.ts 会在检测到这些键时直接抛出异常工具策略由ag-ui/mcp-apps-middleware自行管理。六、MCP 服务端工具与 UI 资源的绑定6.1 资源注册mimeType 是关键标记MCP Apps 的核心约定是资源 MIME 类型text/htmlmcp它向中间件与前端标记这是一个可在 iframe 渲染的 MCP App。见 server.tsserver.registerResource( flights-app-template, ui://flights/flights-app.html, { mimeType: text/htmlmcp, // Critical: marks as MCP App }, contentHandler, );仓库当前实现中每个资源在注册时还会附带title、description并在 handler 内返回完整的 HTML 文本contents: [{ uri, mimeType, text: htmlContent }]HTML 从apps/dist/*.html读取server.ts。资源 URI 使用自定义的ui://scheme如ui://flights/flights-app.html、ui://hotels/hotels-app.html、ui://trading/trading-app.html、ui://kanban/kanban-app.html与工具元数据中的 URI 一一对应。6.2 工具注册_meta[ui/resourceUri]完成链接原文档中的工具注册模式如下这也是当前仓库的实际写法const RESOURCE_URI_META_KEY ui/resourceUri; server.registerTool( workout-generator, { inputSchema: { duration, focus, equipment, difficulty }, _meta: { [RESOURCE_URI_META_KEY]: ui://fitness/workout-app.html }, }, handler, ); server.registerTool( generate-recipe, { inputSchema: { cuisine, dietary, servings, maxTime }, _meta: { [RESOURCE_URI_META_KEY]: ui://recipe/recipe-app.html }, }, handler, ); server.registerTool( create-portfolio, { inputSchema: { initialBalance, riskTolerance, focus }, _meta: { [RESOURCE_URI_META_KEY]: ui://trading/trading-app.html }, }, handler, ); server.registerTool( create-board, { inputSchema: { projectName, template }, _meta: { [RESOURCE_URI_META_KEY]: ui://kanban/kanban-app.html }, }, handler, );在当前仓库的 server.ts 中以search-flights为例工具在_meta中直接引用已注册资源的 URI 对象_meta: { [RESOURCE_URI_META_KEY]: flightsResource.uri }输入参数使用 zod schema 描述含passengers: z.number().min(1).max(9)、cabinClass: z.enum([economy,business,first])等约束返回结果同时提供人类可读的content文本与机器可读的structuredContent。6.3 主工具 辅助工具模式每款应用由一个带 UI 资源的主工具负责触发 iframe 渲染和若干无 UI 的辅助工具组成。仓库当前实现中机票预订search-flights主→select-flight选航班返回座位图→select-seats选座位→book-flight填乘客信息出票酒店预订search-hotels主→select-hotel选酒店返回房型→select-room选房型数量→book-hotel确认预订投资模拟器create-portfolio主→execute-trade、refresh-prices看板create-board主→add-card、update-card、delete-card、move-card。辅助工具虽然不直接携带 UI 资源但会被 iframe 内的应用通过 JSON-RPC 调用是应用与后端逻辑之间的桥梁。服务器内部用MapactivePortfolios、activeBoards按会话维护组合与看板状态server.ts。七、双向通信iframe 内应用如何调用 MCP 工具7.1 通信模块四个应用共用同一模式原文档给出了完整的通信模块实现iframe 内应用通过window.parent.postMessage发送 JSON-RPC 2.0 消息const mcpApp (() { let requestId 1; const pendingRequests new Map(); function sendRequest(method, params) { const id requestId; return new Promise((resolve, reject) { pendingRequests.set(id, { resolve, reject }); window.parent.postMessage({ jsonrpc: 2.0, id, method, params }, *); }); } function sendNotification(method, params) { window.parent.postMessage({ jsonrpc: 2.0, method, params }, *); } // ... notification handlers ... return { sendRequest, sendNotification, onNotification }; })(); // 从 iframe 调用 MCP 工具独立参数非对象风格 mcpApp.sendRequest(tools/call, { name: log-exercise-complete, arguments: {...} }); // 监听工具结果 mcpApp.onNotification(ui/notifications/tool-result, (params) { // 用 params.structuredContent 更新 UI });7.2 消息约定要点请求消息携带递增的id与pendingRequests映射用于把响应关联回对应的 Promisetools/call是调用 MCP 工具的 JSON-RPC 方法arguments传独立参数对象工具执行结果通过ui/notifications/tool-result通知推回应用携带structuredContent服务器在每个工具 handler 中都会构造见 server.ts 中search-flights的返回应用据此渲染真实数据window.parent表明这些应用运行在聊天侧边栏的 iframe 沙箱中应用源码位于mcp-server/apps/*.html。八、关键文件与项目结构8.1 前端src/app/文件用途api/copilotkit/[[...slug]]/route.tsBuiltInAgent MCPAppsMiddleware 配置创建 CopilotRuntime 与 Hono 端点page.tsxCopilotKitProvider CopilotSidebar桌面/ CopilotPopup移动应用卡片与 prompt 入口8.2 MCP Servermcp-server/文件用途server.tsExpress MCP SDK 服务器注册全部工具与资源src/flights.ts航班搜索/选座/预订逻辑15 个机场、6 家航司src/hotels.ts酒店搜索/房型/预订逻辑10 城市、30 家酒店src/stocks.ts股票/组合逻辑18 支股票、6 个板块src/kanban.ts看板/卡片逻辑看板模板apps/*.html交互式 UI 源码flights-app / hotels-app / trading-app / kanban-appapps/dist/*.htmlVite 打包产物供loadHtml读取此外 compatibility.test.mjs 提供了兼容性校验测试。九、依赖版本要求重要原文档明确强调MCP Apps 支持要求copilotkit/*版本不低于1.51.0-next.4——0.0.x老版本不包含MCPAppsActivityRenderer无法渲染 UI 活动快照。原文档给出的依赖清单为copilotkit/core: 1.51.0-next.4, copilotkit/react-core: 1.51.0-next.4, copilotkit/runtime: 1.51.0-next.4, copilotkit/shared: 1.51.0-next.4, copilotkit/web-inspector: 1.51.0-next.4, ag-ui/mcp-apps-middleware: ^0.0.1, zod: ^3.25.75当前仓库中的 mcp-apps/package.json 已将这些包升级到1.68.1copilotkit/react-core、copilotkit/runtime、copilotkit/shared并将ag-ui/mcp-apps-middleware提升到^0.0.3同时引入ag-ui/client0.0.58、hono、next16、react19。各包的职责划分copilotkit/react-core/v2— CopilotKitProvider、CopilotSidebar、MCPAppsActivityRenderercopilotkit/runtime— CopilotRuntime、createCopilotEndpointcopilotkit/runtime/v2— BuiltInAgentAgent 合并进运行时ag-ui/mcp-apps-middleware— MCPAppsMiddlewaremodelcontextprotocol/sdk— MCP 服务器 SDK十、已知问题与注意事项原文档列出了以下注意事项它们对复现与部署都有直接影响BasicAgent 已弃用当前版本中应使用BuiltInAgent原文档指出 BasicAgent 仅产生警告、仍可用但仓库 route.ts 已切换为BuiltInAgent计时器精度演示应用中的计时器精度取决于浏览器标签页是否保持聚焦后台标签页会被浏览器节流版本下限必须使用copilotkit/*1.51.0-next.4更早版本缺少 UI 渲染能力MCPAppsActivityRenderer沙箱限制沙箱化 iframe 会拦截外部 CDN 脚本因此应用样式需使用内联样式不能依赖 Tailwind CDN 等外部资源——这也解释了为何四个应用把图标lucide 风格 SVG直接内联在 HTML 中。十一、源码级佐证中间件与集成测试11.1 运行时对 MCP Apps 服务器的解析在 CopilotKit Runtime 内部mcp-apps-servers.ts 的resolveMcpAppsServers()负责把McpAppsServerConfig[]转换为中间件所需的MCPClientConfig[]同时执行两项约束按agentId过滤未指定agentId的服务器对所有 Agent 生效并对includeTools/excludeTools等不受支持的策略键抛出明确错误。这说明MCP Apps 的服务器接线是运行时与中间件协同完成的配置错误会在请求阶段被快速暴露。11.2 集成测试验证的交互路径mcp-apps-middleware-integration.test.ts 使用MCPMockcopilotkit/aimock模拟 MCP 服务器注册get_weather工具与app://dashboard资源验证了MCPAppsMiddleware与CopilotRuntime的集成行为中间件构造参数被正确传递、下游 Agent 事件正常流转。结合packages/react-core中 MCPAppsActivityRenderer.tsx 及配套的 e2e 测试MCPAppsActivityRenderer.e2e.test.tsx、MCPAppsProxy.e2e.test.tsx、MCPAppsUiMessage.e2e.test.tsx可以确认完整的链路是中间件拦截带 UI 资源的工具调用 → 运行时发出 Activity 快照 →MCPAppsActivityRenderer在 React 端把快照渲染为 iframe。结语通过 examples/showcases/mcp-apps 这份演示你可以完整体验聊天界面内的可交互应用这一 MCP Apps 核心范式服务端用text/htmlmcp资源与_meta[ui/resourceUri]声明工具-UI 绑定前端用MCPAppsMiddleware自动接管渲染应用内通过 postMessage JSON-RPC 保持双向实时通信。这套模式让 Agent 的输出从一段文字升级为一个能操作的界面为机票、酒店、投资、项目管理等场景提供了可直接复用的参考实现。【免费下载链接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考