news 2026/9/14 9:21:48

CopilotKit MCP Apps 实战:.NET Agent 零工具声明,MCP 服务器 UI 自动内嵌聊天

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CopilotKit MCP Apps 实战:.NET Agent 零工具声明,MCP 服务器 UI 自动内嵌聊天

CopilotKit MCP Apps 实战:.NET Agent 零工具声明,MCP 服务器 UI 自动内嵌聊天

【免费下载链接】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

本文基于仓库中 MS Agent Framework(.NET 后端)集成示例的 MCP Apps 演示文档,完整拆解「CopilotKit 聊天 + 带 UI 资源的 MCP 服务器」的接线方式:一个不声明任何自定义工具的 .NET Agent,如何通过 Runtime 侧的mcpApps配置自动获得远程 MCP 工具,并在工具调用后把 MCP 服务器提供的 UI(Excalidraw 画布)以沙箱 iframe 形式渲染进聊天流,且前端一行渲染器注册代码都不用写。读完本文,你可以复现「后端零工具、前端零渲染器」的 MCP Apps 集成链路,并理解serverId固定、专用 runtime 路由等关键设计决策的原因。

一、MCP Apps 演示要解决的问题

MCP Apps 指的是一类特殊的 MCP(Model Context Protocol)服务器:它的每个工具都携带一个关联的UI 资源。传统做法下,要展示工具产出的 UI,前端必须注册对应的渲染器;而 MCP Apps 的机制是——当 Agent 调用这类工具时,CopilotKit Runtime 的中间件会抓取该工具关联的 UI 资源,发出一个activity事件,由 CopilotKit 内置的MCPAppsActivityRenderer把 UI 作为沙箱 iframe直接渲染在聊天消息流里,应用侧无需注册任何渲染器(见 演示说明文档)。

本演示指向公开的 Excalidraw MCP 应用(默认https://mcp.excalidraw.com)。仓库建议的交互方式(对应 suggestions.ts 中配置的两条建议提示):

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

Agent 会调用 MCP 服务器的绘图工具create_view,随后聊天中内联出现可交互的 Excalidraw 画布。

二、整体链路:四个环节如何协作

从 演示文档 的 "Technical Details" 一节可以提炼出这条链路的四个环节,每个环节在仓库中都有对应实现:

  1. .NET Agent 后端(无自定义工具)agent/McpAppsAgent.cs暴露一个"裸"的ChatClientAgenttools为空数组;所有工具都来自远程 MCP 服务器,经 Runtime 的 MCP Apps 中间件注入。
  2. Runtime 配置:前端 API 路由创建专用CopilotRuntime,其中mcpApps.servers声明 HTTP 类型的 MCP 服务器;Runtime 会自动把 MCP Apps 中间件应用到所有注册的 Agent 上。
  3. 中间件行为:每次请求时,中间件拉取远程 MCP 服务器的工具列表并暴露给 Agent;当 Agent 调用其中某个工具时,中间件抓取关联的 UI 资源并发出携带该资源的activity事件。
  4. 内置渲染器CopilotKitProvider<CopilotKit>组件)自动注册MCPAppsActivityRenderer,消费activity事件并把 UI 资源渲染为聊天内联的沙箱 iframe。

这套设计把「工具从哪来、UI 怎么画」全部收敛到 MCP 服务器与 Runtime 配置两个位置,前端只剩一个<CopilotChat />

三、后端:零工具的 .NET Agent

3.1 Agent 工厂:ChatClientAgent + 空工具集

后端 Agent 定义在 McpAppsAgent.cs,核心创建逻辑非常克制:

