mikromcp 1.5.0 → 1.6.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 +9 -2
- package/dist/main.js +1219 -1263
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -24,6 +24,7 @@ function loadAppConfig() {
|
|
|
24
24
|
bindHost: env.MIKROMCP_BIND_HOST ?? "127.0.0.1",
|
|
25
25
|
logLevel: env.MIKROMCP_LOG_LEVEL ?? "info",
|
|
26
26
|
configPath: env.MIKROMCP_CONFIG_PATH ?? join(mikromcpDir(), "routers.yaml"),
|
|
27
|
+
defaultRouter: env.MIKROMCP_DEFAULT_ROUTER || void 0,
|
|
27
28
|
dataDir,
|
|
28
29
|
snapshotDir: `${dataDir}/snapshots`,
|
|
29
30
|
journalPath: `${dataDir}/write-journal.ndjson`,
|
|
@@ -60,10 +61,17 @@ function loadAppConfig() {
|
|
|
60
61
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
61
62
|
|
|
62
63
|
// src/mcp/tool-registry.ts
|
|
63
|
-
import { z as
|
|
64
|
+
import { z as z47 } from "zod";
|
|
64
65
|
|
|
65
66
|
// src/domain/tools/system-tools.ts
|
|
67
|
+
import { z as z2 } from "zod";
|
|
68
|
+
|
|
69
|
+
// src/domain/tools/schema-fields.ts
|
|
66
70
|
import { z } from "zod";
|
|
71
|
+
var routerId = z.string().optional().describe("Router ID; omit to use the default router.");
|
|
72
|
+
var dryRun = z.boolean().default(false).describe("Preview changes without applying.");
|
|
73
|
+
var offset = z.number().int().min(0).default(0).describe("Pagination offset.");
|
|
74
|
+
var limit = z.number().int().min(1).max(500).default(100).describe("Max results to return.");
|
|
67
75
|
|
|
68
76
|
// src/domain/errors/error-enricher.ts
|
|
69
77
|
import { ZodError } from "zod";
|
|
@@ -274,6 +282,11 @@ function enrichError(error, context) {
|
|
|
274
282
|
});
|
|
275
283
|
}
|
|
276
284
|
|
|
285
|
+
// src/domain/tools/tool-definition.ts
|
|
286
|
+
function toolError(err, context, tool) {
|
|
287
|
+
return enrichError(err, { routerId: context.routerId, tool });
|
|
288
|
+
}
|
|
289
|
+
|
|
277
290
|
// src/observability/logger.ts
|
|
278
291
|
import pino from "pino";
|
|
279
292
|
var isDevelopment = process.env.NODE_ENV === "development";
|
|
@@ -320,9 +333,9 @@ var SECTION_PATHS = {
|
|
|
320
333
|
health: "system/health",
|
|
321
334
|
clock: "system/clock"
|
|
322
335
|
};
|
|
323
|
-
var inputSchema =
|
|
324
|
-
routerId
|
|
325
|
-
sections:
|
|
336
|
+
var inputSchema = z2.object({
|
|
337
|
+
routerId,
|
|
338
|
+
sections: z2.array(z2.enum(SECTION_VALUES)).default(["all"]).describe("Which system information sections to include")
|
|
326
339
|
}).strict();
|
|
327
340
|
async function fetchSection(context, section) {
|
|
328
341
|
const path = SECTION_PATHS[section];
|
|
@@ -419,23 +432,39 @@ var getSystemStatusTool = {
|
|
|
419
432
|
}
|
|
420
433
|
};
|
|
421
434
|
} catch (err) {
|
|
422
|
-
throw
|
|
435
|
+
throw toolError(err, context, "get_system_status");
|
|
423
436
|
}
|
|
424
437
|
}
|
|
425
438
|
};
|
|
426
439
|
var systemTools = [getSystemStatusTool];
|
|
427
440
|
|
|
428
441
|
// src/domain/tools/interface-tools.ts
|
|
429
|
-
import { z as
|
|
442
|
+
import { z as z3 } from "zod";
|
|
443
|
+
|
|
444
|
+
// src/domain/tools/pagination.ts
|
|
445
|
+
function paginate(items, offset2, limit2) {
|
|
446
|
+
const total = items.length;
|
|
447
|
+
return {
|
|
448
|
+
items: items.slice(offset2, offset2 + limit2),
|
|
449
|
+
total,
|
|
450
|
+
hasMore: offset2 + limit2 < total
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
function listSummary(label, routerId2, shown, total, offset2) {
|
|
454
|
+
const range = total === 0 ? "none" : `${offset2 + 1}-${offset2 + shown} of ${total}`;
|
|
455
|
+
return `${label} on ${routerId2}: ${range}. Full records in structuredContent.`;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// src/domain/tools/interface-tools.ts
|
|
430
459
|
var log2 = createLogger("interface-tools");
|
|
431
|
-
var listInputSchema =
|
|
432
|
-
routerId
|
|
433
|
-
type:
|
|
434
|
-
status:
|
|
435
|
-
macAddress:
|
|
436
|
-
includeCounters:
|
|
437
|
-
limit
|
|
438
|
-
offset
|
|
460
|
+
var listInputSchema = z3.object({
|
|
461
|
+
routerId,
|
|
462
|
+
type: z3.enum(["ether", "vlan", "bridge", "bonding", "wireguard", "gre", "all"]).default("all").describe("Filter by interface type"),
|
|
463
|
+
status: z3.enum(["up", "down", "all"]).default("all").describe("Filter by running status"),
|
|
464
|
+
macAddress: z3.string().optional().describe("Filter by MAC address (case-insensitive exact match on mac-address field)"),
|
|
465
|
+
includeCounters: z3.boolean().default(false).describe("Include traffic counters (tx-byte, rx-byte, etc.)"),
|
|
466
|
+
limit,
|
|
467
|
+
offset
|
|
439
468
|
}).strict();
|
|
440
469
|
var COUNTER_PROPS = [
|
|
441
470
|
"tx-byte",
|
|
@@ -493,8 +522,7 @@ var listInterfacesTool = {
|
|
|
493
522
|
return true;
|
|
494
523
|
});
|
|
495
524
|
}
|
|
496
|
-
const total = interfaces.
|
|
497
|
-
const paginated = interfaces.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
525
|
+
const { items: paginated, total, hasMore } = paginate(interfaces, parsed.offset, parsed.limit);
|
|
498
526
|
const results2 = paginated.map((iface) => {
|
|
499
527
|
const rec = iface;
|
|
500
528
|
const isRunning2 = rec.running === true || rec.running === "true";
|
|
@@ -507,19 +535,8 @@ var listInterfacesTool = {
|
|
|
507
535
|
}
|
|
508
536
|
return enriched;
|
|
509
537
|
});
|
|
510
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
511
|
-
const lines = [
|
|
512
|
-
`Interfaces on ${context.routerId}: ${total} total, showing ${results2.length} (offset ${parsed.offset})`
|
|
513
|
-
];
|
|
514
|
-
for (const iface of results2) {
|
|
515
|
-
const rec = iface;
|
|
516
|
-
const name = rec.name ?? rec[".id"] ?? "unknown";
|
|
517
|
-
const type = rec.type ?? parsed.type;
|
|
518
|
-
const status = String(rec.status).toUpperCase();
|
|
519
|
-
lines.push(` ${name} [${type}] ${status}`);
|
|
520
|
-
}
|
|
521
538
|
return {
|
|
522
|
-
content:
|
|
539
|
+
content: listSummary("Interfaces", context.routerId, results2.length, total, parsed.offset),
|
|
523
540
|
structuredContent: {
|
|
524
541
|
routerId: context.routerId,
|
|
525
542
|
interfaces: results2,
|
|
@@ -530,17 +547,17 @@ var listInterfacesTool = {
|
|
|
530
547
|
}
|
|
531
548
|
};
|
|
532
549
|
} catch (err) {
|
|
533
|
-
throw
|
|
550
|
+
throw toolError(err, context, "list_interfaces");
|
|
534
551
|
}
|
|
535
552
|
}
|
|
536
553
|
};
|
|
537
554
|
var interfaceTools = [listInterfacesTool];
|
|
538
555
|
|
|
539
556
|
// src/domain/tools/ip-tools.ts
|
|
540
|
-
import { z as
|
|
557
|
+
import { z as z5 } from "zod";
|
|
541
558
|
|
|
542
559
|
// src/domain/tools/cidr.ts
|
|
543
|
-
import { z as
|
|
560
|
+
import { z as z4 } from "zod";
|
|
544
561
|
function validateCidr(value) {
|
|
545
562
|
const withPrefix = value.includes("/") ? value : `${value}/32`;
|
|
546
563
|
const slashIdx = withPrefix.lastIndexOf("/");
|
|
@@ -562,28 +579,28 @@ function validateCidr(value) {
|
|
|
562
579
|
}
|
|
563
580
|
return withPrefix;
|
|
564
581
|
}
|
|
565
|
-
var cidrSchema =
|
|
582
|
+
var cidrSchema = z4.string().transform((v, ctx) => {
|
|
566
583
|
try {
|
|
567
584
|
return validateCidr(v);
|
|
568
585
|
} catch (e) {
|
|
569
|
-
ctx.addIssue({ code:
|
|
570
|
-
return
|
|
586
|
+
ctx.addIssue({ code: z4.ZodIssueCode.custom, message: e.message });
|
|
587
|
+
return z4.NEVER;
|
|
571
588
|
}
|
|
572
589
|
});
|
|
573
590
|
|
|
574
591
|
// src/domain/tools/ip-tools.ts
|
|
575
592
|
var log3 = createLogger("ip-tools");
|
|
576
|
-
var inputSchema2 =
|
|
577
|
-
routerId
|
|
578
|
-
action:
|
|
593
|
+
var inputSchema2 = z5.object({
|
|
594
|
+
routerId,
|
|
595
|
+
action: z5.enum(["add", "update", "remove"]).describe("Action to perform: add, update, or remove an IP address"),
|
|
579
596
|
address: cidrSchema.describe(
|
|
580
597
|
"IP address with optional prefix length in CIDR notation (e.g., 192.168.1.1/24). Defaults to /32 if prefix is omitted."
|
|
581
598
|
),
|
|
582
|
-
interface:
|
|
583
|
-
network:
|
|
584
|
-
comment:
|
|
585
|
-
disabled:
|
|
586
|
-
dryRun:
|
|
599
|
+
interface: z5.string().describe("Interface to assign the IP address to"),
|
|
600
|
+
network: z5.string().optional().describe("Network address (auto-calculated from address if omitted)"),
|
|
601
|
+
comment: z5.string().max(255).optional().describe("Optional comment for the IP address entry"),
|
|
602
|
+
disabled: z5.boolean().default(false).describe("Whether the IP address should be disabled"),
|
|
603
|
+
dryRun: z5.boolean().default(false).describe("If true, validate and return planned changes without applying")
|
|
587
604
|
}).strict();
|
|
588
605
|
function sanitizeComment(comment) {
|
|
589
606
|
if (comment === void 0) return void 0;
|
|
@@ -783,24 +800,23 @@ var manageIpAddressTool = {
|
|
|
783
800
|
}
|
|
784
801
|
});
|
|
785
802
|
} catch (err) {
|
|
786
|
-
|
|
787
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_ip_address" });
|
|
803
|
+
throw toolError(err, context, "manage_ip_address");
|
|
788
804
|
}
|
|
789
805
|
}
|
|
790
806
|
};
|
|
791
807
|
var ipTools = [manageIpAddressTool];
|
|
792
808
|
|
|
793
809
|
// src/domain/tools/dhcp-tools.ts
|
|
794
|
-
import { z as
|
|
810
|
+
import { z as z6 } from "zod";
|
|
795
811
|
var log4 = createLogger("dhcp-tools");
|
|
796
|
-
var listDhcpLeasesInputSchema =
|
|
797
|
-
routerId
|
|
798
|
-
server:
|
|
799
|
-
status:
|
|
800
|
-
macAddress:
|
|
801
|
-
leaseType:
|
|
802
|
-
limit
|
|
803
|
-
offset
|
|
812
|
+
var listDhcpLeasesInputSchema = z6.object({
|
|
813
|
+
routerId,
|
|
814
|
+
server: z6.string().optional().describe("Filter by DHCP server name"),
|
|
815
|
+
status: z6.enum(["bound", "waiting", "offered", "blocked", "all"]).default("all").describe("Filter by lease status"),
|
|
816
|
+
macAddress: z6.string().optional().describe("Filter by MAC address (exact match, case-insensitive)"),
|
|
817
|
+
leaseType: z6.enum(["dynamic", "static", "all"]).default("all").describe("Filter by lease type (dynamic or static)"),
|
|
818
|
+
limit,
|
|
819
|
+
offset
|
|
804
820
|
}).strict();
|
|
805
821
|
var listDhcpLeasesTool = {
|
|
806
822
|
name: "list_dhcp_leases",
|
|
@@ -857,23 +873,9 @@ var listDhcpLeasesTool = {
|
|
|
857
873
|
return !isDynamic;
|
|
858
874
|
});
|
|
859
875
|
}
|
|
860
|
-
const total = leases.
|
|
861
|
-
const paginated = leases.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
862
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
863
|
-
const lines = [
|
|
864
|
-
`DHCP leases on ${context.routerId}: ${total} total, showing ${paginated.length} (offset ${parsed.offset})`
|
|
865
|
-
];
|
|
866
|
-
for (const lease of paginated) {
|
|
867
|
-
const rec = lease;
|
|
868
|
-
const address = rec.address ?? rec["active-address"] ?? "unknown";
|
|
869
|
-
const macAddress = rec["mac-address"] ?? rec["active-mac-address"] ?? "unknown";
|
|
870
|
-
const hostname = rec["host-name"];
|
|
871
|
-
const hostnameStr = hostname && hostname !== "" ? ` (${hostname})` : "";
|
|
872
|
-
const status = rec.status ?? "unknown";
|
|
873
|
-
lines.push(` ${address} ${macAddress}${hostnameStr} [${status}]`);
|
|
874
|
-
}
|
|
876
|
+
const { items: paginated, total, hasMore } = paginate(leases, parsed.offset, parsed.limit);
|
|
875
877
|
return {
|
|
876
|
-
content:
|
|
878
|
+
content: listSummary("DHCP leases", context.routerId, paginated.length, total, parsed.offset),
|
|
877
879
|
structuredContent: {
|
|
878
880
|
routerId: context.routerId,
|
|
879
881
|
leases: paginated,
|
|
@@ -884,17 +886,17 @@ var listDhcpLeasesTool = {
|
|
|
884
886
|
}
|
|
885
887
|
};
|
|
886
888
|
} catch (err) {
|
|
887
|
-
throw
|
|
889
|
+
throw toolError(err, context, "list_dhcp_leases");
|
|
888
890
|
}
|
|
889
891
|
}
|
|
890
892
|
};
|
|
891
|
-
var manageDhcpLeaseInputSchema =
|
|
892
|
-
routerId
|
|
893
|
-
action:
|
|
893
|
+
var manageDhcpLeaseInputSchema = z6.object({
|
|
894
|
+
routerId,
|
|
895
|
+
action: z6.enum(["make-static", "remove"]).describe(
|
|
894
896
|
"Action to perform: make-static converts a dynamic lease to static; remove deletes the lease"
|
|
895
897
|
),
|
|
896
|
-
macAddress:
|
|
897
|
-
dryRun
|
|
898
|
+
macAddress: z6.string().describe("MAC address of the lease \u2014 idempotency key (case-insensitive)"),
|
|
899
|
+
dryRun
|
|
898
900
|
}).strict();
|
|
899
901
|
var manageDhcpLeaseTool = {
|
|
900
902
|
name: "manage_dhcp_lease",
|
|
@@ -986,22 +988,21 @@ var manageDhcpLeaseTool = {
|
|
|
986
988
|
structuredContent: { action: "removed", macAddress: upperMac, id: existing[".id"] }
|
|
987
989
|
};
|
|
988
990
|
} catch (err) {
|
|
989
|
-
|
|
990
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_dhcp_lease" });
|
|
991
|
+
throw toolError(err, context, "manage_dhcp_lease");
|
|
991
992
|
}
|
|
992
993
|
}
|
|
993
994
|
};
|
|
994
995
|
var dhcpTools = [listDhcpLeasesTool, manageDhcpLeaseTool];
|
|
995
996
|
|
|
996
997
|
// src/domain/tools/route-tools.ts
|
|
997
|
-
import { z as
|
|
998
|
+
import { z as z7 } from "zod";
|
|
998
999
|
var log5 = createLogger("route-tools");
|
|
999
|
-
var listRoutesInputSchema =
|
|
1000
|
-
routerId
|
|
1001
|
-
activeOnly:
|
|
1002
|
-
staticOnly:
|
|
1003
|
-
limit
|
|
1004
|
-
offset
|
|
1000
|
+
var listRoutesInputSchema = z7.object({
|
|
1001
|
+
routerId,
|
|
1002
|
+
activeOnly: z7.boolean().default(false).describe("Return only active routes"),
|
|
1003
|
+
staticOnly: z7.boolean().default(false).describe("Return only non-dynamic routes"),
|
|
1004
|
+
limit,
|
|
1005
|
+
offset
|
|
1005
1006
|
}).strict();
|
|
1006
1007
|
var listRoutesTool = {
|
|
1007
1008
|
name: "list_routes",
|
|
@@ -1041,33 +1042,9 @@ var listRoutesTool = {
|
|
|
1041
1042
|
return rec.dynamic !== true && rec.dynamic !== "true";
|
|
1042
1043
|
});
|
|
1043
1044
|
}
|
|
1044
|
-
const total = routes.
|
|
1045
|
-
const paginated = routes.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
1046
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
1047
|
-
const lines = [
|
|
1048
|
-
`Routes on ${context.routerId}: ${total} total, showing ${paginated.length} (offset ${parsed.offset})`
|
|
1049
|
-
];
|
|
1050
|
-
for (const route of paginated) {
|
|
1051
|
-
const rec = route;
|
|
1052
|
-
const dstAddress = rec["dst-address"] ?? "unknown";
|
|
1053
|
-
const gateway = rec.gateway ?? rec["immediate-gw"] ?? "unknown";
|
|
1054
|
-
const distance = rec.distance;
|
|
1055
|
-
const active = rec.active === true || rec.active === "true";
|
|
1056
|
-
const dynamic = rec.dynamic === true || rec.dynamic === "true";
|
|
1057
|
-
let line = ` ${dstAddress} via ${gateway}`;
|
|
1058
|
-
if (distance) {
|
|
1059
|
-
line += ` [${distance}]`;
|
|
1060
|
-
}
|
|
1061
|
-
if (active) {
|
|
1062
|
-
line += " ACTIVE";
|
|
1063
|
-
}
|
|
1064
|
-
if (dynamic) {
|
|
1065
|
-
line += " DYNAMIC";
|
|
1066
|
-
}
|
|
1067
|
-
lines.push(line);
|
|
1068
|
-
}
|
|
1045
|
+
const { items: paginated, total, hasMore } = paginate(routes, parsed.offset, parsed.limit);
|
|
1069
1046
|
return {
|
|
1070
|
-
content:
|
|
1047
|
+
content: listSummary("Routes", context.routerId, paginated.length, total, parsed.offset),
|
|
1071
1048
|
structuredContent: {
|
|
1072
1049
|
routerId: context.routerId,
|
|
1073
1050
|
routes: paginated,
|
|
@@ -1078,22 +1055,22 @@ var listRoutesTool = {
|
|
|
1078
1055
|
}
|
|
1079
1056
|
};
|
|
1080
1057
|
} catch (err) {
|
|
1081
|
-
throw
|
|
1058
|
+
throw toolError(err, context, "list_routes");
|
|
1082
1059
|
}
|
|
1083
1060
|
}
|
|
1084
1061
|
};
|
|
1085
|
-
var manageRouteInputSchema =
|
|
1086
|
-
routerId
|
|
1087
|
-
action:
|
|
1062
|
+
var manageRouteInputSchema = z7.object({
|
|
1063
|
+
routerId,
|
|
1064
|
+
action: z7.enum(["add", "remove"]).describe("Action to perform: add or remove a route"),
|
|
1088
1065
|
dstAddress: cidrSchema.describe(
|
|
1089
1066
|
"Destination address in CIDR notation or plain IP (auto-converted to /32), e.g. 10.0.0.0/8 or 10.77.0.4"
|
|
1090
1067
|
),
|
|
1091
|
-
gateway:
|
|
1092
|
-
distance:
|
|
1093
|
-
comment:
|
|
1094
|
-
routingTable:
|
|
1095
|
-
disabled:
|
|
1096
|
-
dryRun:
|
|
1068
|
+
gateway: z7.string().describe("Gateway IP address"),
|
|
1069
|
+
distance: z7.number().int().min(1).max(255).default(1).describe("Route distance/metric (1-255)"),
|
|
1070
|
+
comment: z7.string().max(255).optional().describe("Optional comment for the route"),
|
|
1071
|
+
routingTable: z7.string().optional().describe("Routing table name (default: main). Use for policy routing with separate tables."),
|
|
1072
|
+
disabled: z7.boolean().default(false).describe("Whether the route should be disabled"),
|
|
1073
|
+
dryRun: z7.boolean().default(false).describe("If true, validate and return planned changes without applying")
|
|
1097
1074
|
}).strict();
|
|
1098
1075
|
function sanitizeComment2(comment) {
|
|
1099
1076
|
if (comment === void 0) return void 0;
|
|
@@ -1251,15 +1228,14 @@ var manageRouteTool = {
|
|
|
1251
1228
|
}
|
|
1252
1229
|
});
|
|
1253
1230
|
} catch (err) {
|
|
1254
|
-
|
|
1255
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_route" });
|
|
1231
|
+
throw toolError(err, context, "manage_route");
|
|
1256
1232
|
}
|
|
1257
1233
|
}
|
|
1258
1234
|
};
|
|
1259
1235
|
var routeTools = [listRoutesTool, manageRouteTool];
|
|
1260
1236
|
|
|
1261
1237
|
// src/domain/tools/firewall-tools.ts
|
|
1262
|
-
import { z as
|
|
1238
|
+
import { z as z8 } from "zod";
|
|
1263
1239
|
var log6 = createLogger("firewall-tools");
|
|
1264
1240
|
function tableToPath(table) {
|
|
1265
1241
|
return table === "filter" ? "ip/firewall/filter" : "ip/firewall/nat";
|
|
@@ -1274,13 +1250,13 @@ async function findRuleByComment(context, path, comment) {
|
|
|
1274
1250
|
});
|
|
1275
1251
|
return results2.length > 0 ? results2[0] : void 0;
|
|
1276
1252
|
}
|
|
1277
|
-
var listFirewallRulesInputSchema =
|
|
1278
|
-
routerId
|
|
1279
|
-
table:
|
|
1280
|
-
chain:
|
|
1281
|
-
disabled:
|
|
1282
|
-
limit
|
|
1283
|
-
offset
|
|
1253
|
+
var listFirewallRulesInputSchema = z8.object({
|
|
1254
|
+
routerId,
|
|
1255
|
+
table: z8.enum(["filter", "nat"]).default("filter").describe("Firewall table to query: filter or nat"),
|
|
1256
|
+
chain: z8.string().optional().describe("Filter rules by chain name (e.g. forward, input, srcnat)"),
|
|
1257
|
+
disabled: z8.enum(["true", "false", "all"]).default("all").describe("Filter by disabled state: true, false, or all"),
|
|
1258
|
+
limit,
|
|
1259
|
+
offset
|
|
1284
1260
|
}).strict();
|
|
1285
1261
|
var listFirewallRulesTool = {
|
|
1286
1262
|
name: "list_firewall_rules",
|
|
@@ -1323,38 +1299,15 @@ var listFirewallRulesTool = {
|
|
|
1323
1299
|
return isDisabled === (parsed.disabled === "true");
|
|
1324
1300
|
});
|
|
1325
1301
|
}
|
|
1326
|
-
const total = rules.
|
|
1327
|
-
const paginated = rules.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
1328
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
1329
|
-
const lines = [
|
|
1330
|
-
`Firewall ${parsed.table} rules on ${context.routerId}: ${total} total, showing ${paginated.length} (offset ${parsed.offset})`
|
|
1331
|
-
];
|
|
1332
|
-
for (const rule of paginated) {
|
|
1333
|
-
const rec = rule;
|
|
1334
|
-
const chain = rec.chain ?? "?";
|
|
1335
|
-
const action = rec.action ?? "?";
|
|
1336
|
-
const isDisabled = rec.disabled === true || rec.disabled === "true";
|
|
1337
|
-
let line = ` [${chain}]`;
|
|
1338
|
-
if (rec.protocol !== void 0) {
|
|
1339
|
-
line += ` ${rec.protocol}`;
|
|
1340
|
-
}
|
|
1341
|
-
if (rec["src-address"] !== void 0) {
|
|
1342
|
-
line += ` src:${rec["src-address"]}`;
|
|
1343
|
-
}
|
|
1344
|
-
if (rec["dst-address"] !== void 0) {
|
|
1345
|
-
line += ` dst:${rec["dst-address"]}`;
|
|
1346
|
-
}
|
|
1347
|
-
line += ` => ${action}`;
|
|
1348
|
-
if (isDisabled) {
|
|
1349
|
-
line += " [disabled]";
|
|
1350
|
-
}
|
|
1351
|
-
if (rec.comment !== void 0) {
|
|
1352
|
-
line += ` // ${rec.comment}`;
|
|
1353
|
-
}
|
|
1354
|
-
lines.push(line);
|
|
1355
|
-
}
|
|
1302
|
+
const { items: paginated, total, hasMore } = paginate(rules, parsed.offset, parsed.limit);
|
|
1356
1303
|
return {
|
|
1357
|
-
content:
|
|
1304
|
+
content: listSummary(
|
|
1305
|
+
`Firewall ${parsed.table} rules`,
|
|
1306
|
+
context.routerId,
|
|
1307
|
+
paginated.length,
|
|
1308
|
+
total,
|
|
1309
|
+
parsed.offset
|
|
1310
|
+
),
|
|
1358
1311
|
structuredContent: {
|
|
1359
1312
|
routerId: context.routerId,
|
|
1360
1313
|
table: parsed.table,
|
|
@@ -1366,28 +1319,27 @@ var listFirewallRulesTool = {
|
|
|
1366
1319
|
}
|
|
1367
1320
|
};
|
|
1368
1321
|
} catch (err) {
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
dryRun: z7.boolean().default(false).describe("If true, validate and return planned changes without applying")
|
|
1322
|
+
throw toolError(err, context, "list_firewall_rules");
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
};
|
|
1326
|
+
var manageFirewallRuleInputSchema = z8.object({
|
|
1327
|
+
routerId,
|
|
1328
|
+
table: z8.enum(["filter", "nat"]).default("filter").describe("Firewall table to manage: filter or nat"),
|
|
1329
|
+
action: z8.enum(["add", "remove", "disable", "enable"]).describe("Action to perform: add, remove, disable, or enable a firewall rule"),
|
|
1330
|
+
chain: z8.string().describe("Firewall chain (e.g. forward, input, output, srcnat, dstnat)"),
|
|
1331
|
+
ruleAction: z8.string().describe("RouterOS rule action (e.g. accept, drop, reject, masquerade)"),
|
|
1332
|
+
srcAddress: z8.string().optional().describe("Source address or network"),
|
|
1333
|
+
dstAddress: z8.string().optional().describe("Destination address or network"),
|
|
1334
|
+
protocol: z8.enum(["tcp", "udp", "icmp", "gre", "ospf", "all"]).optional().describe("Protocol to match"),
|
|
1335
|
+
srcPort: z8.string().optional().describe("Source port or range"),
|
|
1336
|
+
dstPort: z8.string().optional().describe("Destination port or range"),
|
|
1337
|
+
inInterface: z8.string().optional().describe("Incoming interface"),
|
|
1338
|
+
outInterface: z8.string().optional().describe("Outgoing interface"),
|
|
1339
|
+
comment: z8.string().max(255).optional().describe("Comment to identify the rule (used as idempotency key)"),
|
|
1340
|
+
disabled: z8.boolean().default(false).describe("Whether the rule should be disabled"),
|
|
1341
|
+
placeBefore: z8.string().optional().describe("Place the new rule before this rule ID"),
|
|
1342
|
+
dryRun: z8.boolean().default(false).describe("If true, validate and return planned changes without applying")
|
|
1391
1343
|
}).strict();
|
|
1392
1344
|
var manageFirewallRuleTool = {
|
|
1393
1345
|
name: "manage_firewall_rule",
|
|
@@ -1419,13 +1371,17 @@ var manageFirewallRuleTool = {
|
|
|
1419
1371
|
if (comment !== void 0) {
|
|
1420
1372
|
const existing = await findRuleByComment(context, path, comment);
|
|
1421
1373
|
if (existing) {
|
|
1374
|
+
const wantProtocol = parsed.protocol !== void 0 && parsed.protocol !== "all" ? parsed.protocol : "";
|
|
1422
1375
|
const sameChain = existing.chain === parsed.chain;
|
|
1423
1376
|
const sameRuleAction = existing.action === parsed.ruleAction;
|
|
1377
|
+
const sameSrcAddress = (existing["src-address"] ?? "") === (parsed.srcAddress ?? "");
|
|
1378
|
+
const sameDstAddress = (existing["dst-address"] ?? "") === (parsed.dstAddress ?? "");
|
|
1379
|
+
const sameProtocol = (existing.protocol ?? "") === wantProtocol;
|
|
1424
1380
|
const sameSrcPort = (existing["src-port"] ?? "") === (parsed.srcPort ?? "");
|
|
1425
1381
|
const sameDstPort = (existing["dst-port"] ?? "") === (parsed.dstPort ?? "");
|
|
1426
1382
|
const sameInInterface = (existing["in-interface"] ?? "") === (parsed.inInterface ?? "");
|
|
1427
1383
|
const sameOutInterface = (existing["out-interface"] ?? "") === (parsed.outInterface ?? "");
|
|
1428
|
-
if (sameChain && sameRuleAction && sameSrcPort && sameDstPort && sameInInterface && sameOutInterface) {
|
|
1384
|
+
if (sameChain && sameRuleAction && sameSrcAddress && sameDstAddress && sameProtocol && sameSrcPort && sameDstPort && sameInInterface && sameOutInterface) {
|
|
1429
1385
|
return {
|
|
1430
1386
|
content: `Firewall ${parsed.table} rule with comment "${comment}" already exists. No changes made.`,
|
|
1431
1387
|
structuredContent: { action: "already_exists", rule: existing }
|
|
@@ -1439,6 +1395,9 @@ var manageFirewallRuleTool = {
|
|
|
1439
1395
|
existing: {
|
|
1440
1396
|
chain: existing.chain,
|
|
1441
1397
|
action: existing.action,
|
|
1398
|
+
"src-address": existing["src-address"],
|
|
1399
|
+
"dst-address": existing["dst-address"],
|
|
1400
|
+
protocol: existing.protocol,
|
|
1442
1401
|
"src-port": existing["src-port"],
|
|
1443
1402
|
"dst-port": existing["dst-port"],
|
|
1444
1403
|
"in-interface": existing["in-interface"],
|
|
@@ -1447,6 +1406,9 @@ var manageFirewallRuleTool = {
|
|
|
1447
1406
|
requested: {
|
|
1448
1407
|
chain: parsed.chain,
|
|
1449
1408
|
action: parsed.ruleAction,
|
|
1409
|
+
"src-address": parsed.srcAddress,
|
|
1410
|
+
"dst-address": parsed.dstAddress,
|
|
1411
|
+
protocol: wantProtocol || void 0,
|
|
1450
1412
|
"src-port": parsed.srcPort,
|
|
1451
1413
|
"dst-port": parsed.dstPort,
|
|
1452
1414
|
"in-interface": parsed.inInterface,
|
|
@@ -1598,22 +1560,21 @@ var manageFirewallRuleTool = {
|
|
|
1598
1560
|
}
|
|
1599
1561
|
});
|
|
1600
1562
|
} catch (err) {
|
|
1601
|
-
|
|
1602
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_firewall_rule" });
|
|
1563
|
+
throw toolError(err, context, "manage_firewall_rule");
|
|
1603
1564
|
}
|
|
1604
1565
|
}
|
|
1605
1566
|
};
|
|
1606
1567
|
var firewallTools = [listFirewallRulesTool, manageFirewallRuleTool];
|
|
1607
1568
|
|
|
1608
1569
|
// src/domain/tools/diagnostic-tools.ts
|
|
1609
|
-
import { z as
|
|
1570
|
+
import { z as z9 } from "zod";
|
|
1610
1571
|
var log7 = createLogger("diagnostic-tools");
|
|
1611
|
-
var pingInputSchema =
|
|
1612
|
-
routerId
|
|
1613
|
-
address:
|
|
1614
|
-
count:
|
|
1615
|
-
size:
|
|
1616
|
-
routingTable:
|
|
1572
|
+
var pingInputSchema = z9.object({
|
|
1573
|
+
routerId,
|
|
1574
|
+
address: z9.string().describe("Target IP address or hostname to ping"),
|
|
1575
|
+
count: z9.number().int().min(1).max(20).default(4).describe("Number of ICMP echo requests (1\u201320)"),
|
|
1576
|
+
size: z9.number().int().min(14).max(65535).default(56).describe("Packet size in bytes (14\u201365535)"),
|
|
1577
|
+
routingTable: z9.string().optional().describe("Routing table to use for the ping")
|
|
1617
1578
|
}).strict();
|
|
1618
1579
|
var pingTool = {
|
|
1619
1580
|
name: "ping",
|
|
@@ -1658,15 +1619,15 @@ var pingTool = {
|
|
|
1658
1619
|
}
|
|
1659
1620
|
};
|
|
1660
1621
|
} catch (err) {
|
|
1661
|
-
throw
|
|
1622
|
+
throw toolError(err, context, "ping");
|
|
1662
1623
|
}
|
|
1663
1624
|
}
|
|
1664
1625
|
};
|
|
1665
|
-
var tracerouteInputSchema =
|
|
1666
|
-
routerId
|
|
1667
|
-
address:
|
|
1668
|
-
count:
|
|
1669
|
-
maxHops:
|
|
1626
|
+
var tracerouteInputSchema = z9.object({
|
|
1627
|
+
routerId,
|
|
1628
|
+
address: z9.string().describe("Target IP address or hostname to trace"),
|
|
1629
|
+
count: z9.number().int().min(1).max(5).default(3).describe("Probes per hop (1\u20135)"),
|
|
1630
|
+
maxHops: z9.number().int().min(1).max(30).default(15).describe("Maximum number of hops (1\u201330)")
|
|
1670
1631
|
}).strict();
|
|
1671
1632
|
var tracerouteTool = {
|
|
1672
1633
|
name: "traceroute",
|
|
@@ -1713,16 +1674,16 @@ var tracerouteTool = {
|
|
|
1713
1674
|
}
|
|
1714
1675
|
};
|
|
1715
1676
|
} catch (err) {
|
|
1716
|
-
throw
|
|
1677
|
+
throw toolError(err, context, "traceroute");
|
|
1717
1678
|
}
|
|
1718
1679
|
}
|
|
1719
1680
|
};
|
|
1720
|
-
var torchInputSchema =
|
|
1721
|
-
routerId
|
|
1722
|
-
interface:
|
|
1723
|
-
duration:
|
|
1724
|
-
srcAddress:
|
|
1725
|
-
dstAddress:
|
|
1681
|
+
var torchInputSchema = z9.object({
|
|
1682
|
+
routerId,
|
|
1683
|
+
interface: z9.string().describe("Interface name to monitor (e.g. ether1, bridge1)"),
|
|
1684
|
+
duration: z9.number().int().min(1).max(30).default(5).describe("Capture duration in seconds (1\u201330)"),
|
|
1685
|
+
srcAddress: z9.string().optional().describe("Filter by source IP address"),
|
|
1686
|
+
dstAddress: z9.string().optional().describe("Filter by destination IP address")
|
|
1726
1687
|
}).strict();
|
|
1727
1688
|
function parseTorchOutput(output) {
|
|
1728
1689
|
const flows = [];
|
|
@@ -1778,19 +1739,19 @@ var torchTool = {
|
|
|
1778
1739
|
}
|
|
1779
1740
|
};
|
|
1780
1741
|
} catch (err) {
|
|
1781
|
-
throw
|
|
1742
|
+
throw toolError(err, context, "torch");
|
|
1782
1743
|
}
|
|
1783
1744
|
}
|
|
1784
1745
|
};
|
|
1785
|
-
var getLogInputSchema =
|
|
1786
|
-
routerId
|
|
1787
|
-
limit
|
|
1788
|
-
offset
|
|
1789
|
-
topics:
|
|
1746
|
+
var getLogInputSchema = z9.object({
|
|
1747
|
+
routerId,
|
|
1748
|
+
limit,
|
|
1749
|
+
offset,
|
|
1750
|
+
topics: z9.array(z9.string()).optional().describe(
|
|
1790
1751
|
'Filter entries whose topics field contains any of these strings (e.g. ["firewall", "dhcp"])'
|
|
1791
1752
|
),
|
|
1792
|
-
prefix:
|
|
1793
|
-
sinceMinutes:
|
|
1753
|
+
prefix: z9.string().optional().describe("Substring to match against the log message"),
|
|
1754
|
+
sinceMinutes: z9.number().int().min(1).max(1440).optional().describe("Only return entries from the last N minutes (1\u20131440)")
|
|
1794
1755
|
}).strict();
|
|
1795
1756
|
function parseRouterOsTimestamp(ts, now) {
|
|
1796
1757
|
const timeOnly = /^(\d{2}):(\d{2}):(\d{2})$/.exec(ts);
|
|
@@ -1871,8 +1832,7 @@ var getLogTool = {
|
|
|
1871
1832
|
return parsedTs >= cutoff;
|
|
1872
1833
|
});
|
|
1873
1834
|
}
|
|
1874
|
-
const total = filtered.
|
|
1875
|
-
const paginated = filtered.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
1835
|
+
const { items: paginated, total } = paginate(filtered, parsed.offset, parsed.limit);
|
|
1876
1836
|
const lines = [
|
|
1877
1837
|
`Log on ${context.routerId}: ${total} matching entries, showing ${paginated.length} (offset ${parsed.offset})`
|
|
1878
1838
|
];
|
|
@@ -1891,14 +1851,14 @@ var getLogTool = {
|
|
|
1891
1851
|
}
|
|
1892
1852
|
};
|
|
1893
1853
|
} catch (err) {
|
|
1894
|
-
throw
|
|
1854
|
+
throw toolError(err, context, "get_log");
|
|
1895
1855
|
}
|
|
1896
1856
|
}
|
|
1897
1857
|
};
|
|
1898
1858
|
var diagnosticTools = [pingTool, tracerouteTool, torchTool, getLogTool];
|
|
1899
1859
|
|
|
1900
1860
|
// src/domain/tools/system-ops-tools.ts
|
|
1901
|
-
import { z as
|
|
1861
|
+
import { z as z10 } from "zod";
|
|
1902
1862
|
|
|
1903
1863
|
// src/domain/tools/command-guard.ts
|
|
1904
1864
|
var BUILTIN_DENY_PATTERNS = [
|
|
@@ -1961,8 +1921,8 @@ function checkCommand(command, policy) {
|
|
|
1961
1921
|
|
|
1962
1922
|
// src/domain/tools/system-ops-tools.ts
|
|
1963
1923
|
var log8 = createLogger("system-ops-tools");
|
|
1964
|
-
var getSystemClockInputSchema =
|
|
1965
|
-
routerId
|
|
1924
|
+
var getSystemClockInputSchema = z10.object({
|
|
1925
|
+
routerId
|
|
1966
1926
|
}).strict();
|
|
1967
1927
|
var getSystemClockTool = {
|
|
1968
1928
|
name: "get_system_clock",
|
|
@@ -1992,16 +1952,16 @@ var getSystemClockTool = {
|
|
|
1992
1952
|
}
|
|
1993
1953
|
};
|
|
1994
1954
|
} catch (err) {
|
|
1995
|
-
throw
|
|
1955
|
+
throw toolError(err, context, "get_system_clock");
|
|
1996
1956
|
}
|
|
1997
1957
|
}
|
|
1998
1958
|
};
|
|
1999
|
-
var setSystemClockInputSchema =
|
|
2000
|
-
routerId
|
|
2001
|
-
date:
|
|
2002
|
-
time:
|
|
2003
|
-
timeZoneName:
|
|
2004
|
-
dryRun
|
|
1959
|
+
var setSystemClockInputSchema = z10.object({
|
|
1960
|
+
routerId,
|
|
1961
|
+
date: z10.string().optional().describe("Date in RouterOS format: mon/dd/yyyy (e.g. jan/02/2006)"),
|
|
1962
|
+
time: z10.string().optional().describe("Time in RouterOS format: hh:mm:ss (e.g. 15:04:05)"),
|
|
1963
|
+
timeZoneName: z10.string().optional().describe("IANA timezone name (e.g. Europe/London, UTC)"),
|
|
1964
|
+
dryRun
|
|
2005
1965
|
}).strict();
|
|
2006
1966
|
var setSystemClockTool = {
|
|
2007
1967
|
name: "set_system_clock",
|
|
@@ -2059,15 +2019,14 @@ var setSystemClockTool = {
|
|
|
2059
2019
|
structuredContent: { action: "updated", routerId: context.routerId, diff }
|
|
2060
2020
|
};
|
|
2061
2021
|
} catch (err) {
|
|
2062
|
-
|
|
2063
|
-
throw enrichError(err, { routerId: context.routerId, tool: "set_system_clock" });
|
|
2022
|
+
throw toolError(err, context, "set_system_clock");
|
|
2064
2023
|
}
|
|
2065
2024
|
}
|
|
2066
2025
|
};
|
|
2067
|
-
var rebootInputSchema =
|
|
2068
|
-
routerId
|
|
2069
|
-
delay:
|
|
2070
|
-
dryRun:
|
|
2026
|
+
var rebootInputSchema = z10.object({
|
|
2027
|
+
routerId,
|
|
2028
|
+
delay: z10.number().int().min(0).max(3600).default(0).describe("Seconds before rebooting (0\u20133600)"),
|
|
2029
|
+
dryRun: z10.boolean().default(false).describe("Preview the reboot without executing")
|
|
2071
2030
|
}).strict();
|
|
2072
2031
|
var rebootTool = {
|
|
2073
2032
|
name: "reboot",
|
|
@@ -2099,20 +2058,20 @@ var rebootTool = {
|
|
|
2099
2058
|
structuredContent: { action: "rebooting", delay: parsed.delay, routerId: context.routerId }
|
|
2100
2059
|
};
|
|
2101
2060
|
} catch (err) {
|
|
2102
|
-
throw
|
|
2061
|
+
throw toolError(err, context, "reboot");
|
|
2103
2062
|
}
|
|
2104
2063
|
}
|
|
2105
2064
|
};
|
|
2106
2065
|
var OUTPUT_MAX_CHARS = 4e3;
|
|
2107
|
-
var runCommandInputSchema =
|
|
2108
|
-
routerId
|
|
2109
|
-
command:
|
|
2110
|
-
dryRun:
|
|
2066
|
+
var runCommandInputSchema = z10.object({
|
|
2067
|
+
routerId,
|
|
2068
|
+
command: z10.string().min(1).describe("RouterOS console command to execute"),
|
|
2069
|
+
dryRun: z10.boolean().default(false).describe("Preview the command without executing (validates allow/deny policy only)")
|
|
2111
2070
|
}).strict();
|
|
2112
2071
|
var runCommandTool = {
|
|
2113
2072
|
name: "run_command",
|
|
2114
2073
|
title: "Run Command",
|
|
2115
|
-
description: "Execute an arbitrary RouterOS console command via SSH.
|
|
2074
|
+
description: "Execute an arbitrary RouterOS console command via SSH. Guarded by an allow/deny policy (built-in deny list blocks destructive commands; tighten via cmdAllow in routers.yaml or MIKROMCP_CMD_ALLOW). Prefer dedicated tools (reboot, etc.) where available. Output capped at 4000 characters.",
|
|
2116
2075
|
inputSchema: runCommandInputSchema,
|
|
2117
2076
|
annotations: {
|
|
2118
2077
|
readOnlyHint: false,
|
|
@@ -2158,8 +2117,7 @@ ${output}`;
|
|
|
2158
2117
|
}
|
|
2159
2118
|
};
|
|
2160
2119
|
} catch (err) {
|
|
2161
|
-
|
|
2162
|
-
throw enrichError(err, { routerId: context.routerId, tool: "run_command" });
|
|
2120
|
+
throw toolError(err, context, "run_command");
|
|
2163
2121
|
}
|
|
2164
2122
|
}
|
|
2165
2123
|
};
|
|
@@ -2171,12 +2129,12 @@ var systemOpsTools = [
|
|
|
2171
2129
|
];
|
|
2172
2130
|
|
|
2173
2131
|
// src/domain/tools/bridge-tools.ts
|
|
2174
|
-
import { z as
|
|
2132
|
+
import { z as z11 } from "zod";
|
|
2175
2133
|
var log9 = createLogger("bridge-tools");
|
|
2176
|
-
var listBridgesInputSchema =
|
|
2177
|
-
routerId
|
|
2178
|
-
limit
|
|
2179
|
-
offset
|
|
2134
|
+
var listBridgesInputSchema = z11.object({
|
|
2135
|
+
routerId,
|
|
2136
|
+
limit,
|
|
2137
|
+
offset
|
|
2180
2138
|
}).strict();
|
|
2181
2139
|
var listBridgesTool = {
|
|
2182
2140
|
name: "list_bridges",
|
|
@@ -2208,19 +2166,9 @@ var listBridgesTool = {
|
|
|
2208
2166
|
const rec = b;
|
|
2209
2167
|
return { ...rec, ports: portsByBridge[rec.name] ?? [] };
|
|
2210
2168
|
});
|
|
2211
|
-
const total = enriched.
|
|
2212
|
-
const paginated = enriched.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
2213
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
2214
|
-
const lines = [`Bridges on ${context.routerId}: ${total} total`];
|
|
2215
|
-
for (const b of paginated) {
|
|
2216
|
-
const bRec = b;
|
|
2217
|
-
const portList = b.ports.map((p) => p.interface).join(", ");
|
|
2218
|
-
lines.push(
|
|
2219
|
-
` ${String(bRec.name)} [${b.ports.length} ports${portList ? ": " + portList : ""}]`
|
|
2220
|
-
);
|
|
2221
|
-
}
|
|
2169
|
+
const { items: paginated, total, hasMore } = paginate(enriched, parsed.offset, parsed.limit);
|
|
2222
2170
|
return {
|
|
2223
|
-
content:
|
|
2171
|
+
content: listSummary("Bridges", context.routerId, paginated.length, total, parsed.offset),
|
|
2224
2172
|
structuredContent: {
|
|
2225
2173
|
routerId: context.routerId,
|
|
2226
2174
|
bridges: paginated,
|
|
@@ -2231,17 +2179,17 @@ var listBridgesTool = {
|
|
|
2231
2179
|
}
|
|
2232
2180
|
};
|
|
2233
2181
|
} catch (err) {
|
|
2234
|
-
throw
|
|
2182
|
+
throw toolError(err, context, "list_bridges");
|
|
2235
2183
|
}
|
|
2236
2184
|
}
|
|
2237
2185
|
};
|
|
2238
|
-
var manageBridgeInputSchema =
|
|
2239
|
-
routerId
|
|
2240
|
-
action:
|
|
2241
|
-
name:
|
|
2242
|
-
comment:
|
|
2243
|
-
disabled:
|
|
2244
|
-
dryRun
|
|
2186
|
+
var manageBridgeInputSchema = z11.object({
|
|
2187
|
+
routerId,
|
|
2188
|
+
action: z11.enum(["create", "remove"]).describe("Action to perform"),
|
|
2189
|
+
name: z11.string().regex(/^[a-zA-Z0-9_-]+$/).max(15).describe("Bridge interface name"),
|
|
2190
|
+
comment: z11.string().max(255).optional().describe("Optional comment"),
|
|
2191
|
+
disabled: z11.boolean().default(false).describe("Whether the bridge should be disabled"),
|
|
2192
|
+
dryRun
|
|
2245
2193
|
}).strict();
|
|
2246
2194
|
var manageBridgeTool = {
|
|
2247
2195
|
name: "manage_bridge",
|
|
@@ -2325,17 +2273,16 @@ var manageBridgeTool = {
|
|
|
2325
2273
|
structuredContent: { action: "removed", name: parsed.name, id: rec[".id"] }
|
|
2326
2274
|
};
|
|
2327
2275
|
} catch (err) {
|
|
2328
|
-
|
|
2329
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_bridge" });
|
|
2276
|
+
throw toolError(err, context, "manage_bridge");
|
|
2330
2277
|
}
|
|
2331
2278
|
}
|
|
2332
2279
|
};
|
|
2333
|
-
var manageBridgePortInputSchema =
|
|
2334
|
-
routerId
|
|
2335
|
-
action:
|
|
2336
|
-
bridge:
|
|
2337
|
-
interface:
|
|
2338
|
-
dryRun
|
|
2280
|
+
var manageBridgePortInputSchema = z11.object({
|
|
2281
|
+
routerId,
|
|
2282
|
+
action: z11.enum(["add", "remove"]).describe("Action to perform"),
|
|
2283
|
+
bridge: z11.string().describe("Bridge interface name"),
|
|
2284
|
+
interface: z11.string().describe("Interface to add or remove as a bridge port"),
|
|
2285
|
+
dryRun
|
|
2339
2286
|
}).strict();
|
|
2340
2287
|
var manageBridgePortTool = {
|
|
2341
2288
|
name: "manage_bridge_port",
|
|
@@ -2427,8 +2374,7 @@ var manageBridgePortTool = {
|
|
|
2427
2374
|
}
|
|
2428
2375
|
};
|
|
2429
2376
|
} catch (err) {
|
|
2430
|
-
|
|
2431
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_bridge_port" });
|
|
2377
|
+
throw toolError(err, context, "manage_bridge_port");
|
|
2432
2378
|
}
|
|
2433
2379
|
}
|
|
2434
2380
|
};
|
|
@@ -2439,7 +2385,7 @@ var bridgeTools = [
|
|
|
2439
2385
|
];
|
|
2440
2386
|
|
|
2441
2387
|
// src/domain/tools/wifi-tools.ts
|
|
2442
|
-
import { z as
|
|
2388
|
+
import { z as z12 } from "zod";
|
|
2443
2389
|
var log10 = createLogger("wifi-tools");
|
|
2444
2390
|
function wifiPath(rosVersion) {
|
|
2445
2391
|
return rosVersion.startsWith("7") ? "interface/wifi" : "interface/wireless";
|
|
@@ -2447,10 +2393,10 @@ function wifiPath(rosVersion) {
|
|
|
2447
2393
|
function wifiRegistrationPath(rosVersion) {
|
|
2448
2394
|
return rosVersion.startsWith("7") ? "interface/wifi/registration-table" : "interface/wireless/registration-table";
|
|
2449
2395
|
}
|
|
2450
|
-
var listWifiInputSchema =
|
|
2451
|
-
routerId
|
|
2452
|
-
limit
|
|
2453
|
-
offset
|
|
2396
|
+
var listWifiInputSchema = z12.object({
|
|
2397
|
+
routerId,
|
|
2398
|
+
limit,
|
|
2399
|
+
offset
|
|
2454
2400
|
}).strict();
|
|
2455
2401
|
var listWifiTool = {
|
|
2456
2402
|
name: "list_wifi_interfaces",
|
|
@@ -2472,17 +2418,9 @@ var listWifiTool = {
|
|
|
2472
2418
|
limit: void 0,
|
|
2473
2419
|
offset: void 0
|
|
2474
2420
|
});
|
|
2475
|
-
const total = interfaces.
|
|
2476
|
-
const paginated = interfaces.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
2477
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
2478
|
-
const lines = [`WiFi interfaces on ${context.routerId}: ${total} total`];
|
|
2479
|
-
for (const iface of paginated) {
|
|
2480
|
-
const rec = iface;
|
|
2481
|
-
const status = rec.disabled === "true" ? "DISABLED" : "ENABLED";
|
|
2482
|
-
lines.push(` ${rec.name} [${rec.ssid ?? "no-ssid"}] ${status}`);
|
|
2483
|
-
}
|
|
2421
|
+
const { items: paginated, total, hasMore } = paginate(interfaces, parsed.offset, parsed.limit);
|
|
2484
2422
|
return {
|
|
2485
|
-
content:
|
|
2423
|
+
content: listSummary("WiFi interfaces", context.routerId, paginated.length, total, parsed.offset),
|
|
2486
2424
|
structuredContent: {
|
|
2487
2425
|
routerId: context.routerId,
|
|
2488
2426
|
interfaces: paginated,
|
|
@@ -2493,15 +2431,15 @@ var listWifiTool = {
|
|
|
2493
2431
|
}
|
|
2494
2432
|
};
|
|
2495
2433
|
} catch (err) {
|
|
2496
|
-
throw
|
|
2434
|
+
throw toolError(err, context, "list_wifi_interfaces");
|
|
2497
2435
|
}
|
|
2498
2436
|
}
|
|
2499
2437
|
};
|
|
2500
|
-
var listWifiClientsInputSchema =
|
|
2501
|
-
routerId
|
|
2502
|
-
interface:
|
|
2503
|
-
limit
|
|
2504
|
-
offset
|
|
2438
|
+
var listWifiClientsInputSchema = z12.object({
|
|
2439
|
+
routerId,
|
|
2440
|
+
interface: z12.string().optional().describe("Filter by WiFi interface name"),
|
|
2441
|
+
limit,
|
|
2442
|
+
offset
|
|
2505
2443
|
}).strict();
|
|
2506
2444
|
var listWifiClientsTool = {
|
|
2507
2445
|
name: "list_wifi_clients",
|
|
@@ -2521,18 +2459,9 @@ var listWifiClientsTool = {
|
|
|
2521
2459
|
const path = wifiRegistrationPath(context.routerConfig.rosVersion);
|
|
2522
2460
|
const filter = parsed.interface ? { interface: parsed.interface } : void 0;
|
|
2523
2461
|
const allClients = await context.routerClient.get(path, { filter });
|
|
2524
|
-
const total = allClients.
|
|
2525
|
-
const clients = allClients.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
2526
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
2527
|
-
const lines = [`WiFi clients on ${context.routerId}: ${total} total`];
|
|
2528
|
-
for (const c of clients) {
|
|
2529
|
-
const rec = c;
|
|
2530
|
-
lines.push(
|
|
2531
|
-
` ${rec["mac-address"] ?? rec[".id"]} on ${rec.interface ?? "unknown"} signal=${rec["signal-strength"] ?? "?"}`
|
|
2532
|
-
);
|
|
2533
|
-
}
|
|
2462
|
+
const { items: clients, total, hasMore } = paginate(allClients, parsed.offset, parsed.limit);
|
|
2534
2463
|
return {
|
|
2535
|
-
content:
|
|
2464
|
+
content: listSummary("WiFi clients", context.routerId, clients.length, total, parsed.offset),
|
|
2536
2465
|
structuredContent: {
|
|
2537
2466
|
routerId: context.routerId,
|
|
2538
2467
|
clients,
|
|
@@ -2543,16 +2472,16 @@ var listWifiClientsTool = {
|
|
|
2543
2472
|
}
|
|
2544
2473
|
};
|
|
2545
2474
|
} catch (err) {
|
|
2546
|
-
throw
|
|
2475
|
+
throw toolError(err, context, "list_wifi_clients");
|
|
2547
2476
|
}
|
|
2548
2477
|
}
|
|
2549
2478
|
};
|
|
2550
|
-
var manageWifiInputSchema =
|
|
2551
|
-
routerId
|
|
2552
|
-
name:
|
|
2553
|
-
disabled:
|
|
2554
|
-
ssid:
|
|
2555
|
-
dryRun
|
|
2479
|
+
var manageWifiInputSchema = z12.object({
|
|
2480
|
+
routerId,
|
|
2481
|
+
name: z12.string().describe("WiFi interface name (e.g. wifi1, wlan1)"),
|
|
2482
|
+
disabled: z12.boolean().optional().describe("Set to true to disable, false to enable"),
|
|
2483
|
+
ssid: z12.string().max(32).optional().describe("New SSID to set"),
|
|
2484
|
+
dryRun
|
|
2556
2485
|
}).strict();
|
|
2557
2486
|
var manageWifiTool = {
|
|
2558
2487
|
name: "manage_wifi_interface",
|
|
@@ -2629,20 +2558,19 @@ var manageWifiTool = {
|
|
|
2629
2558
|
structuredContent: { action: "updated", name: parsed.name, changes: diff }
|
|
2630
2559
|
};
|
|
2631
2560
|
} catch (err) {
|
|
2632
|
-
|
|
2633
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_wifi_interface" });
|
|
2561
|
+
throw toolError(err, context, "manage_wifi_interface");
|
|
2634
2562
|
}
|
|
2635
2563
|
}
|
|
2636
2564
|
};
|
|
2637
2565
|
var wifiTools = [listWifiTool, listWifiClientsTool, manageWifiTool];
|
|
2638
2566
|
|
|
2639
2567
|
// src/domain/tools/wireguard-tools.ts
|
|
2640
|
-
import { z as
|
|
2568
|
+
import { z as z13 } from "zod";
|
|
2641
2569
|
var log11 = createLogger("wireguard-tools");
|
|
2642
|
-
var listWgInputSchema =
|
|
2643
|
-
routerId
|
|
2644
|
-
limit
|
|
2645
|
-
offset
|
|
2570
|
+
var listWgInputSchema = z13.object({
|
|
2571
|
+
routerId,
|
|
2572
|
+
limit,
|
|
2573
|
+
offset
|
|
2646
2574
|
}).strict();
|
|
2647
2575
|
var listWgTool = {
|
|
2648
2576
|
name: "list_wireguard_interfaces",
|
|
@@ -2663,17 +2591,15 @@ var listWgTool = {
|
|
|
2663
2591
|
limit: void 0,
|
|
2664
2592
|
offset: void 0
|
|
2665
2593
|
});
|
|
2666
|
-
const total = interfaces.
|
|
2667
|
-
const paginated = interfaces.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
2668
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
2669
|
-
const lines = [`WireGuard interfaces on ${context.routerId}: ${total} total`];
|
|
2670
|
-
for (const iface of paginated) {
|
|
2671
|
-
const rec = iface;
|
|
2672
|
-
const running = rec.running === "true" ? "UP" : "DOWN";
|
|
2673
|
-
lines.push(` ${rec.name} [port=${rec["listen-port"] ?? "?"}] ${running}`);
|
|
2674
|
-
}
|
|
2594
|
+
const { items: paginated, total, hasMore } = paginate(interfaces, parsed.offset, parsed.limit);
|
|
2675
2595
|
return {
|
|
2676
|
-
content:
|
|
2596
|
+
content: listSummary(
|
|
2597
|
+
"WireGuard interfaces",
|
|
2598
|
+
context.routerId,
|
|
2599
|
+
paginated.length,
|
|
2600
|
+
total,
|
|
2601
|
+
parsed.offset
|
|
2602
|
+
),
|
|
2677
2603
|
structuredContent: {
|
|
2678
2604
|
routerId: context.routerId,
|
|
2679
2605
|
interfaces: paginated,
|
|
@@ -2684,15 +2610,15 @@ var listWgTool = {
|
|
|
2684
2610
|
}
|
|
2685
2611
|
};
|
|
2686
2612
|
} catch (err) {
|
|
2687
|
-
throw
|
|
2613
|
+
throw toolError(err, context, "list_wireguard_interfaces");
|
|
2688
2614
|
}
|
|
2689
2615
|
}
|
|
2690
2616
|
};
|
|
2691
|
-
var listPeersInputSchema =
|
|
2692
|
-
routerId
|
|
2693
|
-
interface:
|
|
2694
|
-
limit
|
|
2695
|
-
offset
|
|
2617
|
+
var listPeersInputSchema = z13.object({
|
|
2618
|
+
routerId,
|
|
2619
|
+
interface: z13.string().optional().describe("Filter by WireGuard interface name"),
|
|
2620
|
+
limit,
|
|
2621
|
+
offset
|
|
2696
2622
|
}).strict();
|
|
2697
2623
|
var listPeersTool = {
|
|
2698
2624
|
name: "list_wireguard_peers",
|
|
@@ -2716,19 +2642,9 @@ var listPeersTool = {
|
|
|
2716
2642
|
const allPeers = await context.routerClient.get("interface/wireguard/peers", {
|
|
2717
2643
|
filter
|
|
2718
2644
|
});
|
|
2719
|
-
const total = allPeers.
|
|
2720
|
-
const peers = allPeers.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
2721
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
2722
|
-
const lines = [`WireGuard peers on ${context.routerId}: ${total} total`];
|
|
2723
|
-
for (const peer of peers) {
|
|
2724
|
-
const rec = peer;
|
|
2725
|
-
const key2 = rec["public-key"] ? rec["public-key"].slice(0, 8) + "\u2026" : "unknown";
|
|
2726
|
-
lines.push(
|
|
2727
|
-
` [${rec.interface ?? "?"}] ${key2} last-handshake=${rec["last-handshake"] ?? "never"}`
|
|
2728
|
-
);
|
|
2729
|
-
}
|
|
2645
|
+
const { items: peers, total, hasMore } = paginate(allPeers, parsed.offset, parsed.limit);
|
|
2730
2646
|
return {
|
|
2731
|
-
content:
|
|
2647
|
+
content: listSummary("WireGuard peers", context.routerId, peers.length, total, parsed.offset),
|
|
2732
2648
|
structuredContent: {
|
|
2733
2649
|
routerId: context.routerId,
|
|
2734
2650
|
peers,
|
|
@@ -2739,19 +2655,19 @@ var listPeersTool = {
|
|
|
2739
2655
|
}
|
|
2740
2656
|
};
|
|
2741
2657
|
} catch (err) {
|
|
2742
|
-
throw
|
|
2658
|
+
throw toolError(err, context, "list_wireguard_peers");
|
|
2743
2659
|
}
|
|
2744
2660
|
}
|
|
2745
2661
|
};
|
|
2746
|
-
var managePeerInputSchema =
|
|
2747
|
-
routerId
|
|
2748
|
-
action:
|
|
2749
|
-
interface:
|
|
2750
|
-
publicKey:
|
|
2751
|
-
allowedAddress:
|
|
2752
|
-
endpoint:
|
|
2753
|
-
comment:
|
|
2754
|
-
dryRun
|
|
2662
|
+
var managePeerInputSchema = z13.object({
|
|
2663
|
+
routerId,
|
|
2664
|
+
action: z13.enum(["add", "remove"]).describe("Action to perform"),
|
|
2665
|
+
interface: z13.string().describe("WireGuard interface name (e.g. wg0)"),
|
|
2666
|
+
publicKey: z13.string().min(1).describe("Peer public key in base64 format (44 characters)"),
|
|
2667
|
+
allowedAddress: z13.string().optional().describe("Allowed IP address/CIDR for this peer (e.g. 10.0.0.2/32)"),
|
|
2668
|
+
endpoint: z13.string().optional().describe("Peer endpoint as IP:port (e.g. 1.2.3.4:51820)"),
|
|
2669
|
+
comment: z13.string().max(255).optional().describe("Optional comment"),
|
|
2670
|
+
dryRun
|
|
2755
2671
|
}).strict();
|
|
2756
2672
|
var managePeerTool = {
|
|
2757
2673
|
name: "manage_wireguard_peer",
|
|
@@ -2837,19 +2753,18 @@ var managePeerTool = {
|
|
|
2837
2753
|
structuredContent: { action: "removed", interface: parsed.interface, id: rec[".id"] }
|
|
2838
2754
|
};
|
|
2839
2755
|
} catch (err) {
|
|
2840
|
-
|
|
2841
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_wireguard_peer" });
|
|
2756
|
+
throw toolError(err, context, "manage_wireguard_peer");
|
|
2842
2757
|
}
|
|
2843
2758
|
}
|
|
2844
2759
|
};
|
|
2845
|
-
var manageWgIfaceInputSchema =
|
|
2846
|
-
routerId
|
|
2847
|
-
action:
|
|
2848
|
-
name:
|
|
2849
|
-
listenPort:
|
|
2850
|
-
mtu:
|
|
2851
|
-
comment:
|
|
2852
|
-
dryRun
|
|
2760
|
+
var manageWgIfaceInputSchema = z13.object({
|
|
2761
|
+
routerId,
|
|
2762
|
+
action: z13.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
2763
|
+
name: z13.string().describe("Interface name \u2014 idempotency key (e.g. wg0)"),
|
|
2764
|
+
listenPort: z13.number().int().min(1).max(65535).optional().describe("UDP listen port (RouterOS picks one if omitted)"),
|
|
2765
|
+
mtu: z13.number().int().min(1280).max(65535).default(1420).describe("MTU (default 1420)"),
|
|
2766
|
+
comment: z13.string().optional().describe("Optional comment"),
|
|
2767
|
+
dryRun
|
|
2853
2768
|
}).strict();
|
|
2854
2769
|
var manageWgIfaceTool = {
|
|
2855
2770
|
name: "manage_wireguard_interface",
|
|
@@ -2973,8 +2888,7 @@ var manageWgIfaceTool = {
|
|
|
2973
2888
|
structuredContent: { action: resultAction, name: parsed.name, id: existing[".id"] }
|
|
2974
2889
|
};
|
|
2975
2890
|
} catch (err) {
|
|
2976
|
-
|
|
2977
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_wireguard_interface" });
|
|
2891
|
+
throw toolError(err, context, "manage_wireguard_interface");
|
|
2978
2892
|
}
|
|
2979
2893
|
}
|
|
2980
2894
|
};
|
|
@@ -2986,14 +2900,14 @@ var wireguardTools = [
|
|
|
2986
2900
|
];
|
|
2987
2901
|
|
|
2988
2902
|
// src/domain/tools/dns-tools.ts
|
|
2989
|
-
import { z as
|
|
2903
|
+
import { z as z14 } from "zod";
|
|
2990
2904
|
var log12 = createLogger("dns-tools");
|
|
2991
|
-
var listDnsInputSchema =
|
|
2992
|
-
routerId
|
|
2993
|
-
name:
|
|
2994
|
-
type:
|
|
2995
|
-
limit
|
|
2996
|
-
offset
|
|
2905
|
+
var listDnsInputSchema = z14.object({
|
|
2906
|
+
routerId,
|
|
2907
|
+
name: z14.string().optional().describe("Filter by hostname (partial match)"),
|
|
2908
|
+
type: z14.enum(["A", "CNAME", "TXT", "all"]).default("all").describe("Filter by record type"),
|
|
2909
|
+
limit,
|
|
2910
|
+
offset
|
|
2997
2911
|
}).strict();
|
|
2998
2912
|
var listDnsTool = {
|
|
2999
2913
|
name: "list_dns_entries",
|
|
@@ -3023,17 +2937,9 @@ var listDnsTool = {
|
|
|
3023
2937
|
(e) => (e.name ?? "").toLowerCase().includes(needle)
|
|
3024
2938
|
);
|
|
3025
2939
|
}
|
|
3026
|
-
const total = entries.
|
|
3027
|
-
const paginated = entries.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
3028
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
3029
|
-
const lines = [`DNS entries on ${context.routerId}: ${total} total`];
|
|
3030
|
-
for (const entry of paginated) {
|
|
3031
|
-
const rec = entry;
|
|
3032
|
-
const value = rec.address ?? rec.cname ?? rec.text ?? "?";
|
|
3033
|
-
lines.push(` ${rec.name} ${rec.type ?? "A"} \u2192 ${value}`);
|
|
3034
|
-
}
|
|
2940
|
+
const { items: paginated, total, hasMore } = paginate(entries, parsed.offset, parsed.limit);
|
|
3035
2941
|
return {
|
|
3036
|
-
content:
|
|
2942
|
+
content: listSummary("DNS entries", context.routerId, paginated.length, total, parsed.offset),
|
|
3037
2943
|
structuredContent: {
|
|
3038
2944
|
routerId: context.routerId,
|
|
3039
2945
|
entries: paginated,
|
|
@@ -3044,22 +2950,22 @@ var listDnsTool = {
|
|
|
3044
2950
|
}
|
|
3045
2951
|
};
|
|
3046
2952
|
} catch (err) {
|
|
3047
|
-
throw
|
|
3048
|
-
}
|
|
3049
|
-
}
|
|
3050
|
-
};
|
|
3051
|
-
var manageDnsInputSchema =
|
|
3052
|
-
routerId
|
|
3053
|
-
action:
|
|
3054
|
-
name:
|
|
3055
|
-
type:
|
|
3056
|
-
address:
|
|
3057
|
-
cname:
|
|
3058
|
-
text:
|
|
3059
|
-
ttl:
|
|
3060
|
-
comment:
|
|
3061
|
-
disabled:
|
|
3062
|
-
dryRun
|
|
2953
|
+
throw toolError(err, context, "list_dns_entries");
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
};
|
|
2957
|
+
var manageDnsInputSchema = z14.object({
|
|
2958
|
+
routerId,
|
|
2959
|
+
action: z14.enum(["add", "remove"]).describe("Action to perform"),
|
|
2960
|
+
name: z14.string().min(1).describe("Hostname for the DNS record (e.g. server.example.com)"),
|
|
2961
|
+
type: z14.enum(["A", "CNAME", "TXT"]).default("A").describe("DNS record type"),
|
|
2962
|
+
address: z14.string().optional().describe("IP address (required for A records)"),
|
|
2963
|
+
cname: z14.string().optional().describe("Target hostname (required for CNAME records)"),
|
|
2964
|
+
text: z14.string().optional().describe("Text value (required for TXT records)"),
|
|
2965
|
+
ttl: z14.string().optional().describe("TTL value (e.g. 1d, 00:05:00)"),
|
|
2966
|
+
comment: z14.string().max(255).optional().describe("Optional comment"),
|
|
2967
|
+
disabled: z14.boolean().default(false).describe("Whether the entry should be disabled"),
|
|
2968
|
+
dryRun
|
|
3063
2969
|
}).strict();
|
|
3064
2970
|
var manageDnsTool = {
|
|
3065
2971
|
name: "manage_dns_entry",
|
|
@@ -3178,13 +3084,12 @@ var manageDnsTool = {
|
|
|
3178
3084
|
}
|
|
3179
3085
|
};
|
|
3180
3086
|
} catch (err) {
|
|
3181
|
-
|
|
3182
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_dns_entry" });
|
|
3087
|
+
throw toolError(err, context, "manage_dns_entry");
|
|
3183
3088
|
}
|
|
3184
3089
|
}
|
|
3185
3090
|
};
|
|
3186
|
-
var getDnsSettingsInputSchema =
|
|
3187
|
-
routerId
|
|
3091
|
+
var getDnsSettingsInputSchema = z14.object({
|
|
3092
|
+
routerId
|
|
3188
3093
|
}).strict();
|
|
3189
3094
|
var getDnsSettingsTool = {
|
|
3190
3095
|
name: "get_dns_settings",
|
|
@@ -3218,18 +3123,18 @@ var getDnsSettingsTool = {
|
|
|
3218
3123
|
structuredContent: { routerId: context.routerId, settings }
|
|
3219
3124
|
};
|
|
3220
3125
|
} catch (err) {
|
|
3221
|
-
throw
|
|
3126
|
+
throw toolError(err, context, "get_dns_settings");
|
|
3222
3127
|
}
|
|
3223
3128
|
}
|
|
3224
3129
|
};
|
|
3225
|
-
var manageDnsSettingsInputSchema =
|
|
3226
|
-
routerId
|
|
3227
|
-
servers:
|
|
3228
|
-
allowRemoteRequests:
|
|
3229
|
-
maxUdpPacketSize:
|
|
3230
|
-
cacheMaxTtl:
|
|
3231
|
-
cacheSize:
|
|
3232
|
-
dryRun
|
|
3130
|
+
var manageDnsSettingsInputSchema = z14.object({
|
|
3131
|
+
routerId,
|
|
3132
|
+
servers: z14.string().optional().describe("Comma-separated upstream DNS server IPs (e.g. '8.8.8.8,1.1.1.1')"),
|
|
3133
|
+
allowRemoteRequests: z14.boolean().optional().describe("Allow router to answer DNS queries from the network"),
|
|
3134
|
+
maxUdpPacketSize: z14.number().int().min(512).max(65535).optional().describe("Maximum UDP packet size in bytes"),
|
|
3135
|
+
cacheMaxTtl: z14.string().optional().describe("Maximum cache TTL (e.g. '1d', '00:30:00')"),
|
|
3136
|
+
cacheSize: z14.number().int().min(1).optional().describe("DNS cache size in KiB"),
|
|
3137
|
+
dryRun
|
|
3233
3138
|
}).strict();
|
|
3234
3139
|
var manageDnsSettingsTool = {
|
|
3235
3140
|
name: "manage_dns_settings",
|
|
@@ -3300,14 +3205,14 @@ var manageDnsSettingsTool = {
|
|
|
3300
3205
|
structuredContent: { action: "updated", routerId: context.routerId, diff }
|
|
3301
3206
|
};
|
|
3302
3207
|
} catch (err) {
|
|
3303
|
-
throw
|
|
3208
|
+
throw toolError(err, context, "manage_dns_settings");
|
|
3304
3209
|
}
|
|
3305
3210
|
}
|
|
3306
3211
|
};
|
|
3307
3212
|
var dnsTools = [listDnsTool, manageDnsTool, getDnsSettingsTool, manageDnsSettingsTool];
|
|
3308
3213
|
|
|
3309
3214
|
// src/domain/tools/mangle-tools.ts
|
|
3310
|
-
import { z as
|
|
3215
|
+
import { z as z15 } from "zod";
|
|
3311
3216
|
var log13 = createLogger("mangle-tools");
|
|
3312
3217
|
var MANGLE_PATH = "ip/firewall/mangle";
|
|
3313
3218
|
async function findMangleRuleByComment(context, comment) {
|
|
@@ -3316,11 +3221,11 @@ async function findMangleRuleByComment(context, comment) {
|
|
|
3316
3221
|
});
|
|
3317
3222
|
return results2.length > 0 ? results2[0] : void 0;
|
|
3318
3223
|
}
|
|
3319
|
-
var listMangleRulesInputSchema =
|
|
3320
|
-
routerId
|
|
3321
|
-
chain:
|
|
3322
|
-
action:
|
|
3323
|
-
disabled:
|
|
3224
|
+
var listMangleRulesInputSchema = z15.object({
|
|
3225
|
+
routerId,
|
|
3226
|
+
chain: z15.string().optional().describe("Filter by chain name (e.g. prerouting, forward, postrouting)"),
|
|
3227
|
+
action: z15.string().optional().describe("Filter by mangle action (e.g. mark-routing, mark-connection)"),
|
|
3228
|
+
disabled: z15.boolean().optional().describe("Filter by disabled state")
|
|
3324
3229
|
}).strict();
|
|
3325
3230
|
var listMangleRulesTool = {
|
|
3326
3231
|
name: "list_mangle_rules",
|
|
@@ -3359,30 +3264,29 @@ var listMangleRulesTool = {
|
|
|
3359
3264
|
structuredContent: { routerId: context.routerId, rules, total: rules.length }
|
|
3360
3265
|
};
|
|
3361
3266
|
} catch (err) {
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
passthrough: z14.boolean().optional().describe("Whether to continue matching subsequent rules")
|
|
3267
|
+
throw toolError(err, context, "list_mangle_rules");
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
};
|
|
3271
|
+
var manageMangleRuleInputSchema = z15.object({
|
|
3272
|
+
routerId,
|
|
3273
|
+
action: z15.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
3274
|
+
comment: z15.string().describe("Idempotency key \u2014 uniquely identifies this mangle rule"),
|
|
3275
|
+
chain: z15.string().optional().describe("Mangle chain (required on add): prerouting, input, forward, output, postrouting"),
|
|
3276
|
+
dryRun,
|
|
3277
|
+
srcAddress: z15.string().optional().describe("Source IP/CIDR to match"),
|
|
3278
|
+
dstAddress: z15.string().optional().describe("Destination IP/CIDR to match"),
|
|
3279
|
+
srcAddressList: z15.string().optional().describe("Source address list name to match"),
|
|
3280
|
+
dstAddressList: z15.string().optional().describe("Destination address list name to match"),
|
|
3281
|
+
protocol: z15.string().optional().describe("Protocol to match (e.g. tcp, udp)"),
|
|
3282
|
+
srcPort: z15.string().optional().describe("Source port or range"),
|
|
3283
|
+
dstPort: z15.string().optional().describe("Destination port or range"),
|
|
3284
|
+
inInterface: z15.string().optional().describe("Incoming interface to match"),
|
|
3285
|
+
outInterface: z15.string().optional().describe("Outgoing interface to match"),
|
|
3286
|
+
newRoutingMark: z15.string().optional().describe("Routing mark to set"),
|
|
3287
|
+
newConnectionMark: z15.string().optional().describe("Connection mark to set"),
|
|
3288
|
+
newDscpValue: z15.number().int().min(0).max(63).optional().describe("DSCP value to set (0\u201363)"),
|
|
3289
|
+
passthrough: z15.boolean().optional().describe("Whether to continue matching subsequent rules")
|
|
3386
3290
|
}).strict();
|
|
3387
3291
|
var manageMangleRuleTool = {
|
|
3388
3292
|
name: "manage_mangle_rule",
|
|
@@ -3567,21 +3471,20 @@ var manageMangleRuleTool = {
|
|
|
3567
3471
|
}
|
|
3568
3472
|
});
|
|
3569
3473
|
} catch (err) {
|
|
3570
|
-
|
|
3571
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_mangle_rule" });
|
|
3474
|
+
throw toolError(err, context, "manage_mangle_rule");
|
|
3572
3475
|
}
|
|
3573
3476
|
}
|
|
3574
3477
|
};
|
|
3575
3478
|
var mangleTools = [listMangleRulesTool, manageMangleRuleTool];
|
|
3576
3479
|
|
|
3577
3480
|
// src/domain/tools/address-list-tools.ts
|
|
3578
|
-
import { z as
|
|
3481
|
+
import { z as z16 } from "zod";
|
|
3579
3482
|
var log14 = createLogger("address-list-tools");
|
|
3580
3483
|
var ADDRESS_LIST_PATH = "ip/firewall/address-list";
|
|
3581
|
-
var listAddressListInputSchema =
|
|
3582
|
-
routerId
|
|
3583
|
-
list:
|
|
3584
|
-
address:
|
|
3484
|
+
var listAddressListInputSchema = z16.object({
|
|
3485
|
+
routerId,
|
|
3486
|
+
list: z16.string().optional().describe("Filter by address list name"),
|
|
3487
|
+
address: z16.string().optional().describe("Filter by address (IP or CIDR)")
|
|
3585
3488
|
}).strict();
|
|
3586
3489
|
var listAddressListTool = {
|
|
3587
3490
|
name: "list_address_list_entries",
|
|
@@ -3611,19 +3514,18 @@ var listAddressListTool = {
|
|
|
3611
3514
|
structuredContent: { routerId: context.routerId, entries, total: entries.length }
|
|
3612
3515
|
};
|
|
3613
3516
|
} catch (err) {
|
|
3614
|
-
|
|
3615
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_address_list_entries" });
|
|
3517
|
+
throw toolError(err, context, "list_address_list_entries");
|
|
3616
3518
|
}
|
|
3617
3519
|
}
|
|
3618
3520
|
};
|
|
3619
|
-
var manageAddressListInputSchema =
|
|
3620
|
-
routerId
|
|
3621
|
-
action:
|
|
3622
|
-
list:
|
|
3623
|
-
address:
|
|
3624
|
-
comment:
|
|
3625
|
-
timeout:
|
|
3626
|
-
dryRun
|
|
3521
|
+
var manageAddressListInputSchema = z16.object({
|
|
3522
|
+
routerId,
|
|
3523
|
+
action: z16.enum(["add", "remove"]).describe("Action to perform"),
|
|
3524
|
+
list: z16.string().describe("Address list name"),
|
|
3525
|
+
address: z16.string().describe("IP address or CIDR to add/remove"),
|
|
3526
|
+
comment: z16.string().optional().describe("Optional comment for the entry"),
|
|
3527
|
+
timeout: z16.string().optional().describe("Expiry timeout (e.g. 1d, 2h30m) \u2014 omit for permanent"),
|
|
3528
|
+
dryRun
|
|
3627
3529
|
}).strict();
|
|
3628
3530
|
var manageAddressListTool = {
|
|
3629
3531
|
name: "manage_address_list_entry",
|
|
@@ -3716,22 +3618,21 @@ var manageAddressListTool = {
|
|
|
3716
3618
|
recoverability: { retryable: false, suggestedAction: "Use one of: add, remove." }
|
|
3717
3619
|
});
|
|
3718
3620
|
} catch (err) {
|
|
3719
|
-
|
|
3720
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_address_list_entry" });
|
|
3621
|
+
throw toolError(err, context, "manage_address_list_entry");
|
|
3721
3622
|
}
|
|
3722
3623
|
}
|
|
3723
3624
|
};
|
|
3724
3625
|
var addressListTools = [listAddressListTool, manageAddressListTool];
|
|
3725
3626
|
|
|
3726
3627
|
// src/domain/tools/policy-routing-tools.ts
|
|
3727
|
-
import { z as
|
|
3628
|
+
import { z as z17 } from "zod";
|
|
3728
3629
|
var log15 = createLogger("policy-routing-tools");
|
|
3729
3630
|
var ROUTING_RULE_PATH = "routing/rule";
|
|
3730
3631
|
var ROUTING_TABLE_PATH = "routing/table";
|
|
3731
|
-
var listRoutingRulesInputSchema =
|
|
3732
|
-
routerId
|
|
3733
|
-
table:
|
|
3734
|
-
disabled:
|
|
3632
|
+
var listRoutingRulesInputSchema = z17.object({
|
|
3633
|
+
routerId,
|
|
3634
|
+
table: z17.string().optional().describe("Filter by routing table name"),
|
|
3635
|
+
disabled: z17.boolean().optional().describe("Filter by disabled state")
|
|
3735
3636
|
}).strict();
|
|
3736
3637
|
var listRoutingRulesTool = {
|
|
3737
3638
|
name: "list_routing_rules",
|
|
@@ -3767,22 +3668,21 @@ var listRoutingRulesTool = {
|
|
|
3767
3668
|
structuredContent: { routerId: context.routerId, rules, total: rules.length }
|
|
3768
3669
|
};
|
|
3769
3670
|
} catch (err) {
|
|
3770
|
-
|
|
3771
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_routing_rules" });
|
|
3671
|
+
throw toolError(err, context, "list_routing_rules");
|
|
3772
3672
|
}
|
|
3773
3673
|
}
|
|
3774
3674
|
};
|
|
3775
|
-
var manageRoutingRuleInputSchema =
|
|
3776
|
-
routerId
|
|
3777
|
-
action:
|
|
3778
|
-
table:
|
|
3675
|
+
var manageRoutingRuleInputSchema = z17.object({
|
|
3676
|
+
routerId,
|
|
3677
|
+
action: z17.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
3678
|
+
table: z17.string().describe(
|
|
3779
3679
|
"Routing table name \u2014 part of the composite idempotency key; required for all actions"
|
|
3780
3680
|
),
|
|
3781
|
-
srcAddress:
|
|
3782
|
-
dstAddress:
|
|
3783
|
-
interface:
|
|
3784
|
-
priority:
|
|
3785
|
-
dryRun
|
|
3681
|
+
srcAddress: z17.string().optional().describe("Source CIDR to match"),
|
|
3682
|
+
dstAddress: z17.string().optional().describe("Destination CIDR to match"),
|
|
3683
|
+
interface: z17.string().optional().describe("Incoming interface to match"),
|
|
3684
|
+
priority: z17.number().int().min(0).max(4294967295).optional().describe("Rule priority (0\u20134294967295)"),
|
|
3685
|
+
dryRun
|
|
3786
3686
|
}).strict();
|
|
3787
3687
|
function findRoutingRule(rules, srcAddress, dstAddress, iface, table) {
|
|
3788
3688
|
return rules.find((r) => {
|
|
@@ -3938,13 +3838,12 @@ var manageRoutingRuleTool = {
|
|
|
3938
3838
|
}
|
|
3939
3839
|
});
|
|
3940
3840
|
} catch (err) {
|
|
3941
|
-
|
|
3942
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_routing_rule" });
|
|
3841
|
+
throw toolError(err, context, "manage_routing_rule");
|
|
3943
3842
|
}
|
|
3944
3843
|
}
|
|
3945
3844
|
};
|
|
3946
|
-
var listRoutingTablesInputSchema =
|
|
3947
|
-
routerId
|
|
3845
|
+
var listRoutingTablesInputSchema = z17.object({
|
|
3846
|
+
routerId
|
|
3948
3847
|
}).strict();
|
|
3949
3848
|
var listRoutingTablesTool = {
|
|
3950
3849
|
name: "list_routing_tables",
|
|
@@ -3970,17 +3869,16 @@ var listRoutingTablesTool = {
|
|
|
3970
3869
|
structuredContent: { routerId: context.routerId, tables, total: tables.length }
|
|
3971
3870
|
};
|
|
3972
3871
|
} catch (err) {
|
|
3973
|
-
|
|
3974
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_routing_tables" });
|
|
3872
|
+
throw toolError(err, context, "list_routing_tables");
|
|
3975
3873
|
}
|
|
3976
3874
|
}
|
|
3977
3875
|
};
|
|
3978
|
-
var manageRoutingTableInputSchema =
|
|
3979
|
-
routerId
|
|
3980
|
-
action:
|
|
3981
|
-
name:
|
|
3982
|
-
fib:
|
|
3983
|
-
dryRun
|
|
3876
|
+
var manageRoutingTableInputSchema = z17.object({
|
|
3877
|
+
routerId,
|
|
3878
|
+
action: z17.enum(["add", "remove"]).describe("Action to perform"),
|
|
3879
|
+
name: z17.string().describe("Routing table name (idempotency key)"),
|
|
3880
|
+
fib: z17.boolean().default(false).describe("Whether to sync this table with the FIB"),
|
|
3881
|
+
dryRun
|
|
3984
3882
|
}).strict();
|
|
3985
3883
|
var manageRoutingTableTool = {
|
|
3986
3884
|
name: "manage_routing_table",
|
|
@@ -4062,8 +3960,7 @@ var manageRoutingTableTool = {
|
|
|
4062
3960
|
recoverability: { retryable: false, suggestedAction: "Use one of: add, remove." }
|
|
4063
3961
|
});
|
|
4064
3962
|
} catch (err) {
|
|
4065
|
-
|
|
4066
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_routing_table" });
|
|
3963
|
+
throw toolError(err, context, "manage_routing_table");
|
|
4067
3964
|
}
|
|
4068
3965
|
}
|
|
4069
3966
|
};
|
|
@@ -4075,11 +3972,11 @@ var policyRoutingTools = [
|
|
|
4075
3972
|
];
|
|
4076
3973
|
|
|
4077
3974
|
// src/domain/tools/routing-protocol-tools.ts
|
|
4078
|
-
import { z as
|
|
3975
|
+
import { z as z18 } from "zod";
|
|
4079
3976
|
var log16 = createLogger("routing-protocol-tools");
|
|
4080
|
-
var listBgpPeersInputSchema =
|
|
4081
|
-
routerId
|
|
4082
|
-
state:
|
|
3977
|
+
var listBgpPeersInputSchema = z18.object({
|
|
3978
|
+
routerId,
|
|
3979
|
+
state: z18.string().optional().describe("Filter by session state (e.g. established, active, idle)")
|
|
4083
3980
|
}).strict();
|
|
4084
3981
|
var listBgpPeersTool = {
|
|
4085
3982
|
name: "list_bgp_peers",
|
|
@@ -4108,14 +4005,13 @@ var listBgpPeersTool = {
|
|
|
4108
4005
|
structuredContent: { routerId: context.routerId, sessions, total: sessions.length }
|
|
4109
4006
|
};
|
|
4110
4007
|
} catch (err) {
|
|
4111
|
-
|
|
4112
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_bgp_peers" });
|
|
4008
|
+
throw toolError(err, context, "list_bgp_peers");
|
|
4113
4009
|
}
|
|
4114
4010
|
}
|
|
4115
4011
|
};
|
|
4116
|
-
var listOspfNeighborsInputSchema =
|
|
4117
|
-
routerId
|
|
4118
|
-
state:
|
|
4012
|
+
var listOspfNeighborsInputSchema = z18.object({
|
|
4013
|
+
routerId,
|
|
4014
|
+
state: z18.string().optional().describe("Filter by neighbor state (e.g. full, 2-way, init)")
|
|
4119
4015
|
}).strict();
|
|
4120
4016
|
var listOspfNeighborsTool = {
|
|
4121
4017
|
name: "list_ospf_neighbors",
|
|
@@ -4144,20 +4040,19 @@ var listOspfNeighborsTool = {
|
|
|
4144
4040
|
structuredContent: { routerId: context.routerId, neighbors, total: neighbors.length }
|
|
4145
4041
|
};
|
|
4146
4042
|
} catch (err) {
|
|
4147
|
-
|
|
4148
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_ospf_neighbors" });
|
|
4043
|
+
throw toolError(err, context, "list_ospf_neighbors");
|
|
4149
4044
|
}
|
|
4150
4045
|
}
|
|
4151
4046
|
};
|
|
4152
4047
|
var routingProtocolTools = [listBgpPeersTool, listOspfNeighborsTool];
|
|
4153
4048
|
|
|
4154
4049
|
// src/domain/tools/scripts-tools.ts
|
|
4155
|
-
import { z as
|
|
4050
|
+
import { z as z19 } from "zod";
|
|
4156
4051
|
var log17 = createLogger("scripts-tools");
|
|
4157
4052
|
var SCRIPT_PATH = "system/script";
|
|
4158
|
-
var listScriptsInputSchema =
|
|
4159
|
-
routerId
|
|
4160
|
-
name:
|
|
4053
|
+
var listScriptsInputSchema = z19.object({
|
|
4054
|
+
routerId,
|
|
4055
|
+
name: z19.string().optional().describe("Filter by script name (substring match)")
|
|
4161
4056
|
}).strict();
|
|
4162
4057
|
var listScriptsTool = {
|
|
4163
4058
|
name: "list_scripts",
|
|
@@ -4189,19 +4084,18 @@ var listScriptsTool = {
|
|
|
4189
4084
|
structuredContent: { routerId: context.routerId, scripts, total: scripts.length }
|
|
4190
4085
|
};
|
|
4191
4086
|
} catch (err) {
|
|
4192
|
-
|
|
4193
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_scripts" });
|
|
4087
|
+
throw toolError(err, context, "list_scripts");
|
|
4194
4088
|
}
|
|
4195
4089
|
}
|
|
4196
4090
|
};
|
|
4197
|
-
var manageScriptInputSchema =
|
|
4198
|
-
routerId
|
|
4199
|
-
action:
|
|
4200
|
-
name:
|
|
4201
|
-
source:
|
|
4202
|
-
comment:
|
|
4203
|
-
dontRequirePermissions:
|
|
4204
|
-
dryRun
|
|
4091
|
+
var manageScriptInputSchema = z19.object({
|
|
4092
|
+
routerId,
|
|
4093
|
+
action: z19.enum(["add", "update", "remove"]).describe("Action to perform"),
|
|
4094
|
+
name: z19.string().describe("Script name \u2014 idempotency key"),
|
|
4095
|
+
source: z19.string().optional().describe("Script body (required for add and update)"),
|
|
4096
|
+
comment: z19.string().optional().describe("Optional comment"),
|
|
4097
|
+
dontRequirePermissions: z19.boolean().optional().describe("Allow script to run without elevated permissions"),
|
|
4098
|
+
dryRun
|
|
4205
4099
|
}).strict();
|
|
4206
4100
|
var manageScriptTool = {
|
|
4207
4101
|
name: "manage_script",
|
|
@@ -4340,14 +4234,13 @@ var manageScriptTool = {
|
|
|
4340
4234
|
recoverability: { retryable: false, suggestedAction: "Use one of: add, update, remove." }
|
|
4341
4235
|
});
|
|
4342
4236
|
} catch (err) {
|
|
4343
|
-
|
|
4344
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_script" });
|
|
4237
|
+
throw toolError(err, context, "manage_script");
|
|
4345
4238
|
}
|
|
4346
4239
|
}
|
|
4347
4240
|
};
|
|
4348
|
-
var runScriptInputSchema =
|
|
4349
|
-
routerId
|
|
4350
|
-
name:
|
|
4241
|
+
var runScriptInputSchema = z19.object({
|
|
4242
|
+
routerId,
|
|
4243
|
+
name: z19.string().describe("Name of the script to execute")
|
|
4351
4244
|
}).strict();
|
|
4352
4245
|
var runScriptTool = {
|
|
4353
4246
|
name: "run_script",
|
|
@@ -4389,20 +4282,19 @@ var runScriptTool = {
|
|
|
4389
4282
|
structuredContent: { action: "executed", name: parsed.name }
|
|
4390
4283
|
};
|
|
4391
4284
|
} catch (err) {
|
|
4392
|
-
|
|
4393
|
-
throw enrichError(err, { routerId: context.routerId, tool: "run_script" });
|
|
4285
|
+
throw toolError(err, context, "run_script");
|
|
4394
4286
|
}
|
|
4395
4287
|
}
|
|
4396
4288
|
};
|
|
4397
4289
|
var scriptsTools = [listScriptsTool, manageScriptTool, runScriptTool];
|
|
4398
4290
|
|
|
4399
4291
|
// src/domain/tools/scheduler-tools.ts
|
|
4400
|
-
import { z as
|
|
4292
|
+
import { z as z20 } from "zod";
|
|
4401
4293
|
var log18 = createLogger("scheduler-tools");
|
|
4402
4294
|
var SCHEDULER_PATH = "system/scheduler";
|
|
4403
|
-
var listScheduledJobsInputSchema =
|
|
4404
|
-
routerId
|
|
4405
|
-
name:
|
|
4295
|
+
var listScheduledJobsInputSchema = z20.object({
|
|
4296
|
+
routerId,
|
|
4297
|
+
name: z20.string().optional().describe("Filter by job name (exact match)")
|
|
4406
4298
|
}).strict();
|
|
4407
4299
|
var listScheduledJobsTool = {
|
|
4408
4300
|
name: "list_scheduled_jobs",
|
|
@@ -4431,21 +4323,20 @@ var listScheduledJobsTool = {
|
|
|
4431
4323
|
structuredContent: { routerId: context.routerId, jobs, total: jobs.length }
|
|
4432
4324
|
};
|
|
4433
4325
|
} catch (err) {
|
|
4434
|
-
|
|
4435
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_scheduled_jobs" });
|
|
4326
|
+
throw toolError(err, context, "list_scheduled_jobs");
|
|
4436
4327
|
}
|
|
4437
4328
|
}
|
|
4438
4329
|
};
|
|
4439
|
-
var manageScheduledJobInputSchema =
|
|
4440
|
-
routerId
|
|
4441
|
-
action:
|
|
4442
|
-
name:
|
|
4443
|
-
onEvent:
|
|
4444
|
-
startDate:
|
|
4445
|
-
startTime:
|
|
4446
|
-
interval:
|
|
4447
|
-
comment:
|
|
4448
|
-
dryRun
|
|
4330
|
+
var manageScheduledJobInputSchema = z20.object({
|
|
4331
|
+
routerId,
|
|
4332
|
+
action: z20.enum(["add", "update", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
4333
|
+
name: z20.string().describe("Job name \u2014 idempotency key"),
|
|
4334
|
+
onEvent: z20.string().optional().describe("Script name or inline command to run (required on add)"),
|
|
4335
|
+
startDate: z20.string().optional().describe("Start date (e.g. jan/01/2000)"),
|
|
4336
|
+
startTime: z20.string().optional().describe("Start time (e.g. 00:00:00)"),
|
|
4337
|
+
interval: z20.string().optional().describe("Run interval (e.g. 00:05:00 for every 5 minutes)"),
|
|
4338
|
+
comment: z20.string().optional().describe("Optional comment"),
|
|
4339
|
+
dryRun
|
|
4449
4340
|
}).strict();
|
|
4450
4341
|
var manageScheduledJobTool = {
|
|
4451
4342
|
name: "manage_scheduled_job",
|
|
@@ -4637,20 +4528,19 @@ var manageScheduledJobTool = {
|
|
|
4637
4528
|
}
|
|
4638
4529
|
});
|
|
4639
4530
|
} catch (err) {
|
|
4640
|
-
|
|
4641
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_scheduled_job" });
|
|
4531
|
+
throw toolError(err, context, "manage_scheduled_job");
|
|
4642
4532
|
}
|
|
4643
4533
|
}
|
|
4644
4534
|
};
|
|
4645
4535
|
var schedulerTools = [listScheduledJobsTool, manageScheduledJobTool];
|
|
4646
4536
|
|
|
4647
4537
|
// src/domain/tools/packages-tools.ts
|
|
4648
|
-
import { z as
|
|
4538
|
+
import { z as z21 } from "zod";
|
|
4649
4539
|
var log19 = createLogger("packages-tools");
|
|
4650
4540
|
var PACKAGE_PATH = "system/package";
|
|
4651
|
-
var listPackagesInputSchema =
|
|
4652
|
-
routerId
|
|
4653
|
-
name:
|
|
4541
|
+
var listPackagesInputSchema = z21.object({
|
|
4542
|
+
routerId,
|
|
4543
|
+
name: z21.string().optional().describe("Filter by package name (exact match)")
|
|
4654
4544
|
}).strict();
|
|
4655
4545
|
var listPackagesTool = {
|
|
4656
4546
|
name: "list_packages",
|
|
@@ -4679,16 +4569,15 @@ var listPackagesTool = {
|
|
|
4679
4569
|
structuredContent: { routerId: context.routerId, packages, total: packages.length }
|
|
4680
4570
|
};
|
|
4681
4571
|
} catch (err) {
|
|
4682
|
-
|
|
4683
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_packages" });
|
|
4572
|
+
throw toolError(err, context, "list_packages");
|
|
4684
4573
|
}
|
|
4685
4574
|
}
|
|
4686
4575
|
};
|
|
4687
|
-
var managePackageInputSchema =
|
|
4688
|
-
routerId
|
|
4689
|
-
action:
|
|
4690
|
-
name:
|
|
4691
|
-
dryRun
|
|
4576
|
+
var managePackageInputSchema = z21.object({
|
|
4577
|
+
routerId,
|
|
4578
|
+
action: z21.enum(["enable", "disable"]).describe("Action to perform"),
|
|
4579
|
+
name: z21.string().describe("Package name"),
|
|
4580
|
+
dryRun
|
|
4692
4581
|
}).strict();
|
|
4693
4582
|
var managePackageTool = {
|
|
4694
4583
|
name: "manage_package",
|
|
@@ -4754,21 +4643,20 @@ var managePackageTool = {
|
|
|
4754
4643
|
structuredContent: { action: "updated", name: parsed.name, id }
|
|
4755
4644
|
};
|
|
4756
4645
|
} catch (err) {
|
|
4757
|
-
|
|
4758
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_package" });
|
|
4646
|
+
throw toolError(err, context, "manage_package");
|
|
4759
4647
|
}
|
|
4760
4648
|
}
|
|
4761
4649
|
};
|
|
4762
4650
|
var packagesTools = [listPackagesTool, managePackageTool];
|
|
4763
4651
|
|
|
4764
4652
|
// src/domain/tools/files-tools.ts
|
|
4765
|
-
import { z as
|
|
4653
|
+
import { z as z22 } from "zod";
|
|
4766
4654
|
var log20 = createLogger("files-tools");
|
|
4767
4655
|
var FILE_PATH = "file";
|
|
4768
|
-
var listFilesInputSchema =
|
|
4769
|
-
routerId
|
|
4770
|
-
name:
|
|
4771
|
-
type:
|
|
4656
|
+
var listFilesInputSchema = z22.object({
|
|
4657
|
+
routerId,
|
|
4658
|
+
name: z22.string().optional().describe("Filter by file name (substring match)"),
|
|
4659
|
+
type: z22.string().optional().describe("Filter by file type (e.g. script, backup, package)")
|
|
4772
4660
|
}).strict();
|
|
4773
4661
|
var listFilesTool = {
|
|
4774
4662
|
name: "list_files",
|
|
@@ -4803,14 +4691,13 @@ var listFilesTool = {
|
|
|
4803
4691
|
structuredContent: { routerId: context.routerId, files, total: files.length }
|
|
4804
4692
|
};
|
|
4805
4693
|
} catch (err) {
|
|
4806
|
-
|
|
4807
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_files" });
|
|
4694
|
+
throw toolError(err, context, "list_files");
|
|
4808
4695
|
}
|
|
4809
4696
|
}
|
|
4810
4697
|
};
|
|
4811
|
-
var getFileContentInputSchema =
|
|
4812
|
-
routerId
|
|
4813
|
-
name:
|
|
4698
|
+
var getFileContentInputSchema = z22.object({
|
|
4699
|
+
routerId,
|
|
4700
|
+
name: z22.string().describe("Exact file name on the router (e.g. flash/script.rsc)")
|
|
4814
4701
|
}).strict();
|
|
4815
4702
|
var getFileContentTool = {
|
|
4816
4703
|
name: "get_file_content",
|
|
@@ -4854,21 +4741,20 @@ ${contents}`,
|
|
|
4854
4741
|
structuredContent: { routerId: context.routerId, name: parsed.name, contents }
|
|
4855
4742
|
};
|
|
4856
4743
|
} catch (err) {
|
|
4857
|
-
|
|
4858
|
-
throw enrichError(err, { routerId: context.routerId, tool: "get_file_content" });
|
|
4744
|
+
throw toolError(err, context, "get_file_content");
|
|
4859
4745
|
}
|
|
4860
4746
|
}
|
|
4861
4747
|
};
|
|
4862
|
-
var uploadFileInputSchema =
|
|
4863
|
-
routerId
|
|
4864
|
-
name:
|
|
4865
|
-
content:
|
|
4866
|
-
dryRun:
|
|
4748
|
+
var uploadFileInputSchema = z22.object({
|
|
4749
|
+
routerId,
|
|
4750
|
+
name: z22.string().describe("Target filename on the router (e.g. flash/my-script.rsc)"),
|
|
4751
|
+
content: z22.string().describe("File content to upload (text)"),
|
|
4752
|
+
dryRun: z22.boolean().default(false).describe("Validate FTP connectivity without writing the file")
|
|
4867
4753
|
}).strict();
|
|
4868
4754
|
var uploadFileTool = {
|
|
4869
4755
|
name: "upload_file",
|
|
4870
4756
|
title: "Upload File",
|
|
4871
|
-
description: "Upload a text file to a
|
|
4757
|
+
description: "Upload a text file to a router via FTP using the router's credentials, overwriting any existing file of the same name. Requires FTP permission on the router user (see config/routers.example.yaml). Dry-run tests FTP connectivity only.",
|
|
4872
4758
|
inputSchema: uploadFileInputSchema,
|
|
4873
4759
|
annotations: {
|
|
4874
4760
|
readOnlyHint: false,
|
|
@@ -4895,7 +4781,6 @@ var uploadFileTool = {
|
|
|
4895
4781
|
structuredContent: { action: "uploaded", name: parsed.name, routerId: context.routerId }
|
|
4896
4782
|
};
|
|
4897
4783
|
} catch (err) {
|
|
4898
|
-
if (err instanceof MikroMCPError) throw err;
|
|
4899
4784
|
if (err instanceof Error && err.code === "ECONNREFUSED") {
|
|
4900
4785
|
throw new MikroMCPError({
|
|
4901
4786
|
category: "CONFIGURATION" /* CONFIGURATION */,
|
|
@@ -4908,14 +4793,14 @@ var uploadFileTool = {
|
|
|
4908
4793
|
}
|
|
4909
4794
|
});
|
|
4910
4795
|
}
|
|
4911
|
-
throw
|
|
4796
|
+
throw toolError(err, context, "upload_file");
|
|
4912
4797
|
}
|
|
4913
4798
|
}
|
|
4914
4799
|
};
|
|
4915
|
-
var deleteFileInputSchema =
|
|
4916
|
-
routerId
|
|
4917
|
-
name:
|
|
4918
|
-
dryRun:
|
|
4800
|
+
var deleteFileInputSchema = z22.object({
|
|
4801
|
+
routerId,
|
|
4802
|
+
name: z22.string().describe("Exact file name on the router (e.g. flash/backup.backup)"),
|
|
4803
|
+
dryRun: z22.boolean().default(false).describe("Preview deletion without removing the file")
|
|
4919
4804
|
}).strict();
|
|
4920
4805
|
var deleteFileTool = {
|
|
4921
4806
|
name: "delete_file",
|
|
@@ -4966,8 +4851,7 @@ var deleteFileTool = {
|
|
|
4966
4851
|
}
|
|
4967
4852
|
};
|
|
4968
4853
|
} catch (err) {
|
|
4969
|
-
|
|
4970
|
-
throw enrichError(err, { routerId: context.routerId, tool: "delete_file" });
|
|
4854
|
+
throw toolError(err, context, "delete_file");
|
|
4971
4855
|
}
|
|
4972
4856
|
}
|
|
4973
4857
|
};
|
|
@@ -4979,11 +4863,11 @@ var filesTools = [
|
|
|
4979
4863
|
];
|
|
4980
4864
|
|
|
4981
4865
|
// src/domain/tools/container-tools.ts
|
|
4982
|
-
import { z as
|
|
4866
|
+
import { z as z23 } from "zod";
|
|
4983
4867
|
var log21 = createLogger("container-tools");
|
|
4984
4868
|
var CONTAINER_PATH = "container";
|
|
4985
|
-
var listContainersInputSchema =
|
|
4986
|
-
routerId
|
|
4869
|
+
var listContainersInputSchema = z23.object({
|
|
4870
|
+
routerId
|
|
4987
4871
|
}).strict();
|
|
4988
4872
|
var listContainersTool = {
|
|
4989
4873
|
name: "list_containers",
|
|
@@ -5009,28 +4893,27 @@ var listContainersTool = {
|
|
|
5009
4893
|
structuredContent: { routerId: context.routerId, containers, total: containers.length }
|
|
5010
4894
|
};
|
|
5011
4895
|
} catch (err) {
|
|
5012
|
-
|
|
5013
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_containers" });
|
|
4896
|
+
throw toolError(err, context, "list_containers");
|
|
5014
4897
|
}
|
|
5015
4898
|
}
|
|
5016
4899
|
};
|
|
5017
|
-
var manageContainerInputSchema =
|
|
5018
|
-
routerId
|
|
5019
|
-
action:
|
|
5020
|
-
name:
|
|
5021
|
-
remoteImage:
|
|
5022
|
-
interface:
|
|
4900
|
+
var manageContainerInputSchema = z23.object({
|
|
4901
|
+
routerId,
|
|
4902
|
+
action: z23.enum(["create", "start", "stop", "remove"]).describe("Action to perform"),
|
|
4903
|
+
name: z23.string().describe("Container name \u2014 idempotency key"),
|
|
4904
|
+
remoteImage: z23.string().optional().describe("Docker image to pull (required on create, e.g. alpine:latest)"),
|
|
4905
|
+
interface: z23.string().optional().describe(
|
|
5023
4906
|
"veth interface name to attach the container to (required on create \u2014 must be pre-configured in RouterOS)"
|
|
5024
4907
|
),
|
|
5025
|
-
rootDir:
|
|
5026
|
-
envlist:
|
|
5027
|
-
comment:
|
|
5028
|
-
dryRun
|
|
4908
|
+
rootDir: z23.string().optional().describe("Root directory for container files"),
|
|
4909
|
+
envlist: z23.string().optional().describe("RouterOS environment list name for container env vars"),
|
|
4910
|
+
comment: z23.string().optional().describe("Optional comment"),
|
|
4911
|
+
dryRun
|
|
5029
4912
|
}).strict();
|
|
5030
4913
|
var manageContainerTool = {
|
|
5031
4914
|
name: "manage_container",
|
|
5032
4915
|
title: "Manage Container",
|
|
5033
|
-
description: "Create, start, stop, or remove a RouterOS container. create
|
|
4916
|
+
description: "Create, start, stop, or remove a RouterOS container. create needs a pre-configured veth interface; start/stop are no-ops when already in the target state; remove throws NOT_FOUND when absent. Supports dry-run.",
|
|
5034
4917
|
inputSchema: manageContainerInputSchema,
|
|
5035
4918
|
annotations: {
|
|
5036
4919
|
readOnlyHint: false,
|
|
@@ -5194,15 +5077,14 @@ var manageContainerTool = {
|
|
|
5194
5077
|
}
|
|
5195
5078
|
});
|
|
5196
5079
|
} catch (err) {
|
|
5197
|
-
|
|
5198
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_container" });
|
|
5080
|
+
throw toolError(err, context, "manage_container");
|
|
5199
5081
|
}
|
|
5200
5082
|
}
|
|
5201
5083
|
};
|
|
5202
5084
|
var containerTools = [listContainersTool, manageContainerTool];
|
|
5203
5085
|
|
|
5204
5086
|
// src/domain/tools/change-management-tools.ts
|
|
5205
|
-
import { z as
|
|
5087
|
+
import { z as z24 } from "zod";
|
|
5206
5088
|
import { readFileSync } from "fs";
|
|
5207
5089
|
|
|
5208
5090
|
// src/domain/snapshot/snapshot-engine.ts
|
|
@@ -5215,16 +5097,16 @@ function pathToSlug(rosPath) {
|
|
|
5215
5097
|
function timestampPrefix() {
|
|
5216
5098
|
return (/* @__PURE__ */ new Date()).toISOString().replace(/[-:T]/g, "").slice(0, 15);
|
|
5217
5099
|
}
|
|
5218
|
-
async function takeSnapshot(client,
|
|
5100
|
+
async function takeSnapshot(client, routerId2, path, snapshotDir) {
|
|
5219
5101
|
const records = await client.get(path, {});
|
|
5220
5102
|
const id = `${timestampPrefix()}-${pathToSlug(path)}-${nanoid(6)}`;
|
|
5221
|
-
const dir = join2(snapshotDir,
|
|
5103
|
+
const dir = join2(snapshotDir, routerId2);
|
|
5222
5104
|
const filePath = join2(dir, `${id}.json`);
|
|
5223
5105
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
5224
5106
|
await mkdir(dir, { recursive: true });
|
|
5225
|
-
const stored = { id, routerId, path, ts, records };
|
|
5107
|
+
const stored = { id, routerId: routerId2, path, ts, records };
|
|
5226
5108
|
await writeFile(filePath, JSON.stringify(stored, null, 2));
|
|
5227
|
-
return { id, routerId, path, ts, filePath, recordCount: records.length };
|
|
5109
|
+
return { id, routerId: routerId2, path, ts, filePath, recordCount: records.length };
|
|
5228
5110
|
}
|
|
5229
5111
|
async function loadSnapshot(filePath) {
|
|
5230
5112
|
return JSON.parse(await readFile(filePath, "utf-8"));
|
|
@@ -5339,15 +5221,20 @@ var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
|
5339
5221
|
"apikey",
|
|
5340
5222
|
"confirmationsecret"
|
|
5341
5223
|
]);
|
|
5224
|
+
function redactValue(value) {
|
|
5225
|
+
if (Array.isArray(value)) {
|
|
5226
|
+
return value.map(redactValue);
|
|
5227
|
+
}
|
|
5228
|
+
if (value !== null && typeof value === "object") {
|
|
5229
|
+
return redactParams(value);
|
|
5230
|
+
}
|
|
5231
|
+
return value;
|
|
5232
|
+
}
|
|
5342
5233
|
function redactParams(params) {
|
|
5343
5234
|
const out = {};
|
|
5344
5235
|
for (const [key2, value] of Object.entries(params)) {
|
|
5345
5236
|
if (SENSITIVE_KEYS.has(key2.toLowerCase())) continue;
|
|
5346
|
-
|
|
5347
|
-
out[key2] = redactParams(value);
|
|
5348
|
-
} else {
|
|
5349
|
-
out[key2] = value;
|
|
5350
|
-
}
|
|
5237
|
+
out[key2] = redactValue(value);
|
|
5351
5238
|
}
|
|
5352
5239
|
return out;
|
|
5353
5240
|
}
|
|
@@ -5398,23 +5285,23 @@ function recordOutcome(args) {
|
|
|
5398
5285
|
|
|
5399
5286
|
// src/domain/tools/change-management-tools.ts
|
|
5400
5287
|
var log24 = createLogger("change-management");
|
|
5401
|
-
var stepSchema =
|
|
5402
|
-
tool:
|
|
5403
|
-
params:
|
|
5288
|
+
var stepSchema = z24.object({
|
|
5289
|
+
tool: z24.string().min(1).describe("Name of the MikroMCP tool to invoke"),
|
|
5290
|
+
params: z24.record(z24.unknown()).describe("Tool parameters (dryRun is injected automatically)")
|
|
5404
5291
|
}).strict();
|
|
5405
|
-
var planChangesInputSchema =
|
|
5406
|
-
routerId
|
|
5407
|
-
steps:
|
|
5292
|
+
var planChangesInputSchema = z24.object({
|
|
5293
|
+
routerId,
|
|
5294
|
+
steps: z24.array(stepSchema).min(1).max(10).describe("Ordered list of write operations to preview (up to 10)")
|
|
5408
5295
|
}).strict();
|
|
5409
|
-
var applyPlanInputSchema =
|
|
5410
|
-
routerId
|
|
5411
|
-
steps:
|
|
5412
|
-
confirmationToken:
|
|
5296
|
+
var applyPlanInputSchema = z24.object({
|
|
5297
|
+
routerId,
|
|
5298
|
+
steps: z24.array(stepSchema).min(1).max(10).describe("Ordered list of write operations to apply in sequence"),
|
|
5299
|
+
confirmationToken: z24.string().optional()
|
|
5413
5300
|
}).strict();
|
|
5414
|
-
var rollbackChangeInputSchema =
|
|
5415
|
-
routerId
|
|
5416
|
-
journalId:
|
|
5417
|
-
dryRun:
|
|
5301
|
+
var rollbackChangeInputSchema = z24.object({
|
|
5302
|
+
routerId,
|
|
5303
|
+
journalId: z24.string().describe("Journal entry ID from write-journal.ndjson to roll back"),
|
|
5304
|
+
dryRun: z24.boolean().default(false).describe("Preview the restore plan without applying changes")
|
|
5418
5305
|
}).strict();
|
|
5419
5306
|
function createChangeManagementTools(baseTools2) {
|
|
5420
5307
|
const toolMap = new Map(baseTools2.map((t) => [t.name, t]));
|
|
@@ -5436,7 +5323,7 @@ function createChangeManagementTools(baseTools2) {
|
|
|
5436
5323
|
const planChangesTool = {
|
|
5437
5324
|
name: "plan_changes",
|
|
5438
5325
|
title: "Plan Changes",
|
|
5439
|
-
description: "Preview a sequence of write operations
|
|
5326
|
+
description: "Preview a sequence of write operations: each step runs with dryRun=true against live state, returning affected paths and the predicted action per step. Use apply_plan to execute the same steps for real.",
|
|
5440
5327
|
inputSchema: planChangesInputSchema,
|
|
5441
5328
|
annotations: {
|
|
5442
5329
|
readOnlyHint: false,
|
|
@@ -5489,7 +5376,7 @@ function createChangeManagementTools(baseTools2) {
|
|
|
5489
5376
|
const applyPlanTool = {
|
|
5490
5377
|
name: "apply_plan",
|
|
5491
5378
|
title: "Apply Plan",
|
|
5492
|
-
description: "Execute
|
|
5379
|
+
description: "Execute write operations in order, stopping on first failure. Each step is snapshotted and journaled individually. Non-admin identities need a confirmationToken (same two-step flow as other destructive tools). Undo individual steps via rollback_change with the returned journal IDs.",
|
|
5493
5380
|
inputSchema: applyPlanInputSchema,
|
|
5494
5381
|
snapshotPaths: [],
|
|
5495
5382
|
annotations: {
|
|
@@ -5586,7 +5473,7 @@ function createChangeManagementTools(baseTools2) {
|
|
|
5586
5473
|
const rollbackChangeTool = {
|
|
5587
5474
|
name: "rollback_change",
|
|
5588
5475
|
title: "Rollback Change",
|
|
5589
|
-
description: "Restore
|
|
5476
|
+
description: "Restore RouterOS state to before a write, identified by its journal ID: reads the before-snapshot, diffs against live state, and applies the reverse. Use dryRun=true to preview the restore plan. Requires MIKROMCP_DATA_DIR (defaults to data/).",
|
|
5590
5477
|
inputSchema: rollbackChangeInputSchema,
|
|
5591
5478
|
annotations: {
|
|
5592
5479
|
readOnlyHint: false,
|
|
@@ -5637,12 +5524,12 @@ function createChangeManagementTools(baseTools2) {
|
|
|
5637
5524
|
}
|
|
5638
5525
|
|
|
5639
5526
|
// src/domain/tools/ipsec-tools.ts
|
|
5640
|
-
import { z as
|
|
5527
|
+
import { z as z25 } from "zod";
|
|
5641
5528
|
var log25 = createLogger("ipsec-tools");
|
|
5642
|
-
var listIpsecPeersInputSchema =
|
|
5643
|
-
routerId
|
|
5644
|
-
address:
|
|
5645
|
-
limit
|
|
5529
|
+
var listIpsecPeersInputSchema = z25.object({
|
|
5530
|
+
routerId,
|
|
5531
|
+
address: z25.string().optional().describe("Filter by remote address (substring match)"),
|
|
5532
|
+
limit
|
|
5646
5533
|
}).strict();
|
|
5647
5534
|
var listIpsecPeersTool = {
|
|
5648
5535
|
name: "list_ipsec_peers",
|
|
@@ -5677,15 +5564,15 @@ var listIpsecPeersTool = {
|
|
|
5677
5564
|
}
|
|
5678
5565
|
};
|
|
5679
5566
|
} catch (err) {
|
|
5680
|
-
throw
|
|
5567
|
+
throw toolError(err, context, "list_ipsec_peers");
|
|
5681
5568
|
}
|
|
5682
5569
|
}
|
|
5683
5570
|
};
|
|
5684
|
-
var listIpsecPoliciesInputSchema =
|
|
5685
|
-
routerId
|
|
5686
|
-
srcAddress:
|
|
5687
|
-
dstAddress:
|
|
5688
|
-
limit
|
|
5571
|
+
var listIpsecPoliciesInputSchema = z25.object({
|
|
5572
|
+
routerId,
|
|
5573
|
+
srcAddress: z25.string().optional().describe("Filter by source address (substring match)"),
|
|
5574
|
+
dstAddress: z25.string().optional().describe("Filter by destination address (substring match)"),
|
|
5575
|
+
limit
|
|
5689
5576
|
}).strict();
|
|
5690
5577
|
var listIpsecPoliciesTool = {
|
|
5691
5578
|
name: "list_ipsec_policies",
|
|
@@ -5722,20 +5609,20 @@ var listIpsecPoliciesTool = {
|
|
|
5722
5609
|
}
|
|
5723
5610
|
};
|
|
5724
5611
|
} catch (err) {
|
|
5725
|
-
throw
|
|
5612
|
+
throw toolError(err, context, "list_ipsec_policies");
|
|
5726
5613
|
}
|
|
5727
5614
|
}
|
|
5728
5615
|
};
|
|
5729
|
-
var manageIpsecPeerInputSchema =
|
|
5730
|
-
routerId
|
|
5731
|
-
action:
|
|
5732
|
-
name:
|
|
5733
|
-
address:
|
|
5734
|
-
localAddress:
|
|
5735
|
-
exchange:
|
|
5736
|
-
profile:
|
|
5737
|
-
comment:
|
|
5738
|
-
dryRun
|
|
5616
|
+
var manageIpsecPeerInputSchema = z25.object({
|
|
5617
|
+
routerId,
|
|
5618
|
+
action: z25.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
5619
|
+
name: z25.string().describe("Peer name \u2014 idempotency key"),
|
|
5620
|
+
address: z25.string().optional().describe("Remote gateway address (required for add)"),
|
|
5621
|
+
localAddress: z25.string().optional().describe("Local address"),
|
|
5622
|
+
exchange: z25.enum(["ike1", "ike2"]).default("ike2").describe("IKE exchange mode"),
|
|
5623
|
+
profile: z25.string().optional().describe("IKE profile name"),
|
|
5624
|
+
comment: z25.string().optional().describe("Optional comment"),
|
|
5625
|
+
dryRun
|
|
5739
5626
|
}).strict();
|
|
5740
5627
|
var manageIpsecPeerTool = {
|
|
5741
5628
|
name: "manage_ipsec_peer",
|
|
@@ -5885,22 +5772,21 @@ var manageIpsecPeerTool = {
|
|
|
5885
5772
|
structuredContent: { action: resultAction, name: parsed.name, id: existing[".id"] }
|
|
5886
5773
|
};
|
|
5887
5774
|
} catch (err) {
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
dryRun: z24.boolean().default(false).describe("Preview changes without applying")
|
|
5775
|
+
throw toolError(err, context, "manage_ipsec_peer");
|
|
5776
|
+
}
|
|
5777
|
+
}
|
|
5778
|
+
};
|
|
5779
|
+
var manageIpsecPolicyInputSchema = z25.object({
|
|
5780
|
+
routerId,
|
|
5781
|
+
action: z25.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
5782
|
+
srcAddress: z25.string().describe("Source CIDR \u2014 part of composite idempotency key"),
|
|
5783
|
+
dstAddress: z25.string().describe("Destination CIDR \u2014 part of composite idempotency key"),
|
|
5784
|
+
tunnel: z25.boolean().default(false).describe("Tunnel mode \u2014 part of composite idempotency key"),
|
|
5785
|
+
ipsecAction: z25.enum(["encrypt", "discard", "none"]).optional().describe("IPSec action (required for add)"),
|
|
5786
|
+
level: z25.enum(["require", "use", "unique"]).default("require").describe("SA level"),
|
|
5787
|
+
saSourceAddress: z25.string().optional().describe("SA source IP for tunnel mode"),
|
|
5788
|
+
saDstAddress: z25.string().optional().describe("SA destination IP for tunnel mode"),
|
|
5789
|
+
dryRun
|
|
5904
5790
|
}).strict();
|
|
5905
5791
|
var manageIpsecPolicyTool = {
|
|
5906
5792
|
name: "manage_ipsec_policy",
|
|
@@ -6037,8 +5923,7 @@ var manageIpsecPolicyTool = {
|
|
|
6037
5923
|
structuredContent: { action: resultAction, id: existing[".id"] }
|
|
6038
5924
|
};
|
|
6039
5925
|
} catch (err) {
|
|
6040
|
-
|
|
6041
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_ipsec_policy" });
|
|
5926
|
+
throw toolError(err, context, "manage_ipsec_policy");
|
|
6042
5927
|
}
|
|
6043
5928
|
}
|
|
6044
5929
|
};
|
|
@@ -6050,13 +5935,13 @@ var ipsecTools = [
|
|
|
6050
5935
|
];
|
|
6051
5936
|
|
|
6052
5937
|
// src/domain/tools/certificate-tools.ts
|
|
6053
|
-
import { z as
|
|
5938
|
+
import { z as z26 } from "zod";
|
|
6054
5939
|
var log26 = createLogger("certificate-tools");
|
|
6055
|
-
var listCertificatesInputSchema =
|
|
6056
|
-
routerId
|
|
6057
|
-
name:
|
|
6058
|
-
expired:
|
|
6059
|
-
limit
|
|
5940
|
+
var listCertificatesInputSchema = z26.object({
|
|
5941
|
+
routerId,
|
|
5942
|
+
name: z26.string().optional().describe("Filter by certificate name (substring match)"),
|
|
5943
|
+
expired: z26.boolean().optional().describe("Filter by expiry status; omit to return all"),
|
|
5944
|
+
limit
|
|
6060
5945
|
}).strict();
|
|
6061
5946
|
var listCertificatesTool = {
|
|
6062
5947
|
name: "list_certificates",
|
|
@@ -6098,15 +5983,15 @@ var listCertificatesTool = {
|
|
|
6098
5983
|
}
|
|
6099
5984
|
};
|
|
6100
5985
|
} catch (err) {
|
|
6101
|
-
throw
|
|
5986
|
+
throw toolError(err, context, "list_certificates");
|
|
6102
5987
|
}
|
|
6103
5988
|
}
|
|
6104
5989
|
};
|
|
6105
|
-
var manageCertificateInputSchema =
|
|
6106
|
-
routerId
|
|
6107
|
-
action:
|
|
6108
|
-
name:
|
|
6109
|
-
dryRun
|
|
5990
|
+
var manageCertificateInputSchema = z26.object({
|
|
5991
|
+
routerId,
|
|
5992
|
+
action: z26.enum(["remove", "trust", "untrust"]).describe("Action to perform"),
|
|
5993
|
+
name: z26.string().describe("Certificate name \u2014 idempotency key"),
|
|
5994
|
+
dryRun
|
|
6110
5995
|
}).strict();
|
|
6111
5996
|
var manageCertificateTool = {
|
|
6112
5997
|
name: "manage_certificate",
|
|
@@ -6203,20 +6088,19 @@ var manageCertificateTool = {
|
|
|
6203
6088
|
structuredContent: { action: "untrusted", name: parsed.name }
|
|
6204
6089
|
};
|
|
6205
6090
|
} catch (err) {
|
|
6206
|
-
|
|
6207
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_certificate" });
|
|
6091
|
+
throw toolError(err, context, "manage_certificate");
|
|
6208
6092
|
}
|
|
6209
6093
|
}
|
|
6210
6094
|
};
|
|
6211
6095
|
var certificateTools = [listCertificatesTool, manageCertificateTool];
|
|
6212
6096
|
|
|
6213
6097
|
// src/domain/tools/user-tools.ts
|
|
6214
|
-
import { z as
|
|
6098
|
+
import { z as z27 } from "zod";
|
|
6215
6099
|
var log27 = createLogger("user-tools");
|
|
6216
|
-
var listUsersInputSchema =
|
|
6217
|
-
routerId
|
|
6218
|
-
group:
|
|
6219
|
-
limit
|
|
6100
|
+
var listUsersInputSchema = z27.object({
|
|
6101
|
+
routerId,
|
|
6102
|
+
group: z27.string().optional().describe("Filter by group name (exact match)"),
|
|
6103
|
+
limit
|
|
6220
6104
|
}).strict();
|
|
6221
6105
|
var listUsersTool = {
|
|
6222
6106
|
name: "list_users",
|
|
@@ -6258,19 +6142,19 @@ var listUsersTool = {
|
|
|
6258
6142
|
}
|
|
6259
6143
|
};
|
|
6260
6144
|
} catch (err) {
|
|
6261
|
-
throw
|
|
6145
|
+
throw toolError(err, context, "list_users");
|
|
6262
6146
|
}
|
|
6263
6147
|
}
|
|
6264
6148
|
};
|
|
6265
|
-
var manageUserInputSchema =
|
|
6266
|
-
routerId
|
|
6267
|
-
action:
|
|
6268
|
-
name:
|
|
6269
|
-
group:
|
|
6270
|
-
password:
|
|
6271
|
-
address:
|
|
6272
|
-
comment:
|
|
6273
|
-
dryRun
|
|
6149
|
+
var manageUserInputSchema = z27.object({
|
|
6150
|
+
routerId,
|
|
6151
|
+
action: z27.enum(["add", "remove", "enable", "disable", "set-password"]).describe("Action to perform"),
|
|
6152
|
+
name: z27.string().describe("Username \u2014 idempotency key"),
|
|
6153
|
+
group: z27.string().optional().describe("Group name (required for add; e.g. 'read', 'write', 'full')"),
|
|
6154
|
+
password: z27.string().optional().describe("Password (required for add and set-password)"),
|
|
6155
|
+
address: z27.string().optional().describe("Allowed source address or range"),
|
|
6156
|
+
comment: z27.string().optional().describe("Optional comment"),
|
|
6157
|
+
dryRun
|
|
6274
6158
|
}).strict();
|
|
6275
6159
|
var manageUserTool = {
|
|
6276
6160
|
name: "manage_user",
|
|
@@ -6490,19 +6374,18 @@ var manageUserTool = {
|
|
|
6490
6374
|
structuredContent: { action: resultAction, name: parsed.name, id: existing[".id"] }
|
|
6491
6375
|
};
|
|
6492
6376
|
} catch (err) {
|
|
6493
|
-
|
|
6494
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_user" });
|
|
6377
|
+
throw toolError(err, context, "manage_user");
|
|
6495
6378
|
}
|
|
6496
6379
|
}
|
|
6497
6380
|
};
|
|
6498
6381
|
var userTools = [listUsersTool, manageUserTool];
|
|
6499
6382
|
|
|
6500
6383
|
// src/domain/tools/user-group-tools.ts
|
|
6501
|
-
import { z as
|
|
6384
|
+
import { z as z28 } from "zod";
|
|
6502
6385
|
var log28 = createLogger("user-group-tools");
|
|
6503
|
-
var listUserGroupsInputSchema =
|
|
6504
|
-
routerId
|
|
6505
|
-
limit
|
|
6386
|
+
var listUserGroupsInputSchema = z28.object({
|
|
6387
|
+
routerId,
|
|
6388
|
+
limit
|
|
6506
6389
|
}).strict();
|
|
6507
6390
|
var listUserGroupsTool = {
|
|
6508
6391
|
name: "list_user_groups",
|
|
@@ -6534,17 +6417,17 @@ var listUserGroupsTool = {
|
|
|
6534
6417
|
}
|
|
6535
6418
|
};
|
|
6536
6419
|
} catch (err) {
|
|
6537
|
-
throw
|
|
6420
|
+
throw toolError(err, context, "list_user_groups");
|
|
6538
6421
|
}
|
|
6539
6422
|
}
|
|
6540
6423
|
};
|
|
6541
|
-
var manageUserGroupInputSchema =
|
|
6542
|
-
routerId
|
|
6543
|
-
action:
|
|
6544
|
-
name:
|
|
6545
|
-
policy:
|
|
6546
|
-
skin:
|
|
6547
|
-
dryRun
|
|
6424
|
+
var manageUserGroupInputSchema = z28.object({
|
|
6425
|
+
routerId,
|
|
6426
|
+
action: z28.enum(["add", "update", "remove"]).describe("Action to perform"),
|
|
6427
|
+
name: z28.string().describe("Group name \u2014 idempotency key"),
|
|
6428
|
+
policy: z28.string().optional().describe("Comma-separated policy list (e.g. 'read,write,ftp')"),
|
|
6429
|
+
skin: z28.string().optional().describe("Optional skin name for the group"),
|
|
6430
|
+
dryRun
|
|
6548
6431
|
}).strict();
|
|
6549
6432
|
var manageUserGroupTool = {
|
|
6550
6433
|
name: "manage_user_group",
|
|
@@ -6700,21 +6583,20 @@ var manageUserGroupTool = {
|
|
|
6700
6583
|
structuredContent: { action: "removed", name: parsed.name, id: existing[".id"] }
|
|
6701
6584
|
};
|
|
6702
6585
|
} catch (err) {
|
|
6703
|
-
|
|
6704
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_user_group" });
|
|
6586
|
+
throw toolError(err, context, "manage_user_group");
|
|
6705
6587
|
}
|
|
6706
6588
|
}
|
|
6707
6589
|
};
|
|
6708
6590
|
var userGroupTools = [listUserGroupsTool, manageUserGroupTool];
|
|
6709
6591
|
|
|
6710
6592
|
// src/domain/tools/dhcp-server-tools.ts
|
|
6711
|
-
import { z as
|
|
6593
|
+
import { z as z29 } from "zod";
|
|
6712
6594
|
var log29 = createLogger("dhcp-server-tools");
|
|
6713
|
-
var listDhcpServersInputSchema =
|
|
6714
|
-
routerId
|
|
6715
|
-
interface:
|
|
6716
|
-
limit
|
|
6717
|
-
offset
|
|
6595
|
+
var listDhcpServersInputSchema = z29.object({
|
|
6596
|
+
routerId,
|
|
6597
|
+
interface: z29.string().optional().describe("Filter by interface name (exact match)"),
|
|
6598
|
+
limit,
|
|
6599
|
+
offset
|
|
6718
6600
|
}).strict();
|
|
6719
6601
|
var listDhcpServersTool = {
|
|
6720
6602
|
name: "list_dhcp_servers",
|
|
@@ -6736,9 +6618,7 @@ var listDhcpServersTool = {
|
|
|
6736
6618
|
offset: void 0
|
|
6737
6619
|
});
|
|
6738
6620
|
let filtered = parsed.interface ? allServers.filter((s) => s.interface === parsed.interface) : allServers;
|
|
6739
|
-
const total = filtered.
|
|
6740
|
-
const servers = filtered.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
6741
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
6621
|
+
const { items: servers, total, hasMore } = paginate(filtered, parsed.offset, parsed.limit);
|
|
6742
6622
|
return {
|
|
6743
6623
|
content: `DHCP servers on ${context.routerId}: ${total} total, showing ${servers.length} (offset ${parsed.offset})`,
|
|
6744
6624
|
structuredContent: {
|
|
@@ -6751,19 +6631,19 @@ var listDhcpServersTool = {
|
|
|
6751
6631
|
}
|
|
6752
6632
|
};
|
|
6753
6633
|
} catch (err) {
|
|
6754
|
-
throw
|
|
6634
|
+
throw toolError(err, context, "list_dhcp_servers");
|
|
6755
6635
|
}
|
|
6756
6636
|
}
|
|
6757
6637
|
};
|
|
6758
|
-
var manageDhcpServerInputSchema =
|
|
6759
|
-
routerId
|
|
6760
|
-
action:
|
|
6761
|
-
name:
|
|
6762
|
-
interface:
|
|
6763
|
-
addressPool:
|
|
6764
|
-
leaseTime:
|
|
6765
|
-
comment:
|
|
6766
|
-
dryRun
|
|
6638
|
+
var manageDhcpServerInputSchema = z29.object({
|
|
6639
|
+
routerId,
|
|
6640
|
+
action: z29.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
6641
|
+
name: z29.string().describe("Server name \u2014 idempotency key"),
|
|
6642
|
+
interface: z29.string().optional().describe("Interface to serve DHCP on (required for add)"),
|
|
6643
|
+
addressPool: z29.string().optional().describe("IP pool name (required for add)"),
|
|
6644
|
+
leaseTime: z29.string().optional().describe("Lease duration (e.g. '1d', '12h')"),
|
|
6645
|
+
comment: z29.string().optional().describe("Optional comment"),
|
|
6646
|
+
dryRun
|
|
6767
6647
|
}).strict();
|
|
6768
6648
|
var manageDhcpServerTool = {
|
|
6769
6649
|
name: "manage_dhcp_server",
|
|
@@ -6933,21 +6813,20 @@ var manageDhcpServerTool = {
|
|
|
6933
6813
|
structuredContent: { action: resultAction, name: parsed.name, id: existing[".id"] }
|
|
6934
6814
|
};
|
|
6935
6815
|
} catch (err) {
|
|
6936
|
-
|
|
6937
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_dhcp_server" });
|
|
6816
|
+
throw toolError(err, context, "manage_dhcp_server");
|
|
6938
6817
|
}
|
|
6939
6818
|
}
|
|
6940
6819
|
};
|
|
6941
6820
|
var dhcpServerTools = [listDhcpServersTool, manageDhcpServerTool];
|
|
6942
6821
|
|
|
6943
6822
|
// src/domain/tools/ip-pool-tools.ts
|
|
6944
|
-
import { z as
|
|
6823
|
+
import { z as z30 } from "zod";
|
|
6945
6824
|
var log30 = createLogger("ip-pool-tools");
|
|
6946
|
-
var listIpPoolsInputSchema =
|
|
6947
|
-
routerId
|
|
6948
|
-
name:
|
|
6949
|
-
limit
|
|
6950
|
-
offset
|
|
6825
|
+
var listIpPoolsInputSchema = z30.object({
|
|
6826
|
+
routerId,
|
|
6827
|
+
name: z30.string().optional().describe("Filter by pool name (substring match)"),
|
|
6828
|
+
limit,
|
|
6829
|
+
offset
|
|
6951
6830
|
}).strict();
|
|
6952
6831
|
var listIpPoolsTool = {
|
|
6953
6832
|
name: "list_ip_pools",
|
|
@@ -6972,9 +6851,7 @@ var listIpPoolsTool = {
|
|
|
6972
6851
|
if (parsed.name) {
|
|
6973
6852
|
filtered = filtered.filter((p) => (p.name ?? "").includes(parsed.name));
|
|
6974
6853
|
}
|
|
6975
|
-
const total = filtered.
|
|
6976
|
-
const pools = filtered.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
6977
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
6854
|
+
const { items: pools, total, hasMore } = paginate(filtered, parsed.offset, parsed.limit);
|
|
6978
6855
|
return {
|
|
6979
6856
|
content: `IP pools on ${context.routerId}: ${total} total, showing ${pools.length} (offset ${parsed.offset})`,
|
|
6980
6857
|
structuredContent: {
|
|
@@ -6987,17 +6864,17 @@ var listIpPoolsTool = {
|
|
|
6987
6864
|
}
|
|
6988
6865
|
};
|
|
6989
6866
|
} catch (err) {
|
|
6990
|
-
throw
|
|
6867
|
+
throw toolError(err, context, "list_ip_pools");
|
|
6991
6868
|
}
|
|
6992
6869
|
}
|
|
6993
6870
|
};
|
|
6994
|
-
var manageIpPoolInputSchema =
|
|
6995
|
-
routerId
|
|
6996
|
-
action:
|
|
6997
|
-
name:
|
|
6998
|
-
ranges:
|
|
6999
|
-
nextPool:
|
|
7000
|
-
dryRun
|
|
6871
|
+
var manageIpPoolInputSchema = z30.object({
|
|
6872
|
+
routerId,
|
|
6873
|
+
action: z30.enum(["add", "remove"]).describe("Action to perform"),
|
|
6874
|
+
name: z30.string().describe("Pool name \u2014 idempotency key"),
|
|
6875
|
+
ranges: z30.string().optional().describe("IP range (e.g. '192.168.1.100-192.168.1.200'; required for add)"),
|
|
6876
|
+
nextPool: z30.string().optional().describe("Next pool name for overflow"),
|
|
6877
|
+
dryRun
|
|
7001
6878
|
}).strict();
|
|
7002
6879
|
var manageIpPoolTool = {
|
|
7003
6880
|
name: "manage_ip_pool",
|
|
@@ -7091,20 +6968,19 @@ var manageIpPoolTool = {
|
|
|
7091
6968
|
structuredContent: { action: "removed", name: parsed.name, id: existing[".id"] }
|
|
7092
6969
|
};
|
|
7093
6970
|
} catch (err) {
|
|
7094
|
-
|
|
7095
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_ip_pool" });
|
|
6971
|
+
throw toolError(err, context, "manage_ip_pool");
|
|
7096
6972
|
}
|
|
7097
6973
|
}
|
|
7098
6974
|
};
|
|
7099
6975
|
var ipPoolTools = [listIpPoolsTool, manageIpPoolTool];
|
|
7100
6976
|
|
|
7101
6977
|
// src/domain/tools/queue-tools.ts
|
|
7102
|
-
import { z as
|
|
6978
|
+
import { z as z31 } from "zod";
|
|
7103
6979
|
var log31 = createLogger("queue-tools");
|
|
7104
|
-
var listQueuesInputSchema =
|
|
7105
|
-
routerId
|
|
7106
|
-
target:
|
|
7107
|
-
limit
|
|
6980
|
+
var listQueuesInputSchema = z31.object({
|
|
6981
|
+
routerId,
|
|
6982
|
+
target: z31.string().optional().describe("Filter by target address (substring match)"),
|
|
6983
|
+
limit
|
|
7108
6984
|
}).strict();
|
|
7109
6985
|
var listQueuesTool = {
|
|
7110
6986
|
name: "list_queues",
|
|
@@ -7139,19 +7015,19 @@ var listQueuesTool = {
|
|
|
7139
7015
|
}
|
|
7140
7016
|
};
|
|
7141
7017
|
} catch (err) {
|
|
7142
|
-
throw
|
|
7018
|
+
throw toolError(err, context, "list_queues");
|
|
7143
7019
|
}
|
|
7144
7020
|
}
|
|
7145
7021
|
};
|
|
7146
|
-
var manageQueueInputSchema =
|
|
7147
|
-
routerId
|
|
7148
|
-
action:
|
|
7149
|
-
name:
|
|
7150
|
-
target:
|
|
7151
|
-
maxLimit:
|
|
7152
|
-
limitAt:
|
|
7153
|
-
comment:
|
|
7154
|
-
dryRun
|
|
7022
|
+
var manageQueueInputSchema = z31.object({
|
|
7023
|
+
routerId,
|
|
7024
|
+
action: z31.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
7025
|
+
name: z31.string().describe("Queue name \u2014 idempotency key"),
|
|
7026
|
+
target: z31.string().optional().describe("Target address (required for add; e.g. '192.168.1.0/24')"),
|
|
7027
|
+
maxLimit: z31.string().optional().describe("Max upload/download limit (e.g. '10M/10M')"),
|
|
7028
|
+
limitAt: z31.string().optional().describe("Guaranteed rate (e.g. '1M/1M')"),
|
|
7029
|
+
comment: z31.string().optional().describe("Optional comment"),
|
|
7030
|
+
dryRun
|
|
7155
7031
|
}).strict();
|
|
7156
7032
|
var manageQueueTool = {
|
|
7157
7033
|
name: "manage_queue",
|
|
@@ -7297,20 +7173,19 @@ var manageQueueTool = {
|
|
|
7297
7173
|
structuredContent: { action: resultAction, name: parsed.name, id: existing[".id"] }
|
|
7298
7174
|
};
|
|
7299
7175
|
} catch (err) {
|
|
7300
|
-
|
|
7301
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_queue" });
|
|
7176
|
+
throw toolError(err, context, "manage_queue");
|
|
7302
7177
|
}
|
|
7303
7178
|
}
|
|
7304
7179
|
};
|
|
7305
7180
|
var queueTools = [listQueuesTool, manageQueueTool];
|
|
7306
7181
|
|
|
7307
7182
|
// src/domain/tools/vrrp-tools.ts
|
|
7308
|
-
import { z as
|
|
7183
|
+
import { z as z32 } from "zod";
|
|
7309
7184
|
var log32 = createLogger("vrrp-tools");
|
|
7310
|
-
var listVrrpInstancesInputSchema =
|
|
7311
|
-
routerId
|
|
7312
|
-
interface:
|
|
7313
|
-
limit
|
|
7185
|
+
var listVrrpInstancesInputSchema = z32.object({
|
|
7186
|
+
routerId,
|
|
7187
|
+
interface: z32.string().optional().describe("Filter by master interface name (exact match)"),
|
|
7188
|
+
limit
|
|
7314
7189
|
}).strict();
|
|
7315
7190
|
var listVrrpInstancesTool = {
|
|
7316
7191
|
name: "list_vrrp_instances",
|
|
@@ -7345,21 +7220,21 @@ var listVrrpInstancesTool = {
|
|
|
7345
7220
|
}
|
|
7346
7221
|
};
|
|
7347
7222
|
} catch (err) {
|
|
7348
|
-
throw
|
|
7223
|
+
throw toolError(err, context, "list_vrrp_instances");
|
|
7349
7224
|
}
|
|
7350
7225
|
}
|
|
7351
7226
|
};
|
|
7352
|
-
var manageVrrpInstanceInputSchema =
|
|
7353
|
-
routerId
|
|
7354
|
-
action:
|
|
7355
|
-
name:
|
|
7356
|
-
interface:
|
|
7357
|
-
vrid:
|
|
7358
|
-
priority:
|
|
7359
|
-
interval:
|
|
7360
|
-
version:
|
|
7361
|
-
comment:
|
|
7362
|
-
dryRun
|
|
7227
|
+
var manageVrrpInstanceInputSchema = z32.object({
|
|
7228
|
+
routerId,
|
|
7229
|
+
action: z32.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
7230
|
+
name: z32.string().describe("VRRP interface name \u2014 idempotency key"),
|
|
7231
|
+
interface: z32.string().optional().describe("Master interface (required for add)"),
|
|
7232
|
+
vrid: z32.number().int().min(1).max(255).optional().describe("Virtual router ID (required for add)"),
|
|
7233
|
+
priority: z32.number().int().min(1).max(254).default(100).describe("Router priority (1\u2013254)"),
|
|
7234
|
+
interval: z32.number().int().min(1).optional().describe("Advertisement interval in seconds"),
|
|
7235
|
+
version: z32.enum(["2", "3"]).default("3").describe("VRRP protocol version"),
|
|
7236
|
+
comment: z32.string().optional().describe("Optional comment"),
|
|
7237
|
+
dryRun
|
|
7363
7238
|
}).strict();
|
|
7364
7239
|
var manageVrrpInstanceTool = {
|
|
7365
7240
|
name: "manage_vrrp_instance",
|
|
@@ -7527,18 +7402,17 @@ var manageVrrpInstanceTool = {
|
|
|
7527
7402
|
structuredContent: { action: resultAction, name: parsed.name, id: existing[".id"] }
|
|
7528
7403
|
};
|
|
7529
7404
|
} catch (err) {
|
|
7530
|
-
|
|
7531
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_vrrp_instance" });
|
|
7405
|
+
throw toolError(err, context, "manage_vrrp_instance");
|
|
7532
7406
|
}
|
|
7533
7407
|
}
|
|
7534
7408
|
};
|
|
7535
7409
|
var vrrpTools = [listVrrpInstancesTool, manageVrrpInstanceTool];
|
|
7536
7410
|
|
|
7537
7411
|
// src/domain/tools/network-services-tools.ts
|
|
7538
|
-
import { z as
|
|
7412
|
+
import { z as z33 } from "zod";
|
|
7539
7413
|
var log33 = createLogger("network-services-tools");
|
|
7540
|
-
var getSnmpSettingsInputSchema =
|
|
7541
|
-
routerId
|
|
7414
|
+
var getSnmpSettingsInputSchema = z33.object({
|
|
7415
|
+
routerId
|
|
7542
7416
|
}).strict();
|
|
7543
7417
|
var getSnmpSettingsTool = {
|
|
7544
7418
|
name: "get_snmp_settings",
|
|
@@ -7577,13 +7451,12 @@ var getSnmpSettingsTool = {
|
|
|
7577
7451
|
}
|
|
7578
7452
|
};
|
|
7579
7453
|
} catch (err) {
|
|
7580
|
-
|
|
7581
|
-
throw enrichError(err, { routerId: context.routerId, tool: "get_snmp_settings" });
|
|
7454
|
+
throw toolError(err, context, "get_snmp_settings");
|
|
7582
7455
|
}
|
|
7583
7456
|
}
|
|
7584
7457
|
};
|
|
7585
|
-
var getNtpSettingsInputSchema =
|
|
7586
|
-
routerId
|
|
7458
|
+
var getNtpSettingsInputSchema = z33.object({
|
|
7459
|
+
routerId
|
|
7587
7460
|
}).strict();
|
|
7588
7461
|
var getNtpSettingsTool = {
|
|
7589
7462
|
name: "get_ntp_settings",
|
|
@@ -7622,16 +7495,15 @@ var getNtpSettingsTool = {
|
|
|
7622
7495
|
}
|
|
7623
7496
|
};
|
|
7624
7497
|
} catch (err) {
|
|
7625
|
-
|
|
7626
|
-
throw enrichError(err, { routerId: context.routerId, tool: "get_ntp_settings" });
|
|
7498
|
+
throw toolError(err, context, "get_ntp_settings");
|
|
7627
7499
|
}
|
|
7628
7500
|
}
|
|
7629
7501
|
};
|
|
7630
|
-
var listNetwatchEntriesInputSchema =
|
|
7631
|
-
routerId
|
|
7632
|
-
host:
|
|
7633
|
-
status:
|
|
7634
|
-
limit
|
|
7502
|
+
var listNetwatchEntriesInputSchema = z33.object({
|
|
7503
|
+
routerId,
|
|
7504
|
+
host: z33.string().optional().describe("Filter by host (substring match)"),
|
|
7505
|
+
status: z33.enum(["up", "down", "unknown"]).optional().describe("Filter by current status"),
|
|
7506
|
+
limit
|
|
7635
7507
|
}).strict();
|
|
7636
7508
|
var listNetwatchEntriesTool = {
|
|
7637
7509
|
name: "list_netwatch_entries",
|
|
@@ -7664,19 +7536,19 @@ var listNetwatchEntriesTool = {
|
|
|
7664
7536
|
}
|
|
7665
7537
|
};
|
|
7666
7538
|
} catch (err) {
|
|
7667
|
-
throw
|
|
7539
|
+
throw toolError(err, context, "list_netwatch_entries");
|
|
7668
7540
|
}
|
|
7669
7541
|
}
|
|
7670
7542
|
};
|
|
7671
|
-
var manageNetwatchEntryInputSchema =
|
|
7672
|
-
routerId
|
|
7673
|
-
action:
|
|
7674
|
-
host:
|
|
7675
|
-
port:
|
|
7676
|
-
interval:
|
|
7677
|
-
timeout:
|
|
7678
|
-
comment:
|
|
7679
|
-
dryRun
|
|
7543
|
+
var manageNetwatchEntryInputSchema = z33.object({
|
|
7544
|
+
routerId,
|
|
7545
|
+
action: z33.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
7546
|
+
host: z33.string().describe("Host to monitor \u2014 idempotency key"),
|
|
7547
|
+
port: z33.number().int().min(1).max(65535).optional().describe("TCP port (optional; ICMP if omitted)"),
|
|
7548
|
+
interval: z33.string().optional().describe("Check interval (e.g. '1m'; default '1m')"),
|
|
7549
|
+
timeout: z33.string().optional().describe("Probe timeout (e.g. '500ms')"),
|
|
7550
|
+
comment: z33.string().optional().describe("Optional comment"),
|
|
7551
|
+
dryRun
|
|
7680
7552
|
}).strict();
|
|
7681
7553
|
var manageNetwatchEntryTool = {
|
|
7682
7554
|
name: "manage_netwatch_entry",
|
|
@@ -7819,15 +7691,14 @@ var manageNetwatchEntryTool = {
|
|
|
7819
7691
|
structuredContent: { action: resultAction, host: parsed.host, id: existing[".id"] }
|
|
7820
7692
|
};
|
|
7821
7693
|
} catch (err) {
|
|
7822
|
-
|
|
7823
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_netwatch_entry" });
|
|
7694
|
+
throw toolError(err, context, "manage_netwatch_entry");
|
|
7824
7695
|
}
|
|
7825
7696
|
}
|
|
7826
7697
|
};
|
|
7827
|
-
var listNeighborsInputSchema =
|
|
7828
|
-
routerId
|
|
7829
|
-
interface:
|
|
7830
|
-
limit
|
|
7698
|
+
var listNeighborsInputSchema = z33.object({
|
|
7699
|
+
routerId,
|
|
7700
|
+
interface: z33.string().optional().describe("Filter by interface name (substring match)"),
|
|
7701
|
+
limit
|
|
7831
7702
|
}).strict();
|
|
7832
7703
|
var listNeighborsTool = {
|
|
7833
7704
|
name: "list_neighbors",
|
|
@@ -7862,16 +7733,16 @@ var listNeighborsTool = {
|
|
|
7862
7733
|
}
|
|
7863
7734
|
};
|
|
7864
7735
|
} catch (err) {
|
|
7865
|
-
throw
|
|
7736
|
+
throw toolError(err, context, "list_neighbors");
|
|
7866
7737
|
}
|
|
7867
7738
|
}
|
|
7868
7739
|
};
|
|
7869
|
-
var listArpEntriesInputSchema =
|
|
7870
|
-
routerId
|
|
7871
|
-
interface:
|
|
7872
|
-
address:
|
|
7873
|
-
macAddress:
|
|
7874
|
-
limit
|
|
7740
|
+
var listArpEntriesInputSchema = z33.object({
|
|
7741
|
+
routerId,
|
|
7742
|
+
interface: z33.string().optional().describe("Filter by interface (substring match)"),
|
|
7743
|
+
address: z33.string().optional().describe("Filter by IP address (substring match)"),
|
|
7744
|
+
macAddress: z33.string().optional().describe("Filter by MAC address (substring match)"),
|
|
7745
|
+
limit
|
|
7875
7746
|
}).strict();
|
|
7876
7747
|
var listArpEntriesTool = {
|
|
7877
7748
|
name: "list_arp_entries",
|
|
@@ -7906,17 +7777,17 @@ var listArpEntriesTool = {
|
|
|
7906
7777
|
}
|
|
7907
7778
|
};
|
|
7908
7779
|
} catch (err) {
|
|
7909
|
-
throw
|
|
7780
|
+
throw toolError(err, context, "list_arp_entries");
|
|
7910
7781
|
}
|
|
7911
7782
|
}
|
|
7912
7783
|
};
|
|
7913
|
-
var manageNtpClientInputSchema =
|
|
7914
|
-
routerId
|
|
7915
|
-
enabled:
|
|
7916
|
-
mode:
|
|
7917
|
-
servers:
|
|
7918
|
-
vlanInterface:
|
|
7919
|
-
dryRun
|
|
7784
|
+
var manageNtpClientInputSchema = z33.object({
|
|
7785
|
+
routerId,
|
|
7786
|
+
enabled: z33.boolean().optional().describe("Enable or disable the NTP client"),
|
|
7787
|
+
mode: z33.enum(["unicast", "broadcast", "multicast", "manycast"]).optional().describe("NTP client mode"),
|
|
7788
|
+
servers: z33.string().optional().describe("Comma-separated NTP server addresses"),
|
|
7789
|
+
vlanInterface: z33.string().optional().describe("VLAN interface for NTP communication"),
|
|
7790
|
+
dryRun
|
|
7920
7791
|
}).strict();
|
|
7921
7792
|
var manageNtpClientTool = {
|
|
7922
7793
|
name: "manage_ntp_client",
|
|
@@ -7978,7 +7849,7 @@ var manageNtpClientTool = {
|
|
|
7978
7849
|
structuredContent: { action: "updated", routerId: context.routerId, diff }
|
|
7979
7850
|
};
|
|
7980
7851
|
} catch (err) {
|
|
7981
|
-
throw
|
|
7852
|
+
throw toolError(err, context, "manage_ntp_client");
|
|
7982
7853
|
}
|
|
7983
7854
|
}
|
|
7984
7855
|
};
|
|
@@ -7993,22 +7864,22 @@ var networkServicesTools = [
|
|
|
7993
7864
|
];
|
|
7994
7865
|
|
|
7995
7866
|
// src/domain/tools/vlan-tools.ts
|
|
7996
|
-
import { z as
|
|
7867
|
+
import { z as z34 } from "zod";
|
|
7997
7868
|
var log34 = createLogger("vlan-tools");
|
|
7998
7869
|
function sanitizeComment4(comment) {
|
|
7999
7870
|
if (comment === void 0) return void 0;
|
|
8000
7871
|
return comment.replace(/[\x00-\x1f\x7f]/g, "");
|
|
8001
7872
|
}
|
|
8002
|
-
var manageVlanInputSchema =
|
|
8003
|
-
routerId
|
|
8004
|
-
action:
|
|
8005
|
-
name:
|
|
8006
|
-
vlanId:
|
|
8007
|
-
parentInterface:
|
|
8008
|
-
mtu:
|
|
8009
|
-
disabled:
|
|
8010
|
-
comment:
|
|
8011
|
-
dryRun
|
|
7873
|
+
var manageVlanInputSchema = z34.object({
|
|
7874
|
+
routerId,
|
|
7875
|
+
action: z34.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
7876
|
+
name: z34.string().regex(/^[a-zA-Z0-9_-]+$/).max(15).describe("VLAN interface name \u2014 idempotency key (alphanumeric, hyphens, underscores, max 15 chars)"),
|
|
7877
|
+
vlanId: z34.number().int().min(1).max(4094).optional().describe("VLAN ID (1-4094; required for add)"),
|
|
7878
|
+
parentInterface: z34.string().optional().describe("Parent interface name (e.g., ether1, bridge1; required for add)"),
|
|
7879
|
+
mtu: z34.number().int().min(68).max(9e3).default(1500).describe("MTU size (add only)"),
|
|
7880
|
+
disabled: z34.boolean().default(false).describe("Whether to create the VLAN disabled (add only)"),
|
|
7881
|
+
comment: z34.string().max(255).optional().describe("Optional comment (add only)"),
|
|
7882
|
+
dryRun
|
|
8012
7883
|
}).strict();
|
|
8013
7884
|
var manageVlanTool = {
|
|
8014
7885
|
name: "manage_vlan",
|
|
@@ -8154,22 +8025,21 @@ var manageVlanTool = {
|
|
|
8154
8025
|
structuredContent: { action: resultAction, name: parsed.name, id: existing[".id"] }
|
|
8155
8026
|
};
|
|
8156
8027
|
} catch (err) {
|
|
8157
|
-
|
|
8158
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_vlan" });
|
|
8028
|
+
throw toolError(err, context, "manage_vlan");
|
|
8159
8029
|
}
|
|
8160
8030
|
}
|
|
8161
8031
|
};
|
|
8162
8032
|
var vlanTools = [manageVlanTool];
|
|
8163
8033
|
|
|
8164
8034
|
// src/domain/tools/dhcp-client-tools.ts
|
|
8165
|
-
import { z as
|
|
8035
|
+
import { z as z35 } from "zod";
|
|
8166
8036
|
var log35 = createLogger("dhcp-client-tools");
|
|
8167
|
-
var listDhcpClientsInputSchema =
|
|
8168
|
-
routerId
|
|
8169
|
-
interface:
|
|
8170
|
-
status:
|
|
8171
|
-
limit
|
|
8172
|
-
offset
|
|
8037
|
+
var listDhcpClientsInputSchema = z35.object({
|
|
8038
|
+
routerId,
|
|
8039
|
+
interface: z35.string().optional().describe("Filter by interface name (exact match)"),
|
|
8040
|
+
status: z35.enum(["bound", "searching", "requesting", "init", "all"]).default("all").describe("Filter by DHCP client status"),
|
|
8041
|
+
limit,
|
|
8042
|
+
offset
|
|
8173
8043
|
}).strict();
|
|
8174
8044
|
var listDhcpClientsTool = {
|
|
8175
8045
|
name: "list_dhcp_clients",
|
|
@@ -8197,22 +8067,9 @@ var listDhcpClientsTool = {
|
|
|
8197
8067
|
if (parsed.status !== "all") {
|
|
8198
8068
|
filtered = filtered.filter((c) => c.status === parsed.status);
|
|
8199
8069
|
}
|
|
8200
|
-
const total = filtered.
|
|
8201
|
-
const clients = filtered.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
8202
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
8203
|
-
const lines = [
|
|
8204
|
-
`DHCP clients on ${context.routerId}: ${total} total, showing ${clients.length} (offset ${parsed.offset})`
|
|
8205
|
-
];
|
|
8206
|
-
for (const c of clients) {
|
|
8207
|
-
const rec = c;
|
|
8208
|
-
const iface = rec.interface ?? "unknown";
|
|
8209
|
-
const status = rec.status ?? "unknown";
|
|
8210
|
-
const address = rec.address ?? rec["active-address"] ?? "-";
|
|
8211
|
-
const isDisabled = rec.disabled === true || rec.disabled === "true";
|
|
8212
|
-
lines.push(` ${iface} [${status}] ${address}${isDisabled ? " DISABLED" : ""}`);
|
|
8213
|
-
}
|
|
8070
|
+
const { items: clients, total, hasMore } = paginate(filtered, parsed.offset, parsed.limit);
|
|
8214
8071
|
return {
|
|
8215
|
-
content:
|
|
8072
|
+
content: listSummary("DHCP clients", context.routerId, clients.length, total, parsed.offset),
|
|
8216
8073
|
structuredContent: {
|
|
8217
8074
|
routerId: context.routerId,
|
|
8218
8075
|
clients,
|
|
@@ -8223,19 +8080,19 @@ var listDhcpClientsTool = {
|
|
|
8223
8080
|
}
|
|
8224
8081
|
};
|
|
8225
8082
|
} catch (err) {
|
|
8226
|
-
throw
|
|
8083
|
+
throw toolError(err, context, "list_dhcp_clients");
|
|
8227
8084
|
}
|
|
8228
8085
|
}
|
|
8229
8086
|
};
|
|
8230
|
-
var manageDhcpClientInputSchema =
|
|
8231
|
-
routerId
|
|
8232
|
-
action:
|
|
8233
|
-
interface:
|
|
8234
|
-
usePeerDns:
|
|
8235
|
-
usePeerNtp:
|
|
8236
|
-
addDefaultRoute:
|
|
8237
|
-
comment:
|
|
8238
|
-
dryRun
|
|
8087
|
+
var manageDhcpClientInputSchema = z35.object({
|
|
8088
|
+
routerId,
|
|
8089
|
+
action: z35.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
8090
|
+
interface: z35.string().describe("Interface name \u2014 idempotency key (e.g. ether1, ether2)"),
|
|
8091
|
+
usePeerDns: z35.boolean().default(true).describe("Use DNS servers provided by DHCP server (add only)"),
|
|
8092
|
+
usePeerNtp: z35.boolean().default(false).describe("Use NTP servers provided by DHCP server (add only)"),
|
|
8093
|
+
addDefaultRoute: z35.boolean().default(true).describe("Add default route from DHCP (add only)"),
|
|
8094
|
+
comment: z35.string().max(255).optional().describe("Optional comment (add only)"),
|
|
8095
|
+
dryRun
|
|
8239
8096
|
}).strict();
|
|
8240
8097
|
var manageDhcpClientTool = {
|
|
8241
8098
|
name: "manage_dhcp_client",
|
|
@@ -8353,21 +8210,20 @@ var manageDhcpClientTool = {
|
|
|
8353
8210
|
structuredContent: { action: resultAction, interface: parsed.interface, id: existing[".id"] }
|
|
8354
8211
|
};
|
|
8355
8212
|
} catch (err) {
|
|
8356
|
-
|
|
8357
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_dhcp_client" });
|
|
8213
|
+
throw toolError(err, context, "manage_dhcp_client");
|
|
8358
8214
|
}
|
|
8359
8215
|
}
|
|
8360
8216
|
};
|
|
8361
8217
|
var dhcpClientTools = [listDhcpClientsTool, manageDhcpClientTool];
|
|
8362
8218
|
|
|
8363
8219
|
// src/domain/tools/ip-service-tools.ts
|
|
8364
|
-
import { z as
|
|
8220
|
+
import { z as z36 } from "zod";
|
|
8365
8221
|
var log36 = createLogger("ip-service-tools");
|
|
8366
8222
|
var SERVICE_NAMES = ["api", "api-ssl", "ssh", "telnet", "www", "www-ssl", "winbox", "ftp"];
|
|
8367
|
-
var listIpServicesInputSchema =
|
|
8368
|
-
routerId
|
|
8369
|
-
name:
|
|
8370
|
-
enabled:
|
|
8223
|
+
var listIpServicesInputSchema = z36.object({
|
|
8224
|
+
routerId,
|
|
8225
|
+
name: z36.enum(SERVICE_NAMES).optional().describe("Filter by service name (api, api-ssl, ssh, telnet, www, www-ssl, winbox, ftp)"),
|
|
8226
|
+
enabled: z36.boolean().optional().describe("When true, return only enabled services; when false, only disabled services")
|
|
8371
8227
|
}).strict();
|
|
8372
8228
|
var listIpServicesTool = {
|
|
8373
8229
|
name: "list_ip_services",
|
|
@@ -8398,14 +8254,8 @@ var listIpServicesTool = {
|
|
|
8398
8254
|
return parsed.enabled ? !isDisabled : isDisabled;
|
|
8399
8255
|
});
|
|
8400
8256
|
}
|
|
8401
|
-
const lines = [`IP services on ${context.routerId}: ${filtered.length} returned`];
|
|
8402
|
-
for (const s of filtered) {
|
|
8403
|
-
const rec = s;
|
|
8404
|
-
const isDisabled = rec.disabled === true || rec.disabled === "true";
|
|
8405
|
-
lines.push(` ${rec.name} port:${rec.port ?? "-"} [${isDisabled ? "DISABLED" : "enabled"}]`);
|
|
8406
|
-
}
|
|
8407
8257
|
return {
|
|
8408
|
-
content:
|
|
8258
|
+
content: `IP services on ${context.routerId}: ${filtered.length} returned. Full records in structuredContent.`,
|
|
8409
8259
|
structuredContent: {
|
|
8410
8260
|
routerId: context.routerId,
|
|
8411
8261
|
services: filtered,
|
|
@@ -8413,17 +8263,17 @@ var listIpServicesTool = {
|
|
|
8413
8263
|
}
|
|
8414
8264
|
};
|
|
8415
8265
|
} catch (err) {
|
|
8416
|
-
throw
|
|
8266
|
+
throw toolError(err, context, "list_ip_services");
|
|
8417
8267
|
}
|
|
8418
8268
|
}
|
|
8419
8269
|
};
|
|
8420
|
-
var manageIpServiceInputSchema =
|
|
8421
|
-
routerId
|
|
8422
|
-
action:
|
|
8270
|
+
var manageIpServiceInputSchema = z36.object({
|
|
8271
|
+
routerId,
|
|
8272
|
+
action: z36.enum(["enable", "disable"]).describe(
|
|
8423
8273
|
"Action to perform \u2014 only enable/disable to prevent accidental lockout from changing ports"
|
|
8424
8274
|
),
|
|
8425
|
-
name:
|
|
8426
|
-
dryRun
|
|
8275
|
+
name: z36.enum(SERVICE_NAMES).describe("Service name to manage (api, api-ssl, ssh, telnet, www, www-ssl, winbox, ftp)"),
|
|
8276
|
+
dryRun
|
|
8427
8277
|
}).strict();
|
|
8428
8278
|
var manageIpServiceTool = {
|
|
8429
8279
|
name: "manage_ip_service",
|
|
@@ -8491,23 +8341,22 @@ var manageIpServiceTool = {
|
|
|
8491
8341
|
structuredContent: { action: resultAction, name: parsed.name, id: existing[".id"] }
|
|
8492
8342
|
};
|
|
8493
8343
|
} catch (err) {
|
|
8494
|
-
|
|
8495
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_ip_service" });
|
|
8344
|
+
throw toolError(err, context, "manage_ip_service");
|
|
8496
8345
|
}
|
|
8497
8346
|
}
|
|
8498
8347
|
};
|
|
8499
8348
|
var ipServiceTools = [listIpServicesTool, manageIpServiceTool];
|
|
8500
8349
|
|
|
8501
8350
|
// src/domain/tools/pppoe-tools.ts
|
|
8502
|
-
import { z as
|
|
8351
|
+
import { z as z37 } from "zod";
|
|
8503
8352
|
var log37 = createLogger("pppoe-tools");
|
|
8504
8353
|
var PPPOE_PATH = "interface/pppoe-client";
|
|
8505
|
-
var listPppoeClientsInputSchema =
|
|
8506
|
-
routerId
|
|
8507
|
-
interface:
|
|
8508
|
-
status:
|
|
8509
|
-
limit
|
|
8510
|
-
offset
|
|
8354
|
+
var listPppoeClientsInputSchema = z37.object({
|
|
8355
|
+
routerId,
|
|
8356
|
+
interface: z37.string().optional().describe("Filter by parent interface name (exact match)"),
|
|
8357
|
+
status: z37.enum(["connected", "disconnected", "all"]).default("all").describe("Filter by running status"),
|
|
8358
|
+
limit,
|
|
8359
|
+
offset
|
|
8511
8360
|
}).strict();
|
|
8512
8361
|
function isRunning(record) {
|
|
8513
8362
|
return record.running === true || record.running === "true";
|
|
@@ -8540,21 +8389,9 @@ var listPppoeClientsTool = {
|
|
|
8540
8389
|
} else if (parsed.status === "disconnected") {
|
|
8541
8390
|
filtered = filtered.filter((c) => !isRunning(c));
|
|
8542
8391
|
}
|
|
8543
|
-
const total = filtered.
|
|
8544
|
-
const clients = filtered.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
8545
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
8546
|
-
const lines = [
|
|
8547
|
-
`PPPoE clients on ${context.routerId}: ${total} total, showing ${clients.length} (offset ${parsed.offset})`
|
|
8548
|
-
];
|
|
8549
|
-
for (const c of clients) {
|
|
8550
|
-
const name = c.name ?? "unknown";
|
|
8551
|
-
const iface = c.interface ?? "unknown";
|
|
8552
|
-
const user = c.user ?? "-";
|
|
8553
|
-
const status = isRunning(c) ? "connected" : "disconnected";
|
|
8554
|
-
lines.push(` ${name} [${iface}] user=${user} ${status}`);
|
|
8555
|
-
}
|
|
8392
|
+
const { items: clients, total, hasMore } = paginate(filtered, parsed.offset, parsed.limit);
|
|
8556
8393
|
return {
|
|
8557
|
-
content:
|
|
8394
|
+
content: listSummary("PPPoE clients", context.routerId, clients.length, total, parsed.offset),
|
|
8558
8395
|
structuredContent: {
|
|
8559
8396
|
routerId: context.routerId,
|
|
8560
8397
|
clients,
|
|
@@ -8565,26 +8402,26 @@ var listPppoeClientsTool = {
|
|
|
8565
8402
|
}
|
|
8566
8403
|
};
|
|
8567
8404
|
} catch (err) {
|
|
8568
|
-
throw
|
|
8405
|
+
throw toolError(err, context, "list_pppoe_clients");
|
|
8569
8406
|
}
|
|
8570
8407
|
}
|
|
8571
8408
|
};
|
|
8572
|
-
var managePppoeClientInputSchema =
|
|
8573
|
-
routerId
|
|
8574
|
-
action:
|
|
8575
|
-
name:
|
|
8576
|
-
interface:
|
|
8577
|
-
user:
|
|
8578
|
-
password:
|
|
8579
|
-
serviceName:
|
|
8580
|
-
addDefaultRoute:
|
|
8581
|
-
dialOnDemand:
|
|
8582
|
-
dryRun
|
|
8409
|
+
var managePppoeClientInputSchema = z37.object({
|
|
8410
|
+
routerId,
|
|
8411
|
+
action: z37.enum(["add", "update", "remove"]).describe("Action to perform"),
|
|
8412
|
+
name: z37.string().describe("PPPoE client interface name \u2014 idempotency key (e.g. pppoe-wan)"),
|
|
8413
|
+
interface: z37.string().optional().describe("Parent interface (required for add)"),
|
|
8414
|
+
user: z37.string().optional().describe("PPPoE username (required for add)"),
|
|
8415
|
+
password: z37.string().optional().describe("PPPoE password (never logged)"),
|
|
8416
|
+
serviceName: z37.string().optional().describe("PPPoE service name filter (leave empty to match any)"),
|
|
8417
|
+
addDefaultRoute: z37.boolean().optional().describe("Add default route via PPPoE (yes/no)"),
|
|
8418
|
+
dialOnDemand: z37.boolean().optional().describe("Dial on demand instead of always-on (yes/no)"),
|
|
8419
|
+
dryRun
|
|
8583
8420
|
}).strict();
|
|
8584
8421
|
var managePppoeClientTool = {
|
|
8585
8422
|
name: "manage_pppoe_client",
|
|
8586
8423
|
title: "Manage PPPoE Client",
|
|
8587
|
-
description: "Add, update, or remove a PPPoE client interface. Idempotent by name
|
|
8424
|
+
description: "Add, update, or remove a PPPoE client interface. Idempotent by name (already_exists on matching name+interface+user; CONFLICT on differing config; no_change when an update differs in nothing). Password is always written when provided since RouterOS does not return it on GET.",
|
|
8588
8425
|
inputSchema: managePppoeClientInputSchema,
|
|
8589
8426
|
annotations: {
|
|
8590
8427
|
readOnlyHint: false,
|
|
@@ -8775,22 +8612,21 @@ var managePppoeClientTool = {
|
|
|
8775
8612
|
structuredContent: { action: "removed", name: parsed.name, id: existing[".id"] }
|
|
8776
8613
|
};
|
|
8777
8614
|
} catch (err) {
|
|
8778
|
-
|
|
8779
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_pppoe_client" });
|
|
8615
|
+
throw toolError(err, context, "manage_pppoe_client");
|
|
8780
8616
|
}
|
|
8781
8617
|
}
|
|
8782
8618
|
};
|
|
8783
8619
|
var pppoeTools = [listPppoeClientsTool, managePppoeClientTool];
|
|
8784
8620
|
|
|
8785
8621
|
// src/domain/tools/ovpn-tools.ts
|
|
8786
|
-
import { z as
|
|
8622
|
+
import { z as z38 } from "zod";
|
|
8787
8623
|
var log38 = createLogger("ovpn-tools");
|
|
8788
8624
|
var OVPN_CLIENT_PATH = "interface/ovpn-client";
|
|
8789
8625
|
var OVPN_SERVER_PATH = "interface/ovpn-server/server";
|
|
8790
|
-
var listOvpnClientsInputSchema =
|
|
8791
|
-
routerId
|
|
8792
|
-
limit
|
|
8793
|
-
offset
|
|
8626
|
+
var listOvpnClientsInputSchema = z38.object({
|
|
8627
|
+
routerId,
|
|
8628
|
+
limit,
|
|
8629
|
+
offset
|
|
8794
8630
|
}).strict();
|
|
8795
8631
|
var listOvpnClientsTool = {
|
|
8796
8632
|
name: "list_ovpn_clients",
|
|
@@ -8811,9 +8647,7 @@ var listOvpnClientsTool = {
|
|
|
8811
8647
|
limit: void 0,
|
|
8812
8648
|
offset: void 0
|
|
8813
8649
|
});
|
|
8814
|
-
const total = allClients.
|
|
8815
|
-
const clients = allClients.slice(parsed.offset, parsed.offset + parsed.limit);
|
|
8816
|
-
const hasMore = parsed.offset + parsed.limit < total;
|
|
8650
|
+
const { items: clients, total, hasMore } = paginate(allClients, parsed.offset, parsed.limit);
|
|
8817
8651
|
return {
|
|
8818
8652
|
content: `OpenVPN clients on ${context.routerId}: ${total} total, showing ${clients.length} (offset ${parsed.offset})`,
|
|
8819
8653
|
structuredContent: {
|
|
@@ -8826,27 +8660,27 @@ var listOvpnClientsTool = {
|
|
|
8826
8660
|
}
|
|
8827
8661
|
};
|
|
8828
8662
|
} catch (err) {
|
|
8829
|
-
throw
|
|
8663
|
+
throw toolError(err, context, "list_ovpn_clients");
|
|
8830
8664
|
}
|
|
8831
8665
|
}
|
|
8832
8666
|
};
|
|
8833
|
-
var manageOvpnClientInputSchema =
|
|
8834
|
-
routerId
|
|
8835
|
-
action:
|
|
8836
|
-
name:
|
|
8837
|
-
connectTo:
|
|
8838
|
-
port:
|
|
8839
|
-
mode:
|
|
8840
|
-
protocol:
|
|
8841
|
-
certificate:
|
|
8842
|
-
user:
|
|
8843
|
-
password:
|
|
8844
|
-
dryRun
|
|
8667
|
+
var manageOvpnClientInputSchema = z38.object({
|
|
8668
|
+
routerId,
|
|
8669
|
+
action: z38.enum(["add", "update", "remove"]).describe("Action to perform"),
|
|
8670
|
+
name: z38.string().describe("OpenVPN client interface name \u2014 idempotency key"),
|
|
8671
|
+
connectTo: z38.string().optional().describe("Remote server address (required for add)"),
|
|
8672
|
+
port: z38.number().int().min(1).max(65535).optional().describe("Remote port number"),
|
|
8673
|
+
mode: z38.enum(["ip", "ethernet"]).optional().describe("Tunnel mode"),
|
|
8674
|
+
protocol: z38.enum(["tcp-client", "udp"]).optional().describe("Transport protocol"),
|
|
8675
|
+
certificate: z38.string().optional().describe("Client certificate name"),
|
|
8676
|
+
user: z38.string().optional().describe("VPN username"),
|
|
8677
|
+
password: z38.string().optional().describe("VPN password (never logged)"),
|
|
8678
|
+
dryRun
|
|
8845
8679
|
}).strict();
|
|
8846
8680
|
var manageOvpnClientTool = {
|
|
8847
8681
|
name: "manage_ovpn_client",
|
|
8848
8682
|
title: "Manage OpenVPN Client",
|
|
8849
|
-
description: "Add, update, or remove an OpenVPN client interface. Idempotent by name
|
|
8683
|
+
description: "Add, update, or remove an OpenVPN client interface. Idempotent by name (already_exists on matching name+connectTo; CONFLICT on differing connectTo; no_change when an update differs in nothing). Password is always written when provided since RouterOS does not return it on GET.",
|
|
8850
8684
|
inputSchema: manageOvpnClientInputSchema,
|
|
8851
8685
|
annotations: {
|
|
8852
8686
|
readOnlyHint: false,
|
|
@@ -9013,21 +8847,20 @@ var manageOvpnClientTool = {
|
|
|
9013
8847
|
structuredContent: { action: "removed", name: parsed.name, id: existing[".id"] }
|
|
9014
8848
|
};
|
|
9015
8849
|
} catch (err) {
|
|
9016
|
-
|
|
9017
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_ovpn_client" });
|
|
8850
|
+
throw toolError(err, context, "manage_ovpn_client");
|
|
9018
8851
|
}
|
|
9019
8852
|
}
|
|
9020
8853
|
};
|
|
9021
|
-
var getOvpnServerInputSchema =
|
|
9022
|
-
routerId
|
|
8854
|
+
var getOvpnServerInputSchema = z38.object({
|
|
8855
|
+
routerId
|
|
9023
8856
|
}).strict();
|
|
9024
|
-
function fetchOvpnServer(allRecords,
|
|
8857
|
+
function fetchOvpnServer(allRecords, routerId2) {
|
|
9025
8858
|
if (allRecords.length === 0) {
|
|
9026
8859
|
throw new MikroMCPError({
|
|
9027
8860
|
category: "NOT_FOUND" /* NOT_FOUND */,
|
|
9028
8861
|
code: "OVPN_SERVER_NOT_FOUND",
|
|
9029
8862
|
message: "OpenVPN server not found. The OpenVPN package may not be installed on this router.",
|
|
9030
|
-
details: { routerId },
|
|
8863
|
+
details: { routerId: routerId2 },
|
|
9031
8864
|
recoverability: {
|
|
9032
8865
|
retryable: false,
|
|
9033
8866
|
suggestedAction: "Install the OpenVPN package via manage_package.",
|
|
@@ -9049,39 +8882,38 @@ var getOvpnServerTool = {
|
|
|
9049
8882
|
openWorldHint: false
|
|
9050
8883
|
},
|
|
9051
8884
|
async handler(params, context) {
|
|
9052
|
-
|
|
8885
|
+
getOvpnServerInputSchema.parse(params);
|
|
9053
8886
|
log38.info({ routerId: context.routerId }, "Getting OpenVPN server configuration");
|
|
9054
8887
|
try {
|
|
9055
8888
|
const records = await context.routerClient.get(OVPN_SERVER_PATH, {
|
|
9056
8889
|
limit: void 0,
|
|
9057
8890
|
offset: void 0
|
|
9058
8891
|
});
|
|
9059
|
-
const server = fetchOvpnServer(records,
|
|
8892
|
+
const server = fetchOvpnServer(records, context.routerId);
|
|
9060
8893
|
return {
|
|
9061
8894
|
content: `OpenVPN server on ${context.routerId}: enabled=${server.enabled}, port=${server.port}, protocol=${server.protocol}`,
|
|
9062
8895
|
structuredContent: { routerId: context.routerId, server }
|
|
9063
8896
|
};
|
|
9064
8897
|
} catch (err) {
|
|
9065
|
-
|
|
9066
|
-
throw enrichError(err, { routerId: context.routerId, tool: "get_ovpn_server" });
|
|
8898
|
+
throw toolError(err, context, "get_ovpn_server");
|
|
9067
8899
|
}
|
|
9068
8900
|
}
|
|
9069
8901
|
};
|
|
9070
|
-
var manageOvpnServerInputSchema =
|
|
9071
|
-
routerId
|
|
9072
|
-
action:
|
|
9073
|
-
port:
|
|
9074
|
-
mode:
|
|
9075
|
-
protocol:
|
|
9076
|
-
certificate:
|
|
9077
|
-
cipher:
|
|
9078
|
-
auth:
|
|
9079
|
-
dryRun
|
|
8902
|
+
var manageOvpnServerInputSchema = z38.object({
|
|
8903
|
+
routerId,
|
|
8904
|
+
action: z38.enum(["enable", "disable", "set"]).describe("Action to perform"),
|
|
8905
|
+
port: z38.number().int().min(1).max(65535).optional().describe("Listening port (set action only)"),
|
|
8906
|
+
mode: z38.enum(["ip", "ethernet"]).optional().describe("Tunnel mode (set action only)"),
|
|
8907
|
+
protocol: z38.enum(["tcp-server", "udp"]).optional().describe("Transport protocol (set action only)"),
|
|
8908
|
+
certificate: z38.string().optional().describe("Server certificate name (set action only)"),
|
|
8909
|
+
cipher: z38.enum(["blowfish128", "aes128-cbc", "aes192-cbc", "aes256-cbc", "aes128-gcm", "aes256-gcm", "none"]).optional().describe("Encryption cipher (set action only)"),
|
|
8910
|
+
auth: z38.enum(["md5", "sha1", "sha256", "sha512", "null"]).optional().describe("Authentication algorithm (set action only)"),
|
|
8911
|
+
dryRun
|
|
9080
8912
|
}).strict();
|
|
9081
8913
|
var manageOvpnServerTool = {
|
|
9082
8914
|
name: "manage_ovpn_server",
|
|
9083
8915
|
title: "Manage OpenVPN Server",
|
|
9084
|
-
description: "Enable, disable, or configure the OpenVPN server
|
|
8916
|
+
description: "Enable, disable, or configure the OpenVPN server (a per-router singleton). Throws NOT_FOUND if the OpenVPN package is not installed. The set action requires at least one configuration field.",
|
|
9085
8917
|
inputSchema: manageOvpnServerInputSchema,
|
|
9086
8918
|
annotations: {
|
|
9087
8919
|
readOnlyHint: false,
|
|
@@ -9098,7 +8930,7 @@ var manageOvpnServerTool = {
|
|
|
9098
8930
|
limit: void 0,
|
|
9099
8931
|
offset: void 0
|
|
9100
8932
|
});
|
|
9101
|
-
const server = fetchOvpnServer(records,
|
|
8933
|
+
const server = fetchOvpnServer(records, context.routerId);
|
|
9102
8934
|
const serverId = server[".id"];
|
|
9103
8935
|
if (parsed.action === "enable" || parsed.action === "disable") {
|
|
9104
8936
|
const desiredEnabled = parsed.action === "enable";
|
|
@@ -9186,8 +9018,7 @@ var manageOvpnServerTool = {
|
|
|
9186
9018
|
structuredContent: { action: "updated", diff }
|
|
9187
9019
|
};
|
|
9188
9020
|
} catch (err) {
|
|
9189
|
-
|
|
9190
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_ovpn_server" });
|
|
9021
|
+
throw toolError(err, context, "manage_ovpn_server");
|
|
9191
9022
|
}
|
|
9192
9023
|
}
|
|
9193
9024
|
};
|
|
@@ -9199,12 +9030,12 @@ var ovpnTools = [
|
|
|
9199
9030
|
];
|
|
9200
9031
|
|
|
9201
9032
|
// src/domain/tools/ppp-tools.ts
|
|
9202
|
-
import { z as
|
|
9033
|
+
import { z as z39 } from "zod";
|
|
9203
9034
|
var log39 = createLogger("ppp-tools");
|
|
9204
|
-
var listPppProfilesInputSchema =
|
|
9205
|
-
routerId
|
|
9206
|
-
name:
|
|
9207
|
-
limit
|
|
9035
|
+
var listPppProfilesInputSchema = z39.object({
|
|
9036
|
+
routerId,
|
|
9037
|
+
name: z39.string().optional().describe("Filter by profile name (exact match)"),
|
|
9038
|
+
limit
|
|
9208
9039
|
}).strict();
|
|
9209
9040
|
var listPppProfilesTool = {
|
|
9210
9041
|
name: "list_ppp_profiles",
|
|
@@ -9224,22 +9055,21 @@ var listPppProfilesTool = {
|
|
|
9224
9055
|
structuredContent: { routerId: context.routerId, profiles, total: all.length, returned: profiles.length }
|
|
9225
9056
|
};
|
|
9226
9057
|
} catch (err) {
|
|
9227
|
-
|
|
9228
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_ppp_profiles" });
|
|
9058
|
+
throw toolError(err, context, "list_ppp_profiles");
|
|
9229
9059
|
}
|
|
9230
9060
|
}
|
|
9231
9061
|
};
|
|
9232
|
-
var managePppProfileInputSchema =
|
|
9233
|
-
routerId
|
|
9234
|
-
action:
|
|
9235
|
-
name:
|
|
9236
|
-
localAddress:
|
|
9237
|
-
remoteAddress:
|
|
9238
|
-
dnsServer:
|
|
9239
|
-
rateLimit:
|
|
9240
|
-
sessionTimeout:
|
|
9241
|
-
comment:
|
|
9242
|
-
dryRun
|
|
9062
|
+
var managePppProfileInputSchema = z39.object({
|
|
9063
|
+
routerId,
|
|
9064
|
+
action: z39.enum(["add", "update", "remove"]).describe("Action to perform"),
|
|
9065
|
+
name: z39.string().describe("Profile name \u2014 idempotency key"),
|
|
9066
|
+
localAddress: z39.string().optional().describe("Local IP assigned to router end of PPP link"),
|
|
9067
|
+
remoteAddress: z39.string().optional().describe("IP or pool name assigned to client"),
|
|
9068
|
+
dnsServer: z39.string().optional().describe("DNS server IP pushed to client"),
|
|
9069
|
+
rateLimit: z39.string().optional().describe("Rate limit string (e.g. '10M/10M')"),
|
|
9070
|
+
sessionTimeout: z39.string().optional().describe("Session timeout duration string (e.g. '1h')"),
|
|
9071
|
+
comment: z39.string().optional().describe("Optional comment"),
|
|
9072
|
+
dryRun
|
|
9243
9073
|
}).strict();
|
|
9244
9074
|
var managePppProfileTool = {
|
|
9245
9075
|
name: "manage_ppp_profile",
|
|
@@ -9364,18 +9194,17 @@ var managePppProfileTool = {
|
|
|
9364
9194
|
structuredContent: { action: "removed", name: parsed.name, id: existing[".id"] }
|
|
9365
9195
|
};
|
|
9366
9196
|
} catch (err) {
|
|
9367
|
-
|
|
9368
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_ppp_profile" });
|
|
9197
|
+
throw toolError(err, context, "manage_ppp_profile");
|
|
9369
9198
|
}
|
|
9370
9199
|
}
|
|
9371
9200
|
};
|
|
9372
9201
|
var pppTools = [listPppProfilesTool, managePppProfileTool];
|
|
9373
9202
|
|
|
9374
9203
|
// src/domain/tools/upgrade-tools.ts
|
|
9375
|
-
import { z as
|
|
9204
|
+
import { z as z40 } from "zod";
|
|
9376
9205
|
var log40 = createLogger("upgrade-tools");
|
|
9377
|
-
var getUpgradeStatusInputSchema =
|
|
9378
|
-
routerId
|
|
9206
|
+
var getUpgradeStatusInputSchema = z40.object({
|
|
9207
|
+
routerId
|
|
9379
9208
|
}).strict();
|
|
9380
9209
|
var getUpgradeStatusTool = {
|
|
9381
9210
|
name: "get_upgrade_status",
|
|
@@ -9415,16 +9244,16 @@ var getUpgradeStatusTool = {
|
|
|
9415
9244
|
}
|
|
9416
9245
|
};
|
|
9417
9246
|
} catch (err) {
|
|
9418
|
-
throw
|
|
9247
|
+
throw toolError(err, context, "get_upgrade_status");
|
|
9419
9248
|
}
|
|
9420
9249
|
}
|
|
9421
9250
|
};
|
|
9422
|
-
var manageUpgradeInputSchema =
|
|
9423
|
-
routerId
|
|
9424
|
-
action:
|
|
9251
|
+
var manageUpgradeInputSchema = z40.object({
|
|
9252
|
+
routerId,
|
|
9253
|
+
action: z40.enum(["check", "install"]).describe(
|
|
9425
9254
|
"check \u2014 trigger a check for available updates; install \u2014 download and install the latest update (triggers reboot)"
|
|
9426
9255
|
),
|
|
9427
|
-
dryRun:
|
|
9256
|
+
dryRun: z40.boolean().default(false).describe("Preview the action without executing")
|
|
9428
9257
|
}).strict();
|
|
9429
9258
|
var manageUpgradeTool = {
|
|
9430
9259
|
name: "manage_upgrade",
|
|
@@ -9466,20 +9295,20 @@ var manageUpgradeTool = {
|
|
|
9466
9295
|
structuredContent: { action: "install_triggered", routerId: parsed.routerId }
|
|
9467
9296
|
};
|
|
9468
9297
|
} catch (err) {
|
|
9469
|
-
throw
|
|
9298
|
+
throw toolError(err, context, "manage_upgrade");
|
|
9470
9299
|
}
|
|
9471
9300
|
}
|
|
9472
9301
|
};
|
|
9473
9302
|
var upgradeTools = [getUpgradeStatusTool, manageUpgradeTool];
|
|
9474
9303
|
|
|
9475
9304
|
// src/domain/tools/backup-tools.ts
|
|
9476
|
-
import { z as
|
|
9305
|
+
import { z as z41 } from "zod";
|
|
9477
9306
|
var log41 = createLogger("backup-tools");
|
|
9478
|
-
var createBackupInputSchema =
|
|
9479
|
-
routerId
|
|
9480
|
-
name:
|
|
9481
|
-
password:
|
|
9482
|
-
dryRun:
|
|
9307
|
+
var createBackupInputSchema = z41.object({
|
|
9308
|
+
routerId,
|
|
9309
|
+
name: z41.string().default("backup").describe("Backup file name (without extension)"),
|
|
9310
|
+
password: z41.string().optional().describe("Password to encrypt the backup file"),
|
|
9311
|
+
dryRun: z41.boolean().default(false).describe("Preview the backup without creating it")
|
|
9483
9312
|
}).strict();
|
|
9484
9313
|
var createBackupTool = {
|
|
9485
9314
|
name: "create_backup",
|
|
@@ -9517,15 +9346,14 @@ var createBackupTool = {
|
|
|
9517
9346
|
}
|
|
9518
9347
|
};
|
|
9519
9348
|
} catch (err) {
|
|
9520
|
-
|
|
9521
|
-
throw enrichError(err, { routerId: context.routerId, tool: "create_backup" });
|
|
9349
|
+
throw toolError(err, context, "create_backup");
|
|
9522
9350
|
}
|
|
9523
9351
|
}
|
|
9524
9352
|
};
|
|
9525
|
-
var exportConfigInputSchema =
|
|
9526
|
-
routerId
|
|
9527
|
-
compact:
|
|
9528
|
-
file:
|
|
9353
|
+
var exportConfigInputSchema = z41.object({
|
|
9354
|
+
routerId,
|
|
9355
|
+
compact: z41.boolean().default(false).describe("Export only non-default settings (compact format)"),
|
|
9356
|
+
file: z41.string().optional().describe("Save the export to a file on the router (without extension); omit to return inline")
|
|
9529
9357
|
}).strict();
|
|
9530
9358
|
var exportConfigTool = {
|
|
9531
9359
|
name: "export_config",
|
|
@@ -9566,24 +9394,23 @@ ${scriptText}`,
|
|
|
9566
9394
|
}
|
|
9567
9395
|
};
|
|
9568
9396
|
} catch (err) {
|
|
9569
|
-
|
|
9570
|
-
throw enrichError(err, { routerId: context.routerId, tool: "export_config" });
|
|
9397
|
+
throw toolError(err, context, "export_config");
|
|
9571
9398
|
}
|
|
9572
9399
|
}
|
|
9573
9400
|
};
|
|
9574
9401
|
var backupTools = [createBackupTool, exportConfigTool];
|
|
9575
9402
|
|
|
9576
9403
|
// src/domain/tools/log-tools.ts
|
|
9577
|
-
import { z as
|
|
9404
|
+
import { z as z42 } from "zod";
|
|
9578
9405
|
var log42 = createLogger("log-tools");
|
|
9579
9406
|
var LOG_RULES_PATH = "system/logging";
|
|
9580
9407
|
var LOG_ACTIONS_PATH = "system/logging/action";
|
|
9581
|
-
var logActionTypeEnum =
|
|
9582
|
-
var listLogRulesInputSchema =
|
|
9583
|
-
routerId
|
|
9584
|
-
topics:
|
|
9585
|
-
logAction:
|
|
9586
|
-
limit
|
|
9408
|
+
var logActionTypeEnum = z42.enum(["memory", "disk", "remote", "echo", "email"]);
|
|
9409
|
+
var listLogRulesInputSchema = z42.object({
|
|
9410
|
+
routerId,
|
|
9411
|
+
topics: z42.string().optional().describe("Filter by topics (substring match)"),
|
|
9412
|
+
logAction: z42.string().optional().describe("Filter by log action target (exact match on action field)"),
|
|
9413
|
+
limit
|
|
9587
9414
|
}).strict();
|
|
9588
9415
|
var listLogRulesTool = {
|
|
9589
9416
|
name: "list_log_rules",
|
|
@@ -9622,23 +9449,22 @@ var listLogRulesTool = {
|
|
|
9622
9449
|
}
|
|
9623
9450
|
};
|
|
9624
9451
|
} catch (err) {
|
|
9625
|
-
|
|
9626
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_log_rules" });
|
|
9452
|
+
throw toolError(err, context, "list_log_rules");
|
|
9627
9453
|
}
|
|
9628
9454
|
}
|
|
9629
9455
|
};
|
|
9630
|
-
var manageLogRuleInputSchema =
|
|
9631
|
-
routerId
|
|
9632
|
-
action:
|
|
9633
|
-
topics:
|
|
9634
|
-
logAction:
|
|
9635
|
-
prefix:
|
|
9636
|
-
dryRun
|
|
9456
|
+
var manageLogRuleInputSchema = z42.object({
|
|
9457
|
+
routerId,
|
|
9458
|
+
action: z42.enum(["add", "remove", "enable", "disable"]).describe("Action to perform"),
|
|
9459
|
+
topics: z42.string().describe("Log topics (e.g. firewall, system, info) \u2014 idempotency key"),
|
|
9460
|
+
logAction: z42.string().describe("Log action target name (RouterOS action field) \u2014 idempotency key"),
|
|
9461
|
+
prefix: z42.string().optional().describe("Optional prefix to prepend to log messages"),
|
|
9462
|
+
dryRun
|
|
9637
9463
|
}).strict();
|
|
9638
9464
|
var manageLogRuleTool = {
|
|
9639
9465
|
name: "manage_log_rule",
|
|
9640
9466
|
title: "Manage Log Rule",
|
|
9641
|
-
description: "Add, remove, enable, or disable a RouterOS logging rule. Idempotent by topics+logAction
|
|
9467
|
+
description: "Add, remove, enable, or disable a RouterOS logging rule. Idempotent by topics+logAction (add \u2192 already_exists on match; remove \u2192 not_found handled gracefully; enable/disable throw NOT_FOUND when absent). Supports dry-run.",
|
|
9642
9468
|
inputSchema: manageLogRuleInputSchema,
|
|
9643
9469
|
annotations: {
|
|
9644
9470
|
readOnlyHint: false,
|
|
@@ -9771,15 +9597,14 @@ var manageLogRuleTool = {
|
|
|
9771
9597
|
}
|
|
9772
9598
|
});
|
|
9773
9599
|
} catch (err) {
|
|
9774
|
-
|
|
9775
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_log_rule" });
|
|
9600
|
+
throw toolError(err, context, "manage_log_rule");
|
|
9776
9601
|
}
|
|
9777
9602
|
}
|
|
9778
9603
|
};
|
|
9779
|
-
var listLogActionsInputSchema =
|
|
9780
|
-
routerId
|
|
9604
|
+
var listLogActionsInputSchema = z42.object({
|
|
9605
|
+
routerId,
|
|
9781
9606
|
type: logActionTypeEnum.optional().describe("Filter by action type (exact match): memory, disk, remote, echo, email"),
|
|
9782
|
-
limit
|
|
9607
|
+
limit
|
|
9783
9608
|
}).strict();
|
|
9784
9609
|
var listLogActionsTool = {
|
|
9785
9610
|
name: "list_log_actions",
|
|
@@ -9815,20 +9640,19 @@ var listLogActionsTool = {
|
|
|
9815
9640
|
}
|
|
9816
9641
|
};
|
|
9817
9642
|
} catch (err) {
|
|
9818
|
-
|
|
9819
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_log_actions" });
|
|
9643
|
+
throw toolError(err, context, "list_log_actions");
|
|
9820
9644
|
}
|
|
9821
9645
|
}
|
|
9822
9646
|
};
|
|
9823
|
-
var manageLogActionInputSchema =
|
|
9824
|
-
routerId
|
|
9825
|
-
action:
|
|
9826
|
-
name:
|
|
9647
|
+
var manageLogActionInputSchema = z42.object({
|
|
9648
|
+
routerId,
|
|
9649
|
+
action: z42.enum(["add", "remove"]).describe("Action to perform"),
|
|
9650
|
+
name: z42.string().describe("Log action name \u2014 idempotency key"),
|
|
9827
9651
|
type: logActionTypeEnum.optional().describe("Action type: memory, disk, remote, echo, email (required on add)"),
|
|
9828
|
-
remote:
|
|
9829
|
-
remotePort:
|
|
9830
|
-
diskFileName:
|
|
9831
|
-
dryRun
|
|
9652
|
+
remote: z42.string().optional().describe("Remote syslog server address (for type=remote)"),
|
|
9653
|
+
remotePort: z42.number().int().min(1).max(65535).optional().describe("Remote syslog server port (for type=remote)"),
|
|
9654
|
+
diskFileName: z42.string().optional().describe("Disk log file name without extension (for type=disk)"),
|
|
9655
|
+
dryRun
|
|
9832
9656
|
}).strict();
|
|
9833
9657
|
var manageLogActionTool = {
|
|
9834
9658
|
name: "manage_log_action",
|
|
@@ -9944,8 +9768,7 @@ var manageLogActionTool = {
|
|
|
9944
9768
|
}
|
|
9945
9769
|
});
|
|
9946
9770
|
} catch (err) {
|
|
9947
|
-
|
|
9948
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_log_action" });
|
|
9771
|
+
throw toolError(err, context, "manage_log_action");
|
|
9949
9772
|
}
|
|
9950
9773
|
}
|
|
9951
9774
|
};
|
|
@@ -9957,15 +9780,15 @@ var logTools = [
|
|
|
9957
9780
|
];
|
|
9958
9781
|
|
|
9959
9782
|
// src/domain/tools/network-test-tools.ts
|
|
9960
|
-
import { z as
|
|
9783
|
+
import { z as z43 } from "zod";
|
|
9961
9784
|
var log43 = createLogger("network-test-tools");
|
|
9962
9785
|
var BODY_CAP = 65536;
|
|
9963
|
-
var bandwidthTestInputSchema =
|
|
9964
|
-
routerId
|
|
9965
|
-
address:
|
|
9966
|
-
protocol:
|
|
9967
|
-
direction:
|
|
9968
|
-
duration:
|
|
9786
|
+
var bandwidthTestInputSchema = z43.object({
|
|
9787
|
+
routerId,
|
|
9788
|
+
address: z43.string().describe("Remote host running RouterOS btest server"),
|
|
9789
|
+
protocol: z43.enum(["tcp", "udp"]).default("tcp").describe("Test protocol"),
|
|
9790
|
+
direction: z43.enum(["send", "receive", "both"]).default("both").describe("Test direction"),
|
|
9791
|
+
duration: z43.number().int().min(1).max(30).default(5).describe("Test duration in seconds (max 30)")
|
|
9969
9792
|
}).strict();
|
|
9970
9793
|
var bandwidthTestTool = {
|
|
9971
9794
|
name: "bandwidth_test",
|
|
@@ -10000,16 +9823,16 @@ var bandwidthTestTool = {
|
|
|
10000
9823
|
}
|
|
10001
9824
|
};
|
|
10002
9825
|
} catch (err) {
|
|
10003
|
-
throw
|
|
9826
|
+
throw toolError(err, context, "bandwidth_test");
|
|
10004
9827
|
}
|
|
10005
9828
|
}
|
|
10006
9829
|
};
|
|
10007
|
-
var fetchUrlInputSchema =
|
|
10008
|
-
routerId
|
|
10009
|
-
url:
|
|
10010
|
-
method:
|
|
10011
|
-
httpData:
|
|
10012
|
-
outputFile:
|
|
9830
|
+
var fetchUrlInputSchema = z43.object({
|
|
9831
|
+
routerId,
|
|
9832
|
+
url: z43.string().url().describe("URL to fetch from the router"),
|
|
9833
|
+
method: z43.enum(["GET", "POST"]).default("GET").describe("HTTP method"),
|
|
9834
|
+
httpData: z43.string().optional().describe("Request body for POST"),
|
|
9835
|
+
outputFile: z43.string().optional().describe("Save response body to this router file path instead of returning inline")
|
|
10013
9836
|
}).strict();
|
|
10014
9837
|
var fetchUrlTool = {
|
|
10015
9838
|
name: "fetch_url",
|
|
@@ -10047,16 +9870,16 @@ var fetchUrlTool = {
|
|
|
10047
9870
|
structuredContent: { routerId: context.routerId, url: parsed.url, statusCode, body: responseBody }
|
|
10048
9871
|
};
|
|
10049
9872
|
} catch (err) {
|
|
10050
|
-
throw
|
|
9873
|
+
throw toolError(err, context, "fetch_url");
|
|
10051
9874
|
}
|
|
10052
9875
|
}
|
|
10053
9876
|
};
|
|
10054
|
-
var listConnectionsInputSchema =
|
|
10055
|
-
routerId
|
|
10056
|
-
srcAddress:
|
|
10057
|
-
dstAddress:
|
|
10058
|
-
protocol:
|
|
10059
|
-
limit
|
|
9877
|
+
var listConnectionsInputSchema = z43.object({
|
|
9878
|
+
routerId,
|
|
9879
|
+
srcAddress: z43.string().optional().describe("Filter by source address (substring match)"),
|
|
9880
|
+
dstAddress: z43.string().optional().describe("Filter by destination address (substring match)"),
|
|
9881
|
+
protocol: z43.string().optional().describe("Filter by protocol (exact match, e.g. tcp, udp, icmp)"),
|
|
9882
|
+
limit
|
|
10060
9883
|
}).strict();
|
|
10061
9884
|
var listConnectionsTool = {
|
|
10062
9885
|
name: "list_connections",
|
|
@@ -10079,16 +9902,16 @@ var listConnectionsTool = {
|
|
|
10079
9902
|
structuredContent: { routerId: context.routerId, connections, total: all.length, returned: connections.length }
|
|
10080
9903
|
};
|
|
10081
9904
|
} catch (err) {
|
|
10082
|
-
throw
|
|
9905
|
+
throw toolError(err, context, "list_connections");
|
|
10083
9906
|
}
|
|
10084
9907
|
}
|
|
10085
9908
|
};
|
|
10086
9909
|
var networkTestTools = [bandwidthTestTool, fetchUrlTool, listConnectionsTool];
|
|
10087
9910
|
|
|
10088
9911
|
// src/domain/tools/container-config-tools.ts
|
|
10089
|
-
import { z as
|
|
9912
|
+
import { z as z44 } from "zod";
|
|
10090
9913
|
var log44 = createLogger("container-config-tools");
|
|
10091
|
-
var getContainerConfigInputSchema =
|
|
9914
|
+
var getContainerConfigInputSchema = z44.object({ routerId }).strict();
|
|
10092
9915
|
var getContainerConfigTool = {
|
|
10093
9916
|
name: "get_container_config",
|
|
10094
9917
|
title: "Get Container Config",
|
|
@@ -10111,16 +9934,16 @@ var getContainerConfigTool = {
|
|
|
10111
9934
|
}
|
|
10112
9935
|
};
|
|
10113
9936
|
} catch (err) {
|
|
10114
|
-
throw
|
|
9937
|
+
throw toolError(err, context, "get_container_config");
|
|
10115
9938
|
}
|
|
10116
9939
|
}
|
|
10117
9940
|
};
|
|
10118
|
-
var manageContainerConfigInputSchema =
|
|
10119
|
-
routerId
|
|
10120
|
-
registryUrl:
|
|
10121
|
-
ramHighMb:
|
|
10122
|
-
vethInterface:
|
|
10123
|
-
dryRun
|
|
9941
|
+
var manageContainerConfigInputSchema = z44.object({
|
|
9942
|
+
routerId,
|
|
9943
|
+
registryUrl: z44.string().optional().describe("Container registry URL"),
|
|
9944
|
+
ramHighMb: z44.number().int().min(1).optional().describe("RAM high-water mark in MB"),
|
|
9945
|
+
vethInterface: z44.string().optional().describe("Veth interface name for container networking"),
|
|
9946
|
+
dryRun
|
|
10124
9947
|
}).strict();
|
|
10125
9948
|
var manageContainerConfigTool = {
|
|
10126
9949
|
name: "manage_container_config",
|
|
@@ -10172,14 +9995,14 @@ var manageContainerConfigTool = {
|
|
|
10172
9995
|
structuredContent: { action: "updated", routerId: context.routerId, diff }
|
|
10173
9996
|
};
|
|
10174
9997
|
} catch (err) {
|
|
10175
|
-
throw
|
|
9998
|
+
throw toolError(err, context, "manage_container_config");
|
|
10176
9999
|
}
|
|
10177
10000
|
}
|
|
10178
10001
|
};
|
|
10179
|
-
var listContainerEnvsInputSchema =
|
|
10180
|
-
routerId
|
|
10181
|
-
name:
|
|
10182
|
-
limit
|
|
10002
|
+
var listContainerEnvsInputSchema = z44.object({
|
|
10003
|
+
routerId,
|
|
10004
|
+
name: z44.string().optional().describe("Filter by container name (exact match)"),
|
|
10005
|
+
limit
|
|
10183
10006
|
}).strict();
|
|
10184
10007
|
var listContainerEnvsTool = {
|
|
10185
10008
|
name: "list_container_envs",
|
|
@@ -10202,17 +10025,17 @@ var listContainerEnvsTool = {
|
|
|
10202
10025
|
structuredContent: { routerId: context.routerId, envs, total: all.length, returned: envs.length }
|
|
10203
10026
|
};
|
|
10204
10027
|
} catch (err) {
|
|
10205
|
-
throw
|
|
10028
|
+
throw toolError(err, context, "list_container_envs");
|
|
10206
10029
|
}
|
|
10207
10030
|
}
|
|
10208
10031
|
};
|
|
10209
|
-
var manageContainerEnvInputSchema =
|
|
10210
|
-
routerId
|
|
10211
|
-
action:
|
|
10212
|
-
name:
|
|
10213
|
-
key:
|
|
10214
|
-
value:
|
|
10215
|
-
dryRun
|
|
10032
|
+
var manageContainerEnvInputSchema = z44.object({
|
|
10033
|
+
routerId,
|
|
10034
|
+
action: z44.enum(["add", "remove"]).describe("Action to perform"),
|
|
10035
|
+
name: z44.string().describe("Container name"),
|
|
10036
|
+
key: z44.string().describe("Environment variable name \u2014 part of idempotency key"),
|
|
10037
|
+
value: z44.string().optional().describe("Environment variable value (required for add)"),
|
|
10038
|
+
dryRun
|
|
10216
10039
|
}).strict();
|
|
10217
10040
|
var manageContainerEnvTool = {
|
|
10218
10041
|
name: "manage_container_env",
|
|
@@ -10309,15 +10132,14 @@ var manageContainerEnvTool = {
|
|
|
10309
10132
|
structuredContent: { action: "removed", name: parsed.name, key: parsed.key }
|
|
10310
10133
|
};
|
|
10311
10134
|
} catch (err) {
|
|
10312
|
-
|
|
10313
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_container_env" });
|
|
10135
|
+
throw toolError(err, context, "manage_container_env");
|
|
10314
10136
|
}
|
|
10315
10137
|
}
|
|
10316
10138
|
};
|
|
10317
|
-
var listContainerMountsInputSchema =
|
|
10318
|
-
routerId
|
|
10319
|
-
name:
|
|
10320
|
-
limit
|
|
10139
|
+
var listContainerMountsInputSchema = z44.object({
|
|
10140
|
+
routerId,
|
|
10141
|
+
name: z44.string().optional().describe("Filter by mount name (exact match)"),
|
|
10142
|
+
limit
|
|
10321
10143
|
}).strict();
|
|
10322
10144
|
var listContainerMountsTool = {
|
|
10323
10145
|
name: "list_container_mounts",
|
|
@@ -10340,17 +10162,17 @@ var listContainerMountsTool = {
|
|
|
10340
10162
|
structuredContent: { routerId: context.routerId, mounts, total: all.length, returned: mounts.length }
|
|
10341
10163
|
};
|
|
10342
10164
|
} catch (err) {
|
|
10343
|
-
throw
|
|
10165
|
+
throw toolError(err, context, "list_container_mounts");
|
|
10344
10166
|
}
|
|
10345
10167
|
}
|
|
10346
10168
|
};
|
|
10347
|
-
var manageContainerMountInputSchema =
|
|
10348
|
-
routerId
|
|
10349
|
-
action:
|
|
10350
|
-
name:
|
|
10351
|
-
src:
|
|
10352
|
-
dst:
|
|
10353
|
-
dryRun
|
|
10169
|
+
var manageContainerMountInputSchema = z44.object({
|
|
10170
|
+
routerId,
|
|
10171
|
+
action: z44.enum(["add", "remove"]).describe("Action to perform"),
|
|
10172
|
+
name: z44.string().describe("Mount name \u2014 idempotency key"),
|
|
10173
|
+
src: z44.string().optional().describe("Host source path (required for add)"),
|
|
10174
|
+
dst: z44.string().optional().describe("Container destination path (required for add)"),
|
|
10175
|
+
dryRun
|
|
10354
10176
|
}).strict();
|
|
10355
10177
|
var manageContainerMountTool = {
|
|
10356
10178
|
name: "manage_container_mount",
|
|
@@ -10440,8 +10262,7 @@ var manageContainerMountTool = {
|
|
|
10440
10262
|
structuredContent: { action: "removed", name: parsed.name }
|
|
10441
10263
|
};
|
|
10442
10264
|
} catch (err) {
|
|
10443
|
-
|
|
10444
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_container_mount" });
|
|
10265
|
+
throw toolError(err, context, "manage_container_mount");
|
|
10445
10266
|
}
|
|
10446
10267
|
}
|
|
10447
10268
|
};
|
|
@@ -10455,11 +10276,11 @@ var containerConfigTools = [
|
|
|
10455
10276
|
];
|
|
10456
10277
|
|
|
10457
10278
|
// src/domain/tools/interface-list-tools.ts
|
|
10458
|
-
import { z as
|
|
10279
|
+
import { z as z45 } from "zod";
|
|
10459
10280
|
var log45 = createLogger("interface-list-tools");
|
|
10460
|
-
var listInterfaceListsInputSchema =
|
|
10461
|
-
routerId
|
|
10462
|
-
limit
|
|
10281
|
+
var listInterfaceListsInputSchema = z45.object({
|
|
10282
|
+
routerId,
|
|
10283
|
+
limit
|
|
10463
10284
|
}).strict();
|
|
10464
10285
|
var listInterfaceListsTool = {
|
|
10465
10286
|
name: "list_interface_lists",
|
|
@@ -10481,17 +10302,16 @@ var listInterfaceListsTool = {
|
|
|
10481
10302
|
structuredContent: { routerId: context.routerId, lists, total: all.length, returned: lists.length }
|
|
10482
10303
|
};
|
|
10483
10304
|
} catch (err) {
|
|
10484
|
-
|
|
10485
|
-
throw enrichError(err, { routerId: context.routerId, tool: "list_interface_lists" });
|
|
10305
|
+
throw toolError(err, context, "list_interface_lists");
|
|
10486
10306
|
}
|
|
10487
10307
|
}
|
|
10488
10308
|
};
|
|
10489
|
-
var manageInterfaceListInputSchema =
|
|
10490
|
-
routerId
|
|
10491
|
-
action:
|
|
10492
|
-
name:
|
|
10493
|
-
comment:
|
|
10494
|
-
dryRun
|
|
10309
|
+
var manageInterfaceListInputSchema = z45.object({
|
|
10310
|
+
routerId,
|
|
10311
|
+
action: z45.enum(["add", "remove"]).describe("Action to perform"),
|
|
10312
|
+
name: z45.string().describe("Interface list name \u2014 idempotency key"),
|
|
10313
|
+
comment: z45.string().optional().describe("Optional comment"),
|
|
10314
|
+
dryRun
|
|
10495
10315
|
}).strict();
|
|
10496
10316
|
var manageInterfaceListTool = {
|
|
10497
10317
|
name: "manage_interface_list",
|
|
@@ -10555,18 +10375,17 @@ var manageInterfaceListTool = {
|
|
|
10555
10375
|
structuredContent: { action: "removed", name: parsed.name, id: existing[".id"] }
|
|
10556
10376
|
};
|
|
10557
10377
|
} catch (err) {
|
|
10558
|
-
|
|
10559
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_interface_list" });
|
|
10378
|
+
throw toolError(err, context, "manage_interface_list");
|
|
10560
10379
|
}
|
|
10561
10380
|
}
|
|
10562
10381
|
};
|
|
10563
|
-
var manageInterfaceListMemberInputSchema =
|
|
10564
|
-
routerId
|
|
10565
|
-
action:
|
|
10566
|
-
list:
|
|
10567
|
-
interface:
|
|
10568
|
-
comment:
|
|
10569
|
-
dryRun
|
|
10382
|
+
var manageInterfaceListMemberInputSchema = z45.object({
|
|
10383
|
+
routerId,
|
|
10384
|
+
action: z45.enum(["add", "remove"]).describe("Action to perform"),
|
|
10385
|
+
list: z45.string().describe("Interface list name \u2014 part of composite idempotency key"),
|
|
10386
|
+
interface: z45.string().describe("Interface name to add/remove \u2014 part of composite idempotency key"),
|
|
10387
|
+
comment: z45.string().optional().describe("Optional comment"),
|
|
10388
|
+
dryRun
|
|
10570
10389
|
}).strict();
|
|
10571
10390
|
var manageInterfaceListMemberTool = {
|
|
10572
10391
|
name: "manage_interface_list_member",
|
|
@@ -10640,8 +10459,7 @@ var manageInterfaceListMemberTool = {
|
|
|
10640
10459
|
}
|
|
10641
10460
|
};
|
|
10642
10461
|
} catch (err) {
|
|
10643
|
-
|
|
10644
|
-
throw enrichError(err, { routerId: context.routerId, tool: "manage_interface_list_member" });
|
|
10462
|
+
throw toolError(err, context, "manage_interface_list_member");
|
|
10645
10463
|
}
|
|
10646
10464
|
}
|
|
10647
10465
|
};
|
|
@@ -10652,7 +10470,7 @@ var interfaceListTools = [
|
|
|
10652
10470
|
];
|
|
10653
10471
|
|
|
10654
10472
|
// src/domain/tools/fleet-tools.ts
|
|
10655
|
-
import { z as
|
|
10473
|
+
import { z as z46 } from "zod";
|
|
10656
10474
|
|
|
10657
10475
|
// src/middleware/authz.ts
|
|
10658
10476
|
function matchesPattern(name, pattern) {
|
|
@@ -10660,16 +10478,16 @@ function matchesPattern(name, pattern) {
|
|
|
10660
10478
|
const prefix = pattern.slice(0, pattern.indexOf("*"));
|
|
10661
10479
|
return name.startsWith(prefix);
|
|
10662
10480
|
}
|
|
10663
|
-
function checkAuthz(identity, toolName,
|
|
10664
|
-
if (identity.allowedRouters.length > 0 && !identity.allowedRouters.includes(
|
|
10481
|
+
function checkAuthz(identity, toolName, routerId2) {
|
|
10482
|
+
if (identity.allowedRouters.length > 0 && !identity.allowedRouters.includes(routerId2)) {
|
|
10665
10483
|
throw new MikroMCPError({
|
|
10666
10484
|
category: "PERMISSION_DENIED" /* PERMISSION_DENIED */,
|
|
10667
10485
|
code: "ROUTER_NOT_ALLOWED",
|
|
10668
|
-
message: `Identity "${identity.id}" is not allowed to access router "${
|
|
10669
|
-
details: { identityId: identity.id, routerId, allowedRouters: identity.allowedRouters },
|
|
10486
|
+
message: `Identity "${identity.id}" is not allowed to access router "${routerId2}".`,
|
|
10487
|
+
details: { identityId: identity.id, routerId: routerId2, allowedRouters: identity.allowedRouters },
|
|
10670
10488
|
recoverability: {
|
|
10671
10489
|
retryable: false,
|
|
10672
|
-
suggestedAction: `Add "${
|
|
10490
|
+
suggestedAction: `Add "${routerId2}" to allowedRouters for identity "${identity.id}" in identities.yaml.`
|
|
10673
10491
|
}
|
|
10674
10492
|
});
|
|
10675
10493
|
}
|
|
@@ -10952,16 +10770,16 @@ function checkFleetConfirmation(args, secret) {
|
|
|
10952
10770
|
|
|
10953
10771
|
// src/domain/tools/fleet-tools.ts
|
|
10954
10772
|
var log47 = createLogger("fleet-tools");
|
|
10955
|
-
var checkHealthInputSchema =
|
|
10956
|
-
routerId
|
|
10773
|
+
var checkHealthInputSchema = z46.object({
|
|
10774
|
+
routerId
|
|
10957
10775
|
}).strict();
|
|
10958
|
-
var bulkExecuteInputSchema =
|
|
10959
|
-
toolName:
|
|
10960
|
-
routerIds:
|
|
10961
|
-
tags:
|
|
10962
|
-
params:
|
|
10963
|
-
concurrency:
|
|
10964
|
-
confirmationToken:
|
|
10776
|
+
var bulkExecuteInputSchema = z46.object({
|
|
10777
|
+
toolName: z46.string().describe("Name of the tool to fan out (must be a single-router tool)"),
|
|
10778
|
+
routerIds: z46.array(z46.string()).optional().describe("Explicit list of router IDs to target"),
|
|
10779
|
+
tags: z46.array(z46.string()).optional().describe("Target all routers with ALL of these tags (mutually exclusive with routerIds)"),
|
|
10780
|
+
params: z46.record(z46.string(), z46.unknown()).describe("Params to pass to the tool (omit routerId \u2014 injected per router)"),
|
|
10781
|
+
concurrency: z46.number().int().min(1).max(20).default(5).describe("Max simultaneous router calls"),
|
|
10782
|
+
confirmationToken: z46.string().optional().describe(
|
|
10965
10783
|
"Fleet confirmation token from a prior APPROVAL_REQUIRED response. Required to fan out a destructive tool."
|
|
10966
10784
|
)
|
|
10967
10785
|
}).strict();
|
|
@@ -11018,7 +10836,7 @@ function createFleetTools(baseTools2) {
|
|
|
11018
10836
|
const bulkExecuteTool = {
|
|
11019
10837
|
name: "bulk_execute",
|
|
11020
10838
|
title: "Bulk Execute",
|
|
11021
|
-
description: "Fan out a single-router tool to
|
|
10839
|
+
description: "Fan out a single-router tool to many routers in parallel (up to `concurrency`), targeted by routerIds or tag. Destructive tools need two-step confirmation: call without `confirmationToken` to get a fleet token (needs MIKROMCP_CONFIRMATION_SECRET), then re-call with it. Writes snapshot+journal each router for rollback. Returns per-router results with succeeded/failed counts.",
|
|
11022
10840
|
inputSchema: bulkExecuteInputSchema,
|
|
11023
10841
|
annotations: {
|
|
11024
10842
|
readOnlyHint: false,
|
|
@@ -11150,8 +10968,12 @@ function createFleetTools(baseTools2) {
|
|
|
11150
10968
|
}
|
|
11151
10969
|
};
|
|
11152
10970
|
}
|
|
10971
|
+
const isWrite = !targetTool.annotations.readOnlyHint;
|
|
10972
|
+
const snapshotDir = context.appConfig.snapshotDir;
|
|
10973
|
+
const journalPath = context.appConfig.journalPath;
|
|
11153
10974
|
async function runForRouter(router) {
|
|
11154
10975
|
const start = Date.now();
|
|
10976
|
+
let journalId;
|
|
11155
10977
|
try {
|
|
11156
10978
|
checkAuthz(context.identity, parsed.toolName, router.id);
|
|
11157
10979
|
const routerContext = buildRouterToolContext({
|
|
@@ -11163,11 +10985,44 @@ function createFleetTools(baseTools2) {
|
|
|
11163
10985
|
registry: context.routerRegistry
|
|
11164
10986
|
});
|
|
11165
10987
|
const toolParams = { ...parsed.params, routerId: router.id };
|
|
10988
|
+
const snapshotIds = [];
|
|
10989
|
+
if (isWrite && targetTool.snapshotPaths && targetTool.snapshotPaths.length > 0) {
|
|
10990
|
+
for (const path of targetTool.snapshotPaths) {
|
|
10991
|
+
try {
|
|
10992
|
+
const meta = await takeSnapshot(
|
|
10993
|
+
routerContext.routerClient,
|
|
10994
|
+
router.id,
|
|
10995
|
+
path,
|
|
10996
|
+
snapshotDir
|
|
10997
|
+
);
|
|
10998
|
+
snapshotIds.push(meta.id);
|
|
10999
|
+
} catch (err) {
|
|
11000
|
+
log47.warn(
|
|
11001
|
+
{ err, path, routerId: router.id },
|
|
11002
|
+
"bulk_execute snapshot failed \u2014 proceeding without snapshot"
|
|
11003
|
+
);
|
|
11004
|
+
}
|
|
11005
|
+
}
|
|
11006
|
+
}
|
|
11007
|
+
if (isWrite && journalPath) {
|
|
11008
|
+
journalId = recordAttempt({
|
|
11009
|
+
journalPath,
|
|
11010
|
+
identityId: context.identity.id,
|
|
11011
|
+
role: context.identity.role,
|
|
11012
|
+
tool: parsed.toolName,
|
|
11013
|
+
routerId: router.id,
|
|
11014
|
+
params: toolParams,
|
|
11015
|
+
snapshotIds
|
|
11016
|
+
});
|
|
11017
|
+
}
|
|
11166
11018
|
const result = await targetTool.handler(
|
|
11167
11019
|
toolParams,
|
|
11168
11020
|
routerContext
|
|
11169
11021
|
);
|
|
11170
11022
|
const elapsed = Date.now() - start;
|
|
11023
|
+
if (journalId) {
|
|
11024
|
+
recordOutcome({ journalPath, journalId, phase: "success", durationMs: elapsed });
|
|
11025
|
+
}
|
|
11171
11026
|
auditLog({
|
|
11172
11027
|
type: "audit",
|
|
11173
11028
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -11184,6 +11039,9 @@ function createFleetTools(baseTools2) {
|
|
|
11184
11039
|
} catch (err) {
|
|
11185
11040
|
const elapsed = Date.now() - start;
|
|
11186
11041
|
const message = err instanceof Error ? err.message : String(err);
|
|
11042
|
+
if (journalId) {
|
|
11043
|
+
recordOutcome({ journalPath, journalId, phase: "failure", outcome: message, durationMs: elapsed });
|
|
11044
|
+
}
|
|
11187
11045
|
auditLog({
|
|
11188
11046
|
type: "audit",
|
|
11189
11047
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -11378,8 +11236,8 @@ function computeParamHash(params) {
|
|
|
11378
11236
|
const { confirmationToken: _, ...rest } = params;
|
|
11379
11237
|
return createHash3("sha256").update(JSON.stringify(rest)).digest("hex");
|
|
11380
11238
|
}
|
|
11381
|
-
function computeToken(tool,
|
|
11382
|
-
const payload = JSON.stringify({ tool, routerId, paramHash, identityId, expiresAt });
|
|
11239
|
+
function computeToken(tool, routerId2, identityId, paramHash, expiresAt, secret) {
|
|
11240
|
+
const payload = JSON.stringify({ tool, routerId: routerId2, paramHash, identityId, expiresAt });
|
|
11383
11241
|
return createHmac2("sha256", secret).update(payload).digest("hex");
|
|
11384
11242
|
}
|
|
11385
11243
|
function evictExpired2() {
|
|
@@ -11388,7 +11246,7 @@ function evictExpired2() {
|
|
|
11388
11246
|
if (entry.expiresAt <= now) pendingConfirmations.delete(token);
|
|
11389
11247
|
}
|
|
11390
11248
|
}
|
|
11391
|
-
async function checkConfirmation(toolName,
|
|
11249
|
+
async function checkConfirmation(toolName, routerId2, params, identity, secret) {
|
|
11392
11250
|
if (BYPASS_ROLES.includes(identity.role)) return;
|
|
11393
11251
|
evictExpired2();
|
|
11394
11252
|
const submittedToken = typeof params.confirmationToken === "string" ? params.confirmationToken : null;
|
|
@@ -11406,7 +11264,7 @@ async function checkConfirmation(toolName, routerId, params, identity, secret) {
|
|
|
11406
11264
|
});
|
|
11407
11265
|
}
|
|
11408
11266
|
const currentParamHash = computeParamHash(params);
|
|
11409
|
-
if (entry.tool !== toolName || entry.routerId !==
|
|
11267
|
+
if (entry.tool !== toolName || entry.routerId !== routerId2 || entry.identityId !== identity.id || entry.paramHash !== currentParamHash) {
|
|
11410
11268
|
throw new MikroMCPError({
|
|
11411
11269
|
category: "PERMISSION_DENIED" /* PERMISSION_DENIED */,
|
|
11412
11270
|
code: "CONFIRMATION_MISMATCH",
|
|
@@ -11422,11 +11280,11 @@ async function checkConfirmation(toolName, routerId, params, identity, secret) {
|
|
|
11422
11280
|
}
|
|
11423
11281
|
const expiresAt = new Date(Date.now() + CONFIRMATION_TTL_MS2).toISOString();
|
|
11424
11282
|
const paramHash = computeParamHash(params);
|
|
11425
|
-
const token = computeToken(toolName,
|
|
11283
|
+
const token = computeToken(toolName, routerId2, identity.id, paramHash, expiresAt, secret);
|
|
11426
11284
|
pendingConfirmations.set(token, {
|
|
11427
11285
|
expiresAt: new Date(expiresAt),
|
|
11428
11286
|
tool: toolName,
|
|
11429
|
-
routerId,
|
|
11287
|
+
routerId: routerId2,
|
|
11430
11288
|
identityId: identity.id,
|
|
11431
11289
|
paramHash
|
|
11432
11290
|
});
|
|
@@ -11438,7 +11296,7 @@ async function checkConfirmation(toolName, routerId, params, identity, secret) {
|
|
|
11438
11296
|
confirmationToken: token,
|
|
11439
11297
|
expiresAt,
|
|
11440
11298
|
tool: toolName,
|
|
11441
|
-
routerId
|
|
11299
|
+
routerId: routerId2
|
|
11442
11300
|
},
|
|
11443
11301
|
recoverability: {
|
|
11444
11302
|
retryable: true,
|
|
@@ -11578,8 +11436,8 @@ var DEFAULTS2 = {
|
|
|
11578
11436
|
cooldownMs: 3e4
|
|
11579
11437
|
};
|
|
11580
11438
|
var CircuitBreaker = class {
|
|
11581
|
-
constructor(
|
|
11582
|
-
this.routerId =
|
|
11439
|
+
constructor(routerId2, options) {
|
|
11440
|
+
this.routerId = routerId2;
|
|
11583
11441
|
this.options = { ...DEFAULTS2, ...options };
|
|
11584
11442
|
}
|
|
11585
11443
|
routerId;
|
|
@@ -11588,15 +11446,22 @@ var CircuitBreaker = class {
|
|
|
11588
11446
|
consecutiveFailures = 0;
|
|
11589
11447
|
lastFailureTime = 0;
|
|
11590
11448
|
probeInFlight = false;
|
|
11449
|
+
/** Effective state, accounting for an elapsed cooldown. Pure — does not mutate. */
|
|
11591
11450
|
get state() {
|
|
11592
|
-
if (this.currentState === "open") {
|
|
11593
|
-
|
|
11594
|
-
if (elapsed >= this.options.cooldownMs) {
|
|
11595
|
-
this.currentState = "half-open";
|
|
11596
|
-
}
|
|
11451
|
+
if (this.currentState === "open" && this.cooldownElapsed()) {
|
|
11452
|
+
return "half-open";
|
|
11597
11453
|
}
|
|
11598
11454
|
return this.currentState;
|
|
11599
11455
|
}
|
|
11456
|
+
cooldownElapsed() {
|
|
11457
|
+
return Date.now() - this.lastFailureTime >= this.options.cooldownMs;
|
|
11458
|
+
}
|
|
11459
|
+
/** Apply the time-based open→half-open transition. Call before acting on state. */
|
|
11460
|
+
transitionIfCooldownElapsed() {
|
|
11461
|
+
if (this.currentState === "open" && this.cooldownElapsed()) {
|
|
11462
|
+
this.currentState = "half-open";
|
|
11463
|
+
}
|
|
11464
|
+
}
|
|
11600
11465
|
/**
|
|
11601
11466
|
* Execute `fn` through the circuit breaker.
|
|
11602
11467
|
*
|
|
@@ -11605,7 +11470,8 @@ var CircuitBreaker = class {
|
|
|
11605
11470
|
* - **half-open**: execute as a probe; success closes, failure reopens.
|
|
11606
11471
|
*/
|
|
11607
11472
|
async execute(fn) {
|
|
11608
|
-
|
|
11473
|
+
this.transitionIfCooldownElapsed();
|
|
11474
|
+
const currentState = this.currentState;
|
|
11609
11475
|
if (currentState === "open") {
|
|
11610
11476
|
throw new MikroMCPError({
|
|
11611
11477
|
category: "ROUTER_BUSY" /* ROUTER_BUSY */,
|
|
@@ -11677,6 +11543,26 @@ var CircuitBreaker = class {
|
|
|
11677
11543
|
|
|
11678
11544
|
// src/mcp/tool-executor.ts
|
|
11679
11545
|
var log48 = createLogger("tool-executor");
|
|
11546
|
+
function resolveRouterId(explicit, registry, config) {
|
|
11547
|
+
if (explicit) {
|
|
11548
|
+
return explicit;
|
|
11549
|
+
}
|
|
11550
|
+
const fallback = config.defaultRouter ?? registry.soleRouterId();
|
|
11551
|
+
if (fallback) {
|
|
11552
|
+
return fallback;
|
|
11553
|
+
}
|
|
11554
|
+
const available = registry.routerIds();
|
|
11555
|
+
throw new MikroMCPError({
|
|
11556
|
+
category: "VALIDATION" /* VALIDATION */,
|
|
11557
|
+
code: "MISSING_ROUTER_ID",
|
|
11558
|
+
message: available.length > 0 ? `routerId is required: more than one router is configured. Available: ${available.join(", ")}.` : "routerId is required, but no routers are configured.",
|
|
11559
|
+
details: { availableRouters: available },
|
|
11560
|
+
recoverability: {
|
|
11561
|
+
retryable: false,
|
|
11562
|
+
suggestedAction: available.length > 0 ? "Provide a routerId, or set MIKROMCP_DEFAULT_ROUTER to choose a default." : "Configure at least one router in routers.yaml."
|
|
11563
|
+
}
|
|
11564
|
+
});
|
|
11565
|
+
}
|
|
11680
11566
|
async function executeToolCall(tool, args, deps) {
|
|
11681
11567
|
const { registry, pool, circuitBreakers, config, identityRegistry } = deps;
|
|
11682
11568
|
const correlationId = nanoid4();
|
|
@@ -11702,27 +11588,17 @@ async function executeToolCall(tool, args, deps) {
|
|
|
11702
11588
|
recordToolCall(tool.name, "success");
|
|
11703
11589
|
return formatToolResult(fleetResult);
|
|
11704
11590
|
}
|
|
11705
|
-
const
|
|
11706
|
-
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
code: "MISSING_ROUTER_ID",
|
|
11710
|
-
message: "routerId is required",
|
|
11711
|
-
recoverability: {
|
|
11712
|
-
retryable: false,
|
|
11713
|
-
suggestedAction: "Provide a valid routerId parameter."
|
|
11714
|
-
}
|
|
11715
|
-
});
|
|
11716
|
-
}
|
|
11717
|
-
checkAuthz(identity, tool.name, routerId);
|
|
11718
|
-
const routerConfig = registry.getRouter(routerId);
|
|
11591
|
+
const routerId2 = resolveRouterId(args.routerId, registry, config);
|
|
11592
|
+
args.routerId = routerId2;
|
|
11593
|
+
checkAuthz(identity, tool.name, routerId2);
|
|
11594
|
+
const routerConfig = registry.getRouter(routerId2);
|
|
11719
11595
|
if (tool.annotations.destructiveHint) {
|
|
11720
11596
|
const windows = routerConfig.maintenanceWindows;
|
|
11721
11597
|
if (windows && windows.length > 0 && !isWithinMaintenanceWindow(windows, /* @__PURE__ */ new Date())) {
|
|
11722
11598
|
throw new MikroMCPError({
|
|
11723
11599
|
category: "PERMISSION_DENIED" /* PERMISSION_DENIED */,
|
|
11724
11600
|
code: "OUTSIDE_MAINTENANCE_WINDOW",
|
|
11725
|
-
message: `Router "${
|
|
11601
|
+
message: `Router "${routerId2}" has maintenance windows configured. Destructive operations are only permitted during scheduled windows.`,
|
|
11726
11602
|
details: { maintenanceWindows: windows },
|
|
11727
11603
|
recoverability: {
|
|
11728
11604
|
retryable: true,
|
|
@@ -11732,7 +11608,7 @@ async function executeToolCall(tool, args, deps) {
|
|
|
11732
11608
|
}
|
|
11733
11609
|
}
|
|
11734
11610
|
if (tool.annotations.destructiveHint && config.confirmationSecret) {
|
|
11735
|
-
await checkConfirmation(tool.name,
|
|
11611
|
+
await checkConfirmation(tool.name, routerId2, args, identity, config.confirmationSecret);
|
|
11736
11612
|
}
|
|
11737
11613
|
const shouldAudit = tool.annotations.destructiveHint || !tool.annotations.readOnlyHint;
|
|
11738
11614
|
if (shouldAudit) {
|
|
@@ -11743,7 +11619,7 @@ async function executeToolCall(tool, args, deps) {
|
|
|
11743
11619
|
identityId: identity.id,
|
|
11744
11620
|
role: identity.role,
|
|
11745
11621
|
tool: tool.name,
|
|
11746
|
-
routerId,
|
|
11622
|
+
routerId: routerId2,
|
|
11747
11623
|
phase: "attempt",
|
|
11748
11624
|
params: args
|
|
11749
11625
|
}, config.auditLogPath);
|
|
@@ -11756,13 +11632,13 @@ async function executeToolCall(tool, args, deps) {
|
|
|
11756
11632
|
config,
|
|
11757
11633
|
registry
|
|
11758
11634
|
});
|
|
11759
|
-
let cb = circuitBreakers.get(
|
|
11635
|
+
let cb = circuitBreakers.get(routerId2);
|
|
11760
11636
|
if (!cb) {
|
|
11761
|
-
cb = new CircuitBreaker(
|
|
11637
|
+
cb = new CircuitBreaker(routerId2, {
|
|
11762
11638
|
failureThreshold: config.circuitBreaker.failureThreshold,
|
|
11763
11639
|
cooldownMs: config.circuitBreaker.cooldownMs
|
|
11764
11640
|
});
|
|
11765
|
-
circuitBreakers.set(
|
|
11641
|
+
circuitBreakers.set(routerId2, cb);
|
|
11766
11642
|
}
|
|
11767
11643
|
toolContext.circuitBreaker = cb;
|
|
11768
11644
|
const { confirmationToken: _ct, ...handlerArgs } = args;
|
|
@@ -11770,11 +11646,11 @@ async function executeToolCall(tool, args, deps) {
|
|
|
11770
11646
|
if (tool.snapshotPaths && tool.snapshotPaths.length > 0 && !tool.annotations.readOnlyHint) {
|
|
11771
11647
|
for (const path of tool.snapshotPaths) {
|
|
11772
11648
|
try {
|
|
11773
|
-
const meta = await takeSnapshot(toolContext.routerClient,
|
|
11649
|
+
const meta = await takeSnapshot(toolContext.routerClient, routerId2, path, config.snapshotDir);
|
|
11774
11650
|
snapshotIds.push(meta.id);
|
|
11775
11651
|
log48.debug({ snapshotId: meta.id, path }, "Snapshot taken");
|
|
11776
11652
|
} catch (err) {
|
|
11777
|
-
log48.warn({ err, path, routerId }, "Snapshot failed \u2014 proceeding without snapshot");
|
|
11653
|
+
log48.warn({ err, path, routerId: routerId2 }, "Snapshot failed \u2014 proceeding without snapshot");
|
|
11778
11654
|
}
|
|
11779
11655
|
}
|
|
11780
11656
|
}
|
|
@@ -11784,7 +11660,7 @@ async function executeToolCall(tool, args, deps) {
|
|
|
11784
11660
|
identityId: identity.id,
|
|
11785
11661
|
role: identity.role,
|
|
11786
11662
|
tool: tool.name,
|
|
11787
|
-
routerId,
|
|
11663
|
+
routerId: routerId2,
|
|
11788
11664
|
params: handlerArgs,
|
|
11789
11665
|
snapshotIds
|
|
11790
11666
|
});
|
|
@@ -11810,13 +11686,13 @@ async function executeToolCall(tool, args, deps) {
|
|
|
11810
11686
|
identityId: identity.id,
|
|
11811
11687
|
role: identity.role,
|
|
11812
11688
|
tool: tool.name,
|
|
11813
|
-
routerId,
|
|
11689
|
+
routerId: routerId2,
|
|
11814
11690
|
phase: "success",
|
|
11815
11691
|
params: args,
|
|
11816
11692
|
durationMs: Date.now() - startMs
|
|
11817
11693
|
}, config.auditLogPath);
|
|
11818
11694
|
}
|
|
11819
|
-
log48.info({ tool: tool.name, routerId, correlationId }, "Tool executed successfully");
|
|
11695
|
+
log48.info({ tool: tool.name, routerId: routerId2, correlationId }, "Tool executed successfully");
|
|
11820
11696
|
recordToolCall(tool.name, "success");
|
|
11821
11697
|
return formatToolResult(result);
|
|
11822
11698
|
} catch (err) {
|
|
@@ -11839,7 +11715,7 @@ async function executeToolCall(tool, args, deps) {
|
|
|
11839
11715
|
}
|
|
11840
11716
|
const shouldAudit = tool.annotations.destructiveHint || !tool.annotations.readOnlyHint;
|
|
11841
11717
|
if (shouldAudit && error.category !== "APPROVAL_REQUIRED" /* APPROVAL_REQUIRED */) {
|
|
11842
|
-
const
|
|
11718
|
+
const routerId2 = args.routerId ?? "unknown";
|
|
11843
11719
|
const identity = getCurrentIdentity() ?? getStdioIdentity(config.stdioIdentity, identityRegistry);
|
|
11844
11720
|
auditLog({
|
|
11845
11721
|
type: "audit",
|
|
@@ -11848,7 +11724,7 @@ async function executeToolCall(tool, args, deps) {
|
|
|
11848
11724
|
identityId: identity.id,
|
|
11849
11725
|
role: identity.role,
|
|
11850
11726
|
tool: tool.name,
|
|
11851
|
-
routerId,
|
|
11727
|
+
routerId: routerId2,
|
|
11852
11728
|
phase: "failure",
|
|
11853
11729
|
params: args,
|
|
11854
11730
|
outcome: error.code,
|
|
@@ -11868,7 +11744,7 @@ function registerAllTools(server, registry, pool, circuitBreakers, config, ident
|
|
|
11868
11744
|
const deps = { registry, pool, circuitBreakers, config, identityRegistry };
|
|
11869
11745
|
for (const tool of allTools) {
|
|
11870
11746
|
const registrationSchema = tool.annotations.destructiveHint ? tool.inputSchema.extend({
|
|
11871
|
-
confirmationToken:
|
|
11747
|
+
confirmationToken: z47.string().optional().describe(
|
|
11872
11748
|
"Token from a prior APPROVAL_REQUIRED response. Re-submit the identical call with this token to confirm the destructive action."
|
|
11873
11749
|
)
|
|
11874
11750
|
}) : tool.inputSchema;
|
|
@@ -11890,41 +11766,41 @@ function registerAllTools(server, registry, pool, circuitBreakers, config, ident
|
|
|
11890
11766
|
// src/config/router-registry.ts
|
|
11891
11767
|
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
11892
11768
|
import { parse } from "yaml";
|
|
11893
|
-
import { z as
|
|
11769
|
+
import { z as z48 } from "zod";
|
|
11894
11770
|
var log50 = createLogger("router-registry");
|
|
11895
|
-
var RouterConfigSchema =
|
|
11896
|
-
host:
|
|
11897
|
-
port:
|
|
11898
|
-
tls:
|
|
11899
|
-
enabled:
|
|
11900
|
-
rejectUnauthorized:
|
|
11901
|
-
ca:
|
|
11902
|
-
fingerprint:
|
|
11771
|
+
var RouterConfigSchema = z48.object({
|
|
11772
|
+
host: z48.string().min(1, "host is required"),
|
|
11773
|
+
port: z48.number().int().min(1).max(65535),
|
|
11774
|
+
tls: z48.object({
|
|
11775
|
+
enabled: z48.boolean(),
|
|
11776
|
+
rejectUnauthorized: z48.boolean(),
|
|
11777
|
+
ca: z48.string().optional(),
|
|
11778
|
+
fingerprint: z48.string().optional()
|
|
11903
11779
|
}).strict(),
|
|
11904
|
-
credentials:
|
|
11905
|
-
source:
|
|
11906
|
-
envPrefix:
|
|
11907
|
-
vaultPath:
|
|
11780
|
+
credentials: z48.object({
|
|
11781
|
+
source: z48.enum(["env", "vault"]),
|
|
11782
|
+
envPrefix: z48.string().optional(),
|
|
11783
|
+
vaultPath: z48.string().optional()
|
|
11908
11784
|
}).strict(),
|
|
11909
|
-
tags:
|
|
11910
|
-
rosVersion:
|
|
11911
|
-
sshPort:
|
|
11912
|
-
sshFingerprint:
|
|
11913
|
-
cmdAllow:
|
|
11914
|
-
cmdDeny:
|
|
11915
|
-
maintenanceWindows:
|
|
11916
|
-
|
|
11917
|
-
days:
|
|
11918
|
-
|
|
11785
|
+
tags: z48.array(z48.string()).default([]),
|
|
11786
|
+
rosVersion: z48.string().min(1),
|
|
11787
|
+
sshPort: z48.number().int().min(1).max(65535).optional(),
|
|
11788
|
+
sshFingerprint: z48.string().optional(),
|
|
11789
|
+
cmdAllow: z48.array(z48.string()).optional(),
|
|
11790
|
+
cmdDeny: z48.array(z48.string()).optional(),
|
|
11791
|
+
maintenanceWindows: z48.array(
|
|
11792
|
+
z48.object({
|
|
11793
|
+
days: z48.array(
|
|
11794
|
+
z48.enum(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"])
|
|
11919
11795
|
),
|
|
11920
|
-
startTime:
|
|
11921
|
-
endTime:
|
|
11922
|
-
timezone:
|
|
11796
|
+
startTime: z48.string().regex(/^\d{2}:\d{2}$/, "startTime must be HH:MM"),
|
|
11797
|
+
endTime: z48.string().regex(/^\d{2}:\d{2}$/, "endTime must be HH:MM"),
|
|
11798
|
+
timezone: z48.string().min(1)
|
|
11923
11799
|
}).strict()
|
|
11924
11800
|
).optional()
|
|
11925
11801
|
}).strict();
|
|
11926
|
-
var ConfigFileSchema =
|
|
11927
|
-
routers:
|
|
11802
|
+
var ConfigFileSchema = z48.object({
|
|
11803
|
+
routers: z48.record(z48.string(), RouterConfigSchema)
|
|
11928
11804
|
}).strict();
|
|
11929
11805
|
var RouterRegistry = class {
|
|
11930
11806
|
routers;
|
|
@@ -11969,6 +11845,14 @@ ${issues}`);
|
|
|
11969
11845
|
hasRouter(id) {
|
|
11970
11846
|
return this.routers.has(id);
|
|
11971
11847
|
}
|
|
11848
|
+
/** The id of the only configured router, or undefined when zero or more than one exist. */
|
|
11849
|
+
soleRouterId() {
|
|
11850
|
+
return this.routers.size === 1 ? this.routers.keys().next().value : void 0;
|
|
11851
|
+
}
|
|
11852
|
+
/** All configured router ids, for error messages and discovery. */
|
|
11853
|
+
routerIds() {
|
|
11854
|
+
return Array.from(this.routers.keys());
|
|
11855
|
+
}
|
|
11972
11856
|
};
|
|
11973
11857
|
|
|
11974
11858
|
// src/adapter/rest-client.ts
|
|
@@ -12064,10 +11948,10 @@ function buildListQuery(options) {
|
|
|
12064
11948
|
}
|
|
12065
11949
|
return { method: "GET" };
|
|
12066
11950
|
}
|
|
12067
|
-
function applyPagination(items,
|
|
11951
|
+
function applyPagination(items, limit2, offset2) {
|
|
12068
11952
|
const total = items.length;
|
|
12069
|
-
const start =
|
|
12070
|
-
const sliced =
|
|
11953
|
+
const start = offset2 ?? 0;
|
|
11954
|
+
const sliced = limit2 !== void 0 ? items.slice(start, start + limit2) : items.slice(start);
|
|
12071
11955
|
return {
|
|
12072
11956
|
items: sliced,
|
|
12073
11957
|
total,
|
|
@@ -12207,8 +12091,8 @@ var ConnectionPool = class {
|
|
|
12207
12091
|
* Perform a lightweight health check against a router by fetching
|
|
12208
12092
|
* `/rest/system/resource`. Returns `true` if the request succeeds.
|
|
12209
12093
|
*/
|
|
12210
|
-
async healthCheck(
|
|
12211
|
-
const client = this.clients.get(
|
|
12094
|
+
async healthCheck(routerId2) {
|
|
12095
|
+
const client = this.clients.get(routerId2);
|
|
12212
12096
|
if (!client) {
|
|
12213
12097
|
return false;
|
|
12214
12098
|
}
|
|
@@ -12220,11 +12104,11 @@ var ConnectionPool = class {
|
|
|
12220
12104
|
}
|
|
12221
12105
|
}
|
|
12222
12106
|
/** Remove and close a single client by router ID. */
|
|
12223
|
-
removeClient(
|
|
12224
|
-
const client = this.clients.get(
|
|
12107
|
+
removeClient(routerId2) {
|
|
12108
|
+
const client = this.clients.get(routerId2);
|
|
12225
12109
|
if (client) {
|
|
12226
12110
|
client.close();
|
|
12227
|
-
this.clients.delete(
|
|
12111
|
+
this.clients.delete(routerId2);
|
|
12228
12112
|
}
|
|
12229
12113
|
}
|
|
12230
12114
|
/** Close and remove all clients. */
|
|
@@ -12237,18 +12121,30 @@ var ConnectionPool = class {
|
|
|
12237
12121
|
};
|
|
12238
12122
|
|
|
12239
12123
|
// src/version.ts
|
|
12240
|
-
var VERSION = "1.
|
|
12124
|
+
var VERSION = "1.6.0";
|
|
12241
12125
|
|
|
12242
12126
|
// src/mcp/server.ts
|
|
12127
|
+
var SERVER_INSTRUCTIONS = [
|
|
12128
|
+
"MikroMCP manages MikroTik RouterOS devices.",
|
|
12129
|
+
"Reads are safe; treat writes as consequential \u2014 preview a write with dryRun:true and review the diff before applying.",
|
|
12130
|
+
"Destructive operations may require a two-step confirmation token.",
|
|
12131
|
+
"Writes are idempotent: already_exists and no_change are success, not errors.",
|
|
12132
|
+
"Prefer dedicated tools over run_command.",
|
|
12133
|
+
"routerId is optional when a default router is configured.",
|
|
12134
|
+
"For the full operating playbook, install the MikroMCP usage skill."
|
|
12135
|
+
].join(" ");
|
|
12243
12136
|
function createServerFactory(config, identityRegistry) {
|
|
12244
12137
|
const registry = new RouterRegistry(config.configPath);
|
|
12245
12138
|
const pool = new ConnectionPool();
|
|
12246
12139
|
const circuitBreakers = /* @__PURE__ */ new Map();
|
|
12247
12140
|
const makeServer = () => {
|
|
12248
|
-
const server = new McpServer(
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
|
|
12141
|
+
const server = new McpServer(
|
|
12142
|
+
{
|
|
12143
|
+
name: "mikromcp",
|
|
12144
|
+
version: VERSION
|
|
12145
|
+
},
|
|
12146
|
+
{ instructions: SERVER_INSTRUCTIONS }
|
|
12147
|
+
);
|
|
12252
12148
|
registerAllTools(server, registry, pool, circuitBreakers, config, identityRegistry);
|
|
12253
12149
|
return server;
|
|
12254
12150
|
};
|
|
@@ -12478,17 +12374,17 @@ async function handleMcpRequest(pathname, req, res, url, port, maxBodyBytes, mak
|
|
|
12478
12374
|
// src/config/identity-registry.ts
|
|
12479
12375
|
import { readFileSync as readFileSync4, existsSync as existsSync2 } from "fs";
|
|
12480
12376
|
import { parse as parse2 } from "yaml";
|
|
12481
|
-
import { z as
|
|
12377
|
+
import { z as z49 } from "zod";
|
|
12482
12378
|
import bcrypt from "bcryptjs";
|
|
12483
12379
|
var log52 = createLogger("identity-registry");
|
|
12484
|
-
var IdentityConfigSchema =
|
|
12485
|
-
token:
|
|
12486
|
-
role:
|
|
12487
|
-
allowedRouters:
|
|
12488
|
-
allowedToolPatterns:
|
|
12380
|
+
var IdentityConfigSchema = z49.object({
|
|
12381
|
+
token: z49.string().min(1, "token hash is required"),
|
|
12382
|
+
role: z49.enum(["readonly", "operator", "admin", "superadmin"]),
|
|
12383
|
+
allowedRouters: z49.array(z49.string()).default([]),
|
|
12384
|
+
allowedToolPatterns: z49.array(z49.string()).default([])
|
|
12489
12385
|
}).strict();
|
|
12490
|
-
var ConfigFileSchema2 =
|
|
12491
|
-
identities:
|
|
12386
|
+
var ConfigFileSchema2 = z49.object({
|
|
12387
|
+
identities: z49.record(z49.string(), IdentityConfigSchema)
|
|
12492
12388
|
}).strict();
|
|
12493
12389
|
var IdentityRegistry = class {
|
|
12494
12390
|
identities = [];
|
|
@@ -12636,7 +12532,7 @@ import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
|
|
|
12636
12532
|
import { homedir as homedir2 } from "os";
|
|
12637
12533
|
import * as net from "net";
|
|
12638
12534
|
import chalk from "chalk";
|
|
12639
|
-
var localVersion = "1.
|
|
12535
|
+
var localVersion = "1.6.0";
|
|
12640
12536
|
var results = [];
|
|
12641
12537
|
function ok(msg) {
|
|
12642
12538
|
console.log(chalk.green("\u2705 ") + msg);
|
|
@@ -12729,6 +12625,26 @@ function checkEnvVars(routers, transport2) {
|
|
|
12729
12625
|
warn("MIKROMCP_CONFIRMATION_SECRET not set \u2014 required in HTTP mode");
|
|
12730
12626
|
}
|
|
12731
12627
|
}
|
|
12628
|
+
function checkDefaultRouter(defaultRouter, routers) {
|
|
12629
|
+
const ids = routers.map((r) => r.id);
|
|
12630
|
+
if (defaultRouter) {
|
|
12631
|
+
if (ids.includes(defaultRouter)) {
|
|
12632
|
+
ok(`Default router: ${defaultRouter} (MIKROMCP_DEFAULT_ROUTER; used when routerId is omitted)`);
|
|
12633
|
+
} else {
|
|
12634
|
+
fail(
|
|
12635
|
+
`MIKROMCP_DEFAULT_ROUTER="${defaultRouter}" does not match any configured router` + (ids.length > 0 ? ` (available: ${ids.join(", ")})` : "")
|
|
12636
|
+
);
|
|
12637
|
+
}
|
|
12638
|
+
return;
|
|
12639
|
+
}
|
|
12640
|
+
if (routers.length === 1) {
|
|
12641
|
+
ok(`Default router: ${ids[0]} (sole configured router; used when routerId is omitted)`);
|
|
12642
|
+
} else if (routers.length > 1) {
|
|
12643
|
+
warn(
|
|
12644
|
+
`No MIKROMCP_DEFAULT_ROUTER set and ${routers.length} routers configured \u2014 tool calls must specify routerId (set MIKROMCP_DEFAULT_ROUTER to choose a default)`
|
|
12645
|
+
);
|
|
12646
|
+
}
|
|
12647
|
+
}
|
|
12732
12648
|
async function checkRouter(router) {
|
|
12733
12649
|
console.log();
|
|
12734
12650
|
console.log(chalk.bold(`Router: ${router.id} (${router.host})`));
|
|
@@ -12846,6 +12762,16 @@ function checkClaudeDesktop() {
|
|
|
12846
12762
|
warn(`Could not parse Claude Desktop config: ${err instanceof Error ? err.message : String(err)}`);
|
|
12847
12763
|
}
|
|
12848
12764
|
}
|
|
12765
|
+
function checkSkill() {
|
|
12766
|
+
const skillPath = `${homedir2()}/.claude/skills/mikromcp/SKILL.md`;
|
|
12767
|
+
if (existsSync3(skillPath)) {
|
|
12768
|
+
ok("Usage skill: installed (~/.claude/skills/mikromcp)");
|
|
12769
|
+
} else {
|
|
12770
|
+
warn(
|
|
12771
|
+
"Usage skill not installed at ~/.claude/skills/mikromcp \u2014 your AI assistant will lack MikroMCP operating guidance. See docs/wiki/Using-the-Skill.md"
|
|
12772
|
+
);
|
|
12773
|
+
}
|
|
12774
|
+
}
|
|
12849
12775
|
async function checkForUpdates() {
|
|
12850
12776
|
try {
|
|
12851
12777
|
const response = await fetch("https://registry.npmjs.org/mikromcp/latest", {
|
|
@@ -12883,12 +12809,16 @@ async function runDoctor() {
|
|
|
12883
12809
|
if (routers.length > 0) {
|
|
12884
12810
|
checkEnvVars(routers, appConfig.transport);
|
|
12885
12811
|
}
|
|
12812
|
+
if (routers.length > 0) {
|
|
12813
|
+
checkDefaultRouter(appConfig.defaultRouter, routers);
|
|
12814
|
+
}
|
|
12886
12815
|
for (const router of routers) {
|
|
12887
12816
|
await checkRouter(router);
|
|
12888
12817
|
}
|
|
12889
12818
|
console.log();
|
|
12890
12819
|
checkIdentities(appConfig.identitiesPath, appConfig.transport);
|
|
12891
12820
|
checkClaudeDesktop();
|
|
12821
|
+
checkSkill();
|
|
12892
12822
|
await checkForUpdates();
|
|
12893
12823
|
console.log();
|
|
12894
12824
|
console.log(chalk.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
@@ -12940,8 +12870,8 @@ function toYaml(obj) {
|
|
|
12940
12870
|
});
|
|
12941
12871
|
return doc.toString();
|
|
12942
12872
|
}
|
|
12943
|
-
function suggestEnvPrefix(
|
|
12944
|
-
return "ROUTER_" +
|
|
12873
|
+
function suggestEnvPrefix(routerId2) {
|
|
12874
|
+
return "ROUTER_" + routerId2.toUpperCase().replace(/-/g, "_");
|
|
12945
12875
|
}
|
|
12946
12876
|
function validateRouterId(val) {
|
|
12947
12877
|
if (/^[a-zA-Z0-9-]+$/.test(val)) return true;
|
|
@@ -12959,7 +12889,7 @@ function findClaudeDesktopConfig() {
|
|
|
12959
12889
|
}
|
|
12960
12890
|
async function collectRouterInfo() {
|
|
12961
12891
|
console.log(chalk2.bold("\n\u2500\u2500 Router configuration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
12962
|
-
const
|
|
12892
|
+
const routerId2 = await input({
|
|
12963
12893
|
message: "Router ID (e.g. core-01):",
|
|
12964
12894
|
validate: validateRouterId
|
|
12965
12895
|
});
|
|
@@ -12991,7 +12921,7 @@ async function collectRouterInfo() {
|
|
|
12991
12921
|
);
|
|
12992
12922
|
}
|
|
12993
12923
|
}
|
|
12994
|
-
const suggestedPrefix = suggestEnvPrefix(
|
|
12924
|
+
const suggestedPrefix = suggestEnvPrefix(routerId2);
|
|
12995
12925
|
const envPrefix = await input({
|
|
12996
12926
|
message: "Credential env prefix:",
|
|
12997
12927
|
default: suggestedPrefix,
|
|
@@ -13015,7 +12945,13 @@ async function collectRouterInfo() {
|
|
|
13015
12945
|
default: "7",
|
|
13016
12946
|
validate: (v) => v.trim().length > 0 ? true : "Version is required"
|
|
13017
12947
|
});
|
|
13018
|
-
return { routerId, host, port, tlsEnabled, rejectUnauthorized, envPrefix, routerUser, routerPass, tags, rosVersion };
|
|
12948
|
+
return { routerId: routerId2, host, port, tlsEnabled, rejectUnauthorized, envPrefix, routerUser, routerPass, tags, rosVersion };
|
|
12949
|
+
}
|
|
12950
|
+
async function collectDefaultRouterPreference(routerId2) {
|
|
12951
|
+
return confirm({
|
|
12952
|
+
message: `Set "${routerId2}" as the default router? (tools may then omit routerId)`,
|
|
12953
|
+
default: true
|
|
12954
|
+
});
|
|
13019
12955
|
}
|
|
13020
12956
|
async function collectIdentityInfo() {
|
|
13021
12957
|
console.log(chalk2.bold("\n\u2500\u2500 Identity / HTTP transport \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
@@ -13165,6 +13101,10 @@ function writeDotEnv(data) {
|
|
|
13165
13101
|
`MIKROMCP_CONFIG_PATH=${join4(data.configDir, "routers.yaml")}`,
|
|
13166
13102
|
`MIKROMCP_IDENTITIES_PATH=${join4(data.configDir, "identities.yaml")}`,
|
|
13167
13103
|
"",
|
|
13104
|
+
"# \u2500\u2500 Default router \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
13105
|
+
"# Router used when a tool call omits routerId (handy for single-router setups).",
|
|
13106
|
+
data.setAsDefault ? `MIKROMCP_DEFAULT_ROUTER=${data.routerId}` : `# MIKROMCP_DEFAULT_ROUTER=${data.routerId}`,
|
|
13107
|
+
"",
|
|
13168
13108
|
"# \u2500\u2500 Logging \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
13169
13109
|
"# Levels: trace | debug | info | warn | error",
|
|
13170
13110
|
"MIKROMCP_LOG_LEVEL=info",
|
|
@@ -13231,6 +13171,7 @@ async function runInit() {
|
|
|
13231
13171
|
}
|
|
13232
13172
|
}
|
|
13233
13173
|
const routerInfo = await collectRouterInfo();
|
|
13174
|
+
const setAsDefault = await collectDefaultRouterPreference(routerInfo.routerId);
|
|
13234
13175
|
const identityInfo = await collectIdentityInfo();
|
|
13235
13176
|
const transport2 = await collectTransport();
|
|
13236
13177
|
const writeEnv = await collectEnvPreference();
|
|
@@ -13241,6 +13182,7 @@ async function runInit() {
|
|
|
13241
13182
|
transport: transport2,
|
|
13242
13183
|
envPath,
|
|
13243
13184
|
configDir,
|
|
13185
|
+
setAsDefault,
|
|
13244
13186
|
writeEnv,
|
|
13245
13187
|
writeRoutersYaml: true,
|
|
13246
13188
|
writeIdentitiesYaml: identityInfo.createIdentity,
|
|
@@ -13262,6 +13204,16 @@ async function runInit() {
|
|
|
13262
13204
|
writeDotEnv(data);
|
|
13263
13205
|
summary.push(`.env written to ${data.envPath}`);
|
|
13264
13206
|
console.log(chalk2.green(` \u2714 ${data.envPath}`));
|
|
13207
|
+
if (data.setAsDefault) {
|
|
13208
|
+
summary.push(`default router: ${data.routerId}`);
|
|
13209
|
+
console.log(chalk2.green(` \u2714 Default router: ${data.routerId} (MIKROMCP_DEFAULT_ROUTER)`));
|
|
13210
|
+
}
|
|
13211
|
+
} else if (data.setAsDefault) {
|
|
13212
|
+
console.log(
|
|
13213
|
+
chalk2.yellow(
|
|
13214
|
+
` \u26A0 Default router not persisted \u2014 set MIKROMCP_DEFAULT_ROUTER=${data.routerId} in your environment to use it.`
|
|
13215
|
+
)
|
|
13216
|
+
);
|
|
13265
13217
|
}
|
|
13266
13218
|
let desktopRegistered = false;
|
|
13267
13219
|
if (data.registerClaudeDesktop) {
|
|
@@ -13284,11 +13236,15 @@ async function runInit() {
|
|
|
13284
13236
|
console.log(chalk2.bold("\nNext steps:"));
|
|
13285
13237
|
console.log(chalk2.dim(" 1. Run: mikromcp doctor"));
|
|
13286
13238
|
console.log(chalk2.dim(" 2. Restart Claude Desktop to load the MCP server"));
|
|
13239
|
+
console.log(
|
|
13240
|
+
chalk2.dim(" 3. (Optional) Install the usage skill so your AI assistant drives MikroMCP safely")
|
|
13241
|
+
);
|
|
13242
|
+
console.log(chalk2.dim(" See: docs/wiki/Using-the-Skill.md"));
|
|
13287
13243
|
console.log();
|
|
13288
13244
|
}
|
|
13289
13245
|
|
|
13290
13246
|
// src/cli/index.ts
|
|
13291
|
-
var program = new Command().name("mikromcp").description("MikroTik RouterOS MCP server").version("1.
|
|
13247
|
+
var program = new Command().name("mikromcp").description("MikroTik RouterOS MCP server").version("1.6.0");
|
|
13292
13248
|
program.command("serve", { isDefault: true }).description("Start the MCP server (default)").action(runServe);
|
|
13293
13249
|
program.command("doctor").description("Check config, connectivity, and permissions").action(runDoctor);
|
|
13294
13250
|
program.command("init").description("Interactive setup wizard").action(runInit);
|