> ## Documentation Index
> Fetch the complete documentation index at: https://agent.minimaxi.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 架构概览

> Mini App 由哪些部分组成、它们怎么通信，以及一次完整调用的全过程。

## 范围

* **包格式：**一个普通的 MiniMax Plugin 包，加上一份 `miniapp.json` 声明，见[包结构与清单](/docs/miniapp/authors/package)。
* **宿主运行时：**MiniMax Code 桌面端里负责发布、启动、鉴权和回收 Mini App 的部分，见[运行与更新](/docs/miniapp/host/lifecycle)。
* **宿主接口：**Node 侧的 `start(context)`、`context.agent`、`context.hostConnector`，页面侧的 `window.mcode.miniapp`。
* **创建 Skill：**/miniapp-creator，指导 Agent 验证数据、编写、发布和验收，见[用 Agent 构建](/docs/miniapp/authors/quickstart)。

> [!NOTE]
>
> Mini App 只规定运行环境和宿主接口。页面用什么技术栈、业务数据怎么存，由插件决定；宿主也不替插件做操作系统级隔离，见[安全模型](/docs/miniapp/host/security)。

## 核心概念

### 参与方

* **宿主：**MiniMax Code 桌面端。它校验并发布插件包，启动 Node 进程、分配端口、签发凭据，在会话侧栏显示页面，并按清单声明开放 Agent 和 Connector 能力。
* **Mini App 页面：**运行在宿主内置浏览器里的网页，显示在会话侧栏的标签里，也可以弹出成独立窗口。页面只和自己的 Node 服务通信。
* **Mini App Node 服务：**插件的后端。每个插件一个进程，监听宿主分配的本机端口，负责业务逻辑、数据和托管 MCP 工具。即使只有一页 HTML，也由它来提供。
* **Agent：**会话里的 Agent 通过宿主的 MCP 客户端调用 Mini App 的工具；Mini App 也可以通过 Agent API 发起自己的 Agent 会话。

