内容
# autumn-mcpify
将 CLI 应用转换为 **MCP 服务器** (Model Context Protocol, stdio),以便 AI 代理可以像调用工具一样调用应用程序的命令。
**统一的真实来源 - 普通的 CLI 命令。** 标记子命令为 `&可用作MCP工具`,它将自动作为 MCP 工具出现。 参数方案由 autumn-cli 的注解(`&选项`/`&参数`/`&选项集`/`&枚举`/`&T*`)生成 - 无需复制。
## 快速入门
应用程序的 MCP 服务器入口点(例如 `src/mcp.os`):
```bsl
# 使用 autumn
# 使用 autumn-cli
# 使用 autumn-mcpify
# 使用 "." // 应用程序源代码:命令、服务、选项集
启动 = 新的 MCP_启动();
启动.启动();
```
> MCP 服务器的入口点由服务器自动查找 - 根据进程的启动脚本(`启动脚本()`)和包清单,不依赖于 `main.os` 的名称。 不需要传递任何参数。
> 不需要在 CLI 应用程序的入口点(`src/main.os`)连接 `autumn-mcp` - 它由 `autumn-mcpify` 自行连接(在 `MCP_启动`内部)。
在客户端(Claude Code / Cursor / IDE)中注册服务器,工作目录为项目根目录:
```jsonc
// .mcp.json
{ "mcpServers": {
"myapp": { "command": "oscript", "args": ["src/mcp.os"] }
}}
```
> 在普通的 CLI 入口点(`src/main.os`)中,不需要连接 `autumn-mcpify`:OneScript 将注解存储为元数据,并静默忽略未注册的标记(`&可用作MCP工具`等),因此应用程序的标准启动在没有加载库的情况下仍然有效。 库仅在 MCP 服务器入口点处需要。
## 如何标记命令
```bsl
&应用程序子命令(名称 = "compile", 父级 = "Cf 命令", 描述 = "编译 cf")
&可用作MCP工具
过程 创建对象()
结束过程
```
就这样。 命令在 CLI (`myapp cf compile ...`) 和作为 MCP 工具 `cf_compile` 下可用。 工具名称 = 通过 `_` 的子命令路径。
### 意图标记
在 `&可用作MCP工具` 旁边:
```bsl
&MCP长时间运行 // 长时间命令 → 默认在后台(taskId)
&MCP长时间运行(超时 = 600) // 同上 + 600 秒后自动取消后台任务
&MCP只读 // readOnlyHint = true
&MCP破坏性 // destructiveHint = true, readOnlyHint = false
&MCP幂等 // idempotentHint = true
&MCP外部世界 // openWorldHint = true(否则为 false)
&MCP标题("友好名称") // 标题(默认为命令描述)
```
`&MCP长时间运行` 管理后台执行(见下文)。 其他标记转换为 `tools/list` 响应的 `annotations` 块(MCP 协议的提示):客户端根据这些提示做出决定,例如在调用前是否请求确认。 需要 **autumn-mcp ≥ 1.1.0** 服务器(支持 `工具注解()`);旧服务器无害地忽略标记。
## 会话选项缓存
当命令带有选项时,其值**按选项名称存储在会话中**,并在后续具有相同选项的命令中自动应用。 例如,`ibconnection` 连接字符串只需指定一次 - 然后它将应用于所有带有此选项的命令(包括来自公共集 `&选项集` 的选项)。 显式传递的值始终覆盖缓存。
只有选项(`&选项`)会被缓存;位置参数(`&参数`)不会被缓存。 此行为在每个工具的描述中都有说明,以便客户端了解。
**缓存管理。** 对于独立/并行调用,在命令本身上传递 `nocache: true` - 不会读取或写入此调用的缓存(自包含)。 使用 `cache_show` 工具查看当前“粘贴”内容;使用 `cache_clear` 工具清除整个缓存或按名称清除单个选项。
## 执行进度(notifications/progress)
普通(同步)命令将日志流式传输到客户端作为 `notifications/message`,而 **每个 INFO 消息** 还会发送 `notifications/progress`。 传递 `progressToken` 的客户端会在每个此类通知上重置调用超时 - 因此“健谈”的命令不会被切断,而进度反映了实际工作进度(而不是计时器)。 需要 **autumn-mcp ≥ 1.1.0** 服务器;使用旧服务器,进度 simply 不被发送。
> 长时间且“沉默”(无 INFO 日志)的操作最好标记为 `&MCP长时间运行`:它转到后台,不会受到同步调用超时的威胁。
## 长时间命令:后台和轮询
带有 `&MCP长时间运行` 的命令默认在**后台**执行(不阻塞 stdio):启动一个单独的进程 `oscript <CLI 入口点> <子命令> <标志>`,输出**写入文件**(实时日志 - `task_result` 在任务仍在运行时显示进度)。 工具立即返回 `taskId`。 有效选项(考虑缓存)重建为 CLI 标志 - 子进程是自包含的。 参数 `&MCP长时间运行(超时 = N)` 设置截止日期:任务超时后取消(删除进程树),状态变为 `timeout`。
**CLI 入口点** 是应用程序的 CLI 调度程序(通常为 `src/main.os`),而不是 MCP 脚本本身:后台重启它。 服务器根据以下优先级自动确定入口点:
> 1. 显式设置的 `配置().设置CLI入口点(...)`;
> 2. 编译包的 `opm-metadata.xml` - 唯一的 `<executable>`,不等于 MCP 脚本(一个文件可以有多个名称 - 正常);
> 3. `packagedef`(从源代码运行)- 唯一的 `.执行文件(...)`,不等于 MCP 脚本;
> 4. MCP 脚本旁边的 `main.os`。
| 工具 | 用途 |
|---|---|
| `task_status` | 按 `taskId` 状态:`running` / `completed` / `failed` / `cancelled` / `timeout` |
| `task_result` | 结果和日志(实时 - 即使任务正在执行) |
| `task_cancel` | 取消(终止进程树) |
长时间运行命令的 `background: false` 选项 - 同步执行,带有流式日志和进度(见上文)。
## 调试日志:`debug` 选项
每个命令都有 `debug`。 如果 `debug: true`,则命令同步执行,日志级别提升到 调试,所收集的日志在结果中返回(包括在发生异常时)。 长时间运行的命令将 `debug` 转换为同步模式。
## 配置(零配置)
默认情况下,参数从约定中导出(从项目根目录运行 `oscript <entry>`):
| 参数 | 默认值 |
|---|---|
| 工作目录 | `当前目录()` |
| CLI 入口点 | 从包清单(`opm-metadata.xml`/`packagedef`)中排除 MCP 脚本;否则为 MCP 脚本旁边的 `main.os` |
| oscript 路径 | PATH 中的自动检测 |
| 后台任务目录 | `<OS 临时目录>/autumn-mcpify-tasks`(不在项目中) |
| 日志前缀(调试) | `""`(所有日志记录器) |
非标准应用程序覆盖所需的内容,直到 `启动()`:
```bsl
启动 = 新的 MCP_启动();
启动.配置()
.设置CLI入口点("app/cli.os")
.设置日志前缀("myapp");
启动.启动();
```
## 架构
服务器 - **单独的入口点**(不是 `myapp mcp` 子命令):这样,autumn-cli 和 autumn-mcp 的钩子不会冲突(两者都挂起 `应用程序启动时`)。 `MCP_启动` 构建了一个 autumn 上下文,其中 `启动工具 = False`,并手动启动服务器(来自 [autumn-mcp](https://github.com/autumn-library/autumn-mcp) 的 `MCP_服务器`)。 命令**在进程内**执行:命令绑定从容器中解析,`&橡皮泥` 服务自动装配,字段由反射填充。 日志流式传输到客户端作为 `notifications/message`。
> `autumn-mcp` 仅在 `MCP_启动` 处连接(`#使用 autumn-mcp`),用于 `MCP_服务器` 二进制文件。 标准 CLI 入口点不加载库,因此 autumn-mcp 钩子无法捕获普通命令。 即使应用程序出于某种原因在 CLI 入口点连接 `autumn-mcpify`,这也是安全的:OneScript 懒惰地编译类,并且 `#使用 autumn-mcp` 仅在 `MCP_启动` 实例化时(在 MCP 入口点)触发,而不是在标准启动时,其中不实例化 `MCP_启动`。
### 公共 API (`src/类`)
这是消费者使用的全部内容:
| 类 | 角色 |
|---|---|
| `MCP_启动` | **入口点**:`新的 MCP_启动(); 启动()`;`配置()` 进行重写 |
| `MCP_注解可用作MCP工具` | `&可用作MCP工具` 标记(命令到 MCP 的选择加入) |
| `MCP_注解*` | 意图标记(`&MCP长时间运行`、`&MCP破坏性`等) |
### 内部实现 (`src/internal/类`)
不属于公共 API;通过相对 `#使用 "../internal"` 从 `MCP_启动` 连接,不直接由包加载器扫描:
| 类 | 角色 |
|---|---|
| `MCP_配置` | 启动参数(零配置约定 + 集合器) |
| `MCP_工具注册表` | autumn-cli 命令反射 → MCP 工具 + JSON 架构 |
| `MCP_命令工具` | 命令执行(进程内 / 后台 / 调试) |
| `MCP_选项缓存` | 按名称存储的选项值会话缓存 |
| `MCP_缓存工具` | `cache_show` / `cache_clear` 工具 |
| `MCP_任务注册表` | 后台任务注册表:启动、状态、实时日志、取消/超时 |
| `MCP_任务执行器` | 后台任务正文:外部进程、文件实时日志、超时 |
| `MCP_任务工具` | `task_status` / `task_result` / `task_cancel` 工具 |
| `MCP_日志追加器` | 日志记录器到 `notifications/message` 的追加器(日志流式传输) |
| `MCP_进度追加器` | 日志记录器到 `notifications/progress` 的追加器(基于 INFO 日志的进度) |
| `MCP_缓冲区追加器` | 日志记录器的缓冲区追加器,用于捕获调试日志 |
| `MCP_平台` | 跨平台进程操作(按 PID 终止进程树) |
> OneScript 不支持类中的访问修饰符 - 正式地,内部类在加载库后仍然是 `新建`-able。 `src/internal` 目录是一个组织边界(与 `async` 相同):它表示私有契约并保持公共 `src/类` 文件夹干净。
## 手动检查
```sh
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| oscript src/mcp.os
```