2026/9/14 21:46:25

A2UI in MCP Apps:构建可渲染 A2UI 载荷的单文件 MCP 应用工件

A2UI in MCP Apps:构建可渲染 A2UI 载荷的单文件 MCP 应用工件 A2UI in MCP Apps构建可渲染 A2UI 载荷的单文件 MCP 应用工件【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui导读本文围绕samples/community/mcp/a2ui-in-mcpapps示例中MCP Server 托管应用Hosted Application的构建流程展开讲解如何把一个 Angular 应用编译、内联为单个自包含的app.html工件并让 MCP Server 以ui://资源的形式对外提供、进而在沙箱 iframe 中直接渲染 A2UI JSON 载荷。读完本文你将掌握 MCP Apps 场景下微应用源码 → 构建 → 单文件内联 → 资源化托管的完整链路以及 A2UI 渲染器在其中的接入方式。一、托管应用在示例中的定位在samples/community/mcp/a2ui-in-mcpapps这套参考实现中server/apps/目录承载的是MCP Server 托管的独立应用MCP App。其职责是把原始 A2UI JSON 载荷直接翻译成富交互 UI 渲染结果演示 A2UI 在 MCP 生态中的集成方式。其整体架构包含三个层次client/宿主容器应用Angular承载外层安全 iframeserver/MCP ServerPython/uv提供微应用资源与工具server/apps/被隔离的微应用源码与构建产物其中src/对应Basic计数器应用editor/对应Editor富文本编辑器应用。server/apps/README.md即本文核心文档描述的正是最后一个层次托管应用的目录结构、构建工作流与单文件内联过程。二、目录结构与构建工作流2.1 三个目录的职责划分server/apps/下的目录遵循源码 — 临时构建 — 最终产物三段式布局目录作用Git 状态src/托管应用的源码如 Angular 应用basic-mcp-app-angular纳入版本管理dist/原始构建输出目录Angular 编译结果内联脚本的输入被 git 忽略public/最终打包/内联后的单文件工件输出目录被 git 忽略2.2 三步工作流文档明确给出标准工作流写源码在src/中修改应用代码构建运行src/下的构建脚本编译应用并将资源内联发布构建过程生成一个完全自包含的产物如public/app.html由服务器对外提供。由于dist/与public/均被 git 忽略全新 clone 的仓库中并不包含最终工件——这与示例根 README 中的提示一致server/apps/public/下的工件需要自行构建服务器在缺少该文件时仍能正常启动只是对应 surface 无法加载。三、为什么必须单文件内联MCP App 的安全隔离约束文档指出内联是MCP App 安全隔离要求的产物这类应用通常运行在沙箱化 iframe 中。结合仓库实现可以进一步理解这一约束的根源editor/inline.js 中的注释明确指出现代 Angular 17 默认启用 ES Module 代码分割index.html只引用main.js而main.js依赖外部相对路径的分块如 markdown 渲染器、zone.js 等。当这些文件运行在沙箱化的srcdociframe 中时由于缺少可访问的 base origin浏览器会阻止相对路径请求。server.py 通过resources/read返回整个 HTML 文本宿主将其作为text/html;profilemcp-app资源载入沙箱 iframe——这进一步印证了一切资源必须内联进单个 HTML的必要性。因此内联并非可选项而是让 Angular 应用能在沙箱 iframe 中正常运行的强制性前提。四、内联脚本 inline.js 的工作原理文档介绍了内联过程的三步收集dist/raw的 Angular 构建输出 → 将所有 JS/CSS 动态内联进index.html→ 输出public/app.html。仓库中的 inline.js 给出了具体实现4.1 输入输出node inline.js --input input_dir --output output_file--inputAngular 构建输出目录实际构建中为../dist/raw--output最终单文件路径实际构建中为../public/app.html。脚本会先通过getActualBuildDir()兼容两种输出布局优先查找dir/browser/index.htmlAngular 17 的浏览器目标目录否则回退到dir/index.html。4.2 关键处理步骤JS 内联把script src...替换为script typemodule内联内容/script。其中main.js会被 esbuild 显式打包npx -y esbuild file --bundle --outfilemain.bundled.js --formatesm --allow-overwrite这样能自动遍历所有 ES Module import把代码分割产生的多个 chunk 合并为单一自包含文件editor 版本的 inline.js 对这一 CRITICAL 步骤有更详细的注释说明打包失败时回退为原始文件。移除 source map 引用用正则删除//# sourceMappingURL...行减小体积并避免报错。清理 modulepreloadAngular 会自动注入link relmodulepreload指向动态 chunk由于已被强制打包进main.js这些残留的相对请求会在 iframe 内产生 404/CORS 网络错误因此被整体剔除。CSS 内联把link relstylesheet href...替换为style内容/style。落盘递归创建输出目录并写入app.html最后打印产物字节数。五、构建托管应用的具体命令文档给出在src/目录下的构建命令cd src yarn install yarn build:all这条命令实际执行两个步骤见 src/package.jsonbuild: ng build --output-path../dist/raw --configuration production, inline: node ../inline.js --input ../dist/raw --output ../public/app.html, build:all: yarn run build yarn run inline即先以 production 配置运行 Angular 编译到../dist/raw再触发node inline.js将其单文件内联到public/app.html。对于示例中的第二个应用Editor在 editor/ 目录下执行同样的yarn install yarn build:all其inline脚本输出到../public/editor.html。重要提示由于public/被 git 忽略每次修改src/中的源码后都必须重新执行build:all重新生成工件否则服务器对外提供的仍是旧版本服务器启动本身不依赖该文件存在但对应 surface 将无法渲染。六、托管应用如何消费 A2UI 载荷构建出的单文件应用并不仅仅是静态页面它内置了完整的 A2UI 渲染能力。以 Basic 应用为例其入口 main.ts 展示了关键集成点6.1 启动时注册 A2UI 渲染器bootstrapApplication(McpAppRoot, { providers: [ provideZonelessChangeDetection(), provideA2UI({ catalog: DEFAULT_CATALOG, theme: theme, }), provideMarkdownRenderer(renderMarkdown), ], });provideA2UI使用DEFAULT_CATALOG默认组件目录与自定义主题provideMarkdownRenderer接入 markdown 渲染支持依赖声明见 src/package.jsona2ui/angular与a2ui/markdown-it。6.2 三条核心消息通道组件通过window.parent.postMessage与宿主进行 JSON-RPC 通信main.ts初始化握手发送ui/initialize声明protocolVersion: 2026-01-26与appCapabilities: {availableDisplayModes: [inline]}收到响应后再发送ui/notifications/initialized接收工具结果监听ui/notifications/tool-result从content中筛选application/a2uijson或application/jsona2ui类型的EmbeddedResource解析为消息数组后交给processor.processMessages()渲染动作路由订阅MessageProcessor事件流捕获 A2UI 组件产生的userAction将其映射为tools/call请求转发给宿主再把返回结果回灌给处理器更新 UI。6.3 界面模板main.html 提供了获取计数器 A2UI按钮、状态徽章与 A2UI 渲染 surfacea2ui-surface并带有一个用于调试的原始 JSON 展示区。七、服务器端如何对接该工件托管应用的消费端是 server.py资源声明resources/list暴露ui://basic/app与ui://editor/appMIME 类型为text/html;profilemcp-appserver.py资源读取resources/read按 URI 映射到apps/public/app.html或apps/public/editor.html并返回文件文本server.py注释强调 MCP Apps 要求resources/read的返回内容也必须携带text/html;profilemcp-appMIME 类型工具声明get_basic_app通过_meta.ui.resourceUri ui://basic/app预声明 UI 模板宿主用resources/read获取模板而不会在工具结果中内嵌资源fetch_counter_a2ui返回 simple_counter_a2ui.json 中定义的初始 A2UI 载荷dataModelUpdatesurfaceUpdatebeginRendering三段消息包含 Card/Column/Text/Button 组件树与increase_counter动作increase_counter累加内存计数器并返回dataModelUpdate更新counter值server.py。由此形成完整闭环宿主tools/call→ 服务器返回 A2UI JSON → 宿主经沙箱代理转发给 MCP App → Angular 应用MessageProcessor解析渲染 → 用户点击 A2UI Button 触发userAction→ 应用映射为tools/call回传服务器 → 服务器返回dataModelUpdate→ 界面增量更新。八、运行与验证按示例根 README 的步骤即可端到端验证整个链路前提仓库根目录已执行过yarn install链接 workspace 包构建微应用至少构建一个否则对应 surface 无法加载cd server/apps/src yarn install yarn build:all # 生成 server/apps/public/app.html启动 MCP Servercd server uv sync uv run python server.py --transport sse --port 8000也可使用--transport stdio走标准输入输出。启动宿主客户端cd client yarn start访问http://localhost:4200点击宿主界面中的 CTA即可看到沙箱 iframe 内的 Basic 应用渲染出由fetch_counter_a2ui返回的计数器 A2UI 界面点击 Increase counter 按钮后数字随increase_counter工具的dataModelUpdate实时递增。九、小结server/apps/README.md所描述的托管应用构建流程是 MCP Apps A2UI 集成方案中承上启下的关键一环目录上src/源码、dist/中间构建、public/单文件工件三者职责清晰、git 策略明确构建上ng buildinline.jsesbuild 打包 JS/CSS 内联 modulepreload 清理产出完全自包含的app.html满足沙箱 iframe 无法发起相对请求的安全约束运行上服务器以text/html;profilemcp-app资源形式对外提供应用内部通过 JSON-RPC 与宿主握手、接收 A2UI 载荷、回传用户动作构成可交互的富 UI 闭环。对希望在自己项目中复刻隔离化 MCP 微应用 A2UI 渲染模式的开发者而言inline.js、main.ts 与 server.py 三份文件分别对应构建、渲染、服务三个维度可作为最小可运行参考直接借鉴。【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考