![Mini App 架构](https://mintcdn.com/agent-cn/cVBevhAJXWhxEBzo/images/miniapp/architecture-zh.svg?fit=max\&auto=format\&n=cVBevhAJXWhxEBzo\&q=85\&s=27d8ffaa368b6bcf23fcf8a58bc9dd59)

**举个例子：**你在会话里 `@` 股市 Mini App，宿主为它启动一个 Node 进程，并在侧栏打开它的页面。之后你在另一个会话里再打开它，宿主不会再起一个进程，两个页面连的是同一个服务、同一份数据，见 [Mini App 与会话](/docs/miniapp/sessions)。

### 分层

* **展示层（页面）：**HTML、CSS、JavaScript，负责筛选、表格、图表和交互。页面不持有任何凭证。
* **应用层（Node 服务）：**数据聚合、业务规则和持久化。页面接口和 Agent 工具复用同一套业务服务，所以人和 Agent 改的是同一份数据。
* **能力层：**宿主提供的 Agent API、Host Connector 和托管 MCP 接入，以及插件自己访问的命令行、HTTP API 和本地文件。

宿主的管理贯穿三层：它决定进程什么时候运行、谁能访问端口、哪些能力可以用，而业务逻辑始终归插件所有。

### 通信方式

| 谁 → 谁 | 通道 | 身份怎么确认 |
| - | - | - |
| 页面 → Node 服务 | 本机 HTTP，用相对地址或同源 URL | 宿主主进程核对页面的真实来源，再补上本次运行的凭据 |
| 会话 Agent → Node 服务 | 托管 MCP（Streamable HTTP） | 宿主的 MCP 客户端把凭据放在请求头里，不写进配置 |
| Node 服务 → 宿主 | IPC：`context.agent`、`context.hostConnector` | 宿主按进程身份和清单里的授权判断 |
| 页面 → 宿主 | preload 注入的 `window.mcode.miniapp` | 按 Electron 报告的真实页面核对，不采信页面自报的信息 |
| Node 服务 → 外部 | 插件自己发起：命令行、HTTP API、文件 | 由插件自己处理，宿主不额外设关卡 |

### 生命周期

Mini App 按需启动：启用插件不会启动它，`@` 选中、打开页面、发布或重启时才启动。每个插件同一时刻只有一个进程，同时最多运行 3 个不同的 Mini App 服务。更新时先停旧进程、再起新进程，失败可以回滚，见[运行与更新](/docs/miniapp/host/lifecycle)。

## 示例：一次完整的调用

以一个"本周风险"看板为例：用户在页面上点一个按钮，Node 服务请 Agent 整理风险，Agent 回头调用这个 Mini App 自己的工具读数据，结果再回到页面。

![一次完整的调用](https://mintcdn.com/agent-cn/cVBevhAJXWhxEBzo/images/miniapp/call-flow-zh.svg?fit=max\&auto=format\&n=cVBevhAJXWhxEBzo\&q=85\&s=9b482cd4644ad827ba51dd0261cb859f)

**1. 声明能力**

看板需要两样宿主能力：一个给 Agent 用的托管 MCP 服务器，以及发起 Agent 会话的权限。两者都要在 `miniapp.json` 里声明：

```json miniapp/miniapp.json theme={null}
{
  "runtime": { "kind": "process", "entry": "./miniapp/node/server.mjs" },
  "surface": { "path": "/risks" },
  "mcpEndpoints": [{ "server": "risk-board", "path": "/mcp/risk-board" }],
  "agentAccess": ["session.run"]
}
```

宿主据此在发布时接入 MCP 端点，并只为这个插件开放 `context.agent`。没有声明的能力，运行时拿不到。

**2. 启动并就绪**

Node 入口在宿主分配的端口上启动 HTTP 服务，同时提供页面、业务接口和 `/mcp/risk-board`。`start` 返回之后，宿主再做一次鉴权探测，通过了才把服务标为就绪。

```javascript miniapp/node/server.mjs（节选） theme={null}
export async function start(context) {
  const server = createServer((req, res) => route(context, req, res));
  await listen(server, context.listen.host, context.listen.port);
  return { dispose: () => close(server) };
}
```

**3. 页面发起请求**

用户点"整理本周风险"。页面只请求自己的 Node 服务，用相对地址；宿主在请求离开页面时补上凭据，页面代码看不到它。

```javascript miniapp/client/app.js theme={null}
summarizeButton.onclick = async () => {
  const res = await fetch('/api/weekly-risks', { method: 'POST' });
  if (!res.ok) showError(await res.text());
};
```

**4. Node 服务把任务交给 Agent**

请求处理函数调用 `context.agent.run`。宿主为这个 Mini App 创建一个 Agent 会话：它不出现在会话列表里，只有这个 Mini App 能续用。

```javascript miniapp/node/server.mjs（节选） theme={null}
async function handleWeeklyRisks(context, res) {
  const result = await context.agent.run({
    text: '调用 list_risks 读取本周风险，按影响从高到低总结，并列出需要我确认的事项。',
  });
  if (result.status !== 'finished') return sendJson(res, 502, { error: result.status });
  await saveSummary(context.dataDir, result.text);
  broadcast({ type: 'summary.updated' }); // 推给所有打开的页面
  sendJson(res, 200, { sessionId: result.sessionId });
}
```

这里没有传 `onEvent`：回合里如果有工具调用需要审批，又没有人能回答，宿主会直接拒绝并告诉模型原因，不会让任务一直等下去，见[审批和问卷](/docs/miniapp/authors/agent#agent-interaction)。

**5. Agent 调用 Mini App 的工具**

会话里的 Agent 拥有完整能力，也包括这个 Mini App 自己的 MCP 工具。它调用 `list_risks` 时，宿主把请求转回同一个 Node 服务，附上本次运行的凭据：

```json POST /mcp/risk-board theme={null}
{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "tools/call",
  "params": {
    "name": "list_risks",
    "arguments": { "week": "2026-W42" }
  }
}
```

Node 服务从 `dataDir` 读出风险列表，作为工具结果返回。页面接口和这个工具调用的是同一段业务逻辑。

**6. 结果回到页面**

回合结束后 `run()` 返回总结文字。Node 先把结果写进 `dataDir`，再通过 SSE 通知页面；推送失败也不要紧，页面重连后重新读取即可。如果用户想看 Agent 的过程，页面可以调用 `window.mcode.miniapp.agent.open(sessionId)`，把这个会话显示到聊天侧栏。
