> ## 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 的 Node 服务里，页面只调用 Node 提供的业务接口。

## 选择接入方式

| 方式 | 适合 |
| - | - |
| Host Connector | 用户已在 MiniMax Code 授权的第三方应用，比如 Notion |
| CLI 子进程 | 本机已有的命令行工具，由插件拉起、插件负责清理 |
| HTTP API / SDK / 本地文件 | 有自己鉴权方式的服务，或用户授权的本地文件 |
| 统一工具入口 | 用同一个写法调用宿主已挂载的 MCP 工具和 Connector |

Connector 只是数据接入方式之一，Mini App 不依赖它；没有对应的 Connector，也不代表无法获取数据。用户明确指定了方式且可以验证时，就采用该方式；否则根据可用能力、鉴权、运行环境和所需操作选择。

## 先验证，再开发

写包之前，对每个数据源用选定的方式做一次只读查询，确认授权、真实参数、返回字段和类型，取得一条有代表性的数据，或一个真实的空结果，再按观察到的结构编写解析逻辑。

> [!NOTE]
>
> Agent 终端里查询成功，不代表 Mini App 运行时里也能成功。CLI、API、文件访问还要在 Node 服务里实际跑通一次。

## 统一工具入口

Node 服务可以用 `context.tool` 列出和调用宿主已挂载的 MCP 工具及用户连接的 Connector。它不提供 Agent 内置的文件、Shell 或浏览器工具；Mini App 自己实现的托管 MCP 应直接复用本地业务函数。

方法签名、清单与结果类型、取消和超时见 [Node 工具 API 参考](https://agent.minimaxi.com/docs/miniapp/reference/node-api.md#tools)；页面提前申请授权见 [tool.request 参考](https://agent.minimaxi.com/docs/miniapp/reference/client-api.md#tool-request)。

```json miniapp/miniapp.json theme={null}
{
  "toolAccess": ["call"]
}
```

`context.capabilities?.has('tool')` 检查宿主是否实现接口，不代表 manifest 已声明或用户允许调用。用户关闭工具权限后，`context.tool` 仍在，新调用会以 `TOOL_NOT_PERMITTED` 拒绝。

```javascript theme={null}
// 在服务激活后的请求处理里调用；名称、参数和返回结构先用真实查询验证
async function callVerifiedTool(context, args) {
  const { tools } = await context.tool.list();
  const tool = tools.find(
    (item) => item.kind === 'mcp' && item.server === VERIFIED_SERVER && item.tool === VERIFIED_TOOL_NAME,
  );
  if (!tool || tool.permission === 'deny') throw new Error('tool_unavailable');
  return context.tool.call(tool.name, args);
}
```

* 从 `list()` 的结果取 `name`，按 `kind`、`server` / `provider` 和 `tool` 匹配，不拼接工具名。`list()` 返回 `{ tools, partial }`；`partial: true` 表示清单不完整，可能有来源不可用或部分工具因元数据问题被省略；已列出的工具仍按当前权限调用。
* `permission` 是当时的 `allow`、`ask` 或 `deny`；每次调用都会重新判定。规则采用用户的全局工具权限和权限模式，不继承某个 Agent 或会话的规则；宿主内置工具沿用原有放行行为，这条调用链不会执行 Agent 的工具 Hook。
* 需要确认时，由宿主弹框提供「允许一次」「始终允许」「拒绝」。只有用户在宿主框中选择「始终允许」才会写入全局规则，Mini App 不能代答。无人可确认时返回 `TOOL_APPROVAL_REQUIRED`。
* MCP 结果包含 `kind: 'mcp'`、`isError` 和 `content`；`isError: true` 是工具报告业务失败，Promise 仍正常返回。Connector 结果包含 `kind: 'connector'` 和原始 `value`。写操作遇到 `unknown_after_dispatch` 时，先核对业务状态，不要盲目重试。
* Node 的 `context.tool.request(names)` 和页面的 `window.mcode.miniapp.tool.request(names)` 可提前请求授权；需探测 `tool.request` 能力。页面调用必须来自用户手势、每次最多 10 个工具，并要求 Node 服务正在运行。页面只请求授权，工具的列出和调用仍在 Node；把 Node 获取的运行时工具名通过业务接口传给页面。

## Host Connector

Node 服务通过 `context.hostConnector` 使用用户已授权的连接器。访问第三方服务时，用的是用户授权给 MiniMax Code 的账号，Mini App 自己不保存任何凭证。

完整的 `list`、`call`、工具描述与错误结构见 [Host Connector API 参考](https://agent.minimaxi.com/docs/miniapp/reference/node-api.md#connector)。

```json miniapp/miniapp.json theme={null}
{
  "hostConnectorAccess": { "providers": ["notion"] }
}
```

* 只声明运行时真正需要、并且已经验证过的 provider。
* `list()` 随时可用，返回允许的工具清单和输入 schema。`call()` 只在服务激活后、在请求处理里调用，不要在 `start` 里调。
* 不要自己构造或保存 `toolRef`，也不要发给页面。进程重启或遇到过期引用时，重新 `list()`。
* 用户退出登录时，工具清单和授权引用会被撤销；同一账号重新登录后再 `list()` 即可恢复，不用重新发布。换成其他账号后，旧引用永久失效。

```javascript theme={null}
// 在请求处理里调用；工具名和参数以验证时观察到的清单和 schema 为准
async function readRecords(context, args) {
  const { tools } = await context.hostConnector.list();
  const tool = tools.find((t) => t.provider === 'notion' && t.name === VERIFIED_TOOL_NAME);
  if (!tool) throw new Error('connector_tool_unavailable');
  const result = await context.hostConnector.call(tool.toolRef, args);
  return parseRecords(decodeHostConnectorValue(result.value));
}
```

### 错误处理

按 `code` 判断，不要依赖跨进程的 `instanceof`。

| code | 含义 |
| - | - |
| `TOOL_REF_STALE` / `SERVICE_RESTARTED` | 引用过期或服务重启了，重新 `list()` |
| `INVALID_ARGUMENTS` | 参数不符合 schema；`diagnostic.issues` 给出 `path`、`constraint`、`limit`，不含参数值 |
| `CONNECTOR_UNAVAILABLE` | 连接器当前不可用 |
| `CONNECTOR_TIMEOUT` / `REQUEST_CANCELLED` | 超时或已取消 |
| `CONNECTOR_PROVIDER_ERROR` | 第三方服务报错。原因不明时不要推断成授权问题 |
| `CONNECTOR_OUTCOME_UNKNOWN` | 请求已发出，结果未知 |

`disposition` 说明请求有没有发出去：`not_dispatched`、`provider_reported`、`unknown_after_dispatch`。遇到 `unknown_after_dispatch`，先读业务状态核对，再决定写操作要不要重试。

### 解析返回值

`result.value` 是第三方服务的原始结果，宿主不做归一化。Skill 提供的 `host-connector-value.mjs` 处理常见的「单个 text 块」包装，其他结构原样返回。解析出零条数据时，只有服务明确返回空结果才算成功；源数据存在却无法解析时，应按解析错误处理，不要显示为「暂无数据」。

## 状态与持久化

* 运行时数据写在 `context.dataDir`，不要写进工作区或载荷。
* 页面、MCP 调用和 Agent 操作的所有写入都走同一个 Node 业务服务。先将状态写入磁盘，再推送 SSE 或 WebSocket 事件，这样每个打开的页面都能刷新到最新数据。

业务状态变化时就写入 `context.dataDir`，不要只在 `dispose()` 中保存。服务重新启动后应读取已保存的数据继续工作。
