news 2026/9/13 13:36:26

CopilotKit 与 Google ADK 集成实战:基于 MCP Apps 的 Excalidraw 图表生成端到端验证指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CopilotKit 与 Google ADK 集成实战:基于 MCP Apps 的 Excalidraw 图表生成端到端验证指南

CopilotKit 与 Google ADK 集成实战:基于 MCP Apps 的 Excalidraw 图表生成端到端验证指南

【免费下载链接】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(Model Context Protocol)Apps 是一类特殊的 MCP 服务器——它们不仅暴露可被 Agent 调用的工具,还为每个工具关联了可直接渲染的 UI 资源。CopilotKit 通过内置的MCPAppsActivityRenderer,将这类 UI 资源以沙箱化 iframe 的形式内联渲染进聊天记录,从而实现"Agent 调用工具、UI 自动呈现"的生成式界面体验。本文以开源仓库中 Google ADK 集成的 MCP Apps 演示(Excalidraw 图表生成)为主线,完整解析其架构设计、Runtime 配置、Agent 系统提示词约束,并逐条讲解该演示的质量验收(QA)测试要点——包括前置条件、基础功能、工具调用、沙箱渲染、服务端驱动的 UI 更新、错误处理以及最终验收标准。读完本文,你将掌握如何在 CopilotKit 中接入一个 MCP Apps 服务器、理解其端到端调用链路,并具备编写和运行同类 QA 用例的能力。

一、先读懂架构:MCP Apps 在 CopilotKit + Google ADK 中的完整调用链

在进入 QA 测试细节之前,先理解这个演示的架构。它由三层组成:

  1. 前端(Next.js 演示页):位于showcase/integrations/google-adk/src/app/demos/mcp-apps/page.tsx,一个普通的<CopilotChat />组件即可,无需任何应用侧渲染器注册。
  2. CopilotKit Runtime(Next.js API 路由):位于showcase/integrations/google-adk/src/app/api/copilotkit-mcp-apps/route.ts,是整条链路的核心枢纽,负责连接前端与 ADK 后端 Agent,并通过mcpApps.servers配置自动附加 MCP Apps 中间件。
  3. ADK 后端 Agent:位于showcase/integrations/google-adk/src/agents/mcp_apps_agent.py,是一个标准的LlmAgent,本身没有任何自定义后端工具——它需要的全部工具(即 Excalidraw 的create_view)都由 Runtime 的 MCP Apps 中间件在请求时动态注入。

1.1 关键流程

