
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 服务器提供的 UIExcalidraw 画布以沙箱 iframe 形式渲染进聊天流且前端一行渲染器注册代码都不用写。读完本文你可以复现「后端零工具、前端零渲染器」的 MCP Apps 集成链路并理解serverId固定、专用 runtime 路由等关键设计决策的原因。一、MCP Apps 演示要解决的问题MCP Apps 指的是一类特殊的 MCPModel 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 一节可以提炼出这条链路的四个环节每个环节在仓库中都有对应实现.NET Agent 后端无自定义工具agent/McpAppsAgent.cs暴露一个裸的ChatClientAgenttools为空数组所有工具都来自远程 MCP 服务器经 Runtime 的 MCP Apps 中间件注入。Runtime 配置前端 API 路由创建专用CopilotRuntime其中mcpApps.servers声明 HTTP 类型的 MCP 服务器Runtime 会自动把 MCP Apps 中间件应用到所有注册的 Agent 上。中间件行为每次请求时中间件拉取远程 MCP 服务器的工具列表并暴露给 Agent当 Agent 调用其中某个工具时中间件抓取关联的 UI 资源并发出携带该资源的activity事件。内置渲染器CopilotKitProviderCopilotKit组件自动注册MCPAppsActivityRenderer消费activity事件并把 UI 资源渲染为聊天内联的沙箱 iframe。这套设计把「工具从哪来、UI 怎么画」全部收敛到 MCP 服务器与 Runtime 配置两个位置前端只剩一个CopilotChat /。三、后端零工具的 .NET Agent3.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 servers 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-allMCP 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[].typehttpMCP 服务器传输类型此处为 HTTPmcpApps.servers[].urlMCP_SERVER_URL默认https://mcp.excalidraw.comHTTP MCP 服务器地址可通过环境变量指向自建 MCP Apps 服务器mcpApps.servers[].serverIdexcalidraw代码实际值稳定的服务器身份标识原因见下节agents[mcp-apps]HttpAgent指向${AGENT_URL}/mcp-apps/以 AG-UI over HTTP 方式接入 .NET 后端 AgentAGENT_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 加一个 Chatpage.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 agentmcp-apps div classNameflex justify-center items-center h-screen w-full div classNameh-full w-full max-w-4xl Chat / /div /div /CopilotKit ); // endregion[no-frontend-renderer-needed] }文件顶部注释把机制说得很直白CopilotKit指向专用 runtimeagent属性选中 runtime 中注册的mcp-appsAgent不需要renderActivityMessages、不需要useRenderActivityMessage因为 Provider 已为mcp-apps活动类型自动注册内置渲染器。5.2 聊天组件与建议提示chat.tsx 保持最小形态export function Chat() { useMcpAppsSuggestions(); return CopilotChat agentIdmcp-apps classNameh-full rounded-2xl /; }suggestions.ts 通过useConfigureSuggestions注入两条固定建议available: always即第一节提到的两条 Excalidraw 绘图提示。建议消息就是触发 MCP 工具调用的自然语言入口。六、三条可复用的设计决策演示文档的 Building With This 一节给出了三条实践准则结合源码可以进一步落实为具体做法前端不需要渲染器。MCPAppsActivityRenderer由CopilotKitProvider自动注册基础 MCP Apps 场景下useRenderActivityMessage和任何自定义 activity 处理器都不需要——这一点在 page.tsx 的region[no-frontend-renderer-needed]注释块中有明示。只有当你要定制 iframe 外层样式或行为时才考虑介入活动消息渲染。给 MCP Apps 配专用 runtime 路由。MCP Apps 配置挂在 Runtime 上而非 Agent 上因此应给它独立的/api/copilotkit-*路由本例为/api/copilotkit-mcp-apps使其能与主聊天 runtime 独立演进。注意落地时要用 catch-all[[...slug]]形式否则资源代理的子路径请求会漏接。后端 Agent 工具集保持为空。工具经由中间件从 MCP 服务器注入——不要把 MCP 工具再复制成 bespoke agent 工具。McpAppsAgent.cs 的tools: []就是这条准则的直接体现。关于serverId固定pinned server ID的原理README 指出若不显式提供serverIdCopilotKit 会对 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.tsPlaywright 配置见 playwright.config.ts。从源码结构看E2E 验证覆盖发送绘图提示 → Agent 调用create_view→ 聊天中出现 Excalidraw iframe这条完整链路若仓库内启用了 aimock 录制回放参见 AimockHeaderContext.cs 等中间件该链路也可在无真实 LLM 的环境下回放验证。八、小结这套 MCP Apps 接线的分工非常清晰MCP 服务器提供工具 UI 资源Runtime通过mcpApps.servers一条配置声明服务器并自动应用中间件请求期注入工具、工具调用后发射activity事件前端仅以CopilotKit runtimeUrl agentCopilotChat 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),仅供参考