padrone 1.3.0 → 1.5.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/CHANGELOG.md +94 -0
- package/README.md +105 -284
- package/dist/{args-DFEI7_G_.mjs → args-D5PNDyNu.mjs} +46 -21
- package/dist/args-D5PNDyNu.mjs.map +1 -0
- package/dist/chunk-CjcI7cDX.mjs +15 -0
- package/dist/codegen/index.d.mts +28 -3
- package/dist/codegen/index.d.mts.map +1 -1
- package/dist/codegen/index.mjs +169 -19
- package/dist/codegen/index.mjs.map +1 -1
- package/dist/command-utils-B1D-HqCd.mjs +1117 -0
- package/dist/command-utils-B1D-HqCd.mjs.map +1 -0
- package/dist/completion.d.mts +1 -1
- package/dist/completion.d.mts.map +1 -1
- package/dist/completion.mjs +77 -29
- package/dist/completion.mjs.map +1 -1
- package/dist/docs/index.d.mts +22 -2
- package/dist/docs/index.d.mts.map +1 -1
- package/dist/docs/index.mjs +94 -7
- package/dist/docs/index.mjs.map +1 -1
- package/dist/errors-BiVrBgi6.mjs +114 -0
- package/dist/errors-BiVrBgi6.mjs.map +1 -0
- package/dist/{formatter-XroimS3Q.d.mts → formatter-DtHzbP22.d.mts} +35 -5
- package/dist/formatter-DtHzbP22.d.mts.map +1 -0
- package/dist/help-bbmu9-qd.mjs +735 -0
- package/dist/help-bbmu9-qd.mjs.map +1 -0
- package/dist/index.d.mts +32 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +495 -267
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-mLWIdUIu.mjs +379 -0
- package/dist/mcp-mLWIdUIu.mjs.map +1 -0
- package/dist/serve-B0u43DK7.mjs +404 -0
- package/dist/serve-B0u43DK7.mjs.map +1 -0
- package/dist/stream-BcC146Ud.mjs +56 -0
- package/dist/stream-BcC146Ud.mjs.map +1 -0
- package/dist/test.d.mts +1 -1
- package/dist/test.mjs +4 -15
- package/dist/test.mjs.map +1 -1
- package/dist/{types-BS7RP5Ls.d.mts → types-Ch8Mk6Qb.d.mts} +311 -63
- package/dist/types-Ch8Mk6Qb.d.mts.map +1 -0
- package/dist/{update-check-EbNDkzyV.mjs → update-check-CFX1FV3v.mjs} +2 -2
- package/dist/{update-check-EbNDkzyV.mjs.map → update-check-CFX1FV3v.mjs.map} +1 -1
- package/dist/zod.d.mts +32 -0
- package/dist/zod.d.mts.map +1 -0
- package/dist/zod.mjs +50 -0
- package/dist/zod.mjs.map +1 -0
- package/package.json +10 -2
- package/src/args.ts +76 -44
- package/src/cli/docs.ts +1 -7
- package/src/cli/doctor.ts +195 -10
- package/src/cli/index.ts +1 -1
- package/src/cli/init.ts +2 -3
- package/src/cli/link.ts +2 -2
- package/src/codegen/discovery.ts +80 -28
- package/src/codegen/index.ts +2 -1
- package/src/codegen/parsers/bash.ts +179 -0
- package/src/codegen/schema-to-code.ts +2 -1
- package/src/colorizer.ts +126 -13
- package/src/command-utils.ts +401 -23
- package/src/completion.ts +120 -47
- package/src/create.ts +483 -130
- package/src/docs/index.ts +122 -8
- package/src/formatter.ts +173 -125
- package/src/help.ts +46 -12
- package/src/index.ts +29 -1
- package/src/interactive.ts +45 -4
- package/src/mcp.ts +390 -0
- package/src/repl-loop.ts +16 -3
- package/src/runtime.ts +195 -2
- package/src/serve.ts +442 -0
- package/src/stream.ts +75 -0
- package/src/test.ts +7 -16
- package/src/type-utils.ts +28 -4
- package/src/types.ts +212 -30
- package/src/wrap.ts +23 -25
- package/src/zod.ts +50 -0
- package/dist/args-DFEI7_G_.mjs.map +0 -1
- package/dist/chunk-y_GBKt04.mjs +0 -5
- package/dist/formatter-XroimS3Q.d.mts.map +0 -1
- package/dist/help-CgGP7hQU.mjs +0 -1229
- package/dist/help-CgGP7hQU.mjs.map +0 -1
- package/dist/types-BS7RP5Ls.d.mts.map +0 -1
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { t as generateHelp } from "./help-bbmu9-qd.mjs";
|
|
2
|
+
import { E as serializeArgsToFlags, i as collectEndpoints, n as buildInputSchema } from "./command-utils-B1D-HqCd.mjs";
|
|
3
|
+
//#region src/mcp.ts
|
|
4
|
+
const PROTOCOL_VERSION = "2025-11-25";
|
|
5
|
+
/** Convert an endpoint dot-path to a valid MCP tool name. Spec allows: [A-Za-z0-9_\-\.] */
|
|
6
|
+
function toToolName(path) {
|
|
7
|
+
return path.replace(/\s+/g, ".");
|
|
8
|
+
}
|
|
9
|
+
/** Convert a tool name back to a command path (dot → space). */
|
|
10
|
+
function toCommandPath(toolName) {
|
|
11
|
+
return toolName.replace(/\./g, " ");
|
|
12
|
+
}
|
|
13
|
+
/** Build MCP tool annotations from a command's metadata. */
|
|
14
|
+
function buildAnnotations(cmd) {
|
|
15
|
+
if (cmd.mutation == null) return void 0;
|
|
16
|
+
return {
|
|
17
|
+
destructiveHint: cmd.mutation || void 0,
|
|
18
|
+
readOnlyHint: cmd.mutation === false || void 0
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Build an MCP tool definition from a command. */
|
|
22
|
+
function buildToolDefinition(name, cmd) {
|
|
23
|
+
return {
|
|
24
|
+
name: toToolName(name),
|
|
25
|
+
title: cmd.title ?? void 0,
|
|
26
|
+
description: cmd.description || cmd.title || `Run the "${name}" command`,
|
|
27
|
+
inputSchema: buildInputSchema(cmd),
|
|
28
|
+
annotations: buildAnnotations(cmd)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Create the MCP request handler. Returns an async function that processes a JSON-RPC request and returns a response (or undefined for notifications). */
|
|
32
|
+
function createMcpHandler(existingCommand, evalCommand, prefs) {
|
|
33
|
+
const serverName = prefs?.name ?? existingCommand.name;
|
|
34
|
+
const serverVersion = prefs?.version ?? existingCommand.version ?? "0.0.0";
|
|
35
|
+
const rootTools = collectEndpoints(existingCommand.commands, "");
|
|
36
|
+
if (existingCommand.action || existingCommand.argsSchema) rootTools.unshift({
|
|
37
|
+
name: "",
|
|
38
|
+
command: existingCommand
|
|
39
|
+
});
|
|
40
|
+
const toolMap = new Map(rootTools.map((t) => [toToolName(t.name), t]));
|
|
41
|
+
const helpToolName = "help";
|
|
42
|
+
const helpToolDef = {
|
|
43
|
+
name: helpToolName,
|
|
44
|
+
title: "Help",
|
|
45
|
+
description: `Show help for the "${serverName}" program or a specific command`,
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: { command: {
|
|
49
|
+
type: "string",
|
|
50
|
+
description: "Command name to get help for (omit for program help)"
|
|
51
|
+
} },
|
|
52
|
+
additionalProperties: false
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
return async function handleRequest(req) {
|
|
56
|
+
const { id, method, params } = req;
|
|
57
|
+
switch (method) {
|
|
58
|
+
case "initialize": return {
|
|
59
|
+
jsonrpc: "2.0",
|
|
60
|
+
id: id ?? null,
|
|
61
|
+
result: {
|
|
62
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
63
|
+
capabilities: { tools: {} },
|
|
64
|
+
serverInfo: {
|
|
65
|
+
name: serverName,
|
|
66
|
+
version: serverVersion
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
case "notifications/initialized":
|
|
71
|
+
case "notifications/cancelled": return;
|
|
72
|
+
case "ping": return {
|
|
73
|
+
jsonrpc: "2.0",
|
|
74
|
+
id: id ?? null,
|
|
75
|
+
result: {}
|
|
76
|
+
};
|
|
77
|
+
case "tools/list": {
|
|
78
|
+
const tools = [...rootTools.map((t) => buildToolDefinition(t.name, t.command)), helpToolDef];
|
|
79
|
+
return {
|
|
80
|
+
jsonrpc: "2.0",
|
|
81
|
+
id: id ?? null,
|
|
82
|
+
result: { tools }
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
case "tools/call": {
|
|
86
|
+
const toolName = params?.name;
|
|
87
|
+
const args = params?.arguments ?? {};
|
|
88
|
+
if (toolName === helpToolName) {
|
|
89
|
+
const cmdName = args.command;
|
|
90
|
+
const helpText = generateHelp(existingCommand, (cmdName ? rootTools.find((t) => t.name === cmdName || toToolName(t.name) === cmdName)?.command : void 0) ?? existingCommand, {
|
|
91
|
+
format: "text",
|
|
92
|
+
detail: "full"
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
jsonrpc: "2.0",
|
|
96
|
+
id: id ?? null,
|
|
97
|
+
result: {
|
|
98
|
+
content: [{
|
|
99
|
+
type: "text",
|
|
100
|
+
text: helpText
|
|
101
|
+
}],
|
|
102
|
+
isError: false
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const tool = toolMap.get(toolName);
|
|
107
|
+
if (!tool) return {
|
|
108
|
+
jsonrpc: "2.0",
|
|
109
|
+
id: id ?? null,
|
|
110
|
+
error: {
|
|
111
|
+
code: -32602,
|
|
112
|
+
message: `Unknown tool: ${toolName}`
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const input = [toCommandPath(tool.name), ...serializeArgsToFlags(args)].filter(Boolean).join(" ") || void 0;
|
|
116
|
+
try {
|
|
117
|
+
const output = [];
|
|
118
|
+
const errors = [];
|
|
119
|
+
const result = await evalCommand(input, {
|
|
120
|
+
autoOutput: false,
|
|
121
|
+
runtime: {
|
|
122
|
+
output: (...outArgs) => output.push(outArgs.map(String).join(" ")),
|
|
123
|
+
error: (text) => errors.push(text),
|
|
124
|
+
interactive: "unsupported",
|
|
125
|
+
format: "text"
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
const content = [];
|
|
129
|
+
if (result.error) {
|
|
130
|
+
const errorMsg = result.error instanceof Error ? result.error.message : String(result.error);
|
|
131
|
+
if (errors.length) content.push({
|
|
132
|
+
type: "text",
|
|
133
|
+
text: errors.join("\n")
|
|
134
|
+
});
|
|
135
|
+
content.push({
|
|
136
|
+
type: "text",
|
|
137
|
+
text: errorMsg
|
|
138
|
+
});
|
|
139
|
+
return {
|
|
140
|
+
jsonrpc: "2.0",
|
|
141
|
+
id: id ?? null,
|
|
142
|
+
result: {
|
|
143
|
+
content,
|
|
144
|
+
isError: true
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (result.argsResult?.issues) {
|
|
149
|
+
const issueMessages = result.argsResult.issues.map((i) => `${i.path?.join(".") || "root"}: ${i.message}`).join("\n");
|
|
150
|
+
content.push({
|
|
151
|
+
type: "text",
|
|
152
|
+
text: `Validation error:\n${issueMessages}`
|
|
153
|
+
});
|
|
154
|
+
return {
|
|
155
|
+
jsonrpc: "2.0",
|
|
156
|
+
id: id ?? null,
|
|
157
|
+
result: {
|
|
158
|
+
content,
|
|
159
|
+
isError: true
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
if (output.length) content.push({
|
|
164
|
+
type: "text",
|
|
165
|
+
text: output.join("\n")
|
|
166
|
+
});
|
|
167
|
+
if (result.result !== void 0 && result.result !== null) {
|
|
168
|
+
const resultText = typeof result.result === "string" ? result.result : JSON.stringify(result.result, null, 2);
|
|
169
|
+
content.push({
|
|
170
|
+
type: "text",
|
|
171
|
+
text: resultText
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (content.length === 0) content.push({
|
|
175
|
+
type: "text",
|
|
176
|
+
text: "Done."
|
|
177
|
+
});
|
|
178
|
+
return {
|
|
179
|
+
jsonrpc: "2.0",
|
|
180
|
+
id: id ?? null,
|
|
181
|
+
result: {
|
|
182
|
+
content,
|
|
183
|
+
isError: false
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
} catch (err) {
|
|
187
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
188
|
+
return {
|
|
189
|
+
jsonrpc: "2.0",
|
|
190
|
+
id: id ?? null,
|
|
191
|
+
result: {
|
|
192
|
+
content: [{
|
|
193
|
+
type: "text",
|
|
194
|
+
text: errorMsg
|
|
195
|
+
}],
|
|
196
|
+
isError: true
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
default:
|
|
202
|
+
if (id !== void 0) return {
|
|
203
|
+
jsonrpc: "2.0",
|
|
204
|
+
id,
|
|
205
|
+
error: {
|
|
206
|
+
code: -32601,
|
|
207
|
+
message: `Method not found: ${method}`
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/** stdio transport: newline-delimited JSON per 2025-11-25 spec. */
|
|
215
|
+
async function startStdioTransport(handleRequest) {
|
|
216
|
+
const { stdin, stdout } = await import("node:process");
|
|
217
|
+
const { createInterface } = await import("node:readline");
|
|
218
|
+
function send(msg) {
|
|
219
|
+
stdout.write(`${JSON.stringify(msg)}\n`);
|
|
220
|
+
}
|
|
221
|
+
const rl = createInterface({
|
|
222
|
+
input: stdin,
|
|
223
|
+
crlfDelay: Infinity
|
|
224
|
+
});
|
|
225
|
+
for await (const line of rl) {
|
|
226
|
+
if (!line.trim()) continue;
|
|
227
|
+
try {
|
|
228
|
+
const res = await handleRequest(JSON.parse(line));
|
|
229
|
+
if (res) send(res);
|
|
230
|
+
} catch {}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/** Streamable HTTP transport per 2025-11-25 spec. Responds with JSON or SSE based on client's Accept header. */
|
|
234
|
+
async function startHttpTransport(handleRequest, prefs, log) {
|
|
235
|
+
const http = await import("node:http");
|
|
236
|
+
const crypto = await import("node:crypto");
|
|
237
|
+
const port = prefs.port ?? 3e3;
|
|
238
|
+
const host = prefs.host ?? "127.0.0.1";
|
|
239
|
+
const endpoint = prefs.basePath ?? "/mcp";
|
|
240
|
+
let sessionId;
|
|
241
|
+
let negotiatedVersion;
|
|
242
|
+
const corsOrigin = prefs.cors !== false ? prefs.cors ?? "*" : void 0;
|
|
243
|
+
const server = http.createServer(async (req, res) => {
|
|
244
|
+
if (corsOrigin) {
|
|
245
|
+
res.setHeader("Access-Control-Allow-Origin", corsOrigin);
|
|
246
|
+
res.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, OPTIONS");
|
|
247
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, MCP-Session-Id, MCP-Protocol-Version");
|
|
248
|
+
res.setHeader("Access-Control-Expose-Headers", "MCP-Session-Id");
|
|
249
|
+
}
|
|
250
|
+
if (req.method === "OPTIONS") {
|
|
251
|
+
res.writeHead(corsOrigin ? 204 : 405);
|
|
252
|
+
res.end();
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (req.url !== endpoint) {
|
|
256
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
257
|
+
res.end(JSON.stringify({ error: "Not found" }));
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (req.method === "DELETE") {
|
|
261
|
+
const reqSessionId = req.headers["mcp-session-id"];
|
|
262
|
+
if (sessionId && reqSessionId === sessionId) {
|
|
263
|
+
sessionId = void 0;
|
|
264
|
+
negotiatedVersion = void 0;
|
|
265
|
+
res.writeHead(200);
|
|
266
|
+
res.end();
|
|
267
|
+
} else {
|
|
268
|
+
res.writeHead(404);
|
|
269
|
+
res.end();
|
|
270
|
+
}
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (req.method === "GET") {
|
|
274
|
+
res.writeHead(405, { "Content-Type": "application/json" });
|
|
275
|
+
res.end(JSON.stringify({
|
|
276
|
+
jsonrpc: "2.0",
|
|
277
|
+
id: null,
|
|
278
|
+
error: {
|
|
279
|
+
code: -32601,
|
|
280
|
+
message: "SSE stream not supported"
|
|
281
|
+
}
|
|
282
|
+
}));
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (req.method !== "POST") {
|
|
286
|
+
res.writeHead(405);
|
|
287
|
+
res.end();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const reqSessionId = req.headers["mcp-session-id"];
|
|
291
|
+
if (sessionId && reqSessionId && reqSessionId !== sessionId) {
|
|
292
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
293
|
+
res.end(JSON.stringify({
|
|
294
|
+
jsonrpc: "2.0",
|
|
295
|
+
id: null,
|
|
296
|
+
error: {
|
|
297
|
+
code: -32600,
|
|
298
|
+
message: "Invalid session"
|
|
299
|
+
}
|
|
300
|
+
}));
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const reqProtocolVersion = req.headers["mcp-protocol-version"];
|
|
304
|
+
if (negotiatedVersion && reqProtocolVersion && reqProtocolVersion !== negotiatedVersion) {
|
|
305
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
306
|
+
res.end(JSON.stringify({
|
|
307
|
+
jsonrpc: "2.0",
|
|
308
|
+
id: null,
|
|
309
|
+
error: {
|
|
310
|
+
code: -32600,
|
|
311
|
+
message: "Protocol version mismatch"
|
|
312
|
+
}
|
|
313
|
+
}));
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const chunks = [];
|
|
317
|
+
for await (const chunk of req) chunks.push(chunk);
|
|
318
|
+
const body = Buffer.concat(chunks).toString("utf-8");
|
|
319
|
+
let rpcRequest;
|
|
320
|
+
try {
|
|
321
|
+
rpcRequest = JSON.parse(body);
|
|
322
|
+
} catch {
|
|
323
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
324
|
+
res.end(JSON.stringify({
|
|
325
|
+
jsonrpc: "2.0",
|
|
326
|
+
id: null,
|
|
327
|
+
error: {
|
|
328
|
+
code: -32700,
|
|
329
|
+
message: "Parse error"
|
|
330
|
+
}
|
|
331
|
+
}));
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const response = await handleRequest(rpcRequest);
|
|
335
|
+
if (rpcRequest.method === "initialize" && response?.result) {
|
|
336
|
+
sessionId = crypto.randomUUID();
|
|
337
|
+
negotiatedVersion = PROTOCOL_VERSION;
|
|
338
|
+
res.setHeader("MCP-Session-Id", sessionId);
|
|
339
|
+
}
|
|
340
|
+
if (response) if ((req.headers.accept ?? "").includes("text/event-stream")) {
|
|
341
|
+
res.writeHead(200, {
|
|
342
|
+
"Content-Type": "text/event-stream",
|
|
343
|
+
"Cache-Control": "no-cache",
|
|
344
|
+
Connection: "keep-alive"
|
|
345
|
+
});
|
|
346
|
+
res.write(`event: message\ndata: ${JSON.stringify(response)}\n\n`);
|
|
347
|
+
res.end();
|
|
348
|
+
} else {
|
|
349
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
350
|
+
res.end(JSON.stringify(response));
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
res.writeHead(202);
|
|
354
|
+
res.end();
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
return new Promise((resolve, reject) => {
|
|
358
|
+
server.listen(port, host, () => {
|
|
359
|
+
log(`MCP server listening on http://${host}:${port}${endpoint}`);
|
|
360
|
+
});
|
|
361
|
+
server.on("error", reject);
|
|
362
|
+
const onSignal = () => {
|
|
363
|
+
server.close(() => resolve());
|
|
364
|
+
};
|
|
365
|
+
process.on("SIGINT", onSignal);
|
|
366
|
+
process.on("SIGTERM", onSignal);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
async function startMcpServer(_program, existingCommand, evalCommand, prefs) {
|
|
370
|
+
const handleRequest = createMcpHandler(existingCommand, evalCommand, prefs);
|
|
371
|
+
if ((prefs?.transport ?? "http") === "stdio") return startStdioTransport(handleRequest);
|
|
372
|
+
const { getCommandRuntime } = await import("./command-utils-B1D-HqCd.mjs").then((n) => n.o);
|
|
373
|
+
const runtime = getCommandRuntime(existingCommand);
|
|
374
|
+
return startHttpTransport(handleRequest, prefs ?? {}, (msg) => runtime.error(msg));
|
|
375
|
+
}
|
|
376
|
+
//#endregion
|
|
377
|
+
export { startMcpServer };
|
|
378
|
+
|
|
379
|
+
//# sourceMappingURL=mcp-mLWIdUIu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-mLWIdUIu.mjs","names":[],"sources":["../src/mcp.ts"],"sourcesContent":["import { buildInputSchema, collectEndpoints, serializeArgsToFlags } from './command-utils.ts';\nimport { generateHelp } from './help.ts';\nimport type { AnyPadroneCommand, AnyPadroneProgram } from './types.ts';\n\nexport type PadroneMcpPreferences = {\n /** Server name. Defaults to the program name. */\n name?: string;\n /** Server version. Defaults to the program version. */\n version?: string;\n /**\n * Transport mode.\n * - `'http'` — Start a Streamable HTTP server (default). Responds with `application/json` or `text/event-stream` based on the client's `Accept` header. Use `port` and `host` to configure.\n * - `'stdio'` — Communicate over stdin/stdout with newline-delimited JSON.\n */\n transport?: 'http' | 'stdio';\n /** HTTP port. Defaults to `3000`. Only used with `transport: 'http'`. */\n port?: number;\n /** HTTP host. Defaults to `'127.0.0.1'`. Only used with `transport: 'http'`. */\n host?: string;\n /** Base path for the MCP endpoint. Defaults to `'/mcp'`. Only used with `transport: 'http'`. */\n basePath?: string;\n /** CORS allowed origin. Defaults to `'*'`. Set to a specific origin or `false` to disable CORS headers. Only used with HTTP transports. */\n cors?: string | false;\n};\n\nconst PROTOCOL_VERSION = '2025-11-25';\n\ntype JsonRpcRequest = {\n jsonrpc: '2.0';\n id?: string | number;\n method: string;\n params?: Record<string, unknown>;\n};\n\ntype JsonRpcResponse = {\n jsonrpc: '2.0';\n id: string | number | null;\n result?: unknown;\n error?: { code: number; message: string; data?: unknown };\n};\n\n/** Convert an endpoint dot-path to a valid MCP tool name. Spec allows: [A-Za-z0-9_\\-\\.] */\nfunction toToolName(path: string): string {\n return path.replace(/\\s+/g, '.');\n}\n\n/** Convert a tool name back to a command path (dot → space). */\nfunction toCommandPath(toolName: string): string {\n return toolName.replace(/\\./g, ' ');\n}\n\n/** Build MCP tool annotations from a command's metadata. */\nfunction buildAnnotations(cmd: AnyPadroneCommand) {\n if (cmd.mutation == null) return undefined;\n return {\n destructiveHint: cmd.mutation || undefined,\n readOnlyHint: cmd.mutation === false || undefined,\n };\n}\n\n/** Build an MCP tool definition from a command. */\nfunction buildToolDefinition(name: string, cmd: AnyPadroneCommand) {\n return {\n name: toToolName(name),\n title: cmd.title ?? undefined,\n description: cmd.description || cmd.title || `Run the \"${name}\" command`,\n inputSchema: buildInputSchema(cmd),\n annotations: buildAnnotations(cmd),\n };\n}\n\n/** Create the MCP request handler. Returns an async function that processes a JSON-RPC request and returns a response (or undefined for notifications). */\nexport function createMcpHandler(\n existingCommand: AnyPadroneCommand,\n evalCommand: AnyPadroneProgram['eval'],\n prefs?: PadroneMcpPreferences,\n) {\n const serverName = prefs?.name ?? existingCommand.name;\n const serverVersion = prefs?.version ?? existingCommand.version ?? '0.0.0';\n\n const rootTools = collectEndpoints(existingCommand.commands, '');\n if (existingCommand.action || existingCommand.argsSchema) {\n rootTools.unshift({ name: '', command: existingCommand });\n }\n\n const toolMap = new Map(rootTools.map((t) => [toToolName(t.name), t]));\n\n const helpToolName = 'help';\n const helpToolDef = {\n name: helpToolName,\n title: 'Help',\n description: `Show help for the \"${serverName}\" program or a specific command`,\n inputSchema: {\n type: 'object' as const,\n properties: { command: { type: 'string', description: 'Command name to get help for (omit for program help)' } },\n additionalProperties: false,\n },\n };\n\n return async function handleRequest(req: JsonRpcRequest): Promise<JsonRpcResponse | undefined> {\n const { id, method, params } = req;\n\n switch (method) {\n case 'initialize':\n return {\n jsonrpc: '2.0',\n id: id ?? null,\n result: {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: { tools: {} },\n serverInfo: { name: serverName, version: serverVersion },\n },\n };\n\n case 'notifications/initialized':\n case 'notifications/cancelled':\n return undefined;\n\n case 'ping':\n return { jsonrpc: '2.0', id: id ?? null, result: {} };\n\n case 'tools/list': {\n const tools = [...rootTools.map((t) => buildToolDefinition(t.name, t.command)), helpToolDef];\n return { jsonrpc: '2.0', id: id ?? null, result: { tools } };\n }\n\n case 'tools/call': {\n const toolName = params?.name as string;\n const args = (params?.arguments ?? {}) as Record<string, unknown>;\n\n // Built-in help tool\n if (toolName === helpToolName) {\n const cmdName = args.command as string | undefined;\n const targetCmd = cmdName ? rootTools.find((t) => t.name === cmdName || toToolName(t.name) === cmdName)?.command : undefined;\n const helpText = generateHelp(existingCommand, targetCmd ?? existingCommand, { format: 'text', detail: 'full' });\n return {\n jsonrpc: '2.0',\n id: id ?? null,\n result: { content: [{ type: 'text', text: helpText }], isError: false },\n };\n }\n\n const tool = toolMap.get(toolName);\n if (!tool) {\n return {\n jsonrpc: '2.0',\n id: id ?? null,\n error: { code: -32602, message: `Unknown tool: ${toolName}` },\n };\n }\n\n // Build command string: convert tool name back to command path + serialize args as flags\n const commandPath = toCommandPath(tool.name);\n const argParts = serializeArgsToFlags(args);\n const input = [commandPath, ...argParts].filter(Boolean).join(' ') || undefined;\n\n try {\n const output: string[] = [];\n const errors: string[] = [];\n const result = await evalCommand(input as any, {\n autoOutput: false,\n runtime: {\n output: (...outArgs: unknown[]) => output.push(outArgs.map(String).join(' ')),\n error: (text: string) => errors.push(text),\n interactive: 'unsupported',\n format: 'text',\n },\n });\n\n const content: { type: string; text: string }[] = [];\n\n if (result.error) {\n const errorMsg = result.error instanceof Error ? result.error.message : String(result.error);\n if (errors.length) content.push({ type: 'text', text: errors.join('\\n') });\n content.push({ type: 'text', text: errorMsg });\n return { jsonrpc: '2.0', id: id ?? null, result: { content, isError: true } };\n }\n\n if (result.argsResult?.issues) {\n const issueMessages = result.argsResult.issues.map((i: any) => `${i.path?.join('.') || 'root'}: ${i.message}`).join('\\n');\n content.push({ type: 'text', text: `Validation error:\\n${issueMessages}` });\n return { jsonrpc: '2.0', id: id ?? null, result: { content, isError: true } };\n }\n\n if (output.length) content.push({ type: 'text', text: output.join('\\n') });\n if (result.result !== undefined && result.result !== null) {\n const resultText = typeof result.result === 'string' ? result.result : JSON.stringify(result.result, null, 2);\n content.push({ type: 'text', text: resultText });\n }\n if (content.length === 0) content.push({ type: 'text', text: 'Done.' });\n return { jsonrpc: '2.0', id: id ?? null, result: { content, isError: false } };\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n return {\n jsonrpc: '2.0',\n id: id ?? null,\n result: { content: [{ type: 'text', text: errorMsg }], isError: true },\n };\n }\n }\n\n default: {\n if (id !== undefined) {\n return { jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } };\n }\n return undefined;\n }\n }\n };\n}\n\n/** stdio transport: newline-delimited JSON per 2025-11-25 spec. */\nasync function startStdioTransport(handleRequest: (req: JsonRpcRequest) => Promise<JsonRpcResponse | undefined>): Promise<void> {\n const { stdin, stdout } = await import('node:process');\n const { createInterface } = await import('node:readline');\n\n function send(msg: JsonRpcResponse) {\n stdout.write(`${JSON.stringify(msg)}\\n`);\n }\n\n const rl = createInterface({ input: stdin, crlfDelay: Infinity });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n try {\n const req = JSON.parse(line) as JsonRpcRequest;\n const res = await handleRequest(req);\n if (res) send(res);\n } catch {\n // Ignore malformed JSON\n }\n }\n}\n\n/** Streamable HTTP transport per 2025-11-25 spec. Responds with JSON or SSE based on client's Accept header. */\nasync function startHttpTransport(\n handleRequest: (req: JsonRpcRequest) => Promise<JsonRpcResponse | undefined>,\n prefs: PadroneMcpPreferences,\n log: (msg: string) => void,\n): Promise<void> {\n const http = await import('node:http');\n const crypto = await import('node:crypto');\n\n const port = prefs.port ?? 3000;\n const host = prefs.host ?? '127.0.0.1';\n const endpoint = prefs.basePath ?? '/mcp';\n\n // Session management\n let sessionId: string | undefined;\n let negotiatedVersion: string | undefined;\n\n const corsOrigin = prefs.cors !== false ? (prefs.cors ?? '*') : undefined;\n\n const server = http.createServer(async (req, res) => {\n // CORS headers\n if (corsOrigin) {\n res.setHeader('Access-Control-Allow-Origin', corsOrigin);\n res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DELETE, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, MCP-Session-Id, MCP-Protocol-Version');\n res.setHeader('Access-Control-Expose-Headers', 'MCP-Session-Id');\n }\n\n if (req.method === 'OPTIONS') {\n res.writeHead(corsOrigin ? 204 : 405);\n res.end();\n return;\n }\n\n if (req.url !== endpoint) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not found' }));\n return;\n }\n\n // DELETE: terminate session\n if (req.method === 'DELETE') {\n const reqSessionId = req.headers['mcp-session-id'] as string | undefined;\n if (sessionId && reqSessionId === sessionId) {\n sessionId = undefined;\n negotiatedVersion = undefined;\n res.writeHead(200);\n res.end();\n } else {\n res.writeHead(404);\n res.end();\n }\n return;\n }\n\n // GET: SSE stream (not implemented — return 405)\n if (req.method === 'GET') {\n res.writeHead(405, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: -32601, message: 'SSE stream not supported' } }));\n return;\n }\n\n if (req.method !== 'POST') {\n res.writeHead(405);\n res.end();\n return;\n }\n\n // Validate session ID on non-initialize requests\n const reqSessionId = req.headers['mcp-session-id'] as string | undefined;\n if (sessionId && reqSessionId && reqSessionId !== sessionId) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: -32600, message: 'Invalid session' } }));\n return;\n }\n\n // Validate MCP-Protocol-Version header on post-init requests\n const reqProtocolVersion = req.headers['mcp-protocol-version'] as string | undefined;\n if (negotiatedVersion && reqProtocolVersion && reqProtocolVersion !== negotiatedVersion) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: -32600, message: 'Protocol version mismatch' } }));\n return;\n }\n\n // Read request body\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(chunk);\n }\n const body = Buffer.concat(chunks).toString('utf-8');\n\n let rpcRequest: JsonRpcRequest;\n try {\n rpcRequest = JSON.parse(body);\n } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } }));\n return;\n }\n\n const response = await handleRequest(rpcRequest);\n\n // On initialize response: create session and set header\n if (rpcRequest.method === 'initialize' && response?.result) {\n sessionId = crypto.randomUUID();\n negotiatedVersion = PROTOCOL_VERSION;\n res.setHeader('MCP-Session-Id', sessionId);\n }\n\n if (response) {\n const accept = req.headers.accept ?? '';\n if (accept.includes('text/event-stream')) {\n res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });\n res.write(`event: message\\ndata: ${JSON.stringify(response)}\\n\\n`);\n res.end();\n } else {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(response));\n }\n } else {\n // Notification or response from client — no body\n res.writeHead(202);\n res.end();\n }\n });\n\n return new Promise<void>((resolve, reject) => {\n server.listen(port, host, () => {\n log(`MCP server listening on http://${host}:${port}${endpoint}`);\n });\n server.on('error', reject);\n const onSignal = () => {\n server.close(() => resolve());\n };\n process.on('SIGINT', onSignal);\n process.on('SIGTERM', onSignal);\n });\n}\n\nexport async function startMcpServer(\n _program: AnyPadroneProgram,\n existingCommand: AnyPadroneCommand,\n evalCommand: AnyPadroneProgram['eval'],\n prefs?: PadroneMcpPreferences,\n): Promise<void> {\n const handleRequest = createMcpHandler(existingCommand, evalCommand, prefs);\n const transport = prefs?.transport ?? 'http';\n\n if (transport === 'stdio') {\n return startStdioTransport(handleRequest);\n }\n\n const { getCommandRuntime } = await import('./command-utils.ts');\n const runtime = getCommandRuntime(existingCommand);\n return startHttpTransport(handleRequest, prefs ?? {}, (msg) => runtime.error(msg));\n}\n"],"mappings":"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"}
|