@runa-cmd/mcp 0.2.0-beta.0 → 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ Every command becomes an MCP tool. Zod schemas pass directly to the MCP SDK —
7
7
  ## Install
8
8
 
9
9
  ```bash
10
- pnpm add @runa-cmd/mcp
10
+ pnpm add @runa-cmd/mcp@beta
11
11
  ```
12
12
 
13
13
  > Peer dependencies: `@runa-cmd/core` and `zod ^4.0.0`.
@@ -52,15 +52,18 @@ $ my-tool --mcp
52
52
 
53
53
  When `--mcp` is passed, the CLI starts a stdio-based MCP server instead of normal execution. AI agents can then discover and call your commands as tools.
54
54
 
55
+ For a CLI made of one command, use `runCLI(deploy, { plugins: [mcpPlugin()] })`.
56
+
55
57
  ## How It Works
56
58
 
57
59
  1. The plugin adds a `--mcp` global boolean flag
58
60
  2. On `onGlobalFlags` hook, if `--mcp` is true:
59
- - Introspects the CLI schema via `getSchema()`
60
- - Gets the live command tree via `getCommands()`
61
61
  - Maps each leaf command to an MCP tool
62
- - Starts an MCP server over stdio transport
63
- - Short-circuits normal CLI execution
62
+ - Checks that it can run itself
63
+ - Serves over stdio until the client disconnects
64
+ 3. Each tool call runs your CLI again, as a child process
65
+
66
+ A tool is the same command a person runs: env vars, config files, global options, hooks and middleware all apply, and a `process.exit` only ends that call. To tell tool calls apart in a hook, read `ctx.invocation.surface`. Each call is a new process, so nothing is shared between calls.
64
67
 
65
68
  ### Command → Tool Mapping
66
69
 
@@ -79,7 +82,7 @@ CLI: deploy <service> --env staging
79
82
  MCP: { "service": "api", "env": "staging" }
80
83
  ```
81
84
 
82
- The plugin tracks which keys are args vs options internally, so it can reconstruct the proper `RunContext` when executing the command.
85
+ Each key goes to its arg or option by name, so arrays, objects and numbers arrive as they are, and a value can never select another command.
83
86
 
84
87
  ### Output Handling
85
88
 
@@ -88,8 +91,89 @@ The plugin tracks which keys are args vs options internally, so it can reconstru
88
91
  | Command has `output` schema | `structuredContent` with typed data |
89
92
  | Command returns a string (no output schema) | `text` content |
90
93
  | Command returns an object (no output schema) | `text` content (JSON stringified) |
91
- | Command returns void | `text: "ok"` |
92
- | Command throws | `isError: true` with error message |
94
+ | Command returns nothing | `text` with what it printed, or `Command '<name>' executed successfully.` |
95
+ | Command fails | `isError: true`, with the reason and what happened to its effects in the text, plus `_meta['runa/error']` |
96
+
97
+ A returned value wins over what the command printed.
98
+
99
+ ### Errors and Retries
100
+
101
+ A failed call says whether repeating it can repeat its effects. The text says it for the model, and `_meta['runa/error']` for the client, as `{ class, effect, safeToRetry }`:
102
+
103
+ | `effect` | Meaning | `safeToRetry` |
104
+ |---|---|---|
105
+ | `none` | `run()` never started | `true` |
106
+ | `unknown` | `run()` started and did not return | `false` |
107
+ | `completed` | `run()` returned, and something failed after it, like an invalid `output` | `false` |
108
+
109
+ `safeToRetry` is about the command: a middleware or hook may have acted before `run()` started.
110
+
111
+ ### Cancellation
112
+
113
+ Cancelling a call, or closing the server, aborts `ctx.signal` in the command and runs `cleanup`. A command that ignores it stops being waited for after 2 seconds, and its whole process tree ends after 5. Pass `signal` to whatever the command starts:
114
+
115
+ ```ts
116
+ async run({ signal }) {
117
+ await fetch(url, { signal });
118
+ }
119
+ ```
120
+
121
+ ### Output Limit
122
+
123
+ A tool answers with up to 100 KiB, or what `maxOutput` says. Longer output keeps its start and its end, with a notice in between. A returned value isn't cut: a broken JSON helps nobody, so the call fails with `output_too_large` and reports that the command already ran.
124
+
125
+ ## What You Expose
126
+
127
+ Every command is a tool by default. Choose what an agent gets, and how it reads about it:
128
+
129
+ ```ts
130
+ mcpPlugin({
131
+ exclude: ['internal', 'config_reset'],
132
+ tools: {
133
+ status: { annotations: { readOnlyHint: true } },
134
+ deploy: {
135
+ description: 'Deploy to production. Ask before running it.',
136
+ annotations: { destructiveHint: true },
137
+ },
138
+ },
139
+ });
140
+ ```
141
+
142
+ - **`exclude`** removes the tool: it isn't listed and can't be called. This is the only real boundary.
143
+ - **`annotations`** go to the client as the [MCP specification](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations) defines them. **They are hints, not access control:** a client decides what to do with them, and may ignore them. Without them, clients assume a tool can be destructive.
144
+ - **`description`** replaces what the model reads, without changing your CLI's help.
145
+
146
+ An unknown name in `exclude`, an excluded tool with settings, or a tool both read-only and destructive stop the server at startup.
147
+
148
+ ## What the Operator Decides
149
+
150
+ Whoever starts the server beats the model. An option that declares `env`, or has a value in the config file, stays out of the tool's schema, and if a model sends it anyway, it's dropped. This holds even if the env var isn't set: a missing required value fails the call, so a model can't ask anyone for it.
151
+
152
+ ```ts
153
+ mcpPlugin({
154
+ tools: {
155
+ deploy: {
156
+ expose: ['region'], // The model can choose it, even if env gives it a value
157
+ serverOnly: ['token'], // Without a value, the server won't start
158
+ },
159
+ },
160
+ });
161
+ ```
162
+
163
+ Fixed values of 8 characters or more, and the global options the server started with, are redacted from the stdout and stderr returned to the model. What `run()` returns is left as it is, so don't return secrets.
164
+
165
+ **Secrets belong in `env`.** Redaction is a safety net, not a barrier: it matches exact text, so it won't catch a value that was transformed, as with base64, and a command can always leak what it receives. Don't expose a command an agent shouldn't run.
166
+
167
+ ## Current Limitations
168
+
169
+ These matter when you expose a real CLI to an agent:
170
+
171
+ - **A new command becomes a tool unless you exclude it.** Review `exclude` when you add one.
172
+ - **Ending processes is best-effort.** One that created its own process group or session escapes.
173
+ - **Only a direct Node `selfCommand` gets the stop notice.** A compiled binary or a wrapper like `npx` is ended by the deadline, and not at all if the server is killed with `SIGKILL`.
174
+ - **stdio is the only transport.**
175
+
176
+ The [backlog](https://github.com/jrodrigopuca/runa-cmd/blob/main/docs/backlog.md) tracks the fixes.
93
177
 
94
178
  ## API
95
179
 
@@ -104,6 +188,7 @@ mcpPlugin({
104
188
  name: 'my-server', // MCP server name (defaults to CLI name)
105
189
  version: '2.0.0', // MCP server version (defaults to CLI version)
106
190
  instructions: 'Use deploy before running tests', // Cross-tool workflow hints for AI
191
+ selfCommand: ['/usr/local/bin/my-tool'], // How to run the CLI again, if the startup check fails
107
192
  });
108
193
  ```