public AIAgent CreateMcpAppsAgent() { // gpt-4o-mini for speed — Excalidraw element emission is simple JSON // and we bias hard toward sub-30s generation. var chatClient = _openAiClient.GetChatClient("gpt-4o-mini").AsIChatClient(); return new ChatClientAgent( chatClient, name: "McpAppsAgent", instructions: SystemPrompt, tools: []); // 关键:不声明任何 bespoke 工具 }

要点:

  • tools: []是刻意为之。源码注释明确写道:"This agent has no bespoke tools — the CopilotKit runtime is wired withmcpApps: { servers: [...] }... The runtime auto-applies the MCP Apps middleware which exposes the remote MCP server's tools to this agent at request time"。即工具集完全由中间件在请求期从远程服务器动态补齐,后端不应重复声明同一批工具。
  • SystemPrompt是一份针对 Excalidraw 场景高度约束的系统提示词(要求一次性create_view调用、3–5 个元素、每个元素唯一id、末尾附带一个cameraUpdate取景、禁止调用read_me等),目的是让轻量模型gpt-4o-mini在数秒内产出"够用"的图,而非精雕细琢。
  • 模型与 API 凭证通过ApiKeyResolver(见 ApiKeyResolver.cs)从配置解析,模型名硬编码为gpt-4o-mini,注释解释了选型理由:Excalidraw 元素输出就是简单 JSON,速度优先。

3.2 挂载 AG-UI 端点

Agent 在 Program.cs 中通过MapAGUI挂载为 AG-UI 兼容端点:

// MCP Apps demo. var mcpAppsFactory = new McpAppsAgentFactory(builder.Configuration, loggerFactory); app.MapAGUI("/mcp-apps", mcpAppsFactory.CreateMcpAppsAgent());

这对应文档中"mounted at/mcp-appsviaProgram.cs"的说明:.NET进程(默认基址http://localhost:8000)在/mcp-apps路径上以 AG-UI 协议对外提供该 Agent。前端 Runtime 通过HttpAgent客户端按 URL 寻址它。

四、Runtime 侧:专用路由与 mcpApps 配置

4.1 路由文件与单路由模式

Runtime 配置位于 route.ts(注意:实际路径是[[...slug]]可选 catch-all 目录,而非普通单文件route.ts)。文件头部注释解释了为什么需要 catch-all:

MCP Apps resource proxy requests are addressed below/api/copilotkit-mcp-apps, so a plainroute.tsat the parent segment handles the chat POST but misses those subpath requests.

也就是说,MCP Apps 的资源代理请求(iframe 加载 UI 资源时的回源请求)落在/api/copilotkit-mcp-apps的子路径下;只用父级的普通route.ts只能接住聊天的 POST,会漏掉这些子路径请求。catch-all 写法同时兼容两种请求,这也是该演示对齐 langgraph-python 参考实现的细节。

路由处理函数使用单路由模式:

export const POST = async (req: NextRequest) => { try { const copilotHandler = createCopilotRuntimeHandler({ runtime, basePath: "/api/copilotkit-mcp-apps", mode: "single-route", }); return await copilotHandler(req); } catch (error: unknown) { // 错误以 JSON 返回(含 message 与 stack),状态码 500 return NextResponse.json({ error: e.message, stack: e.stack }, { status: 500 }); } };

basePath与前端<CopilotKit runtimeUrl="/api/copilotkit-mcp-apps">一一对应。

4.2 mcpApps.servers 是服务端唯一必需配置

完整 Runtime 构造如下(源码中带@region[runtime-mcpapps-config]标记的核心段):

const AGENT_URL = process.env.AGENT_URL || "http://localhost:8000"; const mcpAppsAgent = new HttpAgent({ url: `${AGENT_URL}/mcp-apps/` }); const runtime = new CopilotRuntime({ agents: { "mcp-apps": mcpAppsAgent, "headless-complete": headlessCompleteAgent, // 共享同一 runtime(见下文说明) }, mcpApps: { servers: [ { type: "http", url: process.env.MCP_SERVER_URL || "https://mcp.excalidraw.com", // Keep the server id 1:1 with langgraph-python so persisted MCP Apps // and fixture-backed resource calls use the same identity. serverId: "excalidraw", }, ], }, });

逐项说明:

配置项取值说明
mcpApps.servers[].type"http"MCP 服务器传输类型,此处为 HTTP
mcpApps.servers[].urlMCP_SERVER_URL,默认https://mcp.excalidraw.comHTTP MCP 服务器地址,可通过环境变量指向自建 MCP Apps 服务器
mcpApps.servers[].serverId"excalidraw"(代码实际值)稳定的服务器身份标识,原因见下节
agents["mcp-apps"]HttpAgent指向${AGENT_URL}/mcp-apps/以 AG-UI over HTTP 方式接入 .NET 后端 Agent
AGENT_URL默认http://localhost:8000.NET Agent 进程基址
basePath/mode/api/copilotkit-mcp-apps/single-route单路由模式,所有请求经同一 POST 入口分发

需要指出一个细节差异:演示 README 文中写的是serverId: "mcp_apps_server",而当前仓库代码中实际值为"excalidraw",注释说明这是为了与 langgraph-python 参考实现(mcp_apps_agent 参考 注释中提到的 parity 目标)保持 1:1,使持久化的 MCP Apps 状态和基于 fixture 的资源调用使用同一身份。以源码为准即可。

该路由同时注册了headless-completeAgent(指向${AGENT_URL}/headless-complete)。源码注释解释了共享原因:headless-complete 演示单元也要验证 MCP Apps activity 渲染(其 "Sketch a diagram" 建议经由同一中间件触发 Excalidraw MCP 服务器),因此复用此 runtime,而不是另建端点。

五、前端:零渲染器接线的三行式实现

5.1 页面:一个 Provider 加一个 Chat

page.tsx 的页面组件全部逻辑只有两行核心代码:

export default function MCPAppsDemo() { // @region[no-frontend-renderer-needed] // No `renderActivityMessages`, no `useRenderActivityMessage` — the // CopilotKitProvider auto-registers the built-in `MCPAppsActivityRenderer` // for the "mcp-apps" activity type. A plain <CopilotChat /> is enough. return ( <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> ); // @endregion[no-frontend-renderer-needed] }

文件顶部注释把机制说得很直白:<CopilotKit>指向专用 runtime,agent属性选中 runtime 中注册的"mcp-apps"Agent;不需要renderActivityMessages不需要useRenderActivityMessage,因为 Provider 已为"mcp-apps"活动类型自动注册内置渲染器。

5.2 聊天组件与建议提示

chat.tsx 保持最小形态:

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

suggestions.ts 通过useConfigureSuggestions注入两条固定建议(available: "always"),即第一节提到的两条 Excalidraw 绘图提示。建议消息就是触发 MCP 工具调用的自然语言入口。

六、三条可复用的设计决策

演示文档的 "Building With This" 一节给出了三条实践准则,结合源码可以进一步落实为具体做法:

  1. 前端不需要渲染器MCPAppsActivityRendererCopilotKitProvider自动注册,基础 MCP Apps 场景下useRenderActivityMessage和任何自定义 activity 处理器都不需要——这一点在 page.tsx 的@region[no-frontend-renderer-needed]注释块中有明示。只有当你要定制 iframe 外层样式或行为时,才考虑介入活动消息渲染。
  2. 给 MCP Apps 配专用 runtime 路由。MCP Apps 配置挂在 Runtime 上而非 Agent 上,因此应给它独立的/api/copilotkit-*路由(本例为/api/copilotkit-mcp-apps),使其能与主聊天 runtime 独立演进。注意落地时要用 catch-all([[...slug]])形式,否则资源代理的子路径请求会漏接。
  3. 后端 Agent 工具集保持为空。工具经由中间件从 MCP 服务器注入——不要把 MCP 工具再复制成 bespoke agent 工具。McpAppsAgent.cs 的tools: []就是这条准则的直接体现。

关于serverId固定(pinned server ID)的原理:README 指出,若不显式提供serverId,CopilotKit 会对 URL 做哈希生成身份;一旦 URL 变化,历史会话线程中持久化的 MCP Apps 状态将无法恢复,且这种破坏是"静默"发生的。因此代码中固定serverId: "excalidraw",并同时保持与 langgraph-python 实现一致,保证跨技术栈的身份可比。

七、配置参数与验证方式

环境变量

变量默认值作用
MCP_SERVER_URLhttps://mcp.excalidraw.com指向任意 HTTP MCP Apps 服务器
AGENT_URLhttp://localhost:8000.NET Agent 进程基址,Runtime 据此拼出/mcp-apps/端点

两个变量均在 route.ts 中以process.env.X || 默认值的写法读取,未设置时演示可开箱运行(前提是 .NET Agent 进程与默认端点可用)。

端到端验证

该演示配有 Playwright E2E 用例 mcp-apps.spec.ts(Playwright 配置见 playwright.config.ts)。从源码结构看,E2E 验证覆盖"发送绘图提示 → Agent 调用create_view→ 聊天中出现 Excalidraw iframe"这条完整链路;若仓库内启用了 aimock 录制回放(参见 AimockHeaderContext.cs 等中间件),该链路也可在无真实 LLM 的环境下回放验证。

八、小结

这套 MCP Apps 接线的分工非常清晰:MCP 服务器提供"工具 + UI 资源",Runtime通过mcpApps.servers一条配置声明服务器并自动应用中间件(请求期注入工具、工具调用后发射activity事件),前端仅以<CopilotKit runtimeUrl agent>+<CopilotChat agentId>完成接线。仓库中 ms-agent-dotnet 集成目录 下的 agent/McpAppsAgent.cs、Program.cs、copilotkit-mcp-apps 路由 与 演示页面 共同构成一个可直接参照的最小完整实现;若需扩展到其他 MCP Apps 服务器,只需替换MCP_SERVER_URL并视情况调整serverId与系统提示词即可。

【免费下载链接】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/14 9:20:13

AI重构光模块三温测试:从30分钟到2分钟的系统级突破

1. 光模块三温测试&#xff1a;一个被低估的“时间黑洞”你有没有见过产线工程师蹲在恒温箱前&#xff0c;盯着仪表盘上跳动的数字&#xff0c;一等就是半个多小时&#xff1f;我去年在一家光通信器件厂做产线自动化咨询时&#xff0c;亲眼看到一台价值百万的三温测试设备&…

作者头像 李华
网站建设 2026/9/14 9:19:41

基于SpringBoot的体育馆使用预约平台设计与实现(SpringBoot+Vue+MySQL)

基于SpringBoot的体育馆使用预约平台设计与实现&#xff08;SpringBootVueMySQL&#xff09; 面向综合性体育馆的场地预约平台&#xff1a;篮球场、足球场、羽毛球场等多类场地在线展示&#xff0c;用户按时段预约场地并在线支付&#xff0c;管理员统筹场地、公告与论坛内容。 …

作者头像 李华
网站建设 2026/9/14 9:19:29

从零构建记单词微信小程序:云数据库与本地存储实践

简介&#xff1a;微信小程序期末大作业「记单词小程序」是一份面向初学者的完整项目源码&#xff0c;覆盖微信开发者工具使用、WXML/WXSS页面搭建、JavaScript业务逻辑、数据绑定、生命周期、组件化、网络请求与本地存储等核心知识点&#xff0c;适合作为课程设计或自学练手项目…

作者头像 李华
网站建设 2026/9/14 9:18:29

从ER模型到SQL实现:图书馆管理系统数据库设计实战指南

简介&#xff1a;一套面向高校数据库系统设计课程的图书馆管理系统大作业实现方案&#xff0c;适用于需要完成类似选题或学习Python GUI与数据库交互的开发者。资源内含完整项目文件与文档资料&#xff0c;共711个文件、压缩包大小6.81MB&#xff0c;其中Python源码、HTML页面、…

作者头像 李华
网站建设 2026/9/14 9:16:46

原神配音网站源码解析:TTS语音合成与音频处理全流程

简介&#xff1a;这款“原神”文本转语音网站源码&#xff0c;面向希望生成游戏风格配音的创作者、玩家与开发者&#xff0c;通过集成第三方TTS API&#xff0c;让用户输入文本即可在线合成并下载语音文件&#xff0c;适合二次创作、视频配音或趣味分享。压缩包共5个文件&#…

作者头像 李华