A2UI 驱动的生成式文档编辑器 Micro-App:基于 Angular + Editor.js 的 MCP App 构建与本地运行指南
2026/9/15 5:10:30 网站建设 项目流程

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:allbuild:sandbox)、双终端启动 MCP Server(Python/uv)与宿主 Web 应用(Angular)的完整流程,以及编辑器如何通过 MCP App 协议在隔离 iframe 中渲染 A2UI 交互控件。

一、项目背景:编辑器微应用在整体架构中的位置

该编辑器是整个a2ui-in-mcpapps示例工程中的两个隔离微应用之一(另一个是位于server/apps/src/的 Basic 计数器应用)。整个示例的核心目标,是在 Model Context Protocol(MCP)生态中演示「MCP App」这一新形态:由 Python 编写的 MCP Server 将一个独立、自包含的静态应用作为资源(resource)暴露给宿主容器,宿主通过双重 iframe 代理模式隔离地加载并安全渲染这个不可信的第三方组件。

从 顶层 README 的目录划分可以看到清晰的职责边界:

  • client/:宿主容器应用(Angular),负责承载外层安全 iframe;
  • server/:MCP Server(Python/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 建议通过 NVM(Node Version Manager)安装:

# 下载并安装 NVM(README 使用的版本为 v0.40.1,按 NVM 官方安装脚本安装) curl -o- <nvm 官方安装脚本> | bash # 刷新终端环境 source ~/.bashrc # 安装 LTS 版本 Node.js nvm install --lts

2.2 安装仓库依赖

由于本示例依赖仓库内的 workspace 包(例如编辑器依赖的@a2ui/angular),README 强调必须从仓库根目录执行一次依赖链接:

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:all=ng build(Angular 生产构建到../dist/raw)+node ../inline.js(内联处理生成单文件editor.html)。这一步背后是 MCP App 安全隔离要求的关键:应用必须能被沙箱 iframe 以单个自包含文件加载。../inline.js(即 inline.js)做了三件事:

  1. 内联 JS:把index.html中所有带src的外部<script>替换为<script type="module">内联内容;其中main.js还会先用npx esbuild --bundle做一次打包再内联,其余脚本直接读取文件内容,并统一剥离//# sourceMappingURL注释;
  2. 清理 modulepreload:移除 Angular 自动注入的<link rel="modulepreload">动态块预加载标签;
  3. 内联 CSS:把<link rel="stylesheet">全部替换为<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 Server(Python)
cd 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 应用(Angular)
cd 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/angularMessageProcessorSurface

bootstrapApplication(McpAppRoot, { providers: [ provideZonelessChangeDetection(), provideA2UI({ catalog: DEFAULT_CATALOG, theme: theme, }), provideMarkdownRenderer(renderMarkdown), ], }).catch(err => console.error(err));

依赖上(见 package.json),该应用组合了@a2ui/angular@a2ui/markdown-it(Markdown 渲染器)、@editorjs/editorjs@editorjs/paragraph,并采用 Angular 21 的 zoneless 变更检测。模板结构(main.html)是典型的双栏布局:左侧#editorjs-container文档画布,右侧a2ui-surface渲染 A2UI 生成式侧边栏,底部还有rawJson的 JSON 调试区。

4.1 与宿主的 MCP App 握手

应用启动后立刻执行两件事(ngOnInit):

  1. initializeHandshake():向window.parent发送ui/initialize消息(JSON-RPC 2.0),携带protocolVersion: '2026-01-26'clientInfoappCapabilities: {availableDisplayModes: ['inline']};收到init-1应答后再发送ui/notifications/initialized
  2. setupActionRouting():订阅MessageProcessor的事件流,监听来自 A2UI 控件的userAction

同时ngAfterViewInit中启动ResizeObserver,通过ui/notifications/size-changed通知宿主侧边栏尺寸变化,保证宿主能正确排版隔离 iframe。所有与宿主通信都通过window.parent.postMessage(msg, 'http://localhost:4200')完成。

4.2 文本选中 → 动态生成 AI 调参控件

这是整个编辑器最有特色的交互闭环:

  1. 用户在 Editor.js 画布上选中一段文本(≥10 字符,且光标确实位于editorjs-container内);
  2. checkTextSelection()拿到当前 block 的完整文本,调用fetchTuningControls(text, fullText)
  3. 应用向父窗口发送tools/call请求,调用名为smart_editor_get_controls的工具,参数为{text, full_text}
  4. 收到响应后,从content中提取 MIME 类型为application/a2ui+json(或application/json+a2ui)的 resource,JSON.parse出 A2UI 消息数组;
  5. 调用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 class="original">/<mark class="revised">高亮差异并更新到 Editor.js 当前 block。

随后showAcceptRejectButtons()通过processor.processMessages注入一个「Revision Options」surface(Card + Column + Text + 两个 Button),分别绑定smart_editor_acceptsmart_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/appui://editor/app两个资源(MIME 类型均为text/html;profile=mcp-app),read_resource会从apps/public/读取对应 HTML 文件返回。编辑器相关工具包括:

工具名说明
get_editor_app打开 Editor A2UI 应用视图,_meta.ui.resourceUri预声明ui://editor/app模板(visibility: ["model"]
smart_editor_get_controls基于高亮文本生成 A2UI 调参控件,入参text(必填)、full_text
smart_editor_apply提交用户调节后的参数,经 Gemini 重写文本,返回纯文本结果

值得一提的是get_basic_app/fetch_counter_a2ui/increase_counter是 Basic 计数器应用的配套工具,而increase_counter返回的是dataModelUpdate形式的 A2UI 增量更新,可作为对照参考。

5.2 智能编辑 Agent:Gemini 驱动的控件生成与文本重写

smart_editor_agent.py 承担了全部 AI 工作,通过google-genai客户端调用模型(默认gemini-2.5-flash,可通过环境变量GENAI_MODEL覆盖,API Key 从.env读取GOOGLE_API_KEY)。

generate_controls(text, full_text)的工作流程:

  1. 定义 JSON Schema:要求模型输出initial_thought(1~2 句创作方向启发)+controls数组(2~3 个控件),控件type枚举为slider/select/checkbox;滑块标签必须遵循"X vs. Y"命名(如 "Academic vs. Casual"),select必须携带options列表;
  2. 调用 Geminiresponse_mime_type="application/json"+response_schema结构化输出);失败或列表为空时回退到DEFAULT_CONTROLS("Verbose vs. Concise"、"Standard vs. Punchy" 两个滑块),控件数上限 3 个;
  3. 组装 A2UI 消息:构造三条消息——dataModelUpdate(初始化summary_textoriginal_textfull_text及各控件默认值:滑块valueNumber: 50、复选框valueBoolean: false、下拉valueString为 JSON 化的{"literalArray": [...]})、surfaceUpdate(组件清单:Card 根节点、标题、摘要文本、Divider、滑块Slider{minValue:0, maxValue:100}、复选框CheckBox、下拉MultipleChoice,以及末尾的 "Generate Revision"Button,其action.context携带control_config_json)、beginRendering(surfaceIdeditor-controls,rootroot)。

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),仅供参考

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

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

立即咨询