109
194
 
@@ -114,6 +199,18 @@ interface McpPluginOptions {
114
199
  name?: string; // Server name override
115
200
  version?: string; // Server version override
116
201
  instructions?: string; // Workflow instructions for AI agents
202
+ selfCommand?: string[]; // Executable and arguments to run this CLI again
203
+ exclude?: string[]; // Tools that won't exist for an agent
204
+ maxOutput?: number; // Most bytes a tool can answer with. Default: 100 KiB
205
+ tools?: Record<string, ToolOptions>; // Per-tool settings, by tool name
206
+ }
207
+
208
+ interface ToolOptions {
209
+ description?: string; // What the model reads, instead of the command's description
210
+ annotations?: ToolAnnotations; // Hints for the client, as MCP defines them
211
+ expose?: string[]; // Options the model can set, even if they declare env
212
+ serverOnly?: string[]; // Options that must come from env or config
213
+ maxOutput?: number; // This tool's limit, instead of the plugin's
117
214
  }
118
215
  ```
119
216
 
package/dist/index.d.ts CHANGED
@@ -4,5 +4,5 @@
4
4
  * Barrel re-exports for the MCP plugin package.
5
5
  */
6
6
  export { mcpPlugin } from './plugin.js';
7
- export type { McpPluginOptions } from './types.js';
7
+ export type { McpPluginOptions, ToolOptions } from './types.js';
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { ToolRegistration } from './schema.js';
2
+ import type { McpPluginOptions } from './types.js';
3
+ export interface OperatorValues {
4
+ configValues?: Record<string, unknown>;
5
+ env: Record<string, string | undefined>;
6
+ /** Global options the server started with */
7
+ globals: Record<string, unknown>;
8
+ }
9
+ type ExposureOptions = Pick<McpPluginOptions, 'exclude' | 'tools' | 'maxOutput'>;
10
+ /** The tools as the model will see them. Fails at startup on an invalid setup. */
11
+ export declare function applyOperatorValues(registrations: ToolRegistration[], options: ExposureOptions, values: OperatorValues): ToolRegistration[];
12
+ /** Hide fixed values from text a command wrote without meaning to expose them. */
13
+ export declare function redact(text: string, values: string[]): string;
14
+ export {};
15
+ //# sourceMappingURL=operator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAe,MAAM,YAAY,CAAC;AAOhE,MAAM,WAAW,cAAc;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,KAAK,eAAe,GAAG,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,OAAO,GAAG,WAAW,CAAC,CAAC;AA4GjF,kFAAkF;AAClF,wBAAgB,mBAAmB,CAClC,aAAa,EAAE,gBAAgB,EAAE,EACjC,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,cAAc,GACpB,gBAAgB,EAAE,CAUpB;AAED,kFAAkF;AAClF,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAE7D"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @runa-cmd/mcp — What the operator of the server decides, not the model
3
+ *
4
+ * At the CLI, a flag beats env because the same person sets both. With a tool,
5
+ * whoever starts the server and whoever calls the tool are different: an option
6
+ * that declares env, or that has a value, stays out of the model's reach. The
7
+ * rule doesn't depend on the value being set, or a forgotten API_TOKEN would
8
+ * turn into a parameter the model can ask a person for.
9
+ */
10
+ import { RunaError } from '@runa-cmd/core';
11
+ import { longFlag } from '@runa-cmd/core/internal';
12
+ const REDACTION = '[redacted]';
13
+ /** Shorter values could be any word, and replacing them would mangle the text. */
14
+ const MIN_REDACTED_LENGTH = 8;
15
+ function invalidTools(message) {
16
+ return new RunaError(`mcpPlugin: ${message}`, { code: 'MCP_INVALID_TOOLS' });
17
+ }
18
+ function assertValidLimit(limit, owner) {
19
+ if (limit === undefined || (Number.isInteger(limit) && limit > 0))
20
+ return;
21
+ throw invalidTools(`maxOutput of ${owner} must be a positive number of bytes.`);
22
+ }
23
+ function assertValidExclude({ exclude = [], tools = {} }, registrations) {
24
+ for (const name of exclude) {
25
+ if (!registrations.some((reg) => reg.name === name)) {
26
+ throw invalidTools(`no tool named '${name}' to exclude.`);
27
+ }
28
+ if (name in tools)
29
+ throw invalidTools(`tool '${name}' is excluded, so it can't have settings.`);
30
+ }
31
+ }
32
+ function assertValidTools(tools, registrations) {
33
+ for (const [name, options] of Object.entries(tools)) {
34
+ const reg = registrations.find((candidate) => candidate.name === name);
35
+ if (!reg)
36
+ throw invalidTools(`no tool named '${name}'.`);
37
+ assertValidLimit(options.maxOutput, `tool '${name}'`);
38
+ if (options.annotations?.readOnlyHint && options.annotations.destructiveHint) {
39
+ throw invalidTools(`tool '${name}' can't be read-only and destructive.`);
40
+ }
41
+ for (const key of [...(options.expose ?? []), ...(options.serverOnly ?? [])]) {
42
+ if (!reg.optionKeys.has(key)) {
43
+ throw invalidTools(`tool '${name}' has no option '${key}'.`);
44
+ }
45
+ if (options.expose?.includes(key) && options.serverOnly?.includes(key)) {
46
+ throw invalidTools(`option '${key}' of tool '${name}' can't be exposed and server-only.`);
47
+ }
48
+ }
49
+ }
50
+ }
51
+ function envNameOf(key, reg) {
52
+ const optionMeta = reg.command.meta.options;
53
+ return optionMeta?.[key]?.env;
54
+ }
55
+ function fixedValue(key, reg, values) {
56
+ const envName = envNameOf(key, reg);
57
+ const fromEnv = envName === undefined ? undefined : values.env[envName];
58
+ return fromEnv ?? values.configValues?.[key];
59
+ }
60
+ function redactable(values) {
61
+ return values
62
+ .filter((value) => typeof value === 'string' && value.length >= MIN_REDACTED_LENGTH)
63
+ .sort((a, b) => b.length - a.length);
64
+ }
65
+ function applyToTool(reg, options, maxOutput, values) {
66
+ const inputShape = { ...reg.inputShape };
67
+ const fixed = new Set();
68
+ const fixedValues = [];
69
+ for (const key of reg.optionKeys) {
70
+ if (options.expose?.includes(key))
71
+ continue;
72
+ const value = fixedValue(key, reg, values);
73
+ const isServerOnly = options.serverOnly?.includes(key) ?? false;
74
+ if (value === undefined && isServerOnly) {
75
+ throw invalidTools(`option ${longFlag(key)} of tool '${reg.name}' is server-only and has no value. ` +
76
+ 'Set it through its env var or the config file.');
77
+ }
78
+ const belongsToOperator = value !== undefined || envNameOf(key, reg) !== undefined;
79
+ if (!belongsToOperator)
80
+ continue;
81
+ delete inputShape[key];
82
+ fixed.add(key);
83
+ if (value !== undefined)
84
+ fixedValues.push(value);
85
+ }
86
+ return {
87
+ ...reg,
88
+ description: options.description ?? reg.description,
89
+ annotations: options.annotations,
90
+ inputShape,
91
+ fixed,
92
+ redactions: redactable([...fixedValues, ...Object.values(values.globals)]),
93
+ maxOutput: options.maxOutput ?? maxOutput ?? reg.maxOutput,
94
+ };
95
+ }
96
+ /** The tools as the model will see them. Fails at startup on an invalid setup. */
97
+ export function applyOperatorValues(registrations, options, values) {
98
+ const { exclude = [], tools = {}, maxOutput } = options;
99
+ assertValidLimit(maxOutput, 'mcpPlugin');
100
+ assertValidExclude(options, registrations);
101
+ assertValidTools(tools, registrations);
102
+ return registrations
103
+ .filter((reg) => !exclude.includes(reg.name))
104
+ .map((reg) => applyToTool(reg, tools[reg.name] ?? {}, maxOutput, values));
105
+ }
106
+ /** Hide fixed values from text a command wrote without meaning to expose them. */
107
+ export function redact(text, values) {
108
+ return values.reduce((result, value) => result.replaceAll(value, REDACTION), text);
109
+ }
110
+ //# sourceMappingURL=operator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operator.js","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"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"}
package/dist/plugin.d.ts CHANGED
@@ -1,17 +1,16 @@
1
1
  /**
2
2
  * @runa-cmd/mcp — mcpPlugin()
3
3
  *
4
- * A Runa plugin that exposes CLI commands as MCP tools.
5
- * When `--mcp` is passed, the plugin short-circuits normal CLI execution,
6
- * starts an MCP server on stdio transport, and registers every CLI
7
- * command as an MCP tool.
4
+ * Exposes CLI commands as MCP tools. With `--mcp`, the CLI becomes a server
5
+ * over stdio, and each tool call runs the CLI again as a child process, so a
6
+ * tool is the same command a person runs (ADR-0030).
8
7
  */