一次完整的"画流程图"对话,其调用链如下:

  1. 用户在聊天框发送提示词,前端将其 POST 到runtimeUrl="/api/copilotkit-mcp-apps"
  2. Runtime 将请求转发给 ADK 后端挂载的mcp-appsAgent(注意挂载路径是连字符mcp-apps,注册于 registry.py);
  3. 当 Agent 决定调用 Excalidraw 的create_view工具时,MCP Apps 中间件截获该调用,向远程 MCP 服务器(https://mcp.excalidraw.com)发起请求并取回与工具关联的 UI 资源;
  4. 中间件将 UI 资源作为activity事件(类型为mcp-apps)写回聊天流;
  5. 前端由CopilotKitProvider自动注册的内置MCPAppsActivityRenderer接收该事件,将资源渲染为带sandbox属性的内联 iframe——全程无需应用侧编写任何渲染器代码。

这一"零前端渲染器"的设计,是本文 QA 文档反复强调的@region[no-frontend-renderer-needed]契约(见 page.tsx)。

二、Runtime 配置解析:mcpApps.servers是服务端唯一需要做的事

在 route.ts 中,MCP Apps 的服务端配置非常简洁,被源码以@region[runtime-mcpapps-config]标记出来:

const runtime = new CopilotRuntime({ agents: { "mcp-apps": mcpAppsAgent, "headless-complete": headlessCompleteAgent, }, mcpApps: { servers: [ { type: "http", url: process.env.MCP_SERVER_URL || "https://mcp.excalidraw.com", // Always pin a stable `serverId`. Without it CopilotKit hashes the // URL, and a URL change silently breaks restoration of persisted // MCP Apps in prior conversation threads. serverId: "excalidraw", }, ], }, });

该配置有三个关键点值得展开:

  • mcpApps.servers自动附加中间件:源码注释明确说明,只需此配置,Runtime 就会对所有已注册 Agent 自动应用 MCP Apps 中间件。中间件的工作方式是:每当 Agent 发起一次 MCP 工具调用,它就获取与该工具关联的 UI 资源,并发出activity事件,交给内置MCPAppsActivityRenderer内联渲染。
  • serverId必须固定(pinned):这是本演示中最容易被忽略却至关重要的配置。源码注释给出了精确理由——如果不显式指定serverId,CopilotKit 会对服务器 URL 做哈希;一旦 URL 发生变化,先前会话线程(thread)中持久化的 MCP Apps 将无法正确恢复,造成历史活动静默失效。固定为"excalidraw"后,即使未来更换 MCP 服务器地址,已保存的对话活动仍能稳定还原。QA 文档中"验证之前的流程图 iframe 依然存在且未过期"的用例,其依据正是这一设计动机。
  • MCP_SERVER_URL环境变量:默认指向公共 Excalidraw MCP 服务,可通过环境变量覆盖,便于在测试环境指向本地或自建的 MCP 服务器。

2.1 Agent 连接细节:连字符路径的教训

同文件中的HttpAgent构建逻辑隐藏了一个值得注意的细节(route.ts):

const mcpAppsAgent: AbstractAgent = new HttpAgent({ // Backend mounts this agent at `/mcp-apps` (dash) per // agents/registry.py — not `/mcp_apps`. Stale underscore here caused // every MCP Apps request to 404 at the ADK FastAPI layer, surfacing // as `HTTP 404: {"detail":"Not Found"}` in the chat. url: `${AGENT_URL}/mcp-apps`, headers, });

源码注释直接记录了此前的一次真实事故:后端在 registry 中把 Agent 挂载为连字符形式的/mcp-apps,而旧代码里使用了下划线/mcp_apps,导致每次请求都在 ADK FastAPI 层返回HTTP 404: {"detail":"Not Found"}。这是一个重要的排障提示:当 MCP Apps 演示出现 404 时,应首先核对 Runtime 中的 Agent URL 与后端 registry 挂载路径是否完全一致。另外,该路由在请求级通过extractForwardedHeaders(req)提取并转发入站请求头(如x-aimock-context),保证多租户上下文能正确传递到 Python 后端。

三、ADK Agent 侧约束:系统提示词如何保证"一次调用、快速出图"

后端 Agent 定义在showcase/integrations/google-adk/src/agents/mcp_apps_agent.py,其核心设计全部浓缩在系统指令_INSTRUCTION中:

mcp_apps_agent = LlmAgent( name="McpAppsAgent", model=get_model(), instruction=_INSTRUCTION, tools=[AGUIToolset()], after_model_callback=stop_on_terminal_text, )

该 Agent 只装配了AGUIToolset(),没有任何业务工具——所有画图能力均来自 Runtime 中间件动态注入的 Excalidraw 工具集。为了让 QA 行为可预测,系统提示词对 Agent 施加了非常明确的约束,这些约束正是 QA 文档中"严格验证create_view恰好调用一次"的判定依据:

必须做到的(DO):

  • create_view只调用一次,元素总数 3–5 个:形状 + 箭头 + 可选标题文本;
  • 使用简单的形状(矩形 rectangle、椭圆 ellipse、菱形 diamond),元素上直接携带label字段({"text": "...", "fontSize": 18});
  • 用箭头连接,端点可用元素中心或简单坐标,无需 edge anchors / fixedPoint 绑定;
  • 在元素数组末尾附带一个cameraUpdate,把整个图框进视口,使用批准的 4:3 尺寸(600x450800x600);
  • 回复一句话简要描述所画内容;
  • 每个元素必须有唯一字符串id(如"b1""a1""title");标准尺寸:矩形160x70、椭圆/菱形120x80、形状间距 40–80px。

明确禁止的(DO NOT):

  • 调用read_me(提示词认为模型已掌握基础形状 API);
  • 多次调用create_view
  • 迭代或返工("Ship on the first shot",一次成型);
  • 添加装饰性颜色/填充/分区背景,除非用户明确要求;
  • 在箭头上加标签,除非至关重要。

提示词开头还明确设定了速度偏好:"SPEED MATTERS. Produce a correct-enough diagram fast; do not optimize for polish."(速度优先,产出"足够正确"的图即可,不为打磨优化)。目标是一次工具调用、数秒内完成。这解释了 QA 文档中 60 秒超时与"偏置为快速出正确图"的验收口径。

同时,after_model_callback=stop_on_terminal_text(来自 shared_chat.py)确保模型一旦输出终止文本即停止生成,避免多余轮次。

四、前端演示页:零渲染器注册的CopilotChat

前端由两个文件构成,极其精简:

page.tsx 使用CopilotKit包裹,runtimeUrl指向/api/copilotkit-mcp-appsagent="mcp-apps",外层层宽限制为max-w-4xl(即约 896px),对应 QA 中的布局断言:

<CopilotKit runtimeUrl="/api/copilotkit-mcp-apps" agent="mcp-apps"> <div className="flex justify-center items-center h-screen w-full"> <div className="h-full w-full max-w-4xl"> <Chat /> </div> </div> </CopilotKit>

chat.tsx 则直接渲染CopilotChat,并调用useMcpAppsSuggestions()注入建议 pill:

export function Chat() { useMcpAppsSuggestions(); return <CopilotChat agentId="mcp-apps" className="h-full rounded-2xl" />; }

两条建议 pill 定义在 suggestions.ts,标题与消息分别为:

  • "Draw a flowchart"→ "Use Excalidraw to draw a simple flowchart with three steps."
  • "Sketch a system diagram"→ "Open Excalidraw and sketch a system diagram with a client, server, and database."

QA 文档要求验证这两条 pill 以逐字标题(verbatim)显示,因为断言依赖可见文本。

五、QA 前置条件(Prerequisites)

依据原文档,运行该演示的 QA 用例前需确认以下环境就绪:

  1. 演示已部署并可访问:Dashboard 主机的/demos/mcp-apps路由可正常打开;
  2. Agent 后端健康GOOGLE_API_KEY已在 Railway 环境变量中设置;AGENT_URL指向暴露mcp_apps端点的 ADK Agent 服务器(Agent 以名称mcp-apps注册,对应 route.ts);
  3. MCP 服务器目标:公共 Excalidraw MCP 应用https://mcp.excalidraw.com(可通过MCP_SERVER_URL覆盖);serverId: "excalidraw"已固定,确保 URL 变化不会静默破坏持久化活动;
  4. 测试前提约束:演示源码不含data-testid属性,也没有注册自定义活动渲染器——内置MCPAppsActivityRenderer自动处理沙箱 iframe。因此 QA 断言只能依赖逐字可见文本、网络流量(DevTools → Network)与 iframe DOM 内部结构,而非测试专用的 DOM 标记。

六、测试步骤详解:从基础功能到端到端 MCP 交互

6.1 基础功能(Basic Functionality)

  • 页面渲染:访问/demos/mcp-apps,页面应在 3 秒内渲染完成,且有一个居中的CopilotChat面板(最大宽度约 896px、rounded-2xl圆角、全高)。
  • Runtime 接线验证:通过 DevTools → Network 发送一条消息,确认请求命中runtimeUrl="/api/copilotkit-mcp-apps",且agent="mcp-apps"
  • 建议 pill:两条 pill 均可见且标题逐字一致("Draw a flowchart" / "Sketch a system diagram")。
  • 纯文本回复:发送 "Hello",10 秒内应收到助手文本回复,且不出现MCP 活动 iframe——纯文本对话不应触发画图工具。

6.2 MCP 服务器连接(mcpApps.servers

  • 发送第一个流程图提示词,在 DevTools → Network 中确认对/api/copilotkit-mcp-apps的 POST 返回 200;
  • 观察服务端日志,Runtime 应从https://mcp.excalidraw.com解析工具,MCP Apps 中间件会附加 Excalidraw 工具集(重点是create_view);
  • 控制台不应出现提及 MCP 服务器 URL、认证或工具 schema 解析失败的报错。

6.3 MCP 工具调用(create_view

  • 点击 "Draw a flowchart",60 秒内验证 Agent恰好调用一次create_view——判据来自 mcp_apps_agent.py 系统提示词"Callcreate_viewONCE with 3-5 elements total",可通过 DevTools 网络流或后端日志确认;
  • 验证工具载荷:包含 3–5 个 Excalidraw 元素(形状 + 箭头 + 可选标题文本),每个元素有唯一字符串id,且以一个cameraUpdate结尾,尺寸为600x450800x600

6.4 活动渲染器(内置MCPAppsActivityRenderer

  • 工具调用后 60 秒内,聊天记录的活动消息槽(activity-message slot)应内联渲染出一个沙箱<iframe>,指向 Excalidraw MCP UI 资源;
  • iframe 必须带sandbox属性(CopilotKit 内置渲染器对 MCP UI 资源始终沙箱化);
  • iframe 应绘制出流程图形态的图形:至少 3 个带文本标签的形状节点(矩形、椭圆或菱形)由箭头连接,并整体框入视口(对应系统提示词要求的cameraUpdate步骤);
  • iframe 下方的助手文本应为一句简短的描述性句子。

6.5 服务端驱动的 UI 更新(同线程第二个提示词)

  • 不刷新页面,发送第二条建议 "Sketch a system diagram",60 秒内应出现一个新的活动 iframe,呈现 客户端 → 服务器 → 数据库 布局(3 个带标签的形状 + 2 个箭头);
  • 验证上一条流程图 iframe 依然存在于回滚区且未过期——活动消息持久保留,这正是 Runtime 配置中固定serverId: "excalidraw"的动机所在:跨线程/跨对话恢复持久化 MCP Apps 时,URL 变化不会导致历史活动静默失效。

6.6 端到端 MCP 交互(单一确定性用例)

发送显式提示词:

"Use Excalidraw to draw exactly 2 rectangles labelled 'A' and 'B' connected by one arrow from A to B."

60 秒内验证四项结果:

  1. create_view恰好调用一次,载荷精确包含 3 个元素(2 个矩形 + 1 个箭头)加上结尾的cameraUpdate
  2. iframe 渲染出两个带标签的矩形及连接箭头;
  3. 助手回复为一句话;
  4. 网络/日志中没有重复的create_view调用或重试。

这类"具体、单一、可判定"的用例,是 MCP Apps 端到端验证的推荐写法——把不确定性压到最低,任何偏离都能快速定位是 Agent 行为问题还是渲染链路问题。

七、错误处理测试(Error Handling)

  • 空消息:发送空消息应为 no-op——不出现用户气泡,也不出现助手回复;
  • 非画图类问题:发送 "What is 2+2?",Agent 应以纯文本回复且调用create_view(无 iframe、流中无 MCP 活动);
  • 控制台巡检:遍历以上所有流程,确认无未捕获错误、无指向mcp.excalidraw.com的 CORS 失败、无 "sandbox"/iframe 权限警告。

八、预期结果与验收口径(Expected Results)

综合全部用例,通过标准为:

  • 聊天 3 秒内加载,纯文本回复 10 秒内返回;MCP 支撑的 iframe 在提示词后 60 秒内渲染(整体偏置是"快速出足够正确的图",一次create_view调用);
  • https://mcp.excalidraw.com的 MCP 服务器连接成功,Excalidraw 工具集(含create_view)在请求时已向 Agent 通告;
  • 至少一个完整的端到端 MCP 交互完成:用户提示词 →create_view工具调用 → activity 事件 → 沙箱 iframe 绘制出所请求的图形;
  • 确认使用的是内置MCPAppsActivityRendererpage.tsx中不存在任何useRenderActivityMessage/renderActivityMessages注册,符合@region[no-frontend-renderer-needed]契约);
  • 无 UI 布局破坏、无未捕获控制台错误、单个提示词轮次内无重复create_view调用。

九、源码深挖:内置MCPAppsActivityRenderer如何工作

QA 文档反复依赖"内置渲染器",它的实现位于 packages/react-core/src/v2/components/MCPAppsActivityRenderer.tsx,由CopilotKitProvider自动注册。理解它的两个设计点,能帮你更准确地定位测试中的渲染问题:

1. 沙箱 iframe 由渲染器构造代理 HTML。渲染器并非直接把 MCP 返回的资源塞进<iframe>,而是通过buildSandboxHTML()生成一段带严格 CSP 的 HTML 文档,再配合@modelcontextprotocol/ext-apps/app-bridge建立 UI 资源与宿主页面间的安全通信桥。CSP 中script-src允许'self' 'wasm-unsafe-eval' 'unsafe-inline' 'unsafe-eval' blob: data: http://localhost:* https://localhost:*frame-src允许* blob: data: http://localhost:* https://localhost:*,并支持从资源元数据中附加额外的 CSP 域(extraCspDomains)。这也是 QA 中"验证 iframe 带sandbox属性、控制台无 sandbox 权限警告"用例的底层依据——任何 CSP 或 sandbox 缺失,都会破坏资源渲染或触发控制台警告。

2. 活动渲染器是惰性加载的。源码注释指出,ext-apps 桥接层是重依赖(拖入 MCP SDK Protocol 与 zod schema,约 40–50 kB gzipped),因此通过动态import()惰性加载——只有当应用真正渲染一个 MCP App 时才付出这部分体积,普通<CopilotKit>应用挂载时不会加载。这一"按需付费"设计与 QA 中"纯文本对话不产生 iframe"的行为相辅相成。

此外,渲染器还处理ui/message后续交互(ɵrunMcpFollowUp),并针对"线程切换"场景做了防御:如果后续工作在排队期间宿主线程发生切换,它宁可丢弃这次可选 Agent 轮次(并输出console.warn),也不让结果泄漏进当前前台线程——这对应 QA 中"上一活动 iframe 仍在滚动区且未过期"与"无重复调用/重试"的稳定性断言。

十、把 QA 方法论复用到你的 MCP Apps 集成

这份 QA 文档的价值不止于验证 Excalidraw 演示,它提炼出一套可复用的 MCP Apps 集成验收方法论:

  1. 锁定确定性的 Agent 行为:通过系统提示词约束工具调用次数、元素数量、元素 ID 唯一性、结尾 cameraUpdate 规格,把随机性压到最低,使每个用例都有可判定的断言;
  2. 三层证据交叉验证:可见文本(逐字标题、一句话回复)+ 网络流量(POST 200、单次create_view)+ iframe DOM(沙箱属性、形状数量、箭头连接),任一层面都能独立发现故障点;
  3. 历史活动持久化必须测试:固定serverId后,务必验证同线程第二个提示词时旧 iframe 仍完好——这是 MCP Apps 与普通工具调用的关键差异(UI 资源是持久的会话资产,不是一次性输出);
  4. 错误路径与成功路径同等重要:空消息 no-op、非画图问题不触发 MCP 调用、控制台无 CORS/sandbox 警告,这三条防线能快速区分"链路没通"与"链路通了但体验有缺陷"。

若要在本地复现该演示,核心配置只需两处:Runtime 路由中声明mcpApps: { servers: [...] }并固定serverId,后端 Agent 保持无自有工具、依靠中间件注入 MCP 工具集即可;前端一个<CopilotChat />即可获得完整的沙箱 iframe 渲染能力,无需任何自定义渲染器。

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 13:36:15

工业级嵌入式以太网采集单元系统方案

1. 项目概述&#xff1a;一个能真正落地的嵌入式以太网采集单元&#xff0c;不是Demo&#xff0c;是产线级方案“以太网采集单元系统方案”——这八个字背后&#xff0c;不是实验室里跑通DHCP就截图发朋友圈的Demo&#xff0c;而是一套要装进工业机柜、连续运行三年不出故障、能…

作者头像 李华
网站建设 2026/9/13 13:36:12

Spring Boot+Vue3自建问卷系统实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 13:35:47

PDF补丁丁完整指南:免费开源的PDF书签编辑器与文档合并工具

PDF补丁丁完整指南&#xff1a;免费开源的PDF书签编辑器与文档合并工具 【免费下载链接】PDFPatcher PDF补丁丁——PDF工具箱&#xff0c;可以编辑书签、剪裁旋转页面、解除限制、提取或合并文档&#xff0c;探查文档结构&#xff0c;提取图片、转成图片等等 项目地址: https…

作者头像 李华
网站建设 2026/9/13 13:33:27

毕业设计软件使用说明书写作指南:从评阅视角出发

每年答辩季&#xff0c;我都会看到同一种场面&#xff1a;系统演示倒还顺利&#xff0c;代码量也凑够了&#xff0c;偏偏评审老师翻开学生交上来的“毕业设计 软件使用说明书”时&#xff0c;眉头皱了一下&#xff0c;翻几页就合上了。倒不是没写&#xff0c;而是写出来的东西要…

作者头像 李华
网站建设 2026/9/13 13:33:10

单机无穷大系统暂态稳定仿真:SMIG_2.m脚本全解析

简介&#xff1a;单机无穷大系统是电力系统暂态稳定分析中的经典简化模型&#xff0c;这份资源面向电力系统专业学生、科研人员及MATLAB仿真学习者&#xff0c;提供该模型的脚本化仿真实现。压缩包内仅含1个m文件&#xff0c;大小约2KB&#xff0c;对应完整MATLAB源码&#xff…

作者头像 李华