@andrei.fyi/picocli 0.1.0
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 +357 -0
- package/dist/create-eQnnIhZu.d.cts +87 -0
- package/dist/create-eQnnIhZu.d.ts +87 -0
- package/dist/index.cjs +1175 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +1166 -0
- package/dist/mcp/index.cjs +507 -0
- package/dist/mcp/index.d.cts +30 -0
- package/dist/mcp/index.d.ts +30 -0
- package/dist/mcp/index.js +502 -0
- package/dist/testing/testkit.cjs +115 -0
- package/dist/testing/testkit.d.cts +23 -0
- package/dist/testing/testkit.d.ts +23 -0
- package/dist/testing/testkit.js +112 -0
- package/package.json +94 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index_js = require('@modelcontextprotocol/sdk/server/index.js');
|
|
4
|
+
var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
5
|
+
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
6
|
+
var zod = require('zod');
|
|
7
|
+
var async_hooks = require('async_hooks');
|
|
8
|
+
|
|
9
|
+
// src/mcp/server.ts
|
|
10
|
+
|
|
11
|
+
// src/flags/tokenizer.ts
|
|
12
|
+
var isLongFlagToken = (token) => {
|
|
13
|
+
return token.startsWith("--") && token.length > 2;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/schemas/zod.ts
|
|
17
|
+
var getShape = (obj) => {
|
|
18
|
+
if (!obj) return void 0;
|
|
19
|
+
return obj.shape;
|
|
20
|
+
};
|
|
21
|
+
var getShapeKeys = (obj) => {
|
|
22
|
+
return Object.keys(getShape(obj) ?? {});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// src/schemas/object.ts
|
|
26
|
+
var overrideDateJsonSchema = (ctx) => {
|
|
27
|
+
if (ctx.zodSchema?._zod?.def?.type === "date") {
|
|
28
|
+
const jsonSchema = ctx.jsonSchema;
|
|
29
|
+
jsonSchema.type = "string";
|
|
30
|
+
jsonSchema.format = "date-time";
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var mergeObjects = (parts) => {
|
|
34
|
+
const shapes = parts.map(getShape).filter((shape) => shape !== void 0);
|
|
35
|
+
if (shapes.length === 0) return void 0;
|
|
36
|
+
return zod.z.object(Object.assign({}, ...shapes));
|
|
37
|
+
};
|
|
38
|
+
var getDuplicateKeys = (parts) => {
|
|
39
|
+
const seen = /* @__PURE__ */ new Set();
|
|
40
|
+
const duplicate = /* @__PURE__ */ new Set();
|
|
41
|
+
for (const part of parts) {
|
|
42
|
+
const shape = getShape(part);
|
|
43
|
+
for (const key of Object.keys(shape ?? {})) {
|
|
44
|
+
if (seen.has(key)) duplicate.add(key);
|
|
45
|
+
else seen.add(key);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return [...duplicate].sort();
|
|
49
|
+
};
|
|
50
|
+
var getDuplicateKeyMessage = (keys) => {
|
|
51
|
+
return `schema fields must be unique across merged inputs: ${keys.join(", ")}`;
|
|
52
|
+
};
|
|
53
|
+
var toJsonSchema = (schema) => {
|
|
54
|
+
if (!schema) return { type: "object", properties: {}, additionalProperties: false };
|
|
55
|
+
return zod.z.toJSONSchema(schema, {
|
|
56
|
+
unrepresentable: "any",
|
|
57
|
+
override: overrideDateJsonSchema
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// src/command/tree.ts
|
|
62
|
+
var isValidCommandName = (name) => name.length > 0 && !isLongFlagToken(name) && name !== "--";
|
|
63
|
+
var commandTreeIssueCache = /* @__PURE__ */ new WeakMap();
|
|
64
|
+
var commandChildrenMap = /* @__PURE__ */ new WeakMap();
|
|
65
|
+
var emptyCommandChildren = /* @__PURE__ */ new Map();
|
|
66
|
+
var getCommandAliases = (def) => typeof def.alias === "string" ? [def.alias] : def.alias ?? [];
|
|
67
|
+
var getCommandChildren = (node) => {
|
|
68
|
+
return commandChildrenMap.get(node) ?? emptyCommandChildren;
|
|
69
|
+
};
|
|
70
|
+
var findCommandTreeIssue = (root) => {
|
|
71
|
+
if (commandTreeIssueCache.has(root)) return commandTreeIssueCache.get(root);
|
|
72
|
+
const walk = (node) => {
|
|
73
|
+
const owner = node.name;
|
|
74
|
+
const seen = /* @__PURE__ */ new Map();
|
|
75
|
+
const children = getCommandChildren(node);
|
|
76
|
+
for (const [name, child] of children) {
|
|
77
|
+
if (!isValidCommandName(name)) return `invalid command name "${name}" under "${owner}"`;
|
|
78
|
+
const existing = seen.get(name);
|
|
79
|
+
if (existing) return `command name "${name}" for "${name}" conflicts with ${existing}`;
|
|
80
|
+
seen.set(name, `command "${name}"`);
|
|
81
|
+
for (const alias of getCommandAliases(child.def)) {
|
|
82
|
+
if (!isValidCommandName(alias)) return `invalid alias "${alias}" for command "${name}"`;
|
|
83
|
+
const conflict = seen.get(alias);
|
|
84
|
+
if (conflict) return `alias "${alias}" for command "${name}" conflicts with ${conflict}`;
|
|
85
|
+
seen.set(alias, `command "${name}"`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const child of children.values()) {
|
|
89
|
+
const issue2 = walk(child);
|
|
90
|
+
if (issue2) return issue2;
|
|
91
|
+
}
|
|
92
|
+
return void 0;
|
|
93
|
+
};
|
|
94
|
+
const issue = walk(root);
|
|
95
|
+
commandTreeIssueCache.set(root, issue);
|
|
96
|
+
return issue;
|
|
97
|
+
};
|
|
98
|
+
var getEffectiveCommandDefinition = (chain) => {
|
|
99
|
+
const node = chain[chain.length - 1];
|
|
100
|
+
if (!node) return {};
|
|
101
|
+
return {
|
|
102
|
+
...node.def,
|
|
103
|
+
options: mergeObjects(chain.map((n) => n.def.options)),
|
|
104
|
+
env: mergeObjects(chain.map((n) => n.def.env))
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
var collectCommandEntries = (root) => {
|
|
108
|
+
const entries = [];
|
|
109
|
+
const walk = (node, commandPath, ancestors) => {
|
|
110
|
+
if (node.def.hidden) return;
|
|
111
|
+
const chain = [...ancestors, node];
|
|
112
|
+
entries.push({ commandPath, node, chain, def: getEffectiveCommandDefinition(chain) });
|
|
113
|
+
for (const [name, child] of getCommandChildren(node)) walk(child, [...commandPath, name], chain);
|
|
114
|
+
};
|
|
115
|
+
walk(root, [], []);
|
|
116
|
+
return entries;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// src/errors.ts
|
|
120
|
+
var PicocliError = class extends Error {
|
|
121
|
+
code;
|
|
122
|
+
constructor(code, message) {
|
|
123
|
+
super(message);
|
|
124
|
+
this.name = "PicocliError";
|
|
125
|
+
this.code = code;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
var isPicocliError = (e) => e instanceof PicocliError || typeof e === "object" && e !== null && e.name === "PicocliError";
|
|
129
|
+
var getExitCodeForError = (code) => code === "UNKNOWN" ? 1 : 2;
|
|
130
|
+
|
|
131
|
+
// src/render/result.ts
|
|
132
|
+
var createSuccessResult = (data) => {
|
|
133
|
+
return {
|
|
134
|
+
ok: true,
|
|
135
|
+
data: data === void 0 ? null : data
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
var createErrorResult = (code, message) => {
|
|
139
|
+
return { ok: false, error: { code, message } };
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// src/schemas/validate.ts
|
|
143
|
+
var parseSchema = (schema, input, kind) => {
|
|
144
|
+
const result = schema.safeParse(input);
|
|
145
|
+
if (result.success) return result.data;
|
|
146
|
+
const issue = result.error.issues[0] ?? {};
|
|
147
|
+
const field = issue.path?.join(".") || "(input)";
|
|
148
|
+
const expected = "expected" in issue ? String(issue.expected) : void 0;
|
|
149
|
+
const coercible = expected === "number" || expected === "int" || expected === "bigint";
|
|
150
|
+
const hint = coercible ? ` (CLI values arrive as strings \u2014 use z.coerce.${expected}() for non-string ${kind}s)` : "";
|
|
151
|
+
const message = `invalid ${kind} "${field}": ${issue.message}${hint}`;
|
|
152
|
+
throw new PicocliError("VALIDATION", message);
|
|
153
|
+
};
|
|
154
|
+
var parseOutputSchema = (schema, data) => {
|
|
155
|
+
const result = schema.safeParse(data);
|
|
156
|
+
if (result.success) return result.data;
|
|
157
|
+
const issue = result.error.issues[0] ?? {};
|
|
158
|
+
const field = issue.path?.join(".") || "(output)";
|
|
159
|
+
const message = `invalid output "${field}": ${issue.message}`;
|
|
160
|
+
throw new PicocliError("VALIDATION", message);
|
|
161
|
+
};
|
|
162
|
+
var validateAll = (params) => {
|
|
163
|
+
const { args, options, env, argsInput, optionsInput, envInput } = params;
|
|
164
|
+
return {
|
|
165
|
+
args: args ? parseSchema(args, argsInput, "argument") : {},
|
|
166
|
+
options: options ? parseSchema(options, optionsInput, "option") : {},
|
|
167
|
+
env: env ? parseSchema(env, envInput, "environment variable") : {}
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
var METHODS = ["log", "info", "debug", "warn", "error"];
|
|
171
|
+
var consoleCaptureStorage = new async_hooks.AsyncLocalStorage();
|
|
172
|
+
var depth = 0;
|
|
173
|
+
var original;
|
|
174
|
+
var createConsoleRouter = (method) => (...args) => {
|
|
175
|
+
const capture = consoleCaptureStorage.getStore();
|
|
176
|
+
const handler = capture?.[method];
|
|
177
|
+
if (handler) handler(args);
|
|
178
|
+
else original?.[method](...args);
|
|
179
|
+
};
|
|
180
|
+
var installConsoleCapture = () => {
|
|
181
|
+
if (depth++ > 0) return;
|
|
182
|
+
original = Object.fromEntries(METHODS.map((method) => [method, console[method].bind(console)]));
|
|
183
|
+
for (const method of METHODS) {
|
|
184
|
+
console[method] = createConsoleRouter(method);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
var uninstallConsoleCapture = () => {
|
|
188
|
+
depth--;
|
|
189
|
+
if (depth > 0 || !original) return;
|
|
190
|
+
for (const method of METHODS) console[method] = original[method];
|
|
191
|
+
original = void 0;
|
|
192
|
+
};
|
|
193
|
+
var withConsoleCapture = async (capture, runCaptured) => {
|
|
194
|
+
installConsoleCapture();
|
|
195
|
+
try {
|
|
196
|
+
return await consoleCaptureStorage.run(capture, runCaptured);
|
|
197
|
+
} finally {
|
|
198
|
+
uninstallConsoleCapture();
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
var suppressedConsole = Object.fromEntries(
|
|
202
|
+
METHODS.map((method) => [method, () => {
|
|
203
|
+
}])
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
// src/runtime/run.ts
|
|
207
|
+
var shouldValidateOutput = (mode, nodeEnv) => {
|
|
208
|
+
const resolved = mode ?? "development";
|
|
209
|
+
if (resolved === true) return true;
|
|
210
|
+
if (resolved === false) return false;
|
|
211
|
+
return nodeEnv === "development";
|
|
212
|
+
};
|
|
213
|
+
var createUnknownErrorResult = (error, debug) => {
|
|
214
|
+
debug?.(`${error.stack ?? String(error)}
|
|
215
|
+
`);
|
|
216
|
+
return {
|
|
217
|
+
ok: false,
|
|
218
|
+
error: { code: "UNKNOWN", message: error.message ?? String(error) },
|
|
219
|
+
exitCode: 1
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
var createThrownErrorResult = (error, debug) => {
|
|
223
|
+
if (isPicocliError(error)) {
|
|
224
|
+
return {
|
|
225
|
+
ok: false,
|
|
226
|
+
error: { code: error.code, message: error.message },
|
|
227
|
+
exitCode: getExitCodeForError(error.code)
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
return createUnknownErrorResult(error, debug);
|
|
231
|
+
};
|
|
232
|
+
var runCommand = async (def, baseContext, opts = {}) => {
|
|
233
|
+
const run = async () => {
|
|
234
|
+
try {
|
|
235
|
+
const retval = await def.run(baseContext);
|
|
236
|
+
const returnedData = retval === void 0 ? null : retval;
|
|
237
|
+
const data = def.outputSchema && shouldValidateOutput(def.validateOutput, opts.nodeEnv) ? parseOutputSchema(def.outputSchema, returnedData) : returnedData;
|
|
238
|
+
return { ok: true, data };
|
|
239
|
+
} catch (error) {
|
|
240
|
+
return createThrownErrorResult(error, opts.debug);
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
return opts.suppressConsole ? withConsoleCapture(suppressedConsole, run) : run();
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// src/runtime/invoke.ts
|
|
247
|
+
var validateCommandInput = (input, values) => {
|
|
248
|
+
try {
|
|
249
|
+
return validateAll({
|
|
250
|
+
args: input.args,
|
|
251
|
+
options: input.options,
|
|
252
|
+
env: input.env,
|
|
253
|
+
argsInput: values.argsInput,
|
|
254
|
+
optionsInput: values.optionsInput,
|
|
255
|
+
envInput: values.envInput
|
|
256
|
+
});
|
|
257
|
+
} catch (error) {
|
|
258
|
+
if (!isPicocliError(error)) throw error;
|
|
259
|
+
return error;
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
var createValidationResult = (error) => ({
|
|
263
|
+
ok: false,
|
|
264
|
+
result: createErrorResult(error.code, error.message),
|
|
265
|
+
error: { code: error.code, message: error.message },
|
|
266
|
+
exitCode: getExitCodeForError(error.code)
|
|
267
|
+
});
|
|
268
|
+
var createInvocationResult = (result) => {
|
|
269
|
+
if (result.ok) {
|
|
270
|
+
return {
|
|
271
|
+
ok: true,
|
|
272
|
+
result: createSuccessResult(result.data),
|
|
273
|
+
exitCode: 0
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
ok: false,
|
|
278
|
+
result: createErrorResult(result.error.code, result.error.message),
|
|
279
|
+
error: result.error,
|
|
280
|
+
exitCode: result.exitCode
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
var invokeCommand = async (params) => {
|
|
284
|
+
const { def, input, name, inputs, isTTY, isJSON, rest, readStdin, suppressConsole, debug, nodeEnv } = params;
|
|
285
|
+
const parsed = validateCommandInput(input, inputs);
|
|
286
|
+
if (isPicocliError(parsed)) return createValidationResult(parsed);
|
|
287
|
+
const result = await runCommand(
|
|
288
|
+
def,
|
|
289
|
+
{
|
|
290
|
+
name,
|
|
291
|
+
args: parsed.args,
|
|
292
|
+
options: parsed.options,
|
|
293
|
+
env: parsed.env,
|
|
294
|
+
isTTY,
|
|
295
|
+
isJSON,
|
|
296
|
+
rest,
|
|
297
|
+
readStdin
|
|
298
|
+
},
|
|
299
|
+
{ suppressConsole, debug, nodeEnv }
|
|
300
|
+
);
|
|
301
|
+
return createInvocationResult(result);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// src/schemas/input-model.ts
|
|
305
|
+
var buildInputModel = (def) => {
|
|
306
|
+
return {
|
|
307
|
+
args: def.args,
|
|
308
|
+
options: def.options,
|
|
309
|
+
env: def.env,
|
|
310
|
+
argKeys: getShapeKeys(def.args),
|
|
311
|
+
optionKeys: getShapeKeys(def.options),
|
|
312
|
+
envKeys: getShapeKeys(def.env)
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
var getInputSchemas = (model, parts) => {
|
|
316
|
+
return parts.map((part) => model[part]);
|
|
317
|
+
};
|
|
318
|
+
var assertUniqueInputKeys = (model, parts) => {
|
|
319
|
+
const conflicts = getDuplicateKeys(getInputSchemas(model, parts));
|
|
320
|
+
if (conflicts.length > 0) throw new PicocliError("VALIDATION", getDuplicateKeyMessage(conflicts));
|
|
321
|
+
};
|
|
322
|
+
var getInputJsonSchema = (model, parts) => {
|
|
323
|
+
return toJsonSchema(mergeObjects(getInputSchemas(model, parts)));
|
|
324
|
+
};
|
|
325
|
+
var splitNamedInput = (model, rawInput) => {
|
|
326
|
+
const argKeys = new Set(model.argKeys);
|
|
327
|
+
const optionKeys = new Set(model.optionKeys);
|
|
328
|
+
const argsInput = {};
|
|
329
|
+
const optionsInput = {};
|
|
330
|
+
let unknownKey;
|
|
331
|
+
for (const [key, value] of Object.entries(rawInput)) {
|
|
332
|
+
if (argKeys.has(key)) argsInput[key] = value;
|
|
333
|
+
else if (optionKeys.has(key)) optionsInput[key] = value;
|
|
334
|
+
else unknownKey ??= key;
|
|
335
|
+
}
|
|
336
|
+
return { argsInput, optionsInput, unknownKey };
|
|
337
|
+
};
|
|
338
|
+
var getEnvInputForKeys = (envKeys, processEnv) => {
|
|
339
|
+
const input = {};
|
|
340
|
+
for (const key of envKeys) {
|
|
341
|
+
const value = processEnv[key];
|
|
342
|
+
if (value !== void 0) input[key] = value;
|
|
343
|
+
}
|
|
344
|
+
return input;
|
|
345
|
+
};
|
|
346
|
+
var getEnvInput = (model, processEnv) => {
|
|
347
|
+
return getEnvInputForKeys(model.envKeys, processEnv);
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// src/mcp/tools.ts
|
|
351
|
+
var createToolResult = (result) => {
|
|
352
|
+
const structuredContent = result;
|
|
353
|
+
return {
|
|
354
|
+
content: [{ type: "text", text: JSON.stringify(structuredContent) }],
|
|
355
|
+
structuredContent,
|
|
356
|
+
isError: !structuredContent.ok
|
|
357
|
+
};
|
|
358
|
+
};
|
|
359
|
+
var createToolErrorResult = (code, message) => createToolResult(createErrorResult(code, message));
|
|
360
|
+
var createUnknownToolResult = (toolName) => createToolErrorResult("COMMAND_NOT_FOUND", `unknown tool: ${toolName}`);
|
|
361
|
+
var getToolInputSchema = (entry) => {
|
|
362
|
+
const model = buildInputModel(entry.def);
|
|
363
|
+
assertUniqueInputKeys(model, ["args", "options"]);
|
|
364
|
+
return getInputJsonSchema(model, ["args", "options"]);
|
|
365
|
+
};
|
|
366
|
+
var getToolOutputSchema = (entry) => {
|
|
367
|
+
if (!entry.def.outputSchema) return void 0;
|
|
368
|
+
return {
|
|
369
|
+
type: "object",
|
|
370
|
+
anyOf: [
|
|
371
|
+
{
|
|
372
|
+
type: "object",
|
|
373
|
+
properties: {
|
|
374
|
+
ok: { const: true },
|
|
375
|
+
data: toJsonSchema(entry.def.outputSchema)
|
|
376
|
+
},
|
|
377
|
+
required: ["ok", "data"],
|
|
378
|
+
additionalProperties: false
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
type: "object",
|
|
382
|
+
properties: {
|
|
383
|
+
ok: { const: false },
|
|
384
|
+
error: {
|
|
385
|
+
type: "object",
|
|
386
|
+
properties: {
|
|
387
|
+
code: { type: "string" },
|
|
388
|
+
message: { type: "string" }
|
|
389
|
+
},
|
|
390
|
+
required: ["code", "message"],
|
|
391
|
+
additionalProperties: false
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
required: ["ok", "error"],
|
|
395
|
+
additionalProperties: false
|
|
396
|
+
}
|
|
397
|
+
]
|
|
398
|
+
};
|
|
399
|
+
};
|
|
400
|
+
var getToolEntries = (root) => {
|
|
401
|
+
const treeIssue = findCommandTreeIssue(root);
|
|
402
|
+
if (treeIssue) throw new Error(treeIssue);
|
|
403
|
+
const tools = [];
|
|
404
|
+
const names = /* @__PURE__ */ new Set();
|
|
405
|
+
for (const entry of collectCommandEntries(root)) {
|
|
406
|
+
if (!entry.node.def.run) continue;
|
|
407
|
+
const name = entry.commandPath.length > 0 ? entry.commandPath.join("_") : root.name;
|
|
408
|
+
if (names.has(name)) throw new Error(`duplicate MCP tool name: ${name}`);
|
|
409
|
+
names.add(name);
|
|
410
|
+
tools.push({
|
|
411
|
+
name,
|
|
412
|
+
description: entry.node.def.description ?? "",
|
|
413
|
+
node: entry.node,
|
|
414
|
+
commandPath: entry.commandPath,
|
|
415
|
+
def: entry.def
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
return tools;
|
|
419
|
+
};
|
|
420
|
+
var listTools = (root) => {
|
|
421
|
+
return getToolEntries(root).map((entry) => ({
|
|
422
|
+
name: entry.name,
|
|
423
|
+
description: entry.description,
|
|
424
|
+
inputSchema: getToolInputSchema(entry),
|
|
425
|
+
...entry.def.outputSchema ? { outputSchema: getToolOutputSchema(entry) } : {}
|
|
426
|
+
}));
|
|
427
|
+
};
|
|
428
|
+
var invokeToolCommand = async (root, entry, rawArgs, opts) => {
|
|
429
|
+
const def = entry.def;
|
|
430
|
+
const model = buildInputModel(def);
|
|
431
|
+
const namedInput = splitNamedInput(model, rawArgs);
|
|
432
|
+
assertUniqueInputKeys(model, ["args", "options"]);
|
|
433
|
+
if (namedInput.unknownKey) {
|
|
434
|
+
throw new PicocliError("VALIDATION", `unknown tool argument "${namedInput.unknownKey}"`);
|
|
435
|
+
}
|
|
436
|
+
const result = await invokeCommand({
|
|
437
|
+
def,
|
|
438
|
+
input: model,
|
|
439
|
+
name: [root.name, ...entry.commandPath].join(" "),
|
|
440
|
+
inputs: {
|
|
441
|
+
argsInput: namedInput.argsInput,
|
|
442
|
+
optionsInput: namedInput.optionsInput,
|
|
443
|
+
envInput: getEnvInput(model, opts.env)
|
|
444
|
+
},
|
|
445
|
+
isTTY: false,
|
|
446
|
+
isJSON: true,
|
|
447
|
+
rest: [],
|
|
448
|
+
readStdin: async () => "",
|
|
449
|
+
suppressConsole: true,
|
|
450
|
+
nodeEnv: opts.env.NODE_ENV
|
|
451
|
+
});
|
|
452
|
+
return result.result;
|
|
453
|
+
};
|
|
454
|
+
var invokeToolEntry = async (root, entry, rawArgs, opts) => {
|
|
455
|
+
try {
|
|
456
|
+
return createToolResult(await invokeToolCommand(root, entry, rawArgs, opts));
|
|
457
|
+
} catch (error) {
|
|
458
|
+
const message = isPicocliError(error) ? error.message : error.message ?? String(error);
|
|
459
|
+
const code = isPicocliError(error) ? error.code : "UNKNOWN";
|
|
460
|
+
return createToolErrorResult(code, message);
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
var invokeTool = async (root, toolName, args = {}, opts = {}) => {
|
|
464
|
+
const runtimeOptions = { env: opts.env ?? process.env };
|
|
465
|
+
const entry = getToolEntries(root).find((tool) => tool.name === toolName);
|
|
466
|
+
if (!entry) return createUnknownToolResult(toolName);
|
|
467
|
+
return invokeToolEntry(root, entry, args, runtimeOptions);
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
// src/mcp/server.ts
|
|
471
|
+
var buildServer = (root, opts = {}) => {
|
|
472
|
+
const runtimeOptions = { env: opts.env ?? process.env };
|
|
473
|
+
const tools = getToolEntries(root);
|
|
474
|
+
const byName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
475
|
+
const toolDefinitions = tools.map((entry) => ({
|
|
476
|
+
name: entry.name,
|
|
477
|
+
description: entry.description,
|
|
478
|
+
inputSchema: getToolInputSchema(entry),
|
|
479
|
+
...entry.def.outputSchema ? { outputSchema: getToolOutputSchema(entry) } : {}
|
|
480
|
+
}));
|
|
481
|
+
const server = new index_js.Server(
|
|
482
|
+
{ name: root.name, version: root.def.version ?? "0.0.0" },
|
|
483
|
+
{ capabilities: { tools: {} } }
|
|
484
|
+
);
|
|
485
|
+
server.setRequestHandler(types_js.ListToolsRequestSchema, async () => ({
|
|
486
|
+
tools: toolDefinitions
|
|
487
|
+
}));
|
|
488
|
+
server.setRequestHandler(types_js.CallToolRequestSchema, async (req) => {
|
|
489
|
+
const entry = byName.get(req.params.name);
|
|
490
|
+
if (!entry) return createUnknownToolResult(req.params.name);
|
|
491
|
+
return invokeToolEntry(
|
|
492
|
+
root,
|
|
493
|
+
entry,
|
|
494
|
+
req.params.arguments ?? {},
|
|
495
|
+
runtimeOptions
|
|
496
|
+
);
|
|
497
|
+
});
|
|
498
|
+
return server;
|
|
499
|
+
};
|
|
500
|
+
var serveMcp = async (root, opts = {}) => {
|
|
501
|
+
await buildServer(root, opts).connect(new stdio_js.StdioServerTransport());
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
exports.buildServer = buildServer;
|
|
505
|
+
exports.invokeTool = invokeTool;
|
|
506
|
+
exports.listTools = listTools;
|
|
507
|
+
exports.serveMcp = serveMcp;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { f as CommandResult, b as Cli } from '../create-eQnnIhZu.cjs';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface McpToolDefinition {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
inputSchema: Record<string, unknown>;
|
|
9
|
+
outputSchema?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
interface McpRuntimeOptions {
|
|
12
|
+
env?: Record<string, string | undefined>;
|
|
13
|
+
}
|
|
14
|
+
interface McpToolResult<T = unknown> {
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
content: {
|
|
17
|
+
type: "text";
|
|
18
|
+
text: string;
|
|
19
|
+
}[];
|
|
20
|
+
structuredContent: CommandResult<T> & Record<string, unknown>;
|
|
21
|
+
isError?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare const buildServer: (root: Cli, opts?: McpRuntimeOptions) => Server;
|
|
25
|
+
declare const serveMcp: (root: Cli, opts?: McpRuntimeOptions) => Promise<void>;
|
|
26
|
+
|
|
27
|
+
declare const listTools: (root: Cli) => McpToolDefinition[];
|
|
28
|
+
declare const invokeTool: <T = unknown>(root: Cli, toolName: string, args?: Record<string, unknown>, opts?: McpRuntimeOptions) => Promise<McpToolResult<T>>;
|
|
29
|
+
|
|
30
|
+
export { type McpRuntimeOptions, type McpToolDefinition, type McpToolResult, buildServer, invokeTool, listTools, serveMcp };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { f as CommandResult, b as Cli } from '../create-eQnnIhZu.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface McpToolDefinition {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
inputSchema: Record<string, unknown>;
|
|
9
|
+
outputSchema?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
interface McpRuntimeOptions {
|
|
12
|
+
env?: Record<string, string | undefined>;
|
|
13
|
+
}
|
|
14
|
+
interface McpToolResult<T = unknown> {
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
content: {
|
|
17
|
+
type: "text";
|
|
18
|
+
text: string;
|
|
19
|
+
}[];
|
|
20
|
+
structuredContent: CommandResult<T> & Record<string, unknown>;
|
|
21
|
+
isError?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare const buildServer: (root: Cli, opts?: McpRuntimeOptions) => Server;
|
|
25
|
+
declare const serveMcp: (root: Cli, opts?: McpRuntimeOptions) => Promise<void>;
|
|
26
|
+
|
|
27
|
+
declare const listTools: (root: Cli) => McpToolDefinition[];
|
|
28
|
+
declare const invokeTool: <T = unknown>(root: Cli, toolName: string, args?: Record<string, unknown>, opts?: McpRuntimeOptions) => Promise<McpToolResult<T>>;
|
|
29
|
+
|
|
30
|
+
export { type McpRuntimeOptions, type McpToolDefinition, type McpToolResult, buildServer, invokeTool, listTools, serveMcp };
|