A2UI in MCP Apps:构建可渲染 A2UI 载荷的单文件 MCP 应用工件
2026/9/14 21:46:23 网站建设 项目流程

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),承载外层安全 iframe;
  • server/:MCP Server(Python/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 三步工作流

文档明确给出标准工作流:

  1. 写源码:在src/中修改应用代码;
  2. 构建:运行src/下的构建脚本,编译应用并将资源内联;
  3. 发布:构建过程生成一个完全自包含的产物(如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;profile=mcp-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>
  • --input:Angular 构建输出目录(实际构建中为../dist/raw);
  • --output:最终单文件路径(实际构建中为../public/app.html)。

脚本会先通过getActualBuildDir()兼容两种输出布局:优先查找<dir>/browser/index.html(Angular 17+ 的浏览器目标目录),否则回退到<dir>/index.html

4.2 关键处理步骤

  1. JS 内联:把<script src="...">替换为<script type="module">内联内容</script>。其中main.js会被 esbuild 显式打包:

    npx -y esbuild "<file>" --bundle --outfile="main.bundled.js" --format=esm --allow-overwrite

    这样能自动遍历所有 ES Module import,把代码分割产生的多个 chunk 合并为单一自包含文件(editor 版本的 inline.js 对这一 "CRITICAL" 步骤有更详细的注释说明);打包失败时回退为原始文件。

  2. 移除 source map 引用:用正则删除//# sourceMappingURL=...行,减小体积并避免报错。

  3. 清理 modulepreload:Angular 会自动注入<link rel="modulepreload">指向动态 chunk,由于已被强制打包进main.js,这些残留的相对请求会在 iframe 内产生 404/CORS 网络错误,因此被整体剔除。

  4. CSS 内联:把<link rel="stylesheet" href="...">替换为<style>内容</style>

  5. 落盘:递归创建输出目录并写入app.html,最后打印产物字节数。


五、构建托管应用的具体命令

文档给出在src/目录下的构建命令:

cd src yarn install yarn build:all

这条命令实际执行两个步骤(见 src/package.json):

"build": "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.json(@a2ui/angular@a2ui/markdown-it)。

6.2 三条核心消息通道

组件通过window.parent.postMessage与宿主进行 JSON-RPC 通信(main.ts):

  1. 初始化握手:发送ui/initialize,声明protocolVersion: '2026-01-26'appCapabilities: {availableDisplayModes: ['inline']},收到响应后再发送ui/notifications/initialized
  2. 接收工具结果:监听ui/notifications/tool-result,从content中筛选application/a2ui+json(或application/json+a2ui)类型的EmbeddedResource,解析为消息数组后交给processor.processMessages()渲染;
  3. 动作路由:订阅MessageProcessor事件流,捕获 A2UI 组件产生的userAction,将其映射为tools/call请求转发给宿主,再把返回结果回灌给处理器更新 UI。

6.3 界面模板

main.html 提供了"获取计数器 A2UI"按钮、状态徽章与 A2UI 渲染 surface(<a2ui-surface>),并带有一个用于调试的原始 JSON 展示区。


七、服务器端如何对接该工件

托管应用的消费端是 server.py:

  • 资源声明resources/list暴露ui://basic/appui://editor/app,MIME 类型为text/html;profile=mcp-app(server.py);
  • 资源读取resources/read按 URI 映射到apps/public/app.htmlapps/public/editor.html并返回文件文本(server.py),注释强调 MCP Apps 要求resources/read的返回内容也必须携带text/html;profile=mcp-appMIME 类型;
  • 工具声明get_basic_app通过_meta.ui.resourceUri = "ui://basic/app"预声明 UI 模板,宿主用resources/read获取模板而不会在工具结果中内嵌资源;fetch_counter_a2ui返回 simple_counter_a2ui.json 中定义的初始 A2UI 载荷(dataModelUpdate+surfaceUpdate+beginRendering三段消息,包含 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 包):

  1. 构建微应用(至少构建一个,否则对应 surface 无法加载):

    cd server/apps/src yarn install yarn build:all # 生成 server/apps/public/app.html
  2. 启动 MCP Server

    cd server uv sync uv run python server.py --transport sse --port 8000

    (也可使用--transport stdio走标准输入输出。)

  3. 启动宿主客户端

    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 build+inline.js(esbuild 打包 + JS/CSS 内联 + modulepreload 清理)产出完全自包含的app.html,满足沙箱 iframe 无法发起相对请求的安全约束;
  • 运行上,服务器以text/html;profile=mcp-app资源形式对外提供,应用内部通过 JSON-RPC 与宿主握手、接收 A2UI 载荷、回传用户动作,构成可交互的富 UI 闭环。

对希望在自己项目中复刻"隔离化 MCP 微应用 + A2UI 渲染"模式的开发者而言,inline.js、main.ts 与 server.py 三份文件分别对应构建、渲染、服务三个维度,可作为最小可运行参考直接借鉴。

【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询