# autos.mcp.worker

在**同一个 aardio 进程**内，跨隔离线程或多次 `execute_code` 复用有状态 MCP 连接。版本 `0.1.0`。

每次 `open` 创建一个专有线程，在该线程内创建、调用并关闭现有 `autos.mcp.client`。调用者只持有不透明 `workerId`，不能获得或跨线程传递原始 client。导入不启动服务；没有全局进程池、自动重连、业务重放或隐式切换 backend。`autos.mcp.session` 的当前上下文契约不变。

## 何时使用

- 同一次执行中的短流程：优先 `autos.mcp.withClient` 或 `autos.mcp.session`。
- 连续多次调用需要保留服务端已打开的文档、工程、原生分析 Program：显式使用 worker。
- worker 不跨进程、Autos 重启或 `threadMode="process"` 保留。进程隔离测试结束会连同所有后代清理。
- 完成后主动 `close`。本版本不做空闲超时回收，避免意外丢失工作状态。更新库源码前先关闭现有 worker；不支持存活 worker 的热升级。

## 打开与跨调用复用

以下示例中的程序与参数须替换为已信任的实际 MCP 服务；worker 不将服务描述或结果提升为系统指令。

```aardio
import autos.mcp.worker;
var id,err,detail=autos.mcp.worker.open({
    command="C:\Program Files\nodejs\node.exe";
    args=["C:\my-app\server.js"];
    timeoutMs=60000;
});
if(!id) return null,err,detail;
thread.set("my.mcp.workerId",id); // 仅保存定位符，不保存 client。
return {workerId=id;status=autos.mcp.worker.status(id)};
```

在后续隔离执行中读取同一 ID；先按需取得工具 Schema，不猜工具名和参数：

```aardio
import autos.mcp.worker;
var id=thread.get("my.mcp.workerId");
var tools,err,detail=autos.mcp.worker.listTools(id);
// 审核实际工具定义后：
// var result,err,detail=autos.mcp.worker.callTool(id,"实际工具名",{参数名="值"});
return tools,err,detail;
```

结果保持原始 MCP 结构，`isError=true` 是合法业务失败；优先读取 `structuredContent`，避免再重复输出 `content.text`。大结果应落盘后只返回路径和小摘要。

```aardio
import autos.mcp.worker;
var id=thread.get("my.mcp.workerId");
var ok,err,detail=autos.mcp.worker.close(id);
if(ok) thread.set("my.mcp.workerId",null);
return ok,err,detail;
```

## 接口与状态

- `open(config[,options])` → `workerId` 或 `null,err,detail`。配置遵守 `autos.mcp.normalizeConfig`（包括 stdio 的纯字符串数组 args）；在调用者先解析 `envFrom`。原有 stdio 私有 Job 和 HTTP 传输均复用，不改父环境。
- `callTool(id,name,arguments[,options])` / `listTools(id[,options])` → 原始业务结果或 `null,err,detail`。
- `status(id)` → 小型纯状态：`state`、`busy`、`requestId`、`pid`、`threadId`、协议版本、有限服务器身份和最后失败/清理摘要。不包含连接配置、调用参数或完整结果；服务器身份只是展示信息。
- `cancel(id,requestId)` → 仅针对正在等待的精确请求；过期 ID 不会取消下一请求。`requestId` 从 `status` 获取。不支持没有 ID 的盲目取消。
- `close(id[,options])` → 成功 `true,null,最终状态` 并使 ID 失效；stdio 的 `cleanup.activeProcesses=0` 来自既有 `job.dispose` 的归零确认。失败返回 `null,err,detail`，保留所有者及 ID 供重试。不能通过杀死 aardio 线程代替清理。

`state` 为 `opening / ready / failed / closed`；`busy` 独立表示已有请求占用。并发调用立即返回 `kind="busy", delivery="not_sent"`，不排队。关闭后不保留全局墓碑；已关闭/未知 ID 均不可调用。

## 截止时间、取消与失败

- `options.timeoutMs` 为整个 worker 请求等待预算，默认取配置的 timeoutMs，否则 30 秒。`close` 默认等待 5 秒；其清理本身遵守原传输的有界规则，可能另需重试。
- `options.shouldStop()` 留在调用者上下文执行，不序列化给所有者。活动请求通过纯取消标志通知既有 client；取消不保证服务端操作未执行。
- 已投递请求超时、取消或异常：保守返回 `delivery="unknown"`。迟到结果丢弃，不会成为下一请求结果。协议/传输失败后连接失效，禁止继续调用；检查业务副作用后显式重新 open，不重放上次调用。
- JSON-RPC 错误或 `isError=true` 不会无故重启进程。清理失败仍由专有线程保留资源，主动再次 close 重试。
- `close` 不能撤销远端 HTTP 操作或已发生的本地应用副作用；stdio Job 只管理此连接自己的树，不影响其它 worker。

## 纯数据边界

配置与 arguments 必须为 JSON 兼容纯数据，不接受函数、代理、句柄、实例或循环引用。跨线程以 JSON 文本保留显式 null、空字符串、0、false 和 nullable-array 的逻辑长度，避免 aardio 普通线程表序列化丢失数组长度元信息。

没有逻辑长度的稀疏数组会被拒绝，而不是静默截断；需要 null 缺口时用 `JSON.parse` 创建 JSON 数组，或显式指定 `array@={length=N}`。`shouldStop` 是调用者本地 options，不受纯数据限制。不要将凭据或完整大结果写入状态日志。
