ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

A2UI 驱动的生成式文档编辑器 Micro-App:基于 Angular + Editor.js 的 MCP App 构建与本地运行指南

A2UI 驱动的生成式文档编辑器 Micro-App:基于 Angular + Editor.js 的 MCP App 构建与本地运行指南 A2UI 驱动的生成式文档编辑器 Micro-App基于 Angular Editor.js 的 MCP App 构建与本地运行指南【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui本篇技术指南围绕开源仓库 a2ui 中samples/community/mcp/a2ui-in-mcpapps/server/apps/editor的 README 展开系统讲解如何构建并本地运行一个「由 A2UI 驱动、基于 Angular 与 Editor.js 的生成式文档编辑器」微应用。读者将掌握该微应用的产物形态单文件 HTML 静态包、完整的构建命令链yarn build:all、build:sandbox、双终端启动 MCP ServerPython/uv与宿主 Web 应用Angular的完整流程以及编辑器如何通过 MCP App 协议在隔离 iframe 中渲染 A2UI 交互控件。一、项目背景编辑器微应用在整体架构中的位置该编辑器是整个a2ui-in-mcpapps示例工程中的两个隔离微应用之一另一个是位于server/apps/src/的 Basic 计数器应用。整个示例的核心目标是在 Model Context ProtocolMCP生态中演示「MCP App」这一新形态由 Python 编写的 MCP Server 将一个独立、自包含的静态应用作为资源resource暴露给宿主容器宿主通过双重 iframe 代理模式隔离地加载并安全渲染这个不可信的第三方组件。从 顶层 README 的目录划分可以看到清晰的职责边界client/宿主容器应用Angular负责承载外层安全 iframeserver/MCP ServerPython/uv提供微应用资源与工具server/apps/src/Basic 隔离微应用源码server/apps/editor/本文主角——Editor 隔离微应用源码。本文所依据的 编辑器 README 明确说明了它的定位一个基于 Angular 和 Editor.js 的生成式文档编辑器微应用被构建为独立的静态 bundle由 MCP Server 作为隔离资源提供以便在宿主容器内安全渲染。需要特别注意的是这个编辑器不是普通的富文本编辑器而是一个「生成式」编辑器用户在文档画布上选中一段文本侧边栏会动态生成一套 AI 调参控件滑块、复选框、下拉选择调节后即可让大模型按指定的风格方向重写该段落。二、前置条件Node.js 与仓库依赖2.1 Node.js推荐 LTS v20 或 v22按照 README 的要求本地环境需要安装 Node.js推荐 LTS v20 或 v22。如果node命令不在 PATH 中README 建议通过 NVMNode Version Manager安装# 下载并安装 NVMREADME 使用的版本为 v0.40.1按 NVM 官方安装脚本安装 curl -o- nvm 官方安装脚本 | bash # 刷新终端环境 source ~/.bashrc # 安装 LTS 版本 Node.js nvm install --lts2.2 安装仓库依赖由于本示例依赖仓库内的 workspace 包例如编辑器依赖的a2ui/angularREADME 强调必须从仓库根目录执行一次依赖链接yarn install这一步在根目录完成 workspace 链接后后续在editor子目录单独执行yarn install时才能正确解析a2ui/angular、a2ui/markdown-it等工作区依赖。三、本地执行工作流三步构建与启动README 给出了完整的本地执行流程概括为「构建编辑器 bundle → 准备宿主环境资源 → 启动服务」。下面按原文档步骤逐一展开。Step 1构建编辑器 App Bundle在编辑器源码目录仓库相对路径samples/community/mcp/a2ui-in-mcpapps/server/apps/editor内执行# 安装本目录的包依赖 yarn install # 构建 Angular 工程并生成单个自包含 HTML 文件 yarn build:all最终产物输出到server/apps/public/editor.html该文件正是 Python 服务端读取并对外提供的资源。要理解build:all干了什么可以查看 package.json 中的脚本定义scripts: { build: ng build --output-path../dist/raw --configuration production, inline: node ../inline.js --input ../dist/raw --output ../public/editor.html, build:all: yarn run build yarn run inline }即build:allng buildAngular 生产构建到../dist/rawnode ../inline.js内联处理生成单文件editor.html。这一步背后是 MCP App 安全隔离要求的关键应用必须能被沙箱 iframe 以单个自包含文件加载。../inline.js即 inline.js做了三件事内联 JS把index.html中所有带src的外部script替换为script typemodule内联内容其中main.js还会先用npx esbuild --bundle做一次打包再内联其余脚本直接读取文件内容并统一剥离//# sourceMappingURL注释清理 modulepreload移除 Angular 自动注入的link relmodulepreload动态块预加载标签内联 CSS把link relstylesheet全部替换为style标签。Step 2构建客户端宿主桥仅需一次宿主容器需要它的安全沙箱桥资源切换到客户端宿主目录执行cd ../../../client yarn install yarn build:sandbox说明从编辑器目录向上三级即samples/community/mcp/a2ui-in-mcpapps/client。该命令生成宿主所需的 sandbox iframe 资源包。这一步骤是仅需一次的sandbox 桥属于宿主侧基础设施除非其源码被修改否则无需每次重新构建。Step 3运行完整本地环境README 要求开两个终端分别启动栈的两端终端 A运行 MCP ServerPythoncd samples/mcp/a2ui-in-mcpapps/server uv sync uv run python server.py --transport sse --port 8000仓库相对路径为samples/community/mcp/a2ui-in-mcpapps/server--transport sse与--port 8000也是默认值直接uv run python server.py亦可。终端 B运行宿主 Web 应用Angularcd samples/mcp/a2ui-in-mcpapps/client yarn start访问应用浏览器打开http://localhost:4200宿主容器会自动加载并通过 MCP Server 连接载入这个 Editor 微应用。四、编辑器微应用的内部机制从 MCP App 协议到 A2UI 渲染构建流程之外理解「编辑器如何工作」是深入使用本示例的关键。核心源码在 src/main.ts主组件McpAppRoot是一个 standalone Angular 组件通过bootstrapApplication启动并注入了a2ui/angular的MessageProcessor与SurfacebootstrapApplication(McpAppRoot, { providers: [ provideZonelessChangeDetection(), provideA2UI({ catalog: DEFAULT_CATALOG, theme: theme, }), provideMarkdownRenderer(renderMarkdown), ], }).catch(err console.error(err));依赖上见 package.json该应用组合了a2ui/angular、a2ui/markdown-itMarkdown 渲染器、editorjs/editorjs与editorjs/paragraph并采用 Angular 21 的 zoneless 变更检测。模板结构main.html是典型的双栏布局左侧#editorjs-container文档画布右侧a2ui-surface渲染 A2UI 生成式侧边栏底部还有rawJson的 JSON 调试区。4.1 与宿主的 MCP App 握手应用启动后立刻执行两件事ngOnInitinitializeHandshake()向window.parent发送ui/initialize消息JSON-RPC 2.0携带protocolVersion: 2026-01-26、clientInfo与appCapabilities: {availableDisplayModes: [inline]}收到init-1应答后再发送ui/notifications/initializedsetupActionRouting()订阅MessageProcessor的事件流监听来自 A2UI 控件的userAction。同时ngAfterViewInit中启动ResizeObserver通过ui/notifications/size-changed通知宿主侧边栏尺寸变化保证宿主能正确排版隔离 iframe。所有与宿主通信都通过window.parent.postMessage(msg, http://localhost:4200)完成。4.2 文本选中 → 动态生成 AI 调参控件这是整个编辑器最有特色的交互闭环用户在 Editor.js 画布上选中一段文本≥10 字符且光标确实位于editorjs-container内checkTextSelection()拿到当前 block 的完整文本调用fetchTuningControls(text, fullText)应用向父窗口发送tools/call请求调用名为smart_editor_get_controls的工具参数为{text, full_text}收到响应后从content中提取 MIME 类型为application/a2uijson或application/jsona2ui的 resourceJSON.parse出 A2UI 消息数组调用processor.clearSurfaces()与processor.processMessages(messages)让Surface组件渲染出侧边栏控件状态置为UI Generated。4.3 A2UI 控件动作 → 文本重写 → 接受/拒绝setupActionRouting()中按action.name分发smart_editor_accept/smart_editor_reject直接调handleAccept()/handleReject()smart_editor_apply先从MessageProcessor的 surface data model 中取出所有滑块/输入值再合并action.context构造tools/call请求发送给宿主。响应分两种情形处理情形 A返回的是标准 A2UI 资源链式动作则processMessages继续渲染情形 B返回纯文本smart_editor_apply的重写结果则handleTextRevision(text)解析 JSON{text_before, original_text, revised_text, text_after}用mark classoriginal/mark classrevised高亮差异并更新到 Editor.js 当前 block。随后showAcceptRejectButtons()通过processor.processMessages注入一个「Revision Options」surfaceCard Column Text 两个 Button分别绑定smart_editor_accept与smart_editor_reject动作。接受时用text_before revised_text text_after回写文档拒绝时则回滚为text_before original_text text_after操作后调用clearSurfaces()收起侧边栏。五、服务端与智能编辑 Agent工具与资源如何支撑编辑器编辑器自身并不内置任何 AI 逻辑它只是 MCP App 协议中的一个瘦客户端真正的「智能」在服务端。5.1 MCP Server 暴露的资源与工具查看 server.py 可以看到服务端通过list_resources暴露了ui://basic/app与ui://editor/app两个资源MIME 类型均为text/html;profilemcp-appread_resource会从apps/public/读取对应 HTML 文件返回。编辑器相关工具包括工具名说明get_editor_app打开 Editor A2UI 应用视图_meta.ui.resourceUri预声明ui://editor/app模板visibility: [model]smart_editor_get_controls基于高亮文本生成 A2UI 调参控件入参text必填、full_textsmart_editor_apply提交用户调节后的参数经 Gemini 重写文本返回纯文本结果值得一提的是get_basic_app/fetch_counter_a2ui/increase_counter是 Basic 计数器应用的配套工具而increase_counter返回的是dataModelUpdate形式的 A2UI 增量更新可作为对照参考。5.2 智能编辑 AgentGemini 驱动的控件生成与文本重写smart_editor_agent.py 承担了全部 AI 工作通过google-genai客户端调用模型默认gemini-2.5-flash可通过环境变量GENAI_MODEL覆盖API Key 从.env读取GOOGLE_API_KEY。generate_controls(text, full_text)的工作流程定义 JSON Schema要求模型输出initial_thought1~2 句创作方向启发controls数组2~3 个控件控件type枚举为slider/select/checkbox滑块标签必须遵循X vs. Y命名如 Academic vs. Casualselect必须携带options列表调用 Geminiresponse_mime_typeapplication/jsonresponse_schema结构化输出失败或列表为空时回退到DEFAULT_CONTROLSVerbose vs. Concise、Standard vs. Punchy 两个滑块控件数上限 3 个组装 A2UI 消息构造三条消息——dataModelUpdate初始化summary_text、original_text、full_text及各控件默认值滑块valueNumber: 50、复选框valueBoolean: false、下拉valueString为 JSON 化的{literalArray: [...]}、surfaceUpdate组件清单Card 根节点、标题、摘要文本、Divider、滑块Slider{minValue:0, maxValue:100}、复选框CheckBox、下拉MultipleChoice以及末尾的 Generate RevisionButton其action.context携带control_config_json、beginRenderingsurfaceIdeditor-controlsrootroot。apply_revision(text, user_parameters)则把用户在 A2UI 侧边栏调好的参数重新拼装成自然语言调节说明如- Verbose vs. Concise: 0.80 (0 meaning low/minimum expression, 1 meaning high/maximum)连同full_text一起交给 Gemini用结构化 Schema 要求模型返回{text_before, original_text, revised_text, text_after}四段式 JSON从而支撑前文所述的差异高亮与接受/拒绝回滚机制。六、产物说明与常见检查点单文件产物yarn build:all输出的server/apps/public/editor.html是 git-ignored 的构建产物全新 checkout 的仓库中并不存在服务端即使没有它也能正常启动但编辑器 surface 无法加载——因此首次使用必须先构建。同理宿主 sandbox 桥client/public/sandbox_iframe/sandbox.{js,html}也需要先由yarn build:sandbox生成详见 顶层 README。目录职责src/是源码dist/是 Angular 原始构建的临时输出public/是最终内联产物目录。修改源码后必须重新执行build:all才能让服务端读到新内容见 apps 目录 README。环境变量AI 能力依赖GOOGLE_API_KEY.env文件由dotenv加载与可选GENAI_MODEL未配置时编辑器仍可构建运行但侧边栏控件生成与文本重写会走异常回退路径。CORS 提示server.py的 SSE 模式默认allow_origins[*]源码注释明确警告生产环境应收紧为宿主来源如http://localhost:4200。至此从 Node.js 环境准备、三步构建启动到编辑器与 MCP Server、Gemini Agent 之间的完整交互链路均已在你本地的 a2ui 仓库中可复现。若需对照另一侧更基础的实现可阅读同目录下的 Basic 微应用 与 服务端说明 加深理解。【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进