@usex/mikrotik-mcp 3.58.0 → 3.60.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.
Files changed (36) hide show
  1. package/dist/cli.js +31 -3
  2. package/dist/index.d.ts +5 -0
  3. package/dist/index.js +1 -1
  4. package/dist/shared/{cli-zq0rg72c.js → cli-7yjsmkwg.js} +1 -1
  5. package/dist/shared/{cli-r5p22dag.js → cli-ghatyv7e.js} +154 -88
  6. package/dist/shared/{library-41tn0b6b.js → library-1hs18tmh.js} +1 -1
  7. package/dist/shared/{library-84jwmz7a.js → library-7j22z9a8.js} +154 -88
  8. package/dist/ui/aaa.html +1 -1
  9. package/dist/ui/connected-devices.html +1 -1
  10. package/dist/ui/dashboard.html +1 -1
  11. package/dist/ui/firewall-audit.html +1 -1
  12. package/dist/ui/firewall.html +1 -1
  13. package/dist/ui/interfaces.html +1 -1
  14. package/dist/ui/observability.html +1 -1
  15. package/dist/ui/records.html +1 -1
  16. package/package.json +1 -1
  17. package/schemas/README.md +5 -5
  18. package/schemas/config.schema.json +47 -10
  19. package/schemas/tool-catalog.json +2941 -736
  20. package/schemas/tools/check_server_pulse.json +12 -0
  21. package/schemas/tools/config_check_drift.json +5 -1
  22. package/schemas/tools/config_reconcile.json +3 -1
  23. package/schemas/tools/config_set_baseline.json +4 -1
  24. package/schemas/tools/correlate_events.json +4 -1
  25. package/schemas/tools/diagnose.json +3 -1
  26. package/schemas/tools/get_filter_rule.json +1 -1
  27. package/schemas/tools/memory_add_observations.json +7 -2
  28. package/schemas/tools/memory_create_entities.json +7 -2
  29. package/schemas/tools/memory_create_relations.json +8 -2
  30. package/schemas/tools/memory_delete_entities.json +3 -1
  31. package/schemas/tools/memory_delete_observations.json +7 -2
  32. package/schemas/tools/memory_delete_relations.json +8 -2
  33. package/schemas/tools/memory_open_nodes.json +3 -1
  34. package/schemas/tools/memory_search_nodes.json +3 -1
  35. package/schemas/tools/suggest_fix.json +3 -1
  36. package/schemas/tools/trace_path.json +5 -1
@@ -310,7 +310,7 @@ var McpServerSettingsSchema = z.object({
310
310
  allowedOrigins: z.string().default(""),
311
311
  corsOrigins: z.string().default(""),
312
312
  toolPageSize: z.coerce.number().int().min(0).default(0),
313
- appViews: z.boolean().default(true)
313
+ appViews: z.boolean().default(false)
314
314
  });