9
8
  import type { PluginConfig } from '@runa-cmd/core';
10
9
  import type { McpPluginOptions } from './types.js';
11
10
  /**
12
11
  * Create an MCP plugin that exposes CLI commands as MCP tools.
13
12
  *
14
- * @param opts - Optional server name, version, or instructions override
13
+ * @param opts - Optional server name, version, instructions or selfCommand
15
14
  */
16
15
  export declare function mcpPlugin(opts?: McpPluginOptions): PluginConfig;
17
16
  //# sourceMappingURL=plugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,GAAE,gBAAqB,GAAG,YAAY,CAuCnE"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAMhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAOnD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,GAAE,gBAAqB,GAAG,YAAY,CA6CnE"}
package/dist/plugin.js CHANGED
@@ -1,17 +1,21 @@
1
1
  import { definePlugin } from '@runa-cmd/core';
2
2
  import { z } from 'zod';
3
+ import { applyOperatorValues } from './operator.js';
4
+ import { defaultSelfCommand } from './runner.js';
3
5
  import { buildToolRegistrations } from './schema.js';
4
- import { createMcpServer, registerTools, startServer } from './server.js';
6
+ /** What a child repeats from the server's own start: everything but `--mcp`. */
7
+ function startupArgv() {
8
+ return process.argv.slice(2).filter((token) => token !== '--mcp' && !token.startsWith('--mcp='));
9
+ }
5
10
  /**
6
11
  * Create an MCP plugin that exposes CLI commands as MCP tools.
7
12
  *
8
- * @param opts - Optional server name, version, or instructions override
13
+ * @param opts - Optional server name, version, instructions or selfCommand
9
14
  */
