Content
# autumn-mcpify
Transforms a [autumn-cli](https://github.com/autumn-library/autumn-cli) CLI application into an **MCP server** (Model Context Protocol, stdio) so that AI agents can call application commands as tools.
**Single source of truth — a regular CLI command.** Mark a subcommand with the `&ДоступноВMCP` marker, and it automatically appears as an MCP tool. The parameter scheme is generated by reflection from autumn-cli annotations (`&Опция`/`&Аргумент`/`&НаборОпций`/`&Перечисление`/`&Т*`) — no need to duplicate.
## Quick Start
The entry point of the application's MCP server (e.g., `src/mcp.os`):
```bsl
#Использовать autumn
#Использовать autumn-cli
#Использовать autumn-mcpify
#Использовать "." // application sources: commands, services, option sets
Запуск = Новый MCP_Запуск();
Запуск.Старт();
```
> The MCP server finds the CLI application's entry point for **background tasks** (see below) by itself — by the process startup script (`СтартовыйСценарий()`) and package manifest, without relying on the `main.os` name. No arguments need to be passed.
> `autumn-mcp` does not need to be connected at the entry point — it is pulled by `autumn-mcpify` itself (inside `MCP_Запуск`).
Registering the server with the client (Claude Code / Cursor / IDE), working directory — project root:
```jsonc
// .mcp.json
{ "mcpServers": {
"myapp": { "command": "oscript", "args": ["src/mcp.os"] }
}}
```
> In the usual CLI entry point (`src/main.os`), there is no need to connect `autumn-mcpify`: OneScript stores annotations as metadata and quietly ignores unregistered markers (`&ДоступноВMCP` and others), so the standard application launch works without loading the library.
## How to Mark a Command
```bsl
&ПодкомандаПриложения(Имя = "compile", Родитель = "КомандаCf", Описание = "Собрать cf")
&ДоступноВMCP
Процедура ПриСозданииОбъекта()
КонецПроцедуры
```
That's it. The command works both in CLI (`myapp cf compile ...`) and as an MCP tool `cf_compile`. The tool name is the subcommand path through `_`.
### Intention Markers
Next to `&ДоступноВMCP`:
```bsl
&MCPДлительная // long-running command → by default in background (taskId)
&MCPДлительная(Таймаут = 600) // same + auto-cancel background task after 600 s
&MCPТолькоЧтение // readOnlyHint = true
&MCPРазрушающая // destructiveHint = true, readOnlyHint = false
&MCPИдемпотентная // idempotentHint = true
&MCPВнешнийМир // openWorldHint = true (otherwise false)
&MCPЗаголовок("Friendly name") // title (by default = command description)
```
`&MCPДлительная` manages background execution (see below). Other markers are translated into the `annotations` block of the `tools/list` response (MCP protocol hints): by them, the client decides, for example, whether to ask for confirmation before calling. Requires **autumn-mcp ≥ 1.1.0** server (with support for `АннотацииИнструмента()`); with an older server, markers are harmlessly ignored.
## Session Option Cache
When a command is called with options, their values are **remembered for the session by option name** and automatically substituted into subsequent commands with the same option. For example, the `ibconnection` connection string needs to be specified only once — then it is applied to all commands that have this option (including options from common sets `&НаборОпций`). An explicitly passed value in the call always overrides the cache.
Only options (`&Опция`) are cached; positional arguments (`&Аргумент`) are not. This behavior is described in the description of each tool so that it is clear to the client.
**Cache management.** For independent/parallel calling, pass `nocache: true` to the command itself — the cache for this call is not read or written (the call is self-sufficient). To see what is currently "stuck", use the `cache_show` tool; to reset the entire cache or one option by name, use `cache_clear`.
## Execution Progress (notifications/progress)
A regular (synchronous) command streams the log to the client as `notifications/message`, and **each INFO message** additionally sends `notifications/progress`. The client that passed `progressToken` resets the call timeout for each such notification — therefore, a "talkative" command is not interrupted, and progress reflects the actual work (not a timer). Requires **autumn-mcp ≥ 1.1.0**; with an older one, progress is simply not sent.
> A long and at the same time "silent" (without INFO log) operation is better marked with `&MCPДлительная`: it goes to the background and is not threatened by a synchronous call timeout.
## Long-Running Commands: Background and Polling
Commands with `&MCPДлительная` are executed **in the background** by default (do not block stdio): a separate `oscript <entry point> <subcommand> <flags>` process is launched, output is written to a file **as it is executed** (live log — `task_result` shows progress while the task is running), the tool immediately returns `taskId`. Effective options (taking into account the cache) are reconstructed into CLI flags — the child process is self-sufficient. The `&MCPДлительная(Таймаут = N)` parameter sets the deadline: after it expires, the task is auto-canceled (the process tree is removed), and the status becomes `timeout`.
**CLI entry point** is the application's CLI dispatcher (usually `src/main.os`), not the mcp script itself: the background restarts it. The server determines it automatically (the mcp script path is taken from `СтартовыйСценарий()`), by priority:
> 1. explicitly specified `Конфигурация().УстановитьТочкаВходаCLI(...)`;
> 2. `opm-metadata.xml` of the compiled package — the only `<executable>` not equal to the mcp script (several names per file are normal);
> 3. `packagedef` (launch from sources) — the only `.ИсполняемыйФайл(...)` not equal to the mcp script;
> 4. `main.os` next to the mcp script.
>
> The `main.os` name is not assumed anywhere — it is only an extreme fallback. If auto-detection is ambiguous (several different executables), specify the entry point explicitly.
| Tool | Purpose |
|---|---|
| `task_status` | status by `taskId`: `running` / `completed` / `failed` / `cancelled` / `timeout` |
| `task_result` | result and log (live — available even while the task is running) |
| `task_cancel` | cancel (completes the process tree) |
The `background: false` option for a long-running command — execute synchronously with a streaming log and progress (see above).
## Debug Log: `debug` Option
Each command has a `debug` option. When `debug: true`, the command is executed synchronously, the logger level is raised to Debug, and the collected log is returned in the result (including when an exception occurs). A long-running command `debug` translates into synchronous mode.
## Configuration (zero-config)
By default, parameters are derived from conventions (launch `oscript <entry>` from the project root):
| Parameter | Default |
|---|---|
| Working directory | `ТекущийКаталог()` |
| CLI entry point | from package manifest (`opm-metadata.xml`/`packagedef`), excluding mcp script; otherwise `main.os` next to it |
| oscript path | auto-detection in PATH |
| Background task directory | `<temporary OS directory>/autumn-mcpify-tasks` (not in the project) |
| Logger prefix (debug) | `""` (all loggers) |
A non-standard application overrides the necessary one before `Старт()`:
```bsl
Запуск = Новый MCP_Запуск();
Запуск.Конфигурация()
.УстановитьТочкаВходаCLI("app/cli.os")
.УстановитьПрефиксЛоггера("myapp");
Запуск.Старт();
```
## Architecture
The server is a **separate entry point** (not a subcommand `myapp mcp`): this is how autumn-cli and autumn-mcp hooks do not conflict (both hang `ПриЗапускеПриложения`). `MCP_Запуск` builds an autumn context with `ЗапускатьРогатки = Ложь` and launches the server (`MCP_Сервер` from [autumn-mcp](https://github.com/autumn-library/autumn-mcp)) manually. Commands are executed **in-process**: the command bin is resolved from the container, services `&Пластилин` are autowired, and fields are filled by Reflector. The log is streamed to the client as `notifications/message`.
> `autumn-mcp` is connected only in `MCP_Запуск` (`#Использовать autumn-mcp`), for the `MCP_Сервер` bin. The standard CLI entry point does not load the library, so the autumn-mcp hook cannot intercept regular commands. Even if the application somehow connects `autumn-mcpify` in the CLI point, it is safe: OneScript compiles classes lazily, and `#Использовать autumn-mcp` inside `MCP_Запуск` works only when `Новый MCP_Запуск()` (in the MCP entry point), and not during a standard launch where `MCP_Запуск` is not instantiated.
### Public API (`src/Классы`)
This is everything that the consumer uses:
| Class | Role |
|---|---|
| `MCP_Запуск` | **entry point**: `Новый MCP_Запуск(); Старт()`; `Конфигурация()` for override |
| `MCP_АннотацияДоступноВMCP` | `&ДоступноВMCP` marker (opt-in command in MCP) |
| `MCP_Аннотация*` | intention markers (`&MCPДлительная`, `&MCPРазрушающая`, etc.) |
### Internal Implementation (`src/internal/Classes`)
Not part of the public API; connected by relative `#Use "../internal"`
from `MCP_Launch` and not scanned directly by the package loader:
| Class | Role |
|---|---|
| `MCP_Configuration` | launch parameters (zero-config agreements + setters) |
| `MCP_ToolRegistry` | reflection of autumn-cli commands → MCP tools + JSON Schema |
| `MCP_ToolCommands` | command execution in-process: synchronous / background / debug |
| `MCP_OptionsCache` | session cache of option values by name |
| `MCP_ToolCache` | `cache_show` / `cache_clear` tools |
| `MCP_TaskRegistry` | background task registry: launch, status, live log, cancel/timeout |
| `MCP_TaskExecutor` | background task body: external process, live log to file, timeout |
| `MCP_TaskTool` | `task_status` / `task_result` / `task_cancel` tools |
| `MCP_NotificationAppender` | appender logos → `notifications/message` (log streaming) |
| `MCP_ProgressAppender` | appender logos → `notifications/progress` (progress by INFO log) |
| `MCP_BufferAppender` | buffer appender logos for capturing debug log |
| `MCP_Platform` | cross-platform process operations (killing tree by PID) |
> OneScript does not support access modifiers for classes — formally
> internal classes remain `New`-able after loading the library. The directory
> `src/internal` is an organizational boundary (the same idiom as in `async`): it
> denotes a private contract and keeps the public folder `src/Classes` clean.
## Manual Verification
```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
```
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available