315
315
  var JumpHostSchema = z.object({
316
316
  host: z.string(),
@@ -2430,7 +2430,7 @@ function defineTool(def) {
2430
2430
  handler: def.handler,
2431
2431
  register(server, opts = {}) {
2432
2432
  const { sendLog, deviceNames, deviceAliases, deviceDirectory: deviceDirectory2, appViews } = opts;
2433
- const multiDevice = !!deviceNames && deviceNames.length > 1;
2433
+ const multiDevice = !def.noDevice && !!deviceNames && deviceNames.length > 1;
2434
2434
  const { ui, auto } = appViews === false ? { ui: undefined, auto: false } : effectiveUi(def);
2435
2435
  const selectorNames = multiDevice && deviceNames ? [...new Set([...deviceNames, ...deviceAliases ?? []])] : [];
2436
2436
  let inputSchema = multiDevice ? {
@@ -8138,7 +8138,7 @@ var rawCommandTools = [
8138
8138
  if (!cmd)
8139
8139
  return "Provide a RouterOS command to run.";
8140
8140
  ctx.info(`Running raw RouterOS command: ${cmd}`);
8141
- const result = await executeMikrotikCommand(cmd, ctx);
8141
+ const result = await executeMikrotikCommand(cmd, ctx, { maxMs: 30000 });
8142
8142
  if (looksLikeError(result))
8143
8143
  return `RouterOS command error: ${result}`;
8144
8144
  return result.trim() ? result : "(command completed with no output)";
@@ -8260,7 +8260,7 @@ var cache = null;
8260
8260
  async function gateway() {
8261
8261
  if (cache)
8262
8262
  return cache;
8263
- const { moduleCatalog } = await import("./library-41tn0b6b.js");
8263
+ const { moduleCatalog } = await import("./library-1hs18tmh.js");
8264
8264
  const forIndex = [];
8265
8265
  const byName = new Map;
8266
8266
  for (const mod of moduleCatalog) {
@@ -10457,7 +10457,30 @@ ${results.join(`
10457
10457
 
10458
10458
  // src/tools/firewall-nat.ts
10459
10459
  import { z as z29 } from "zod";
10460
+
10461
+ // src/tools/_resolve-rule-id.ts
10462
+ function ruleResolver(scope) {
10463
+ return async function resolveRuleId(ruleId, ctx) {
10464
+ if (/^\d+$/.test(ruleId)) {
10465
+ const id = `*${ruleId}`;
10466
+ const byId = await executeMikrotikCommand(`${scope} print count-only where .id=${id}`, ctx);
10467
+ if (byId.trim() !== "0")
10468
+ return id;
10469
+ const idsRaw = await executeMikrotikCommand(`:foreach i in=[${scope} find] do={:put $i}`, ctx);
10470
+ if (isEmpty(idsRaw))
10471
+ return null;
10472
+ const ids = idsRaw.trim().split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
10473
+ const pos = Number.parseInt(ruleId, 10);
10474
+ return pos >= 0 && pos < ids.length ? ids[pos] : null;
10475
+ }
10476
+ const count = await executeMikrotikCommand(`${scope} print count-only where .id=${ruleId}`, ctx);
10477
+ return count.trim() !== "0" ? ruleId : null;
10478
+ };
10479
+ }
10480
+
10481
+ // src/tools/firewall-nat.ts
10460
10482
  var isDigits2 = (s) => /^\d+$/.test(s);
10483
+ var resolveNatRuleId = ruleResolver("/ip firewall nat");
10461
10484
  async function updateNatRule(a, ctx) {
10462
10485
  ctx.info(`Updating NAT rule: rule_id=${a.rule_id}`);
10463
10486
  const updates = [];
@@ -10533,11 +10556,14 @@ async function updateNatRule(a, ctx) {
10533
10556
  }
10534
10557
  if (updates.length === 0)
10535
10558
  return "No updates specified.";
10536
- const cmd = `/ip firewall nat set ${a.rule_id} ${updates.join(" ")}`;
10559
+ const id = await resolveNatRuleId(a.rule_id, ctx);
10560
+ if (!id)
10561
+ return `NAT rule '${a.rule_id}' not found.`;
10562
+ const cmd = `/ip firewall nat set ${id} ${updates.join(" ")}`;
10537
10563
  const result = await executeMikrotikCommand(cmd, ctx);
10538
10564
  if (looksLikeError(result))
10539
10565
  return `Failed to update NAT rule: ${result}`;
10540
- const details = await executeMikrotikCommand(`/ip firewall nat print detail where .id=${a.rule_id}`, ctx);
10566
+ const details = await executeMikrotikCommand(`/ip firewall nat print detail where .id=${id}`, ctx);
10541
10567
  return `NAT rule updated successfully:
10542
10568
 
10543
10569
  ${details}`;
@@ -10715,8 +10741,11 @@ ${result}`;
10715
10741
  },
10716
10742
  async handler(a, ctx) {
10717
10743
  ctx.info(`Getting NAT rule details: rule_id=${a.rule_id}`);
10718
- const result = await executeMikrotikCommand(`/ip firewall nat print detail where .id=${a.rule_id}`, ctx);
10719
- return isEmpty(result) ? `NAT rule with ID '${a.rule_id}' not found.` : `NAT RULE DETAILS:
10744
+ const id = await resolveNatRuleId(a.rule_id, ctx);
10745
+ if (!id)
10746
+ return `NAT rule '${a.rule_id}' not found.`;
10747
+ const result = await executeMikrotikCommand(`/ip firewall nat print detail where .id=${id}`, ctx);
10748
+ return isEmpty(result) ? `NAT rule '${a.rule_id}' not found.` : `NAT RULE DETAILS:
10720
10749
 
10721
10750
  ${result}`;
10722
10751
  }
@@ -10798,13 +10827,13 @@ ${result}`;
10798
10827
  inputSchema: { rule_id: z29.string() },
10799
10828
  async handler(a, ctx) {
10800
10829
  ctx.info(`Removing NAT rule: rule_id=${a.rule_id}`);
10801
- const count = await executeMikrotikCommand(`/ip firewall nat print count-only where .id=${a.rule_id}`, ctx);
10802
- if (count.trim() === "0")
10803
- return `NAT rule with ID '${a.rule_id}' not found.`;
10804
- const result = await executeMikrotikCommand(`/ip firewall nat remove ${a.rule_id}`, ctx);
10830
+ const id = await resolveNatRuleId(a.rule_id, ctx);
10831
+ if (!id)
10832
+ return `NAT rule '${a.rule_id}' not found.`;
10833
+ const result = await executeMikrotikCommand(`/ip firewall nat remove ${id}`, ctx);
10805
10834
  if (looksLikeError(result))
10806
10835
  return `Failed to remove NAT rule: ${result}`;
10807
- return `NAT rule with ID '${a.rule_id}' removed successfully.`;
10836
+ return `NAT rule '${a.rule_id}' (${id}) removed successfully.`;
10808
10837
  }
10809
10838
  }),
10810
10839
  defineTool({
@@ -10818,13 +10847,13 @@ ${result}`;
10818
10847
  },
10819
10848
  async handler(a, ctx) {
10820
10849
  ctx.info(`Moving NAT rule: rule_id=${a.rule_id} to position ${a.destination}`);
10821
- const count = await executeMikrotikCommand(`/ip firewall nat print count-only where .id=${a.rule_id}`, ctx);
10822
- if (count.trim() === "0")
10823
- return `NAT rule with ID '${a.rule_id}' not found.`;
10824
- const result = await executeMikrotikCommand(`/ip firewall nat move ${a.rule_id} destination=${a.destination}`, ctx);
10850
+ const id = await resolveNatRuleId(a.rule_id, ctx);
10851
+ if (!id)
10852
+ return `NAT rule '${a.rule_id}' not found.`;
10853
+ const result = await executeMikrotikCommand(`/ip firewall nat move ${id} destination=${a.destination}`, ctx);
10825
10854
  if (looksLikeError(result))
10826
10855
  return `Failed to move NAT rule: ${result}`;
10827
- return `NAT rule with ID '${a.rule_id}' moved to position ${a.destination}.`;
10856
+ return `NAT rule '${a.rule_id}' (${id}) moved to position ${a.destination}.`;
10828
10857
  }
10829
10858
  }),
10830
10859
  defineTool({
@@ -10852,6 +10881,7 @@ ${result}`;
10852
10881
  // src/tools/firewall-mangle.ts
10853
10882
  import { z as z30 } from "zod";
10854
10883
  var isDigits3 = (s) => /^\d+$/.test(s);
10884
+ var resolveMangleRuleId = ruleResolver("/ip firewall mangle");
10855
10885
  async function updateMangleRule(a, ctx) {
10856
10886
  ctx.info(`Updating mangle rule: rule_id=${a.rule_id}`);
10857
10887
  const updates = [];
@@ -10937,11 +10967,14 @@ async function updateMangleRule(a, ctx) {
10937
10967
  }
10938
10968
  if (updates.length === 0)
10939
10969
  return "No updates specified.";
10940
- const cmd = `/ip firewall mangle set ${a.rule_id} ${updates.join(" ")}`;
10970
+ const id = await resolveMangleRuleId(a.rule_id, ctx);
10971
+ if (!id)
10972
+ return `Mangle rule '${a.rule_id}' not found.`;
10973
+ const cmd = `/ip firewall mangle set ${id} ${updates.join(" ")}`;
10941
10974
  const result = await executeMikrotikCommand(cmd, ctx);
10942
10975
  if (looksLikeError(result))
10943
10976
  return `Failed to update mangle rule: ${result}`;
10944
- const details = await executeMikrotikCommand(`/ip firewall mangle print detail where .id=${a.rule_id}`, ctx);
10977
+ const details = await executeMikrotikCommand(`/ip firewall mangle print detail where .id=${id}`, ctx);
10945
10978
  return `Mangle rule updated successfully:
10946
10979
 
10947
10980
  ${details}`;
@@ -11116,8 +11149,11 @@ ${result}`;
11116
11149
  },
11117
11150
  async handler(a, ctx) {
11118
11151
  ctx.info(`Getting mangle rule details: rule_id=${a.rule_id}`);
11119
- const result = await executeMikrotikCommand(`/ip firewall mangle print detail where .id=${a.rule_id}`, ctx);
11120
- return isEmpty(result) ? `Mangle rule with ID '${a.rule_id}' not found.` : `MANGLE RULE DETAILS:
11152
+ const id = await resolveMangleRuleId(a.rule_id, ctx);
11153
+ if (!id)
11154
+ return `Mangle rule '${a.rule_id}' not found.`;
11155
+ const result = await executeMikrotikCommand(`/ip firewall mangle print detail where .id=${id}`, ctx);
11156
+ return isEmpty(result) ? `Mangle rule '${a.rule_id}' not found.` : `MANGLE RULE DETAILS:
11121
11157
 
11122
11158
  ${result}`;
11123
11159
  }
@@ -11208,13 +11244,13 @@ ${result}`;
11208
11244
  inputSchema: { rule_id: z30.string() },
11209
11245
  async handler(a, ctx) {
11210
11246
  ctx.info(`Removing mangle rule: rule_id=${a.rule_id}`);
11211
- const count = await executeMikrotikCommand(`/ip firewall mangle print count-only where .id=${a.rule_id}`, ctx);
11212
- if (count.trim() === "0")
11213
- return `Mangle rule with ID '${a.rule_id}' not found.`;
11214
- const result = await executeMikrotikCommand(`/ip firewall mangle remove ${a.rule_id}`, ctx);
11247
+ const id = await resolveMangleRuleId(a.rule_id, ctx);
11248
+ if (!id)
11249
+ return `Mangle rule '${a.rule_id}' not found.`;
11250
+ const result = await executeMikrotikCommand(`/ip firewall mangle remove ${id}`, ctx);
11215
11251
  if (looksLikeError(result))
11216
11252
  return `Failed to remove mangle rule: ${result}`;
11217
- return `Mangle rule with ID '${a.rule_id}' removed successfully.`;
11253
+ return `Mangle rule '${a.rule_id}' (${id}) removed successfully.`;
11218
11254
  }
11219
11255
  }),
11220
11256
  defineTool({
@@ -11228,13 +11264,13 @@ ${result}`;
11228
11264
  },
11229
11265
  async handler(a, ctx) {
11230
11266
  ctx.info(`Moving mangle rule: rule_id=${a.rule_id} to position ${a.destination}`);
11231
- const count = await executeMikrotikCommand(`/ip firewall mangle print count-only where .id=${a.rule_id}`, ctx);
11232
- if (count.trim() === "0")
11233
- return `Mangle rule with ID '${a.rule_id}' not found.`;
11234
- const result = await executeMikrotikCommand(`/ip firewall mangle move ${a.rule_id} destination=${a.destination}`, ctx);
11267
+ const id = await resolveMangleRuleId(a.rule_id, ctx);
11268
+ if (!id)
11269
+ return `Mangle rule '${a.rule_id}' not found.`;
11270
+ const result = await executeMikrotikCommand(`/ip firewall mangle move ${id} destination=${a.destination}`, ctx);
11235
11271
  if (looksLikeError(result))
11236
11272
  return `Failed to move mangle rule: ${result}`;
11237
- return `Mangle rule with ID '${a.rule_id}' moved to position ${a.destination}.`;
11273
+ return `Mangle rule '${a.rule_id}' (${id}) moved to position ${a.destination}.`;
11238
11274
  }
11239
11275
  }),
11240
11276
  defineTool({
@@ -13370,6 +13406,7 @@ ${result}`;
13370
13406
  // src/tools/ipv6-firewall-filter.ts
13371
13407
  import { z as z44 } from "zod";
13372
13408
  var isDigits4 = (s) => /^\d+$/.test(s);
13409
+ var resolveRuleId = ruleResolver("/ipv6 firewall filter");
13373
13410
  async function updateFilterRule2(a, ctx) {
13374
13411
  ctx.info(`Updating IPv6 firewall filter rule: rule_id=${a.rule_id}`);
13375
13412
  const updates = [];
@@ -13438,11 +13475,14 @@ async function updateFilterRule2(a, ctx) {
13438
13475
  }
13439
13476
  if (updates.length === 0)
13440
13477
  return "No updates specified.";
13441
- const cmd = `/ipv6 firewall filter set ${a.rule_id} ${updates.join(" ")}`;
13478
+ const id = await resolveRuleId(a.rule_id, ctx);
13479
+ if (!id)
13480
+ return `IPv6 firewall filter rule '${a.rule_id}' not found.`;
13481
+ const cmd = `/ipv6 firewall filter set ${id} ${updates.join(" ")}`;
13442
13482
  const result = await executeMikrotikCommand(cmd, ctx);
13443
13483
  if (looksLikeError(result))
13444
13484
  return `Failed to update IPv6 firewall filter rule: ${result}`;
13445
- const details = await executeMikrotikCommand(`/ipv6 firewall filter print detail where .id=${a.rule_id}`, ctx);
13485
+ const details = await executeMikrotikCommand(`/ipv6 firewall filter print detail where .id=${id}`, ctx);
13446
13486
  return `IPv6 firewall filter rule updated successfully:
13447
13487
 
13448
13488
  ${details}`;
@@ -13599,8 +13639,11 @@ ${result}`;
13599
13639
  },
13600
13640
  async handler(a, ctx) {
13601
13641
  ctx.info(`Getting IPv6 firewall filter rule details: rule_id=${a.rule_id}`);
13602
- const result = await executeMikrotikCommand(`/ipv6 firewall filter print detail where .id=${a.rule_id}`, ctx);
13603
- return isEmpty(result) ? `IPv6 firewall filter rule with ID '${a.rule_id}' not found.` : `IPV6 FIREWALL FILTER RULE DETAILS:
13642
+ const id = await resolveRuleId(a.rule_id, ctx);
13643
+ if (!id)
13644
+ return `IPv6 firewall filter rule '${a.rule_id}' not found.`;
13645
+ const result = await executeMikrotikCommand(`/ipv6 firewall filter print detail where .id=${id}`, ctx);
13646
+ return isEmpty(result) ? `IPv6 firewall filter rule '${a.rule_id}' not found.` : `IPV6 FIREWALL FILTER RULE DETAILS:
13604
13647
 
13605
13648
  ${result}`;
13606
13649
  }
@@ -13676,13 +13719,13 @@ ${result}`;
13676
13719
  inputSchema: { rule_id: z44.string() },
13677
13720
  async handler(a, ctx) {
13678
13721
  ctx.info(`Removing IPv6 firewall filter rule: rule_id=${a.rule_id}`);
13679
- const count = await executeMikrotikCommand(`/ipv6 firewall filter print count-only where .id=${a.rule_id}`, ctx);
13680
- if (count.trim() === "0")
13681
- return `IPv6 firewall filter rule with ID '${a.rule_id}' not found.`;
13682
- const result = await executeMikrotikCommand(`/ipv6 firewall filter remove ${a.rule_id}`, ctx);
13722
+ const id = await resolveRuleId(a.rule_id, ctx);
13723
+ if (!id)
13724
+ return `IPv6 firewall filter rule '${a.rule_id}' not found.`;
13725
+ const result = await executeMikrotikCommand(`/ipv6 firewall filter remove ${id}`, ctx);
13683
13726
  if (looksLikeError(result))
13684
13727
  return `Failed to remove IPv6 firewall filter rule: ${result}`;
13685
- return `IPv6 firewall filter rule with ID '${a.rule_id}' removed successfully.`;
13728
+ return `IPv6 firewall filter rule '${a.rule_id}' (${id}) removed successfully.`;
13686
13729
  }
13687
13730
  }),
13688
13731
  defineTool({
@@ -13696,13 +13739,13 @@ ${result}`;
13696
13739
  },
13697
13740
  async handler(a, ctx) {
13698
13741
  ctx.info(`Moving IPv6 firewall filter rule: rule_id=${a.rule_id} to position ${a.destination}`);
13699
- const count = await executeMikrotikCommand(`/ipv6 firewall filter print count-only where .id=${a.rule_id}`, ctx);
13700
- if (count.trim() === "0")
13701
- return `IPv6 firewall filter rule with ID '${a.rule_id}' not found.`;
13702
- const result = await executeMikrotikCommand(`/ipv6 firewall filter move ${a.rule_id} destination=${a.destination}`, ctx);
13742
+ const id = await resolveRuleId(a.rule_id, ctx);
13743
+ if (!id)
13744
+ return `IPv6 firewall filter rule '${a.rule_id}' not found.`;
13745
+ const result = await executeMikrotikCommand(`/ipv6 firewall filter move ${id} destination=${a.destination}`, ctx);
13703
13746
  if (looksLikeError(result))
13704
13747
  return `Failed to move IPv6 firewall filter rule: ${result}`;
13705
- return `IPv6 firewall filter rule with ID '${a.rule_id}' moved to position ${a.destination}.`;
13748
+ return `IPv6 firewall filter rule '${a.rule_id}' (${id}) moved to position ${a.destination}.`;
13706
13749
  }
13707
13750
  }),
13708
13751
  defineTool({
@@ -13730,6 +13773,7 @@ ${result}`;
13730
13773
  // src/tools/ipv6-firewall-nat.ts
13731
13774
  import { z as z45 } from "zod";
13732
13775
  var isDigits5 = (s) => /^\d+$/.test(s);
13776
+ var resolveRuleId2 = ruleResolver("/ipv6 firewall nat");
13733
13777
  async function updateNatRule2(a, ctx) {
13734
13778
  ctx.info(`Updating IPv6 firewall NAT rule: rule_id=${a.rule_id}`);
13735
13779
  const updates = [];
@@ -13797,11 +13841,14 @@ async function updateNatRule2(a, ctx) {
13797
13841
  }
13798
13842
  if (updates.length === 0)
13799
13843
  return "No updates specified.";
13800
- const cmd = `/ipv6 firewall nat set ${a.rule_id} ${updates.join(" ")}`;
13844
+ const id = await resolveRuleId2(a.rule_id, ctx);
13845
+ if (!id)
13846
+ return `IPv6 NAT rule '${a.rule_id}' not found.`;
13847
+ const cmd = `/ipv6 firewall nat set ${id} ${updates.join(" ")}`;
13801
13848
  const result = await executeMikrotikCommand(cmd, ctx);
13802
13849
  if (looksLikeError(result))
13803
13850
  return `Failed to update IPv6 firewall NAT rule: ${result}`;
13804
- const details = await executeMikrotikCommand(`/ipv6 firewall nat print detail where .id=${a.rule_id}`, ctx);
13851
+ const details = await executeMikrotikCommand(`/ipv6 firewall nat print detail where .id=${id}`, ctx);
13805
13852
  return `IPv6 firewall NAT rule updated successfully:
13806
13853
 
13807
13854
  ${details}`;
@@ -13952,8 +13999,11 @@ ${result}`;
13952
13999
  },
13953
14000
  async handler(a, ctx) {
13954
14001
  ctx.info(`Getting IPv6 firewall NAT rule details: rule_id=${a.rule_id}`);
13955
- const result = await executeMikrotikCommand(`/ipv6 firewall nat print detail where .id=${a.rule_id}`, ctx);
13956
- return isEmpty(result) ? `IPv6 firewall NAT rule with ID '${a.rule_id}' not found.` : `IPV6 FIREWALL NAT RULE DETAILS:
14002
+ const id = await resolveRuleId2(a.rule_id, ctx);
14003
+ if (!id)
14004
+ return `IPv6 firewall NAT rule '${a.rule_id}' not found.`;
14005
+ const result = await executeMikrotikCommand(`/ipv6 firewall nat print detail where .id=${id}`, ctx);
14006
+ return isEmpty(result) ? `IPv6 firewall NAT rule '${a.rule_id}' not found.` : `IPV6 FIREWALL NAT RULE DETAILS:
13957
14007
 
13958
14008
  ${result}`;
13959
14009
  }
@@ -14028,13 +14078,13 @@ ${result}`;
14028
14078
  inputSchema: { rule_id: z45.string() },
14029
14079
  async handler(a, ctx) {
14030
14080
  ctx.info(`Removing IPv6 firewall NAT rule: rule_id=${a.rule_id}`);
14031
- const count = await executeMikrotikCommand(`/ipv6 firewall nat print count-only where .id=${a.rule_id}`, ctx);
14032
- if (count.trim() === "0")
14033
- return `IPv6 firewall NAT rule with ID '${a.rule_id}' not found.`;
14034
- const result = await executeMikrotikCommand(`/ipv6 firewall nat remove ${a.rule_id}`, ctx);
14081
+ const id = await resolveRuleId2(a.rule_id, ctx);
14082
+ if (!id)
14083
+ return `IPv6 firewall NAT rule '${a.rule_id}' not found.`;
14084
+ const result = await executeMikrotikCommand(`/ipv6 firewall nat remove ${id}`, ctx);
14035
14085
  if (looksLikeError(result))
14036
14086
  return `Failed to remove IPv6 firewall NAT rule: ${result}`;
14037
- return `IPv6 firewall NAT rule with ID '${a.rule_id}' removed successfully.`;
14087
+ return `IPv6 firewall NAT rule '${a.rule_id}' (${id}) removed successfully.`;
14038
14088
  }
14039
14089
  }),
14040
14090
  defineTool({
@@ -14048,13 +14098,13 @@ ${result}`;
14048
14098
  },
14049
14099
  async handler(a, ctx) {
14050
14100
  ctx.info(`Moving IPv6 firewall NAT rule: rule_id=${a.rule_id} to position ${a.destination}`);
14051
- const count = await executeMikrotikCommand(`/ipv6 firewall nat print count-only where .id=${a.rule_id}`, ctx);
14052
- if (count.trim() === "0")
14053
- return `IPv6 firewall NAT rule with ID '${a.rule_id}' not found.`;
14054
- const result = await executeMikrotikCommand(`/ipv6 firewall nat move ${a.rule_id} destination=${a.destination}`, ctx);
14101
+ const id = await resolveRuleId2(a.rule_id, ctx);
14102
+ if (!id)
14103
+ return `IPv6 firewall NAT rule '${a.rule_id}' not found.`;
14104
+ const result = await executeMikrotikCommand(`/ipv6 firewall nat move ${id} destination=${a.destination}`, ctx);
14055
14105
  if (looksLikeError(result))
14056
14106
  return `Failed to move IPv6 firewall NAT rule: ${result}`;
14057
- return `IPv6 firewall NAT rule with ID '${a.rule_id}' moved to position ${a.destination}.`;
14107
+ return `IPv6 firewall NAT rule '${a.rule_id}' (${id}) moved to position ${a.destination}.`;
14058
14108
  }
14059
14109
  }),
14060
14110
  defineTool({
@@ -14082,6 +14132,7 @@ ${result}`;
14082
14132
  // src/tools/ipv6-firewall-mangle.ts
14083
14133
  import { z as z46 } from "zod";
14084
14134
  var isDigits6 = (s) => /^\d+$/.test(s);
14135
+ var resolveRuleId3 = ruleResolver("/ipv6 firewall mangle");
14085
14136
  async function updateMangleRule2(a, ctx) {
14086
14137
  ctx.info(`Updating IPv6 firewall mangle rule: rule_id=${a.rule_id}`);
14087
14138
  const updates = [];
@@ -14157,11 +14208,14 @@ async function updateMangleRule2(a, ctx) {
14157
14208
  }
14158
14209
  if (updates.length === 0)
14159
14210
  return "No updates specified.";
14160
- const cmd = `/ipv6 firewall mangle set ${a.rule_id} ${updates.join(" ")}`;
14211
+ const id = await resolveRuleId3(a.rule_id, ctx);
14212
+ if (!id)
14213
+ return `IPv6 mangle rule '${a.rule_id}' not found.`;
14214
+ const cmd = `/ipv6 firewall mangle set ${id} ${updates.join(" ")}`;
14161
14215
  const result = await executeMikrotikCommand(cmd, ctx);
14162
14216
  if (looksLikeError(result))
14163
14217
  return `Failed to update IPv6 firewall mangle rule: ${result}`;
14164
- const details = await executeMikrotikCommand(`/ipv6 firewall mangle print detail where .id=${a.rule_id}`, ctx);
14218
+ const details = await executeMikrotikCommand(`/ipv6 firewall mangle print detail where .id=${id}`, ctx);
14165
14219
  return `IPv6 firewall mangle rule updated successfully:
14166
14220
 
14167
14221
  ${details}`;
@@ -14320,8 +14374,11 @@ ${result}`;
14320
14374
  },
14321
14375
  async handler(a, ctx) {
14322
14376
  ctx.info(`Getting IPv6 firewall mangle rule details: rule_id=${a.rule_id}`);
14323
- const result = await executeMikrotikCommand(`/ipv6 firewall mangle print detail where .id=${a.rule_id}`, ctx);
14324
- return isEmpty(result) ? `IPv6 firewall mangle rule with ID '${a.rule_id}' not found.` : `IPV6 FIREWALL MANGLE RULE DETAILS:
14377
+ const id = await resolveRuleId3(a.rule_id, ctx);
14378
+ if (!id)
14379
+ return `IPv6 mangle rule '${a.rule_id}' not found.`;
14380
+ const result = await executeMikrotikCommand(`/ipv6 firewall mangle print detail where .id=${id}`, ctx);
14381
+ return isEmpty(result) ? `IPv6 mangle rule '${a.rule_id}' not found.` : `IPV6 FIREWALL MANGLE RULE DETAILS:
14325
14382
 
14326
14383
  ${result}`;
14327
14384
  }
@@ -14403,13 +14460,13 @@ ${result}`;
14403
14460
  inputSchema: { rule_id: z46.string() },
14404
14461
  async handler(a, ctx) {
14405
14462
  ctx.info(`Removing IPv6 firewall mangle rule: rule_id=${a.rule_id}`);
14406
- const count = await executeMikrotikCommand(`/ipv6 firewall mangle print count-only where .id=${a.rule_id}`, ctx);
14407
- if (count.trim() === "0")
14408
- return `IPv6 firewall mangle rule with ID '${a.rule_id}' not found.`;
14409
- const result = await executeMikrotikCommand(`/ipv6 firewall mangle remove ${a.rule_id}`, ctx);
14463
+ const id = await resolveRuleId3(a.rule_id, ctx);
14464
+ if (!id)
14465
+ return `IPv6 mangle rule '${a.rule_id}' not found.`;
14466
+ const result = await executeMikrotikCommand(`/ipv6 firewall mangle remove ${id}`, ctx);
14410
14467
  if (looksLikeError(result))
14411
14468
  return `Failed to remove IPv6 firewall mangle rule: ${result}`;
14412
- return `IPv6 firewall mangle rule with ID '${a.rule_id}' removed successfully.`;
14469
+ return `IPv6 mangle rule '${a.rule_id}' (${id}) removed successfully.`;
14413
14470
  }
14414
14471
  }),
14415
14472
  defineTool({
@@ -14423,13 +14480,13 @@ ${result}`;
14423
14480
  },
14424
14481
  async handler(a, ctx) {
14425
14482
  ctx.info(`Moving IPv6 firewall mangle rule: rule_id=${a.rule_id} to position ${a.destination}`);
14426
- const count = await executeMikrotikCommand(`/ipv6 firewall mangle print count-only where .id=${a.rule_id}`, ctx);
14427
- if (count.trim() === "0")
14428
- return `IPv6 firewall mangle rule with ID '${a.rule_id}' not found.`;
14429
- const result = await executeMikrotikCommand(`/ipv6 firewall mangle move ${a.rule_id} destination=${a.destination}`, ctx);
14483
+ const id = await resolveRuleId3(a.rule_id, ctx);
14484
+ if (!id)
14485
+ return `IPv6 mangle rule '${a.rule_id}' not found.`;
14486
+ const result = await executeMikrotikCommand(`/ipv6 firewall mangle move ${id} destination=${a.destination}`, ctx);
14430
14487
  if (looksLikeError(result))
14431
14488
  return `Failed to move IPv6 firewall mangle rule: ${result}`;
14432
- return `IPv6 firewall mangle rule with ID '${a.rule_id}' moved to position ${a.destination}.`;
14489
+ return `IPv6 mangle rule '${a.rule_id}' (${id}) moved to position ${a.destination}.`;
14433
14490
  }
14434
14491
  }),
14435
14492
  defineTool({
@@ -14457,6 +14514,7 @@ ${result}`;
14457
14514
  // src/tools/ipv6-firewall-raw.ts
14458
14515
  import { z as z47 } from "zod";
14459
14516
  var isDigits7 = (s) => /^\d+$/.test(s);
14517
+ var resolveRuleId4 = ruleResolver("/ipv6 firewall raw");
14460
14518
  async function updateRawRule(a, ctx) {
14461
14519
  ctx.info(`Updating IPv6 firewall raw rule: rule_id=${a.rule_id}`);
14462
14520
  const updates = [];
@@ -14502,11 +14560,14 @@ async function updateRawRule(a, ctx) {
14502
14560
  }
14503
14561
  if (updates.length === 0)
14504
14562
  return "No updates specified.";
14505
- const cmd = `/ipv6 firewall raw set ${a.rule_id} ${updates.join(" ")}`;
14563
+ const id = await resolveRuleId4(a.rule_id, ctx);
14564
+ if (!id)
14565
+ return `IPv6 raw rule '${a.rule_id}' not found.`;
14566
+ const cmd = `/ipv6 firewall raw set ${id} ${updates.join(" ")}`;
14506
14567
  const result = await executeMikrotikCommand(cmd, ctx);
14507
14568
  if (looksLikeError(result))
14508
14569
  return `Failed to update IPv6 firewall raw rule: ${result}`;
14509
- const details = await executeMikrotikCommand(`/ipv6 firewall raw print detail where .id=${a.rule_id}`, ctx);
14570
+ const details = await executeMikrotikCommand(`/ipv6 firewall raw print detail where .id=${id}`, ctx);
14510
14571
  return `IPv6 firewall raw rule updated successfully:
14511
14572
 
14512
14573
  ${details}`;
@@ -14621,7 +14682,10 @@ ${result}`;
14621
14682
  },
14622
14683
  async handler(a, ctx) {
14623
14684
  ctx.info(`Getting IPv6 firewall raw rule details: rule_id=${a.rule_id}`);
14624
- const result = await executeMikrotikCommand(`/ipv6 firewall raw print detail where .id=${a.rule_id}`, ctx);
14685
+ const id = await resolveRuleId4(a.rule_id, ctx);
14686
+ if (!id)
14687
+ return `IPv6 firewall raw rule with ID '${a.rule_id}' not found.`;
14688
+ const result = await executeMikrotikCommand(`/ipv6 firewall raw print detail where .id=${id}`, ctx);
14625
14689
  return isEmpty(result) ? `IPv6 firewall raw rule with ID '${a.rule_id}' not found.` : `IPV6 FIREWALL RAW RULE DETAILS:
14626
14690
 
14627
14691
  ${result}`;
@@ -14675,13 +14739,13 @@ ${result}`;
14675
14739
  inputSchema: { rule_id: z47.string() },
14676
14740
  async handler(a, ctx) {
14677
14741
  ctx.info(`Removing IPv6 firewall raw rule: rule_id=${a.rule_id}`);
14678
- const count = await executeMikrotikCommand(`/ipv6 firewall raw print count-only where .id=${a.rule_id}`, ctx);
14679
- if (count.trim() === "0")
14742
+ const id = await resolveRuleId4(a.rule_id, ctx);
14743
+ if (!id)
14680
14744
  return `IPv6 firewall raw rule with ID '${a.rule_id}' not found.`;
14681
- const result = await executeMikrotikCommand(`/ipv6 firewall raw remove ${a.rule_id}`, ctx);
14745
+ const result = await executeMikrotikCommand(`/ipv6 firewall raw remove ${id}`, ctx);
14682
14746
  if (looksLikeError(result))
14683
14747
  return `Failed to remove IPv6 firewall raw rule: ${result}`;
14684
- return `IPv6 firewall raw rule with ID '${a.rule_id}' removed successfully.`;
14748
+ return `IPv6 firewall raw rule '${a.rule_id}' (${id}) removed successfully.`;
14685
14749
  }
14686
14750
  }),
14687
14751
  defineTool({
@@ -14695,13 +14759,13 @@ ${result}`;
14695
14759
  },
14696
14760
  async handler(a, ctx) {
14697
14761
  ctx.info(`Moving IPv6 firewall raw rule: rule_id=${a.rule_id} to position ${a.destination}`);
14698
- const count = await executeMikrotikCommand(`/ipv6 firewall raw print count-only where .id=${a.rule_id}`, ctx);
14699
- if (count.trim() === "0")
14762
+ const id = await resolveRuleId4(a.rule_id, ctx);
14763
+ if (!id)
14700
14764
  return `IPv6 firewall raw rule with ID '${a.rule_id}' not found.`;
14701
- const result = await executeMikrotikCommand(`/ipv6 firewall raw move ${a.rule_id} destination=${a.destination}`, ctx);
14765
+ const result = await executeMikrotikCommand(`/ipv6 firewall raw move ${id} destination=${a.destination}`, ctx);
14702
14766
  if (looksLikeError(result))
14703
14767
  return `Failed to move IPv6 firewall raw rule: ${result}`;
14704
- return `IPv6 firewall raw rule with ID '${a.rule_id}' moved to position ${a.destination}.`;
14768
+ return `IPv6 firewall raw rule '${a.rule_id}' (${id}) moved to position ${a.destination}.`;
14705
14769
  }
14706
14770
  }),
14707
14771
  defineTool({
@@ -22063,7 +22127,7 @@ ${result}`;
22063
22127
  ${v6Result}`;
22064
22128
  }
22065
22129
  const where = [`dst-address in ${a.destination}`, "active=yes"];
22066
- if (table)
22130
+ if (table && table !== "main")
22067
22131
  where.push(`routing-table=${quoteValue(table)}`);
22068
22132
  const v7Cmd = `/ip route print detail where ${where.join(" ")}`;
22069
22133
  const v7Result = await executeMikrotikCommand(v7Cmd, ctx);
@@ -24956,6 +25020,7 @@ var serverPulseTools = [
24956
25020
  defineTool({
24957
25021
  name: "check_server_pulse",
24958
25022
  title: "Server Pulse & Update Check",
25023
+ noDevice: true,
24959
25024
  annotations: READ,
24960
25025
  description: "Check the MCP server's own heartbeat: running version, whether a newer release " + "is available, release notes for the latest version, upgrade commands, and server " + "vitals (tool count, uptime). This is server self-awareness \u2014 no RouterOS device " + "is contacted. Call this when the user asks about the MCP server version, updates, " + "what's new, or 'is my server up to date'. Returns rich release notes from GitHub " + "so you can summarize what changed.",
24961
25026
  inputSchema: {
@@ -24985,8 +25050,9 @@ var serverPulseTools = [
24985
25050
  }
24986
25051
  sections.push("", `Release: ${result.release.url}`);
24987
25052
  }
24988
- if (includeNotes && result.release.body && result.release.isNewer) {
24989
- sections.push("", `WHAT'S NEW IN v${result.release.version}`, sep, result.release.body);
25053
+ if (includeNotes && result.release.body) {
25054
+ const notesHeader = result.release.isNewer ? `WHAT'S NEW IN v${result.release.version}` : `RELEASE NOTES \u2014 v${result.release.version}`;
25055
+ sections.push("", notesHeader, sep, result.release.body);
24990
25056
  }
24991
25057
  } else {
24992
25058
  sections.push("", "UPDATE STATUS: UNKNOWN", sep, `Could not check for updates${result.error ? `: ${result.error}` : "."}`, `Current version: v${VERSION}`, result.fromCache ? "(showing cached data)" : "(no cached data available \u2014 check network connectivity)");