10
15
  export function mcpPlugin(opts = {}) {
11
16
  return definePlugin({
12
17
  meta: {
13
18
  name: '@runa-cmd/mcp',
14
- version: '0.1.0',
15
19
  description: 'MCP server generation from CLI commands',
16
20
  },
17
21
  capabilities: { addGlobalOptions: true },
@@ -23,17 +27,21 @@ export function mcpPlugin(opts = {}) {
23
27
  if (!ctx.globalOptions?.mcp)
24
28
  return;
25
29
  const schema = api.getSchema();
26
- const commands = api.getCommands();
27
- const registrations = buildToolRegistrations(commands, schema);
28
- const server = createMcpServer({
30
+ const registrations = applyOperatorValues(buildToolRegistrations(api.getCommands(), schema), opts, {
31
+ configValues: await api.getConfigValues(),
32
+ env: process.env,
33
+ globals: ctx.globalOptions,
34
+ });
35
+ // Loaded here so a plain CLI run doesn't pay for the MCP SDK
36
+ const { serve } = await import('./server.js');
37
+ await serve(registrations, {
29
38
  name: opts.name ?? schema.meta.name,
30
39
  version: opts.version ?? schema.meta.version ?? '0.0.0',
31
40
  instructions: opts.instructions,
41
+ selfCommand: opts.selfCommand ?? defaultSelfCommand(),
42
+ argv: startupArgv(),
32
43
  });
33
- registerTools(server, registrations);
34
- await startServer(server);
35
- // Short-circuit — MCP server now running, don't execute CLI command
36
- // NOTE: Do NOT call process.exit() — server must stay alive for tool invocations
44
+ // The server closed: there is no command to run
37
45
  ctx.shortCircuit?.();
38
46
  });
39
47
  },
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1E;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,OAAyB,EAAE;IACpD,OAAO,YAAY,CAAC;QACnB,IAAI,EAAE;YACL,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,yCAAyC;SACtD;QACD,YAAY,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE;QACxC,KAAK,CAAC,GAAG;YACR,uCAAuC;YACvC,GAAG,CAAC,eAAe,CAClB,KAAK,EACL,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAClE,CAAC;YAEF,mCAAmC;YACnC,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,EAAE,GAAgB,EAAE,EAAE;gBACpD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG;oBAAE,OAAO;gBAEpC,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;gBAEnC,MAAM,aAAa,GAAG,sBAAsB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAE/D,MAAM,MAAM,GAAG,eAAe,CAAC;oBAC9B,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI;oBACnC,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO;oBACvD,YAAY,EAAE,IAAI,CAAC,YAAY;iBAC/B,CAAC,CAAC;gBAEH,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;gBACrC,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;gBAE1B,oEAAoE;gBACpE,iFAAiF;gBACjF,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;YACtB,CAAC,CAAC,CAAC;QACJ,CAAC;KACD,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAGrD,gFAAgF;AAChF,SAAS,WAAW;IACnB,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,OAAyB,EAAE;IACpD,OAAO,YAAY,CAAC;QACnB,IAAI,EAAE;YACL,IAAI,EAAE,eAAe;YACrB,WAAW,EAAE,yCAAyC;SACtD;QACD,YAAY,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE;QACxC,KAAK,CAAC,GAAG;YACR,uCAAuC;YACvC,GAAG,CAAC,eAAe,CAClB,KAAK,EACL,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAClE,CAAC;YAEF,mCAAmC;YACnC,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,EAAE,GAAgB,EAAE,EAAE;gBACpD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG;oBAAE,OAAO;gBAEpC,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;gBAC/B,MAAM,aAAa,GAAG,mBAAmB,CACxC,sBAAsB,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,EACjD,IAAI,EACJ;oBACC,YAAY,EAAE,MAAM,GAAG,CAAC,eAAe,EAAE;oBACzC,GAAG,EAAE,OAAO,CAAC,GAAG;oBAChB,OAAO,EAAE,GAAG,CAAC,aAAa;iBAC1B,CACD,CAAC;gBAEF,6DAA6D;gBAC7D,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;gBAE9C,MAAM,KAAK,CAAC,aAAa,EAAE;oBAC1B,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI;oBACnC,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO;oBACvD,YAAY,EAAE,IAAI,CAAC,YAAY;oBAC/B,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,kBAAkB,EAAE;oBACrD,IAAI,EAAE,WAAW,EAAE;iBACnB,CAAC,CAAC;gBAEH,gDAAgD;gBAChD,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;YACtB,CAAC,CAAC,CAAC;QACJ,CAAC;KACD,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { type ToolReport, type ToolRequest } from '@runa-cmd/core/internal';
2
+ /** About 25,000 tokens, more than what a model can use from one call. */
3
+ export declare const DEFAULT_MAX_OUTPUT: number;
4
+ export interface RunOptions {
5
+ /** How to start this CLI: executable and arguments */
6
+ selfCommand: string[];
7
+ /** Startup arguments every child receives, like global options */
8
+ argv: string[];
9
+ signal?: AbortSignal;
10
+ /** Most bytes kept from stdout, and from stderr */
11
+ maxOutput?: number;
12
+ /** Values to hide from what the command prints */
13
+ redactions?: string[];
14
+ }
15
+ export interface ChildOutcome {
16
+ status: number | null;
17
+ stdout: string;
18
+ stderr: string;
19
+ reports: ToolReport[];
20
+ /** It ended because it was told to stop */
21
+ cancelled?: boolean;
22
+ }
23
+ /** Resolves once every child ended, for a server that is closing. */
24
+ export declare function childrenFinished(): Promise<void>;
25
+ /** How this process was started, which is how to start it again. */
26
+ export declare function defaultSelfCommand(): string[];
27
+ export declare function runChild(request: ToolRequest, options: RunOptions): Promise<ChildOutcome>;
28
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAWA,OAAO,EAMN,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,MAAM,yBAAyB,CAAC;AAQjC,yEAAyE;AACzE,eAAO,MAAM,kBAAkB,QAAa,CAAC;AAE7C,MAAM,WAAW,UAAU;IAC1B,sDAAsD;IACtD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,kEAAkE;IAClE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAID,qEAAqE;AACrE,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEtD;AAaD,oEAAoE;AACpE,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAE7C;AA8CD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAgEzF"}
package/dist/runner.js ADDED
@@ -0,0 +1,142 @@
1
+ /**
2
+ * @runa-cmd/mcp — Runs the CLI itself as a child process (ADR-0030)
3
+ *
4
+ * The request and the reports travel over their own channels, so whatever the
5
+ * command does with stdout, stderr or process.exit stays inside the child.
6
+ * Each child leads its own process group and holds an IPC channel with this
7
+ * process: cutting it tells the child to stop, and so does this process dying,
8
+ * however it dies (ADR-0033).
9
+ */
10
+ import { spawn } from 'node:child_process';
11
+ import { killProcessTree, STOP_DEADLINE_MS, TOOL_CALL_ENV, TOOL_INPUT_FD, TOOL_REPORT_FD, } from '@runa-cmd/core/internal';
12
+ import { redact } from './operator.js';
13
+ const IPC_CHANNEL = 'ipc';
14
+ /** Enough for what the child wrote to reach us; a process it left holding stdio can't delay more. */
15
+ const DRAIN_MS = 250;
16
+ /** About 25,000 tokens, more than what a model can use from one call. */
17
+ export const DEFAULT_MAX_OUTPUT = 100 * 1024;
18
+ const running = new Map();
19
+ /** Resolves once every child ended, for a server that is closing. */
20
+ export async function childrenFinished() {
21
+ await Promise.all(running.values());
22
+ }
23
+ let endsChildrenOnExit = false;
24
+ /** The last net for an exit that didn't go through closing the server. */
25
+ function endChildrenOnExit() {
26
+ if (endsChildrenOnExit)
27
+ return;
28
+ endsChildrenOnExit = true;
29
+ process.on('exit', () => {
30
+ for (const pid of running.keys())
31
+ killProcessTree(pid);
32
+ });
33
+ }
34
+ /** How this process was started, which is how to start it again. */
35
+ export function defaultSelfCommand() {
36
+ return [process.execPath, ...process.execArgv, process.argv[1] ?? ''];
37
+ }
38
+ function parseReports(raw) {
39
+ return raw
40
+ .split('\n')
41
+ .filter(Boolean)
42
+ .map((line) => JSON.parse(line));
43
+ }
44
+ function collect(stream) {
45
+ const chunks = [];
46
+ stream.on('data', (chunk) => chunks.push(chunk));
47
+ return () => Buffer.concat(chunks).toString('utf8');
48
+ }
49
+ /**
50
+ * Keep the start and the end of a stream, whatever its size. Both ends hold
51
+ * extra bytes, dropped after redacting: a value cut in half can't be found, so
52
+ * the cut must never fall on something still visible.
53
+ */
54
+ function collectEnds(stream, limit, redactions) {
55
+ const margin = Math.max(0, ...redactions.map((value) => Buffer.byteLength(value)));
56
+ const keep = Math.ceil(limit / 2) + margin;
57
+ let head = Buffer.alloc(0);
58
+ let tail = Buffer.alloc(0);
59
+ let seen = 0;
60
+ stream.on('data', (chunk) => {
61
+ seen += chunk.length;
62
+ const room = keep - head.length;
63
+ if (room > 0)
64
+ head = Buffer.concat([head, chunk.subarray(0, room)]);
65
+ const rest = chunk.subarray(Math.max(room, 0));
66
+ if (rest.length > 0)
67
+ tail = Buffer.concat([tail, rest]).subarray(-keep);
68
+ });
69
+ return () => {
70
+ if (head.length + tail.length === seen) {
71
+ return redact(Buffer.concat([head, tail]).toString('utf8'), redactions);
72
+ }
73
+ const start = redact(head.toString('utf8'), redactions);
74
+ const end = redact(tail.toString('utf8'), redactions);
75
+ const notice = `[Output truncated: ${seen - limit} bytes omitted]`;
76
+ return `${start.slice(0, start.length - margin)}\n\n${notice}\n\n${end.slice(margin)}`;
77
+ };
78
+ }
79
+ export function runChild(request, options) {
80
+ const [executable = '', ...selfArgs] = options.selfCommand;
81
+ const { maxOutput = DEFAULT_MAX_OUTPUT, redactions = [], signal } = options;
82
+ endChildrenOnExit();
83
+ const child = spawn(executable, [...selfArgs, ...options.argv], {
84
+ stdio: ['ignore', 'pipe', 'pipe', 'pipe', 'pipe', IPC_CHANNEL],
85
+ env: { ...process.env, [TOOL_CALL_ENV]: '1' },
86
+ // Also on Windows: otherwise a job object kills the child with this process,
87
+ // and it never gets to run its cleanup.
88
+ detached: true,
89
+ windowsHide: true,
90
+ });
91
+ const finished = new Promise((resolve) => {
92
+ const stdout = collectEnds(child.stdout, maxOutput, redactions);
93
+ const stderr = collectEnds(child.stderr, maxOutput, redactions);
94
+ const reports = collect(child.stdio[TOOL_REPORT_FD]);
95
+ const input = child.stdio[TOOL_INPUT_FD];
96
+ input.on('error', () => { }); // A child that dies early closes this pipe: its exit tells why
97
+ input.end(JSON.stringify(request));
98
+ let force;
99
+ const cancel = () => {
100
+ if (child.connected)
101
+ child.disconnect();
102
+ force = setTimeout(() => {
103
+ if (child.pid !== undefined)
104
+ killProcessTree(child.pid);
105
+ }, STOP_DEADLINE_MS);
106
+ };
107
+ if (signal?.aborted)
108
+ cancel();
109
+ else
110
+ signal?.addEventListener('abort', cancel, { once: true });
111
+ let spawnError = '';
112
+ let settled = false;
113
+ const settle = (status) => {
114
+ if (settled)
115
+ return;
116
+ settled = true;
117
+ clearTimeout(force);
118
+ signal?.removeEventListener('abort', cancel);
119
+ if (child.pid !== undefined)
120
+ running.delete(child.pid);
121
+ for (const stream of child.stdio)
122
+ stream?.destroy();
123
+ resolve({
124
+ status,
125
+ stdout: stdout(),
126
+ stderr: stderr() || spawnError,
127
+ reports: parseReports(reports()),
128
+ cancelled: signal?.aborted,
129
+ });
130
+ };
131
+ child.on('error', (error) => {
132
+ spawnError = error.message;
133
+ });
134
+ child.on('close', settle);
135
+ // A process the command left behind can hold stdio long after this one is gone
136
+ child.on('exit', (status) => setTimeout(() => settle(status), DRAIN_MS).unref());
137
+ });
138
+ if (child.pid !== undefined)
139
+ running.set(child.pid, finished);
140
+ return finished;
141
+ }
142
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
package/dist/schema.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * Walks the CommandTree and builds ToolRegistration objects
5
5
  * that map each command to an MCP tool with merged input schema.
6
6
  */
7
+ import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
7
8
  import type { CLISchema, Command, CommandTree } from '@runa-cmd/core';
8
9
  import type { ZodType } from 'zod';
9
10
  /**
@@ -12,6 +13,8 @@ import type { ZodType } from 'zod';
12
13
  export interface ToolRegistration {
13
14
  /** MCP tool name (e.g., 'config_set') */
14
15
  name: string;
16
+ /** Command path in the tree (e.g., ['config', 'set']) */
17
+ path: string[];
15
18
  /** Tool description from command metadata */
16
19
  description: string;
17
20
  /** Merged args + options as a Zod shape (Record<string, ZodType>) */
@@ -24,6 +27,14 @@ export interface ToolRegistration {
24
27
  argKeys: Set<string>;
25
28
  /** Keys that belong to options */
26
29
  optionKeys: Set<string>;
30
+ /** Options the operator fixed: out of the schema, and dropped from any call */
31
+ fixed: Set<string>;
32
+ /** Text to hide from what the command writes */
33
+ redactions: string[];
34
+ /** Most bytes of output this tool can answer with */
35
+ maxOutput: number;
36
+ /** Hints for the client, only if the author declared them */
37
+ annotations?: ToolAnnotations;
27
38
  }
28
39
  /**
29
40
  * Build MCP tool registrations from a CommandTree and CLISchema.
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAiB,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAInC;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,uCAAuC;IACvC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mDAAmD;IACnD,OAAO,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,kCAAkC;IAClC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB;AAyFD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,SAAS,GACf,gBAAgB,EAAE,CAEpB"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAiB,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAKnC;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,uCAAuC;IACvC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mDAAmD;IACnD,OAAO,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,kCAAkC;IAClC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,+EAA+E;IAC/E,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,gDAAgD;IAChD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,eAAe,CAAC;CAC9B;AA6FD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,SAAS,GACf,gBAAgB,EAAE,CAEpB"}
package/dist/schema.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { DEFAULT_MAX_OUTPUT } from './runner.js';
1
2
  // ─── Helpers ────────────────────────────────────────────────
2
3
  function isCommand(value) {
3
4
  return '_type' in value && value._type === 'runa:command';
@@ -52,12 +53,16 @@ function walkTree(tree, parentPath, cliSchema) {
52
53
  }
53
54
  registrations.push({
54
55
  name: toolName,
56
+ path: fullPath,
55
57
  description: cmdSchema?.description ?? entry.meta.description,
56
58
  inputShape,
57
59
  outputSchema: entry.output,
58
60
  command: entry,
59
61
  argKeys,
60
62
  optionKeys,
63
+ fixed: new Set(),
64
+ redactions: [],
65
+ maxOutput: DEFAULT_MAX_OUTPUT,
61
66
  });
62
67
  }
63
68
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -1,36 +1,29 @@
1
1
  /**
2
- * @runa-cmd/mcp — MCP server creation and tool registration
2
+ * @runa-cmd/mcp — MCP server over a CLI run as subprocesses
3
3
  *
4
- * Creates an MCP server, registers tools from ToolRegistrations,
5
- * and manages the server lifecycle (stdio transport, signal handlers).
4
+ * Uses the SDK's low-level Server: schemas are only described here, because
5
+ * validating in the server would apply transforms and defaults that the child
6
+ * applies again. The child owns validation, as in any run of the CLI.
6
7
  */
7
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
9
+ import { type CallToolResult, type Tool } from '@modelcontextprotocol/sdk/types.js';
10
+ import type { ChildOutcome, RunOptions } from './runner.js';
8
11
  import type { ToolRegistration } from './schema.js';
12
+ export declare function toolDefinition(reg: ToolRegistration): Tool;
9
13
  /**
10
- * Create an MCP server with the given metadata.
14
+ * Exit code 0 is not enough: a middleware can skip the command and a command
15
+ * can exit on its own. Only the reports say how far it got.
11
16
  */
12
- export declare function createMcpServer(opts: {
17
+ export declare function toToolResult(reg: ToolRegistration, outcome: ChildOutcome): CallToolResult;
18
+ export interface ServeOptions extends RunOptions {
13
19
  name: string;
14
20
  version: string;
15
21
  instructions?: string;
16
- }): McpServer;
22
+ }
23
+ export declare function createMcpServer(registrations: ToolRegistration[], options: ServeOptions): Server;
17
24
  /**
18
- * Register MCP tools on the server from ToolRegistration objects.
19
- *
20
- * Each tool's handler:
21
- * 1. Splits the input back into args/options using stored key sets
22
- * 2. Calls command.run() with a constructed RunContext
23
- * 3. Returns structured content if outputSchema exists, text otherwise
24
- * 4. Catches errors and returns isError: true
25
- */
26
- export declare function registerTools(server: McpServer, registrations: ToolRegistration[]): void;
27
- /**
28
- * Start the MCP server on stdio transport.
29
- * Registers signal handlers for graceful shutdown.
30
- *
31
- * Returns a close function for cleanup.
25
+ * Serve until the client disconnects or the process is told to stop, so the
26
+ * lifecycle of the CLI, cleanup included, ends when the server does.
32
27
  */
33
- export declare function startServer(server: McpServer): Promise<{
34
- close: () => Promise<void>;
35
- }>;
28
+ export declare function serve(registrations: ToolRegistration[], options: ServeOptions): Promise<void>;
36
29
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,SAAS,CAKZ;AAID;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,GAAG,IAAI,CA6BxF;AAoED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAiB5F"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,EAEN,KAAK,cAAc,EAEnB,KAAK,IAAI,EACT,MAAM,oCAAoC,CAAC;AAI5C,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAgBpD,wBAAgB,cAAc,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,CAS1D;AAyFD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,YAAY,GAAG,cAAc,CAiBzF;AAID,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAiBD,wBAAgB,eAAe,CAAC,aAAa,EAAE,gBAAgB,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CAkChG;AAED;;;GAGG;AACH,wBAAsB,KAAK,CAC1B,aAAa,EAAE,gBAAgB,EAAE,EACjC,OAAO,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAuBf"}
package/dist/server.js CHANGED
@@ -1,126 +1,169 @@
1
1
  /**
2
- * @runa-cmd/mcp — MCP server creation and tool registration
2
+ * @runa-cmd/mcp — MCP server over a CLI run as subprocesses
3
3
  *
4
- * Creates an MCP server, registers tools from ToolRegistrations,
5
- * and manages the server lifecycle (stdio transport, signal handlers).
4
+ * Uses the SDK's low-level Server: schemas are only described here, because
5
+ * validating in the server would apply transforms and defaults that the child
6
+ * applies again. The child owns validation, as in any run of the CLI.
6
7
  */
7
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
+ import { setImmediate } from 'node:timers/promises';
9
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
10
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
9
- // ─── Server Creation ────────────────────────────────────────
10
- /**
11
- * Create an MCP server with the given metadata.
12
- */
13
- export function createMcpServer(opts) {
14
- return new McpServer({ name: opts.name, version: opts.version }, { instructions: opts.instructions });
11
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
12
+ import { RunaError } from '@runa-cmd/core';
13
+ import { z } from 'zod';
14
+ import { childrenFinished, runChild } from './runner.js';
15
+ const SELF_CHECK_TIMEOUT_MS = 10_000;
16
+ // ─── Tool definitions ───────────────────────────────────────
17
+ function toJsonSchema(schema) {
18
+ return z.toJSONSchema(schema, { io: 'input', unrepresentable: 'any' });
15
19
  }
16
- // ─── Tool Registration ──────────────────────────────────────
20
+ /** MCP only allows objects as structured output. */
21
+ function structuredOutput(reg) {
22
+ if (!reg.outputSchema)
23
+ return undefined;
24
+ return toJsonSchema(reg.outputSchema).type === 'object' ? reg.outputSchema : undefined;
25
+ }
26
+ export function toolDefinition(reg) {
27
+ const output = structuredOutput(reg);
28
+ return {
29
+ name: reg.name,
30
+ description: reg.description,
31
+ inputSchema: toJsonSchema(z.object(reg.inputShape)),
32
+ ...(output ? { outputSchema: toJsonSchema(output) } : {}),
33
+ ...(reg.annotations ? { annotations: reg.annotations } : {}),
34
+ };
35
+ }
36
+ // ─── Results ────────────────────────────────────────────────
37
+ const success = (text) => ({ content: [{ type: 'text', text }] });
38
+ const EFFECT_TEXT = {
39
+ none: 'The command did not run, so it is safe to retry.',
40
+ completed: 'The command already ran. Do not retry it.',
41
+ unknown: 'The command started, so it may have taken effect. Check before retrying.',
42
+ };
17
43
  /**
18
- * Register MCP tools on the server from ToolRegistration objects.
19
- *
20
- * Each tool's handler:
21
- * 1. Splits the input back into args/options using stored key sets
22
- * 2. Calls command.run() with a constructed RunContext
23
- * 3. Returns structured content if outputSchema exists, text otherwise
24
- * 4. Catches errors and returns isError: true
44
+ * The reports say how far the command got, which is what decides whether a
45
+ * retry can repeat its effects. Without one, a command may have done anything:
46
+ * the safe reading of the unknown is never that nothing happened.
25
47
  */
26
- export function registerTools(server, registrations) {
27
- for (const reg of registrations) {
28
- const hasInput = Object.keys(reg.inputShape).length > 0;
29
- if (hasInput) {
30
- server.registerTool(reg.name, {
31
- description: reg.description,
32
- inputSchema: reg.inputShape,
33
- ...(reg.outputSchema ? { outputSchema: reg.outputSchema } : {}),
34
- }, async (input) => {
35
- return executeToolHandler(reg, input);
36
- });
37
- }
38
- else {
39
- server.registerTool(reg.name, {
40
- description: reg.description,
41
- ...(reg.outputSchema ? { outputSchema: reg.outputSchema } : {}),
42
- }, async () => {
43
- return executeToolHandler(reg, {});
44
- });
45
- }
48
+ function findFailure({ reports, status, cancelled }) {
49
+ const reached = (kind) => reports.some((report) => report.kind === kind);
50
+ const failed = reports.find((report) => report.kind === 'failed');
51
+ if (cancelled)
52
+ return { class: 'cancelled', effect: 'unknown' };
53
+ if (reached('oversized'))
54
+ return { class: 'output_too_large', effect: 'completed' };
55
+ if (reached('result')) {
56
+ if (!failed && status === 0)
57
+ return undefined;
58
+ return { class: 'after_run_failed', effect: 'completed' };
59
+ }
60
+ if (reached('ran')) {
61
+ const invalid = failed?.reason === 'output';
62
+ return { class: invalid ? 'invalid_output' : 'after_run_failed', effect: 'completed' };
63
+ }
64
+ if (reached('running')) {
65
+ return { class: failed ? 'command_failed' : 'crashed', effect: 'unknown' };
66
+ }
67
+ if (failed) {
68
+ return { class: failed.reason === 'input' ? 'invalid_input' : 'rejected', effect: 'none' };
69
+ }
70
+ return { class: status === 0 ? 'not_run' : 'crashed', effect: 'none' };
71
+ }
72
+ /** Anything the model has to read goes in the text: `_meta` is for the client. */
73
+ const failure = (reason, found) => ({
74
+ isError: true,
75
+ content: [{ type: 'text', text: `${reason}\n\n${EFFECT_TEXT[found.effect]}` }],
76
+ _meta: { 'runa/error': { ...found, safeToRetry: found.effect === 'none' } },
77
+ });
78
+ function failedChild(reg, outcome, found) {
79
+ const oversized = outcome.reports.find((report) => report.kind === 'oversized');
80
+ if (oversized) {
81
+ return failure(`Command '${reg.name}' returned ${oversized.bytes} bytes, over the limit of ${reg.maxOutput}.`, found);
46
82
  }
83
+ const written = outcome.stderr.trim();
84
+ const printed = outcome.stdout.trim();
85
+ return failure(written || printed || silentFailure(reg, outcome, found), found);
86
+ }
87
+ function silentFailure(reg, outcome, found) {
88
+ if (found.class === 'cancelled')
89
+ return `Command '${reg.name}' was cancelled.`;
90
+ if (outcome.status !== 0)
91
+ return `Command '${reg.name}' exited with code ${outcome.status}.`;
92
+ return `Command '${reg.name}' did not ${found.effect === 'none' ? 'run' : 'finish'}.`;
47
93
  }
48
94
  /**
49
- * Execute a tool handler — splits input into args/options, runs the command,
50
- * and returns the appropriate MCP result.
95
+ * Exit code 0 is not enough: a middleware can skip the command and a command
96
+ * can exit on its own. Only the reports say how far it got.
51
97
  */
52
- async function executeToolHandler(reg, input) {
53
- // Split input back into args and options
54
- const runArgs = {};
55
- const runOptions = {};
56
- for (const [key, value] of Object.entries(input)) {
57
- if (reg.argKeys.has(key)) {
58
- runArgs[key] = value;
59
- }
60
- else {
61
- runOptions[key] = value;
62
- }
98
+ export function toToolResult(reg, outcome) {
99
+ const found = findFailure(outcome);
100
+ if (found)
101
+ return failedChild(reg, outcome, found);
102
+ const finished = outcome.reports.find((report) => report.kind === 'result');
103
+ const stdout = outcome.stdout.trim();
104
+ // What run() returned is the author's choice, so it goes as it is.
105
+ const value = finished?.value;
106
+ if (value === undefined || value === null) {
107
+ return success(stdout || `Command '${reg.name}' executed successfully.`);
63
108
  }
64
- try {
65
- const result = await reg.command.run({
66
- args: runArgs,
67
- options: runOptions,
68
- globalOptions: {},
69
- command: reg.command.meta,
70
- rawArgs: [],
71
- rest: [],
72
- });
73
- // Command has output schema — return structured content
74
- if (reg.outputSchema) {
75
- reg.outputSchema.parse(result);
76
- return {
77
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
78
- structuredContent: result,
79
- };
80
- }
81
- // Command returned something (but no output schema)
82
- if (result !== undefined && result !== null) {
83
- const text = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
84
- return {
85
- content: [{ type: 'text', text }],
86
- };
109
+ const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
110
+ return structuredOutput(reg)
111
+ ? { ...success(text), structuredContent: value }
112
+ : success(text);
113
+ }
114
+ /** Fails at startup, with a way out, instead of on the first tool call. */
115
+ async function assertCanRunItself(options) {
116
+ const { reports } = await runChild({ kind: 'ping' }, { ...options, signal: AbortSignal.timeout(SELF_CHECK_TIMEOUT_MS) });
117
+ if (reports.some((report) => report.kind === 'pong'))
118
+ return;
119
+ throw new RunaError(`Cannot run this CLI as a subprocess with: ${options.selfCommand.join(' ')}. ` +
120
+ 'If it is a compiled binary, set mcpPlugin({ selfCommand }).', { code: 'MCP_SELF_CHECK_FAILED' });
121
+ }
122
+ export function createMcpServer(registrations, options) {
123
+ const server = new Server({ name: options.name, version: options.version }, { capabilities: { tools: {} }, instructions: options.instructions });
124
+ server.setRequestHandler(ListToolsRequestSchema, () => ({
125
+ tools: registrations.map(toolDefinition),
126
+ }));
127
+ server.setRequestHandler(CallToolRequestSchema, async ({ params }, extra) => {
128
+ const reg = registrations.find((candidate) => candidate.name === params.name);
129
+ if (!reg) {
130
+ return failure(`Unknown tool: ${params.name}`, { class: 'unknown_tool', effect: 'none' });
87
131
  }
88
- // Void command — success message
89
- return {
90
- content: [{ type: 'text', text: `Command '${reg.name}' executed successfully.` }],
91
- };
92
- }
93
- catch (err) {
94
- return {
95
- isError: true,
96
- content: [
97
- {
98
- type: 'text',
99
- text: err instanceof Error ? err.message : String(err),
100
- },
101
- ],
102
- };
103
- }
132
+ // A fixed option stays what the operator set, whatever the call says
133
+ const input = Object.fromEntries(Object.entries(params.arguments ?? {}).filter(([key]) => !reg.fixed.has(key)));
134
+ const outcome = await runChild({ kind: 'call', path: reg.path, input, maxResultBytes: reg.maxOutput }, {
135
+ ...options,
136
+ signal: options.signal ? AbortSignal.any([extra.signal, options.signal]) : extra.signal,
137
+ maxOutput: reg.maxOutput,
138
+ redactions: reg.redactions,
139
+ });
140
+ return toToolResult(reg, outcome);
141
+ });
142
+ return server;
104
143
  }
105
- // ─── Server Lifecycle ───────────────────────────────────────
106
144
  /**
107
- * Start the MCP server on stdio transport.
108
- * Registers signal handlers for graceful shutdown.
109
- *
110
- * Returns a close function for cleanup.
145
+ * Serve until the client disconnects or the process is told to stop, so the
146
+ * lifecycle of the CLI, cleanup included, ends when the server does.
111
147
  */
112
- export async function startServer(server) {
113
- const transport = new StdioServerTransport();
114
- await server.connect(transport);
148
+ export async function serve(registrations, options) {
149
+ await assertCanRunItself(options);
150
+ const stopping = new AbortController();
151
+ const server = createMcpServer(registrations, { ...options, signal: stopping.signal });
152
+ const closed = new Promise((resolve) => {
153
+ server.onclose = resolve;
154
+ });
155
+ // Calls in flight end first: closing would leave their answers with no way out
115
156
  const close = async () => {
157
+ stopping.abort();
158
+ await childrenFinished();
159
+ await setImmediate(); // Each answer is a few promises away from the child's end
116
160
  await server.close();
117
161
  };
118
- const handleShutdown = async () => {
119
- await close();
120
- process.exit(0);
121
- };
122
- process.on('SIGINT', handleShutdown);
123
- process.on('SIGTERM', handleShutdown);
124
- return { close };
162
+ process.once('SIGINT', close);
163
+ process.once('SIGTERM', close);
164
+ process.stdin.once('end', close);
165
+ process.stdout.on('error', () => { }); // A client that left can't be answered, and that's fine
166
+ await server.connect(new StdioServerTransport());
167
+ await closed;
125
168
  }
126
169
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -3,6 +3,23 @@
3
3
  *
4
4
  * Plugin options for mcpPlugin().
5
5
  */
6
+ import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
7
+ /** What the model can do with one tool, and how it is told about it. */
8
+ export interface ToolOptions {
9
+ /** What the model reads about this tool, instead of the command's description */
10
+ description?: string;
11
+ /**
12
+ * Hints for the client, as MCP defines them, e.g. `{ destructiveHint: true }`.
13
+ * They are not access control: to keep a command from an agent, use `exclude`.
14
+ */
15
+ annotations?: ToolAnnotations;
16
+ /** Options the model can set, even if they declare env or have a config value */
17
+ expose?: string[];
18
+ /** Options that must come from env or config: without a value, the server won't start */
19
+ serverOnly?: string[];
20
+ /** Most bytes of output for this tool, instead of the plugin's `maxOutput` */
21
+ maxOutput?: number;
22
+ }
6
23
  /**
7
24
  * Options for mcpPlugin().
8
25
  */
@@ -13,5 +30,22 @@ export interface McpPluginOptions {
13
30
  version?: string;
14
31
  /** Server instructions for cross-tool workflows */
15
32
  instructions?: string;
33
+ /**
34
+ * How to start this CLI again: executable and arguments. Each tool call runs
35
+ * it as a child process. The default repeats how this process was started,
36
+ * and the server checks it before accepting calls. Set it if that check fails,
37
+ * e.g. `[process.execPath]` for a binary.
38
+ */
39
+ selfCommand?: string[];
40
+ /** Tools that won't exist for an agent, e.g. `['deploy', 'config_reset']` */
41
+ exclude?: string[];
42
+ /**
43
+ * Most bytes a tool can answer with. Longer output keeps its start and end,
44
+ * with a notice. A returned value isn't cut: over this limit, the call fails.
45
+ * Default: 100 KiB.
46
+ */
47
+ maxOutput?: number;
48
+ /** Per-tool settings, by tool name, e.g. `{ deploy: { serverOnly: ['token'] } }` */
49
+ tools?: Record<string, ToolOptions>;
16
50
  }
17
51
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAE1E,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC3B,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACpC"}
package/dist/types.js CHANGED
@@ -1,7 +1,2 @@
1
- /**
2
- * @runa-cmd/mcp — Type definitions
3
- *
4
- * Plugin options for mcpPlugin().
5
- */
6
1
  export {};
7
2
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runa-cmd/mcp",
3
- "version": "0.2.0-beta.0",
3
+ "version": "0.2.0-beta.1",
4
4
  "description": "MCP (Model Context Protocol) server mode for Runa CLIs. Turn commands into AI-callable tools.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -25,7 +25,7 @@
25
25
  "@modelcontextprotocol/sdk": "^1.29.0"
26
26
  },
27
27
  "peerDependencies": {
28
- "@runa-cmd/core": "^0.2.0-beta.0",
28
+ "@runa-cmd/core": "^0.2.0-beta.1",
29
29
  "zod": "^4.0.0"
30
30
  },
31
31
  "engines": {
@@ -51,7 +51,7 @@
51
51
  "@types/node": "^25.6.0",
52
52
  "typescript": "^6.0.2",
53
53
  "zod": "^4.3.6",
54
- "@runa-cmd/core": "0.2.0-beta.0"
54
+ "@runa-cmd/core": "0.2.0-beta.1"
55
55
  },
56
56
  "scripts": {
57
57
  "build": "tsc",