@runa-cmd/mcp 0.2.0-beta.0 → 0.2.0-beta.2
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 +105 -8
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/operator.d.ts +15 -0
- package/dist/operator.d.ts.map +1 -0
- package/dist/operator.js +110 -0
- package/dist/operator.js.map +1 -0
- package/dist/plugin.d.ts +4 -5
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +18 -10
- package/dist/plugin.js.map +1 -1
- package/dist/runner.d.ts +28 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +142 -0
- package/dist/runner.js.map +1 -0
- package/dist/schema.d.ts +11 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +5 -0
- package/dist/schema.js.map +1 -1
- package/dist/server.d.ts +17 -24
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +148 -105
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -5
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
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
|
-
-
|
|
63
|
-
-
|
|
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
|
-
|
|
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
|
|
92
|
-
| Command
|
|
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
package/dist/index.d.ts.map
CHANGED
|
@@ -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"}
|
package/dist/operator.js
ADDED
|
@@ -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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
|
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
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA
|
|
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
|
-
|
|
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
|
|
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
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
},
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/runner.d.ts
ADDED
|
@@ -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.
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -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;
|
|
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 {
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"
|
|
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
|
|
2
|
+
* @runa-cmd/mcp — MCP server over a CLI run as subprocesses
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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 {
|
|
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
|
-
*
|
|
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
|
|
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
|
-
}
|
|
22
|
+
}
|
|
23
|
+
export declare function createMcpServer(registrations: ToolRegistration[], options: ServeOptions): Server;
|
|
17
24
|
/**
|
|
18
|
-
*
|
|
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
|
|
34
|
-
close: () => Promise<void>;
|
|
35
|
-
}>;
|
|
28
|
+
export declare function serve(registrations: ToolRegistration[], options: ServeOptions): Promise<void>;
|
|
36
29
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA
|
|
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
|
|
2
|
+
* @runa-cmd/mcp — MCP server over a CLI run as subprocesses
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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 {
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
*
|
|
50
|
-
*
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
//
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
*
|
|
108
|
-
*
|
|
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
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
|
|
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
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA
|
|
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
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
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
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
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.
|
|
3
|
+
"version": "0.2.0-beta.2",
|
|
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.
|
|
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.
|
|
54
|
+
"@runa-cmd/core": "0.2.0-beta.2"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "tsc",
|