unicommand 0.0.3 → 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 +46 -0
- package/dist/index.d.ts +160 -105
- package/dist/index.js +287 -49
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { z as
|
|
2
|
+
import { z as z5 } from "zod";
|
|
3
3
|
|
|
4
4
|
// src/command/runtime-metadata.ts
|
|
5
5
|
var commandMetadata = /* @__PURE__ */ new WeakMap();
|
|
@@ -514,14 +514,13 @@ import { basename, extname, join } from "path";
|
|
|
514
514
|
import { pathToFileURL } from "url";
|
|
515
515
|
var COMMAND_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs", ".ts"]);
|
|
516
516
|
var IGNORED_COMMAND_FILE_NAMES = /* @__PURE__ */ new Set(["index", "options"]);
|
|
517
|
-
var loadCommandModules = async (commandsDir) => {
|
|
518
|
-
return loadCommandModulesFromFiles(await commandFiles(commandsDir));
|
|
517
|
+
var loadCommandModules = async (commandsDir, importModule = importCommandModule) => {
|
|
518
|
+
return loadCommandModulesFromFiles(await commandFiles(commandsDir), importModule);
|
|
519
519
|
};
|
|
520
|
-
var loadCommandModulesFromFiles = async (files) => {
|
|
521
|
-
return Promise.all(
|
|
522
|
-
files.map((file) => import(pathToFileURL(file).href))
|
|
523
|
-
);
|
|
520
|
+
var loadCommandModulesFromFiles = async (files, importModule = importCommandModule) => {
|
|
521
|
+
return Promise.all(files.map(importModule));
|
|
524
522
|
};
|
|
523
|
+
var importCommandModule = (file) => import(pathToFileURL(file).href);
|
|
525
524
|
var commandDefinitionsFromModules = (modules) => {
|
|
526
525
|
return modules.flatMap(
|
|
527
526
|
(module) => Object.values(module).flatMap(
|
|
@@ -812,6 +811,7 @@ var createCommandProgram = async ({
|
|
|
812
811
|
commandsDir,
|
|
813
812
|
description,
|
|
814
813
|
getContext,
|
|
814
|
+
importCommandModule: importCommandModule2,
|
|
815
815
|
importMetaUrl,
|
|
816
816
|
isDevRun = false,
|
|
817
817
|
packageName,
|
|
@@ -825,6 +825,7 @@ var createCommandProgram = async ({
|
|
|
825
825
|
binName,
|
|
826
826
|
commandsDir: commandsDir ?? defaultCommandsDir(importMetaUrl),
|
|
827
827
|
getContext,
|
|
828
|
+
importCommandModule: importCommandModule2,
|
|
828
829
|
program
|
|
829
830
|
});
|
|
830
831
|
registerUpdateCommand(program, { isDevRun, packageName: packageName ?? binName, version });
|
|
@@ -863,9 +864,10 @@ var registerCliCommandsFromDirectory = async ({
|
|
|
863
864
|
binName,
|
|
864
865
|
commandsDir,
|
|
865
866
|
getContext,
|
|
867
|
+
importCommandModule: importCommandModule2,
|
|
866
868
|
program
|
|
867
869
|
}) => {
|
|
868
|
-
const modules = await loadCommandModules(commandsDir);
|
|
870
|
+
const modules = await loadCommandModules(commandsDir, importCommandModule2);
|
|
869
871
|
const definitions = commandDefinitionsFromModules(modules);
|
|
870
872
|
registerParentCommandsFromDefinitions(program, definitions);
|
|
871
873
|
const commands = commandExportsFromModules(
|
|
@@ -1057,6 +1059,7 @@ var createCommandCliRunner = ({
|
|
|
1057
1059
|
description,
|
|
1058
1060
|
envBinName,
|
|
1059
1061
|
getContext,
|
|
1062
|
+
importCommandModule: importCommandModule2,
|
|
1060
1063
|
importMetaUrl,
|
|
1061
1064
|
isDevRun,
|
|
1062
1065
|
packageName,
|
|
@@ -1070,6 +1073,7 @@ var createCommandCliRunner = ({
|
|
|
1070
1073
|
commandsDir,
|
|
1071
1074
|
description,
|
|
1072
1075
|
getContext,
|
|
1076
|
+
importCommandModule: importCommandModule2,
|
|
1073
1077
|
importMetaUrl,
|
|
1074
1078
|
isDevRun,
|
|
1075
1079
|
packageName,
|
|
@@ -1083,14 +1087,16 @@ var createCommandCliRunner = ({
|
|
|
1083
1087
|
};
|
|
1084
1088
|
|
|
1085
1089
|
// src/mcp/router.ts
|
|
1086
|
-
import { z as
|
|
1090
|
+
import { z as z4 } from "zod";
|
|
1087
1091
|
|
|
1088
1092
|
// src/mcp/constants.ts
|
|
1089
1093
|
var DEFAULT_MCP_SERVER_VERSION = "0.0.0";
|
|
1090
1094
|
var DEFAULT_RESOURCE_MIME_TYPE = "application/json";
|
|
1091
|
-
var
|
|
1095
|
+
var MCP_SUPPORTED_PROTOCOL_VERSIONS = ["2025-06-18", "2025-03-26", "2024-11-05"];
|
|
1092
1096
|
var JSON_RPC_METHOD_NOT_FOUND = -32601;
|
|
1093
1097
|
var JSON_RPC_INTERNAL_ERROR = -32603;
|
|
1098
|
+
var JSON_RPC_INVALID_PARAMS = -32602;
|
|
1099
|
+
var JSON_RPC_PARSE_ERROR = -32700;
|
|
1094
1100
|
var JSON_RPC_VERSION = "2.0";
|
|
1095
1101
|
var MCP_STATUS_COMPLETED = "completed";
|
|
1096
1102
|
var MCP_STATUS_ERROR = "error";
|
|
@@ -1103,6 +1109,7 @@ var RESULT_ENVELOPE_PROGRESS_KEY = "progress";
|
|
|
1103
1109
|
var PROGRESS_LIST_KEYS = ["items", "threads", "files", "events", "messages"];
|
|
1104
1110
|
var CURSOR_KEYS = ["nextCursor", "nextPageToken"];
|
|
1105
1111
|
var MCP_METHOD_INITIALIZE = "initialize";
|
|
1112
|
+
var MCP_METHOD_PING = "ping";
|
|
1106
1113
|
var MCP_METHOD_TOOLS_LIST = "tools/list";
|
|
1107
1114
|
var MCP_METHOD_TOOLS_CALL = "tools/call";
|
|
1108
1115
|
var MCP_METHOD_RESOURCES_LIST = "resources/list";
|
|
@@ -1110,16 +1117,27 @@ var MCP_METHOD_RESOURCES_TEMPLATES_LIST = "resources/templates/list";
|
|
|
1110
1117
|
var MCP_METHOD_RESOURCES_READ = "resources/read";
|
|
1111
1118
|
|
|
1112
1119
|
// src/mcp/errors.ts
|
|
1120
|
+
var McpProtocolError = class extends Error {
|
|
1121
|
+
constructor(code, message) {
|
|
1122
|
+
super(message);
|
|
1123
|
+
this.code = code;
|
|
1124
|
+
}
|
|
1125
|
+
code;
|
|
1126
|
+
};
|
|
1113
1127
|
var assertToolName = (expectedName, actualName) => {
|
|
1114
1128
|
if (actualName !== expectedName) {
|
|
1115
1129
|
throwUnknownTool(actualName);
|
|
1116
1130
|
}
|
|
1117
1131
|
};
|
|
1118
1132
|
var throwUnknownTool = (name) => {
|
|
1119
|
-
throw new
|
|
1133
|
+
throw new McpProtocolError(
|
|
1134
|
+
JSON_RPC_INVALID_PARAMS,
|
|
1135
|
+
`Unknown tool: ${name ?? EMPTY_DISPLAY_VALUE2}`
|
|
1136
|
+
);
|
|
1120
1137
|
};
|
|
1121
1138
|
|
|
1122
1139
|
// src/mcp/progress.ts
|
|
1140
|
+
import { z as z2 } from "zod";
|
|
1123
1141
|
var toolResult = (result, startedAt) => {
|
|
1124
1142
|
const envelope = resultEnvelope(result);
|
|
1125
1143
|
const data = envelope.data;
|
|
@@ -1133,16 +1151,22 @@ var toolResult = (result, startedAt) => {
|
|
|
1133
1151
|
content: [{ type: MCP_TEXT_CONTENT_TYPE, text: JSON.stringify(structuredContent, null, 2) }]
|
|
1134
1152
|
};
|
|
1135
1153
|
};
|
|
1154
|
+
var errorMessage = (caught) => {
|
|
1155
|
+
if (isZodError(caught)) return `Invalid input:
|
|
1156
|
+
${z2.prettifyError(caught)}`;
|
|
1157
|
+
return caught instanceof Error ? caught.message : String(caught);
|
|
1158
|
+
};
|
|
1159
|
+
var isZodError = (caught) => caught instanceof Error && caught.name === "ZodError" && Array.isArray(caught.issues);
|
|
1136
1160
|
var toolErrorResult = (caught, startedAt = Date.now()) => {
|
|
1137
|
-
const message =
|
|
1138
|
-
const
|
|
1161
|
+
const message = errorMessage(caught);
|
|
1162
|
+
const errorContent = {
|
|
1139
1163
|
status: MCP_STATUS_ERROR,
|
|
1140
1164
|
progress: { elapsedMs: elapsedMs(startedAt), errors: [message] },
|
|
1141
1165
|
error: { message }
|
|
1142
1166
|
};
|
|
1143
1167
|
return {
|
|
1144
|
-
|
|
1145
|
-
content: [{ type: MCP_TEXT_CONTENT_TYPE, text: JSON.stringify(
|
|
1168
|
+
isError: true,
|
|
1169
|
+
content: [{ type: MCP_TEXT_CONTENT_TYPE, text: JSON.stringify(errorContent, null, 2) }]
|
|
1146
1170
|
};
|
|
1147
1171
|
};
|
|
1148
1172
|
var commandProgressSummary = (data, command) => {
|
|
@@ -1249,11 +1273,11 @@ var resourceInputNames = (uriTemplate) => [...uriTemplate.matchAll(/\{([^}]+)\}/
|
|
|
1249
1273
|
});
|
|
1250
1274
|
|
|
1251
1275
|
// src/mcp/schema.ts
|
|
1252
|
-
import { z as
|
|
1276
|
+
import { z as z3 } from "zod";
|
|
1253
1277
|
var mcpToolOutputSchema = (dataSchema) => ({
|
|
1254
1278
|
type: "object",
|
|
1255
1279
|
properties: {
|
|
1256
|
-
data:
|
|
1280
|
+
data: z3.toJSONSchema(dataSchema),
|
|
1257
1281
|
progress: {
|
|
1258
1282
|
type: "object",
|
|
1259
1283
|
properties: {
|
|
@@ -1293,10 +1317,10 @@ var createCommandMcpRoute = ({
|
|
|
1293
1317
|
inputSchema,
|
|
1294
1318
|
outputSchema
|
|
1295
1319
|
});
|
|
1296
|
-
var commandMcpRouteToTool = (route, prefix) => ({
|
|
1320
|
+
var commandMcpRouteToTool = (route, prefix, boundOptions = {}) => ({
|
|
1297
1321
|
name: commandNameToMcpToolName(route.command.name, prefix),
|
|
1298
|
-
description: route.command
|
|
1299
|
-
inputSchema:
|
|
1322
|
+
description: commandMcpDescription(route.command),
|
|
1323
|
+
inputSchema: z4.toJSONSchema(commandMcpInputSchema(route, boundOptions)),
|
|
1300
1324
|
outputSchema: mcpToolOutputSchema(route.outputSchema),
|
|
1301
1325
|
annotations: commandMcpAnnotations(route.command)
|
|
1302
1326
|
});
|
|
@@ -1304,12 +1328,51 @@ var commandNameToMcpToolName = (name, prefix) => {
|
|
|
1304
1328
|
const baseName = name.replaceAll(COMMAND_NAME_SEPARATOR, TOOL_NAME_SEPARATOR);
|
|
1305
1329
|
return prefix ? `${prefix}_${baseName}` : baseName;
|
|
1306
1330
|
};
|
|
1307
|
-
var
|
|
1331
|
+
var commandMcpInputSchema = (route, boundOptions = {}) => {
|
|
1332
|
+
const schema = route.inputSchema;
|
|
1333
|
+
const shape = objectShape(schema);
|
|
1334
|
+
if (!shape) return schema;
|
|
1335
|
+
const hidden = hiddenInputNames(route.command, boundOptions);
|
|
1336
|
+
const required = new Set(
|
|
1337
|
+
(route.command.options ?? []).filter((option) => option.mcp === "required").map(optionInputName)
|
|
1338
|
+
);
|
|
1339
|
+
return z4.object(
|
|
1340
|
+
Object.fromEntries(
|
|
1341
|
+
Object.entries(shape).filter(([name]) => !hidden.has(name)).map(([name, property]) => [
|
|
1342
|
+
name,
|
|
1343
|
+
required.has(name) ? requiredProperty(property) : property
|
|
1344
|
+
])
|
|
1345
|
+
)
|
|
1346
|
+
);
|
|
1347
|
+
};
|
|
1348
|
+
var commandMcpInput = (route, args, boundOptions = {}) => {
|
|
1349
|
+
const inputNames = objectInputNames(route.inputSchema);
|
|
1350
|
+
const routeBoundOptions = Object.entries(boundOptions).filter(([name]) => inputNames.has(name));
|
|
1351
|
+
for (const [name, value] of routeBoundOptions) {
|
|
1352
|
+
if (args[name] !== void 0 && args[name] !== value) {
|
|
1353
|
+
throw new Error(`'${name}' is fixed to '${value}' by this MCP server`);
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
commandMcpInputSchema(route, boundOptions).parse(args);
|
|
1357
|
+
const hidden = hiddenInputNames(route.command, boundOptions);
|
|
1358
|
+
const visibleArgs = Object.fromEntries(
|
|
1359
|
+
Object.entries(args).filter(([name]) => !hidden.has(name))
|
|
1360
|
+
);
|
|
1361
|
+
return route.inputSchema.parse({
|
|
1362
|
+
...visibleArgs,
|
|
1363
|
+
...Object.fromEntries(routeBoundOptions)
|
|
1364
|
+
});
|
|
1365
|
+
};
|
|
1366
|
+
var createCommandMcpRouter = ({
|
|
1367
|
+
boundOptions = {},
|
|
1368
|
+
prefix,
|
|
1369
|
+
routes
|
|
1370
|
+
}) => {
|
|
1308
1371
|
const mcpRoutes = routes.filter((route) => route.command.mcp);
|
|
1309
1372
|
const toolRoutes = mcpRoutes.filter((route) => isCommandMcpToolMetadata(route.command.mcp));
|
|
1310
1373
|
const resourceRoutes = mcpRoutes.flatMap(commandMcpRouteToResourceRoute);
|
|
1311
1374
|
return {
|
|
1312
|
-
tools: toolRoutes.map((route) => commandMcpRouteToTool(route, prefix)),
|
|
1375
|
+
tools: toolRoutes.map((route) => commandMcpRouteToTool(route, prefix, boundOptions)),
|
|
1313
1376
|
resources: resourceRoutes.filter((route) => !isResourceTemplate(route.uriTemplate)).map(commandResourceRouteToResource),
|
|
1314
1377
|
resourceTemplates: resourceRoutes.filter((route) => isResourceTemplate(route.uriTemplate)).map(commandResourceRouteToResourceTemplate),
|
|
1315
1378
|
callTool: async (params) => {
|
|
@@ -1320,7 +1383,7 @@ var createCommandMcpRouter = ({ prefix, routes }) => {
|
|
|
1320
1383
|
if (!route) {
|
|
1321
1384
|
return throwUnknownTool(toolCall.name);
|
|
1322
1385
|
}
|
|
1323
|
-
const input = route
|
|
1386
|
+
const input = commandMcpInput(route, toolCall.arguments ?? {}, boundOptions);
|
|
1324
1387
|
const data = route.outputSchema.parse(await route.handler(input));
|
|
1325
1388
|
return { data, progress: commandProgressSummary(data, route.command) };
|
|
1326
1389
|
},
|
|
@@ -1331,11 +1394,29 @@ var createCommandMcpRouter = ({ prefix, routes }) => {
|
|
|
1331
1394
|
throw new Error(`Unknown resource: ${resourceRead.uri ?? EMPTY_DISPLAY_VALUE2}`);
|
|
1332
1395
|
}
|
|
1333
1396
|
return routeMatch.route.command.outputSchema.parse(
|
|
1334
|
-
await routeMatch.route.handler(routeMatch.input)
|
|
1397
|
+
await routeMatch.route.handler({ ...routeMatch.input, ...boundOptions })
|
|
1335
1398
|
);
|
|
1336
1399
|
}
|
|
1337
1400
|
};
|
|
1338
1401
|
};
|
|
1402
|
+
var hiddenInputNames = (command, boundOptions) => /* @__PURE__ */ new Set([
|
|
1403
|
+
...Object.keys(boundOptions),
|
|
1404
|
+
...(command.options ?? []).filter((option) => option.mcp === false).map(optionInputName)
|
|
1405
|
+
]);
|
|
1406
|
+
var objectShape = (schema) => schema.def.type === "object" ? schema.shape : void 0;
|
|
1407
|
+
var requiredProperty = (property) => property.def.type === "optional" ? property.unwrap() : property;
|
|
1408
|
+
var objectInputNames = (schema) => new Set(Object.keys(objectShape(schema) ?? {}));
|
|
1409
|
+
var commandMcpDescription = (command) => {
|
|
1410
|
+
const mcp = command.mcp;
|
|
1411
|
+
if (!isCommandMcpToolMetadata(mcp)) return command.description;
|
|
1412
|
+
const notes = [
|
|
1413
|
+
...mcp.sideEffects?.length ? [`Side effects: ${mcp.sideEffects.join(" ")}`] : [],
|
|
1414
|
+
...mcp.requiresConfirmation ? ["Confirm with the user before calling this tool."] : []
|
|
1415
|
+
];
|
|
1416
|
+
return notes.length ? `${command.description}
|
|
1417
|
+
|
|
1418
|
+
${notes.join("\n")}` : command.description;
|
|
1419
|
+
};
|
|
1339
1420
|
var commandMcpAnnotations = (command) => {
|
|
1340
1421
|
const mcp = command.mcp;
|
|
1341
1422
|
if (!isCommandMcpToolMetadata(mcp)) return void 0;
|
|
@@ -1343,9 +1424,7 @@ var commandMcpAnnotations = (command) => {
|
|
|
1343
1424
|
readOnlyHint: mcp.readOnly,
|
|
1344
1425
|
destructiveHint: mcp.destructive,
|
|
1345
1426
|
idempotentHint: mcp.idempotent,
|
|
1346
|
-
openWorldHint: mcp.openWorld
|
|
1347
|
-
requiresConfirmation: mcp.requiresConfirmation,
|
|
1348
|
-
sideEffects: mcp.sideEffects
|
|
1427
|
+
openWorldHint: mcp.openWorld
|
|
1349
1428
|
};
|
|
1350
1429
|
};
|
|
1351
1430
|
|
|
@@ -1391,12 +1470,13 @@ var generateReadmeCommandDocs = async ({
|
|
|
1391
1470
|
binName,
|
|
1392
1471
|
commandDefinitions = [],
|
|
1393
1472
|
commandsDir = join4(process.cwd(), "src", "commands"),
|
|
1473
|
+
importCommandModule: importCommandModule2,
|
|
1394
1474
|
markerName = "COMMANDS",
|
|
1395
1475
|
readmePath = "README.md"
|
|
1396
1476
|
}) => {
|
|
1397
1477
|
const readme = readFileSync2(readmePath, "utf8");
|
|
1398
1478
|
const loadedCommandDefinitions = commandDefinitionsFromModules(
|
|
1399
|
-
await loadCommandModules(commandsDir)
|
|
1479
|
+
await loadCommandModules(commandsDir, importCommandModule2)
|
|
1400
1480
|
);
|
|
1401
1481
|
const generated = formatCommandDocs(
|
|
1402
1482
|
[...commandDefinitions, ...loadedCommandDefinitions],
|
|
@@ -1480,8 +1560,14 @@ var createSingleToolMcpServer = ({
|
|
|
1480
1560
|
}
|
|
1481
1561
|
});
|
|
1482
1562
|
};
|
|
1563
|
+
var negotiateMcpProtocolVersion = (params) => {
|
|
1564
|
+
const requested = params?.protocolVersion;
|
|
1565
|
+
return typeof requested === "string" && MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(requested) ? requested : MCP_SUPPORTED_PROTOCOL_VERSIONS[0];
|
|
1566
|
+
};
|
|
1483
1567
|
var createMcpServer = ({
|
|
1484
1568
|
name,
|
|
1569
|
+
version = DEFAULT_MCP_SERVER_VERSION,
|
|
1570
|
+
instructions,
|
|
1485
1571
|
tools,
|
|
1486
1572
|
resources = [],
|
|
1487
1573
|
resourceTemplates = [],
|
|
@@ -1498,15 +1584,24 @@ var createMcpServer = ({
|
|
|
1498
1584
|
const error = (id, code, message) => {
|
|
1499
1585
|
send({ jsonrpc: JSON_RPC_VERSION, id, error: { code, message } });
|
|
1500
1586
|
};
|
|
1587
|
+
const protocolError = (id, caught) => {
|
|
1588
|
+
const code = caught instanceof McpProtocolError ? caught.code : JSON_RPC_INTERNAL_ERROR;
|
|
1589
|
+
error(id, code, caught instanceof Error ? caught.message : String(caught));
|
|
1590
|
+
};
|
|
1501
1591
|
const handleRequest = async (request) => {
|
|
1502
1592
|
if (request.method === MCP_METHOD_INITIALIZE) {
|
|
1503
1593
|
result(request.id, {
|
|
1504
|
-
protocolVersion:
|
|
1594
|
+
protocolVersion: negotiateMcpProtocolVersion(request.params),
|
|
1505
1595
|
capabilities: { resources: {}, tools: {} },
|
|
1506
|
-
serverInfo: { name, version
|
|
1596
|
+
serverInfo: { name, version },
|
|
1597
|
+
instructions
|
|
1507
1598
|
});
|
|
1508
1599
|
return;
|
|
1509
1600
|
}
|
|
1601
|
+
if (request.method === MCP_METHOD_PING) {
|
|
1602
|
+
result(request.id, {});
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1510
1605
|
if (request.method === MCP_METHOD_TOOLS_LIST) {
|
|
1511
1606
|
result(request.id, { tools });
|
|
1512
1607
|
return;
|
|
@@ -1528,11 +1623,10 @@ var createMcpServer = ({
|
|
|
1528
1623
|
);
|
|
1529
1624
|
return;
|
|
1530
1625
|
}
|
|
1531
|
-
const startedAt = Date.now();
|
|
1532
1626
|
try {
|
|
1533
1627
|
result(request.id, resourceResult(request.params, await readResource(request.params)));
|
|
1534
1628
|
} catch (caught) {
|
|
1535
|
-
|
|
1629
|
+
protocolError(request.id, caught);
|
|
1536
1630
|
}
|
|
1537
1631
|
return;
|
|
1538
1632
|
}
|
|
@@ -1541,7 +1635,11 @@ var createMcpServer = ({
|
|
|
1541
1635
|
try {
|
|
1542
1636
|
result(request.id, toolResult(await callTool(request.params), startedAt));
|
|
1543
1637
|
} catch (caught) {
|
|
1544
|
-
|
|
1638
|
+
if (caught instanceof McpProtocolError) {
|
|
1639
|
+
protocolError(request.id, caught);
|
|
1640
|
+
} else {
|
|
1641
|
+
result(request.id, toolErrorResult(caught, startedAt));
|
|
1642
|
+
}
|
|
1545
1643
|
}
|
|
1546
1644
|
return;
|
|
1547
1645
|
}
|
|
@@ -1554,27 +1652,91 @@ var createMcpServer = ({
|
|
|
1554
1652
|
}
|
|
1555
1653
|
};
|
|
1556
1654
|
return {
|
|
1655
|
+
handleRequest,
|
|
1557
1656
|
start: async () => {
|
|
1558
1657
|
const input = createInterface({ input: process.stdin });
|
|
1658
|
+
const pending = /* @__PURE__ */ new Set();
|
|
1559
1659
|
for await (const line of input) {
|
|
1560
1660
|
if (!line.trim()) continue;
|
|
1661
|
+
let request;
|
|
1561
1662
|
try {
|
|
1562
|
-
|
|
1663
|
+
request = JSON.parse(line);
|
|
1563
1664
|
} catch (caught) {
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
caught instanceof Error ? caught.message : String(caught)
|
|
1568
|
-
);
|
|
1665
|
+
const message = caught instanceof Error ? caught.message : String(caught);
|
|
1666
|
+
protocolError(void 0, new McpProtocolError(JSON_RPC_PARSE_ERROR, message));
|
|
1667
|
+
continue;
|
|
1569
1668
|
}
|
|
1669
|
+
const task = handleRequest(request).catch((caught) => protocolError(request.id, caught)).finally(() => pending.delete(task));
|
|
1670
|
+
pending.add(task);
|
|
1570
1671
|
}
|
|
1672
|
+
await Promise.all(pending);
|
|
1571
1673
|
}
|
|
1572
1674
|
};
|
|
1573
1675
|
};
|
|
1574
1676
|
|
|
1677
|
+
// src/mcp/server-options.ts
|
|
1678
|
+
var parseMcpServerArgv = (argv) => {
|
|
1679
|
+
const flags = {};
|
|
1680
|
+
const positionals = [];
|
|
1681
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
1682
|
+
const token = argv[index] ?? "";
|
|
1683
|
+
if (!token.startsWith("--")) {
|
|
1684
|
+
positionals.push(token);
|
|
1685
|
+
continue;
|
|
1686
|
+
}
|
|
1687
|
+
const [rawName, inlineValue] = splitFlag(token.slice(2));
|
|
1688
|
+
const nextToken = argv[index + 1];
|
|
1689
|
+
if (inlineValue !== void 0) {
|
|
1690
|
+
flags[kebabToCamel2(rawName)] = inlineValue;
|
|
1691
|
+
} else if (nextToken !== void 0 && !nextToken.startsWith("--")) {
|
|
1692
|
+
flags[kebabToCamel2(rawName)] = nextToken;
|
|
1693
|
+
index += 1;
|
|
1694
|
+
} else {
|
|
1695
|
+
flags[kebabToCamel2(rawName)] = "true";
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return { flags, positionals };
|
|
1699
|
+
};
|
|
1700
|
+
var mcpServerOptionEnvName = (envPrefix, option) => option.env ?? `${envPrefix}_${camelToConstant(kebabToCamel2(option.name))}`;
|
|
1701
|
+
var resolveMcpServerOptions = ({
|
|
1702
|
+
argvFlags,
|
|
1703
|
+
definitions,
|
|
1704
|
+
env,
|
|
1705
|
+
envPrefix
|
|
1706
|
+
}) => {
|
|
1707
|
+
const values = {};
|
|
1708
|
+
const missing = [];
|
|
1709
|
+
for (const definition of definitions) {
|
|
1710
|
+
const inputName = kebabToCamel2(definition.name);
|
|
1711
|
+
const envName = mcpServerOptionEnvName(envPrefix, definition);
|
|
1712
|
+
const value = argvFlags[inputName] ?? nonEmpty(env[envName]);
|
|
1713
|
+
if (value !== void 0) {
|
|
1714
|
+
values[inputName] = value;
|
|
1715
|
+
} else if (definition.required) {
|
|
1716
|
+
missing.push(`--${definition.name} <value> (or ${envName})`);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
if (missing.length > 0) {
|
|
1720
|
+
throw new Error(`Missing required MCP server option: ${missing.join(", ")}`);
|
|
1721
|
+
}
|
|
1722
|
+
return values;
|
|
1723
|
+
};
|
|
1724
|
+
var withoutMcpServerOptionFlags = (flags, definitions) => {
|
|
1725
|
+
const optionNames = new Set(definitions.map((definition) => kebabToCamel2(definition.name)));
|
|
1726
|
+
return Object.fromEntries(Object.entries(flags).filter(([name]) => !optionNames.has(name)));
|
|
1727
|
+
};
|
|
1728
|
+
var splitFlag = (flag) => {
|
|
1729
|
+
const separatorIndex = flag.indexOf("=");
|
|
1730
|
+
if (separatorIndex === -1) return [flag, void 0];
|
|
1731
|
+
return [flag.slice(0, separatorIndex), flag.slice(separatorIndex + 1)];
|
|
1732
|
+
};
|
|
1733
|
+
var nonEmpty = (value) => value?.trim() ? value : void 0;
|
|
1734
|
+
var kebabToCamel2 = (value) => value.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
|
|
1735
|
+
var camelToConstant = (value) => value.replace(/([A-Z])/g, "_$1").toUpperCase();
|
|
1736
|
+
|
|
1575
1737
|
// src/mcp/command-server.ts
|
|
1576
|
-
var loadCommandMcpRoutes = async (commandsDir, getContext = () => void 0) => {
|
|
1577
|
-
const modules = await loadCommandModules(commandsDir);
|
|
1738
|
+
var loadCommandMcpRoutes = async (commandsDir, getContext = () => void 0, importCommandModule2) => {
|
|
1739
|
+
const modules = await loadCommandModules(commandsDir, importCommandModule2);
|
|
1578
1740
|
const factories = commandExportsFromModules(
|
|
1579
1741
|
modules,
|
|
1580
1742
|
(_name, value) => isCommandAdapterExport(value)
|
|
@@ -1582,37 +1744,103 @@ var loadCommandMcpRoutes = async (commandsDir, getContext = () => void 0) => {
|
|
|
1582
1744
|
return factories.map((factory) => factory(getContext)).filter((route) => route.command.mcp);
|
|
1583
1745
|
};
|
|
1584
1746
|
var createCommandMcpServer = async ({
|
|
1747
|
+
argv = process.argv.slice(2),
|
|
1585
1748
|
commandsDir,
|
|
1749
|
+
env = process.env,
|
|
1750
|
+
envPrefix,
|
|
1586
1751
|
getContext,
|
|
1752
|
+
importCommandModule: importCommandModule2,
|
|
1587
1753
|
importMetaUrl,
|
|
1754
|
+
instructions,
|
|
1588
1755
|
name,
|
|
1589
|
-
prefix
|
|
1756
|
+
prefix,
|
|
1757
|
+
serverOptions = [],
|
|
1758
|
+
version
|
|
1590
1759
|
}) => {
|
|
1591
1760
|
const commandDirectory = commandsDir ?? join5(dirname3(fileURLToPath4(importMetaUrl)), DEFAULT_COMMANDS_DIR);
|
|
1592
|
-
const
|
|
1593
|
-
|
|
1594
|
-
|
|
1761
|
+
const parsedArgv = parseMcpServerArgv(argv);
|
|
1762
|
+
const boundOptions = resolveMcpServerOptions({
|
|
1763
|
+
argvFlags: parsedArgv.flags,
|
|
1764
|
+
definitions: serverOptions,
|
|
1765
|
+
env,
|
|
1766
|
+
envPrefix: envPrefix ?? packageEnvPrefix(name)
|
|
1767
|
+
});
|
|
1768
|
+
const routes = await loadCommandMcpRoutes(
|
|
1769
|
+
commandDirectory,
|
|
1770
|
+
() => getContext ? getContext(boundOptions) : void 0,
|
|
1771
|
+
importCommandModule2
|
|
1772
|
+
);
|
|
1773
|
+
const router = createCommandMcpRouter({ boundOptions, prefix, routes });
|
|
1774
|
+
const server = createMcpServer({
|
|
1775
|
+
name,
|
|
1776
|
+
version,
|
|
1777
|
+
instructions: typeof instructions === "function" ? instructions(boundOptions) : instructions,
|
|
1778
|
+
tools: router.tools,
|
|
1779
|
+
resources: router.resources,
|
|
1780
|
+
resourceTemplates: router.resourceTemplates,
|
|
1781
|
+
callTool: router.callTool,
|
|
1782
|
+
readResource: router.readResource
|
|
1595
1783
|
});
|
|
1596
|
-
return
|
|
1784
|
+
return {
|
|
1785
|
+
...server,
|
|
1786
|
+
boundOptions,
|
|
1787
|
+
command: parsedArgv.positionals.length > 0 ? parsedArgv.positionals.join(" ") : void 0,
|
|
1788
|
+
runCommand: (commandName, flags = {}) => runMcpCommandOnce(routes, commandName, withoutMcpServerOptionFlags(flags, serverOptions), {
|
|
1789
|
+
boundOptions
|
|
1790
|
+
}),
|
|
1791
|
+
commandFlags: withoutMcpServerOptionFlags(parsedArgv.flags, serverOptions)
|
|
1792
|
+
};
|
|
1793
|
+
};
|
|
1794
|
+
var runMcpCommandOnce = async (routes, commandName, flags, { boundOptions }) => {
|
|
1795
|
+
const route = routes.find(
|
|
1796
|
+
(candidate) => candidate.command.name === commandName && isCommandMcpToolMetadata(candidate.command.mcp)
|
|
1797
|
+
);
|
|
1798
|
+
if (!route) throw new Error(`Unknown command: ${commandName}`);
|
|
1799
|
+
const input = commandMcpInput(route, oneShotInput(flags), boundOptions);
|
|
1800
|
+
return route.outputSchema.parse(await route.handler(input));
|
|
1597
1801
|
};
|
|
1598
1802
|
var startCommandMcpServer = async (options) => {
|
|
1599
|
-
|
|
1803
|
+
try {
|
|
1804
|
+
const server = await createCommandMcpServer(options);
|
|
1805
|
+
if (!server.command) {
|
|
1806
|
+
await server.start();
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
const data = await server.runCommand(server.command, server.commandFlags);
|
|
1810
|
+
process.stdout.write(`${JSON.stringify(data)}
|
|
1811
|
+
`);
|
|
1812
|
+
} catch (caught) {
|
|
1813
|
+
process.stderr.write(`${errorMessage(caught)}
|
|
1814
|
+
`);
|
|
1815
|
+
process.exitCode = 1;
|
|
1816
|
+
}
|
|
1600
1817
|
};
|
|
1601
1818
|
var startPackageCommandMcpServer = async ({
|
|
1819
|
+
envPrefix,
|
|
1602
1820
|
importMetaUrl,
|
|
1603
1821
|
mcpServerPrefix,
|
|
1604
1822
|
name,
|
|
1605
1823
|
prefix,
|
|
1824
|
+
version,
|
|
1606
1825
|
...options
|
|
1607
1826
|
}) => {
|
|
1608
1827
|
const metadata = packageCommandMetadata(importMetaUrl, { mcpServerPrefix });
|
|
1609
1828
|
await startCommandMcpServer({
|
|
1610
1829
|
...options,
|
|
1830
|
+
envPrefix: envPrefix ?? packageEnvPrefix(metadata.packageName),
|
|
1611
1831
|
importMetaUrl,
|
|
1612
1832
|
name: name ?? metadata.mcpServerName,
|
|
1613
|
-
prefix: prefix ?? metadata.mcpPrefix
|
|
1833
|
+
prefix: prefix ?? metadata.mcpPrefix,
|
|
1834
|
+
version: version ?? metadata.version
|
|
1614
1835
|
});
|
|
1615
1836
|
};
|
|
1837
|
+
var ONE_SHOT_BOOLEANS = /* @__PURE__ */ new Map([
|
|
1838
|
+
["true", true],
|
|
1839
|
+
["false", false]
|
|
1840
|
+
]);
|
|
1841
|
+
var oneShotInput = (flags) => Object.fromEntries(
|
|
1842
|
+
Object.entries(flags).map(([name, value]) => [name, ONE_SHOT_BOOLEANS.get(value) ?? value])
|
|
1843
|
+
);
|
|
1616
1844
|
|
|
1617
1845
|
// src/scripts/dev-command.ts
|
|
1618
1846
|
import { mkdirSync, rmSync as rmSync2 } from "fs";
|
|
@@ -1736,6 +1964,7 @@ var packageDevCommandConfig = (importMetaUrl, options) => {
|
|
|
1736
1964
|
};
|
|
1737
1965
|
export {
|
|
1738
1966
|
DEFAULT_COMMANDS_DIR,
|
|
1967
|
+
McpProtocolError,
|
|
1739
1968
|
PROGRAM_NAME_ENV_SUFFIX,
|
|
1740
1969
|
PackageManager,
|
|
1741
1970
|
assertToolName,
|
|
@@ -1746,6 +1975,8 @@ export {
|
|
|
1746
1975
|
commandExportsFromModules,
|
|
1747
1976
|
commandInputString,
|
|
1748
1977
|
commandInputValue,
|
|
1978
|
+
commandMcpInput,
|
|
1979
|
+
commandMcpInputSchema,
|
|
1749
1980
|
commandMcpRouteToResourceRoute,
|
|
1750
1981
|
commandMcpRouteToTool,
|
|
1751
1982
|
commandNameToMcpToolName,
|
|
@@ -1784,12 +2015,16 @@ export {
|
|
|
1784
2015
|
loadCommandMcpRoutes,
|
|
1785
2016
|
loadCommandModules,
|
|
1786
2017
|
loadCommandModulesFromFiles,
|
|
2018
|
+
mcpServerOptionEnvName,
|
|
1787
2019
|
mcpToolOutputSchema,
|
|
2020
|
+
negotiateMcpProtocolVersion,
|
|
1788
2021
|
normalizeCommandInputAliases,
|
|
2022
|
+
optionInputName,
|
|
1789
2023
|
packageBinEntry,
|
|
1790
2024
|
packageCommandMetadata,
|
|
1791
2025
|
packageEnvPrefix,
|
|
1792
2026
|
packageRoot,
|
|
2027
|
+
parseMcpServerArgv,
|
|
1793
2028
|
printProgramHelp,
|
|
1794
2029
|
readPackageJson,
|
|
1795
2030
|
registerCliCommandsFromDirectory,
|
|
@@ -1797,7 +2032,9 @@ export {
|
|
|
1797
2032
|
registerCompletionCommand,
|
|
1798
2033
|
registerParentCommandsFromDefinitions,
|
|
1799
2034
|
registerUpdateCommand,
|
|
2035
|
+
resolveMcpServerOptions,
|
|
1800
2036
|
resourceResult,
|
|
2037
|
+
runMcpCommandOnce,
|
|
1801
2038
|
setProgramHelpData,
|
|
1802
2039
|
shortPackageName,
|
|
1803
2040
|
startCommandMcpServer,
|
|
@@ -1806,6 +2043,7 @@ export {
|
|
|
1806
2043
|
uninstallDevCommand,
|
|
1807
2044
|
uninstallPackageDevCommand,
|
|
1808
2045
|
uninstallPackageDevCommands,
|
|
1809
|
-
|
|
2046
|
+
withoutMcpServerOptionFlags,
|
|
2047
|
+
z5 as z
|
|
1810
2048
|
};
|
|
1811
2049
|
//# sourceMappingURL=index.js.map
|