@usex/mikrotik-mcp 3.38.0 → 3.40.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/dist/cli.js CHANGED
@@ -84,7 +84,7 @@ import {
84
84
  toggleAaaEntity,
85
85
  updateAaaEntity,
86
86
  writeBackup
87
- } from "./shared/cli-e484wzek.js";
87
+ } from "./shared/cli-jsf7zy89.js";
88
88
 
89
89
  // src/cli.ts
90
90
  import { existsSync as existsSync2 } from "fs";
@@ -2242,7 +2242,7 @@ function registerPrompts(server) {
2242
2242
  // package.json
2243
2243
  var package_default = {
2244
2244
  name: "@usex/mikrotik-mcp",
2245
- version: "3.38.0",
2245
+ version: "3.40.0",
2246
2246
  description: "MCP server for MikroTik RouterOS \u2014 660+ tools over SSH for firewall, NAT, routing, DHCP, DNS, WireGuard, wireless, QoS and more.",
2247
2247
  keywords: [
2248
2248
  "ai",
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  resolveDeviceName,
22
22
  selectToolModules,
23
23
  setConfig
24
- } from "./shared/library-nxh3rb8t.js";
24
+ } from "./shared/library-0x8fc0rw.js";
25
25
  // src/server.ts
26
26
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
27
27
  import { ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
@@ -131,7 +131,7 @@ function registerPrompts(server) {
131
131
  // package.json
132
132
  var package_default = {
133
133
  name: "@usex/mikrotik-mcp",
134
- version: "3.38.0",
134
+ version: "3.40.0",
135
135
  description: "MCP server for MikroTik RouterOS \u2014 660+ tools over SSH for firewall, NAT, routing, DHCP, DNS, WireGuard, wireless, QoS and more.",
136
136
  keywords: [
137
137
  "ai",
@@ -4,7 +4,7 @@ import {
4
4
  allToolModules,
5
5
  moduleCatalog,
6
6
  selectToolModules
7
- } from "./cli-e484wzek.js";
7
+ } from "./cli-jsf7zy89.js";
8
8
  export {
9
9
  selectToolModules,
10
10
  moduleCatalog,
@@ -3212,24 +3212,24 @@ ${fileDetails}` : `Section export '${name}.rsc' created successfully.`;
3212
3212
  }),
3213
3213
  defineTool({
3214
3214
  name: "download_file",
3215
- title: "Download File as Base64",
3215
+ title: "Download File from Device",
3216
3216
  annotations: READ,
3217
- description: "Attempts to read a file from the device filesystem via `/file print file=<filename>` and" + " returns the RouterOS API text response base64-encoded as `FILE_CONTENT_BASE64:<data>`." + " NOTE: this is a simplified implementation. RouterOS has no file-content-read API over SSH;" + " `/file print file=<name>` saves the directory-listing output to a file named `<name>` rather" + " than streaming an existing file's bytes. The returned base64 payload is the RouterOS text" + " response to that command \u2014 not the actual file contents. Binary `.backup` files cannot be" + " reliably retrieved this way. Verifies file existence first" + " (`/file print count-only where name=<filename>`); returns a not-found message if absent." + " To list available files use `list_backups`; for file metadata only use `backup_info`.",
3217
+ description: "Downloads a file from the device filesystem over SFTP and returns its raw bytes base64-encoded" + " as `FILE_CONTENT_BASE64:<data>`. Works for any file type \u2014 `.backup`, `.rsc`, `.p12`" + " certificates, keys, etc. Verifies file existence first (`/file print count-only`). The SSH" + " user MUST have the `read` policy (and `sensitive` for `.backup` / certificate files) on" + " RouterOS for SFTP downloads to work. NOT available on MAC-Telnet devices (Layer-2 has no" + " file transfer). To list available files use `list_backups`; for file metadata use" + " `backup_info`; to push a file onto the device use `upload_file`.",
3218
3218
  inputSchema: {
3219
- filename: z5.string(),
3220
- file_type: z5.enum(["backup", "export"]).default("backup")
3219
+ filename: z5.string().describe("Name of the file on the device, e.g. 'cert.p12' or 'backup.backup'")
3221
3220
  },
3222
3221
  async handler(a, ctx) {
3223
- ctx.info(`Downloading file: filename=${a.filename}, type=${a.file_type}`);
3222
+ ctx.info(`Downloading file: filename=${a.filename}`);
3224
3223
  const count = await executeMikrotikCommand(`/file print count-only where name=${a.filename}`, ctx);
3225
3224
  if (count.trim() === "0")
3226
- return `File '${a.filename}' not found.`;
3227
- const content = await executeMikrotikCommand(`/file print file=${a.filename}`, ctx);
3228
- if (content) {
3229
- const encoded = Buffer.from(content, "utf8").toString("base64");
3225
+ return `File '${a.filename}' not found on the device.`;
3226
+ try {
3227
+ const data = await downloadFileFromDevice(ctx.device, a.filename);
3228
+ const encoded = data.toString("base64");
3230
3229
  return `FILE_CONTENT_BASE64:${encoded}`;
3230
+ } catch (e) {
3231
+ return `Failed to download '${a.filename}': ${e instanceof Error ? e.message : String(e)}. ` + "Ensure the SSH user has the 'read' and 'sensitive' policies on RouterOS.";
3231
3232
  }
3232
- return `Failed to download file '${a.filename}'.`;
3233
3233
  }
3234
3234
  }),
3235
3235
  defineTool({
@@ -6141,7 +6141,7 @@ var cache = null;
6141
6141
  async function gateway() {
6142
6142
  if (cache)
6143
6143
  return cache;
6144
- const { moduleCatalog } = await import("./cli-h0gydx8r.js");
6144
+ const { moduleCatalog } = await import("./cli-28w9b076.js");
6145
6145
  const forIndex = [];
6146
6146
  const byName = new Map;
6147
6147
  for (const mod of moduleCatalog) {
@@ -8038,11 +8038,11 @@ ${details}`;
8038
8038
  const c = count.trim();
8039
8039
  if (isDigits(c) && Number.parseInt(c, 10) > 0) {
8040
8040
  const details = await executeMikrotikCommand(`/ip firewall filter print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
8041
- return `Firewall filter rule created successfully:
8041
+ return readBackUnavailable(details) ? "Firewall filter rule created successfully." : `Firewall filter rule created successfully:
8042
8042
 
8043
8043
  ${details}`;
8044
8044
  }
8045
- return "Firewall filter rule creation completed but unable to verify.";
8045
+ return "Firewall filter rule created successfully.";
8046
8046
  }
8047
8047
  }),
8048
8048
  defineTool({
@@ -8452,11 +8452,11 @@ ${details}`;
8452
8452
  const c = count.trim();
8453
8453
  if (isDigits2(c) && Number.parseInt(c, 10) > 0) {
8454
8454
  const details = await executeMikrotikCommand(`/ip firewall nat print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
8455
- return `NAT rule created successfully:
8455
+ return readBackUnavailable(details) ? "NAT rule created successfully." : `NAT rule created successfully:
8456
8456
 
8457
8457
  ${details}`;
8458
8458
  }
8459
- return "NAT rule creation completed but unable to verify.";
8459
+ return "NAT rule created successfully.";
8460
8460
  }
8461
8461
  }),
8462
8462
  defineTool({
@@ -8857,11 +8857,11 @@ ${details}`;
8857
8857
  const c = count.trim();
8858
8858
  if (isDigits3(c) && Number.parseInt(c, 10) > 0) {
8859
8859
  const details = await executeMikrotikCommand(`/ip firewall mangle print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
8860
- return `Mangle rule created successfully:
8860
+ return readBackUnavailable(details) ? "Mangle rule created successfully." : `Mangle rule created successfully:
8861
8861
 
8862
8862
  ${details}`;
8863
8863
  }
8864
- return "Mangle rule creation completed but unable to verify.";
8864
+ return "Mangle rule created successfully.";
8865
8865
  }
8866
8866
  }),
8867
8867
  defineTool({
@@ -10765,11 +10765,11 @@ ${details}`;
10765
10765
  const c = count.trim();
10766
10766
  if (isDigits4(c) && Number.parseInt(c, 10) > 0) {
10767
10767
  const details = await executeMikrotikCommand(`/ipv6 firewall filter print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
10768
- return `IPv6 firewall filter rule created successfully:
10768
+ return readBackUnavailable(details) ? "IPv6 firewall filter rule created successfully." : `IPv6 firewall filter rule created successfully:
10769
10769
 
10770
10770
  ${details}`;
10771
10771
  }
10772
- return "IPv6 firewall filter rule creation completed but unable to verify.";
10772
+ return "IPv6 firewall filter rule created successfully.";
10773
10773
  }
10774
10774
  }),
10775
10775
  defineTool({
@@ -11125,11 +11125,11 @@ ${details}`;
11125
11125
  const c = count.trim();
11126
11126
  if (isDigits5(c) && Number.parseInt(c, 10) > 0) {
11127
11127
  const details = await executeMikrotikCommand(`/ipv6 firewall nat print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
11128
- return `IPv6 firewall NAT rule created successfully:
11128
+ return readBackUnavailable(details) ? "IPv6 firewall NAT rule created successfully." : `IPv6 firewall NAT rule created successfully:
11129
11129
 
11130
11130
  ${details}`;
11131
11131
  }
11132
- return "IPv6 firewall NAT rule creation completed but unable to verify.";
11132
+ return "IPv6 firewall NAT rule created successfully.";
11133
11133
  }
11134
11134
  }),
11135
11135
  defineTool({
@@ -11493,11 +11493,11 @@ ${details}`;
11493
11493
  const c = count.trim();
11494
11494
  if (isDigits6(c) && Number.parseInt(c, 10) > 0) {
11495
11495
  const details = await executeMikrotikCommand(`/ipv6 firewall mangle print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
11496
- return `IPv6 firewall mangle rule created successfully:
11496
+ return readBackUnavailable(details) ? "IPv6 firewall mangle rule created successfully." : `IPv6 firewall mangle rule created successfully:
11497
11497
 
11498
11498
  ${details}`;
11499
11499
  }
11500
- return "IPv6 firewall mangle rule creation completed but unable to verify.";
11500
+ return "IPv6 firewall mangle rule created successfully.";
11501
11501
  }
11502
11502
  }),
11503
11503
  defineTool({
@@ -11794,11 +11794,11 @@ ${details}`;
11794
11794
  const c = count.trim();
11795
11795
  if (isDigits7(c) && Number.parseInt(c, 10) > 0) {
11796
11796
  const details = await executeMikrotikCommand(`/ipv6 firewall raw print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
11797
- return `IPv6 firewall raw rule created successfully:
11797
+ return readBackUnavailable(details) ? "IPv6 firewall raw rule created successfully." : `IPv6 firewall raw rule created successfully:
11798
11798
 
11799
11799
  ${details}`;
11800
11800
  }
11801
- return "IPv6 firewall raw rule creation completed but unable to verify.";
11801
+ return "IPv6 firewall raw rule created successfully.";
11802
11802
  }
11803
11803
  }),
11804
11804
  defineTool({
@@ -21587,11 +21587,11 @@ ${details}`;
21587
21587
  const c = count.trim();
21588
21588
  if (isDigits8(c) && Number.parseInt(c, 10) > 0) {
21589
21589
  const details = await executeMikrotikCommand(`/interface ethernet switch rule print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
21590
- return `Switch rule added successfully:
21590
+ return readBackUnavailable(details) ? "Switch rule added successfully." : `Switch rule added successfully:
21591
21591
 
21592
21592
  ${details}`;
21593
21593
  }
21594
- return "Switch rule addition completed but unable to verify.";
21594
+ return "Switch rule added successfully.";
21595
21595
  }
21596
21596
  }),
21597
21597
  defineTool({
@@ -3188,24 +3188,24 @@ ${fileDetails}` : `Section export '${name}.rsc' created successfully.`;
3188
3188
  }),
3189
3189
  defineTool({
3190
3190
  name: "download_file",
3191
- title: "Download File as Base64",
3191
+ title: "Download File from Device",
3192
3192
  annotations: READ,
3193
- description: "Attempts to read a file from the device filesystem via `/file print file=<filename>` and" + " returns the RouterOS API text response base64-encoded as `FILE_CONTENT_BASE64:<data>`." + " NOTE: this is a simplified implementation. RouterOS has no file-content-read API over SSH;" + " `/file print file=<name>` saves the directory-listing output to a file named `<name>` rather" + " than streaming an existing file's bytes. The returned base64 payload is the RouterOS text" + " response to that command \u2014 not the actual file contents. Binary `.backup` files cannot be" + " reliably retrieved this way. Verifies file existence first" + " (`/file print count-only where name=<filename>`); returns a not-found message if absent." + " To list available files use `list_backups`; for file metadata only use `backup_info`.",
3193
+ description: "Downloads a file from the device filesystem over SFTP and returns its raw bytes base64-encoded" + " as `FILE_CONTENT_BASE64:<data>`. Works for any file type \u2014 `.backup`, `.rsc`, `.p12`" + " certificates, keys, etc. Verifies file existence first (`/file print count-only`). The SSH" + " user MUST have the `read` policy (and `sensitive` for `.backup` / certificate files) on" + " RouterOS for SFTP downloads to work. NOT available on MAC-Telnet devices (Layer-2 has no" + " file transfer). To list available files use `list_backups`; for file metadata use" + " `backup_info`; to push a file onto the device use `upload_file`.",
3194
3194
  inputSchema: {
3195
- filename: z5.string(),
3196
- file_type: z5.enum(["backup", "export"]).default("backup")
3195
+ filename: z5.string().describe("Name of the file on the device, e.g. 'cert.p12' or 'backup.backup'")
3197
3196
  },
3198
3197
  async handler(a, ctx) {
3199
- ctx.info(`Downloading file: filename=${a.filename}, type=${a.file_type}`);
3198
+ ctx.info(`Downloading file: filename=${a.filename}`);
3200
3199
  const count = await executeMikrotikCommand(`/file print count-only where name=${a.filename}`, ctx);
3201
3200
  if (count.trim() === "0")
3202
- return `File '${a.filename}' not found.`;
3203
- const content = await executeMikrotikCommand(`/file print file=${a.filename}`, ctx);
3204
- if (content) {
3205
- const encoded = Buffer.from(content, "utf8").toString("base64");
3201
+ return `File '${a.filename}' not found on the device.`;
3202
+ try {
3203
+ const data = await downloadFileFromDevice(ctx.device, a.filename);
3204
+ const encoded = data.toString("base64");
3206
3205
  return `FILE_CONTENT_BASE64:${encoded}`;
3206
+ } catch (e) {
3207
+ return `Failed to download '${a.filename}': ${e instanceof Error ? e.message : String(e)}. ` + "Ensure the SSH user has the 'read' and 'sensitive' policies on RouterOS.";
3207
3208
  }
3208
- return `Failed to download file '${a.filename}'.`;
3209
3209
  }
3210
3210
  }),
3211
3211
  defineTool({
@@ -6117,7 +6117,7 @@ var cache = null;
6117
6117
  async function gateway() {
6118
6118
  if (cache)
6119
6119
  return cache;
6120
- const { moduleCatalog } = await import("./library-q0q3kf6m.js");
6120
+ const { moduleCatalog } = await import("./library-ke4kdmyj.js");
6121
6121
  const forIndex = [];
6122
6122
  const byName = new Map;
6123
6123
  for (const mod of moduleCatalog) {
@@ -8014,11 +8014,11 @@ ${details}`;
8014
8014
  const c = count.trim();
8015
8015
  if (isDigits(c) && Number.parseInt(c, 10) > 0) {
8016
8016
  const details = await executeMikrotikCommand(`/ip firewall filter print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
8017
- return `Firewall filter rule created successfully:
8017
+ return readBackUnavailable(details) ? "Firewall filter rule created successfully." : `Firewall filter rule created successfully:
8018
8018
 
8019
8019
  ${details}`;
8020
8020
  }
8021
- return "Firewall filter rule creation completed but unable to verify.";
8021
+ return "Firewall filter rule created successfully.";
8022
8022
  }
8023
8023
  }),
8024
8024
  defineTool({
@@ -8428,11 +8428,11 @@ ${details}`;
8428
8428
  const c = count.trim();
8429
8429
  if (isDigits2(c) && Number.parseInt(c, 10) > 0) {
8430
8430
  const details = await executeMikrotikCommand(`/ip firewall nat print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
8431
- return `NAT rule created successfully:
8431
+ return readBackUnavailable(details) ? "NAT rule created successfully." : `NAT rule created successfully:
8432
8432
 
8433
8433
  ${details}`;
8434
8434
  }
8435
- return "NAT rule creation completed but unable to verify.";
8435
+ return "NAT rule created successfully.";
8436
8436
  }
8437
8437
  }),
8438
8438
  defineTool({
@@ -8833,11 +8833,11 @@ ${details}`;
8833
8833
  const c = count.trim();
8834
8834
  if (isDigits3(c) && Number.parseInt(c, 10) > 0) {
8835
8835
  const details = await executeMikrotikCommand(`/ip firewall mangle print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
8836
- return `Mangle rule created successfully:
8836
+ return readBackUnavailable(details) ? "Mangle rule created successfully." : `Mangle rule created successfully:
8837
8837
 
8838
8838
  ${details}`;
8839
8839
  }
8840
- return "Mangle rule creation completed but unable to verify.";
8840
+ return "Mangle rule created successfully.";
8841
8841
  }
8842
8842
  }),
8843
8843
  defineTool({
@@ -10741,11 +10741,11 @@ ${details}`;
10741
10741
  const c = count.trim();
10742
10742
  if (isDigits4(c) && Number.parseInt(c, 10) > 0) {
10743
10743
  const details = await executeMikrotikCommand(`/ipv6 firewall filter print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
10744
- return `IPv6 firewall filter rule created successfully:
10744
+ return readBackUnavailable(details) ? "IPv6 firewall filter rule created successfully." : `IPv6 firewall filter rule created successfully:
10745
10745
 
10746
10746
  ${details}`;
10747
10747
  }
10748
- return "IPv6 firewall filter rule creation completed but unable to verify.";
10748
+ return "IPv6 firewall filter rule created successfully.";
10749
10749
  }
10750
10750
  }),
10751
10751
  defineTool({
@@ -11101,11 +11101,11 @@ ${details}`;
11101
11101
  const c = count.trim();
11102
11102
  if (isDigits5(c) && Number.parseInt(c, 10) > 0) {
11103
11103
  const details = await executeMikrotikCommand(`/ipv6 firewall nat print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
11104
- return `IPv6 firewall NAT rule created successfully:
11104
+ return readBackUnavailable(details) ? "IPv6 firewall NAT rule created successfully." : `IPv6 firewall NAT rule created successfully:
11105
11105
 
11106
11106
  ${details}`;
11107
11107
  }
11108
- return "IPv6 firewall NAT rule creation completed but unable to verify.";
11108
+ return "IPv6 firewall NAT rule created successfully.";
11109
11109
  }
11110
11110
  }),
11111
11111
  defineTool({
@@ -11469,11 +11469,11 @@ ${details}`;
11469
11469
  const c = count.trim();
11470
11470
  if (isDigits6(c) && Number.parseInt(c, 10) > 0) {
11471
11471
  const details = await executeMikrotikCommand(`/ipv6 firewall mangle print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
11472
- return `IPv6 firewall mangle rule created successfully:
11472
+ return readBackUnavailable(details) ? "IPv6 firewall mangle rule created successfully." : `IPv6 firewall mangle rule created successfully:
11473
11473
 
11474
11474
  ${details}`;
11475
11475
  }
11476
- return "IPv6 firewall mangle rule creation completed but unable to verify.";
11476
+ return "IPv6 firewall mangle rule created successfully.";
11477
11477
  }
11478
11478
  }),
11479
11479
  defineTool({
@@ -11770,11 +11770,11 @@ ${details}`;
11770
11770
  const c = count.trim();
11771
11771
  if (isDigits7(c) && Number.parseInt(c, 10) > 0) {
11772
11772
  const details = await executeMikrotikCommand(`/ipv6 firewall raw print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
11773
- return `IPv6 firewall raw rule created successfully:
11773
+ return readBackUnavailable(details) ? "IPv6 firewall raw rule created successfully." : `IPv6 firewall raw rule created successfully:
11774
11774
 
11775
11775
  ${details}`;
11776
11776
  }
11777
- return "IPv6 firewall raw rule creation completed but unable to verify.";
11777
+ return "IPv6 firewall raw rule created successfully.";
11778
11778
  }
11779
11779
  }),
11780
11780
  defineTool({
@@ -21563,11 +21563,11 @@ ${details}`;
21563
21563
  const c = count.trim();
21564
21564
  if (isDigits8(c) && Number.parseInt(c, 10) > 0) {
21565
21565
  const details = await executeMikrotikCommand(`/interface ethernet switch rule print detail from=${Number.parseInt(c, 10) - 1}`, ctx);
21566
- return `Switch rule added successfully:
21566
+ return readBackUnavailable(details) ? "Switch rule added successfully." : `Switch rule added successfully:
21567
21567
 
21568
21568
  ${details}`;
21569
21569
  }
21570
- return "Switch rule addition completed but unable to verify.";
21570
+ return "Switch rule added successfully.";
21571
21571
  }
21572
21572
  }),
21573
21573
  defineTool({
@@ -4,7 +4,7 @@ import {
4
4
  allToolModules,
5
5
  moduleCatalog,
6
6
  selectToolModules
7
- } from "./library-nxh3rb8t.js";
7
+ } from "./library-0x8fc0rw.js";
8
8
  export {
9
9
  selectToolModules,
10
10
  moduleCatalog,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usex/mikrotik-mcp",
3
- "version": "3.38.0",
3
+ "version": "3.40.0",
4
4
  "description": "MCP server for MikroTik RouterOS — 660+ tools over SSH for firewall, NAT, routing, DHCP, DNS, WireGuard, wireless, QoS and more.",
5
5
  "keywords": [
6
6
  "ai",