@usex/mikrotik-mcp 3.15.0 → 3.17.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
@@ -13070,6 +13070,152 @@ ${result}`;
13070
13070
  ${details}`;
13071
13071
  }
13072
13072
  }),
13073
+ defineTool({
13074
+ name: "add_ovpn_server",
13075
+ title: "Add Named OpenVPN Server",
13076
+ annotations: WRITE,
13077
+ description: "Add a named inbound OpenVPN server instance (`/interface ovpn-server server add`) \u2014 the" + " RouterOS 7.17+ multi-server model, where several OVPN servers can run side by side, each on" + " its own port/certificate/profile. Provide a unique name; port defaults to 1194. Supports" + " protocol (tcp/udp), ip or ethernet mode, certificate, auth/cipher algorithm lists, netmask," + " max_mtu, default_profile, mac_address (ethernet mode) and require_client_certificate. For the" + " legacy single-server (selector-less) menu on older RouterOS use set_ovpn_server. To remove a" + " named server use remove_ovpn_server; to list them use list_ovpn_servers. For outbound tunnels" + " use create_ovpn_client. Returns the created server's detail including its name.",
13078
+ inputSchema: {
13079
+ name: z68.string().describe("Unique name for the new OpenVPN server instance"),
13080
+ port: z68.number().int().default(1194),
13081
+ protocol: z68.enum(["tcp", "udp"]).optional(),
13082
+ mode: z68.enum(["ip", "ethernet"]).optional(),
13083
+ netmask: z68.number().int().optional(),
13084
+ mac_address: z68.string().optional().describe("Server MAC for ethernet mode"),
13085
+ certificate: z68.string().optional(),
13086
+ auth: z68.string().optional().describe("Comma-separated, e.g. 'sha256,sha1'"),
13087
+ cipher: z68.string().optional().describe("Comma-separated, e.g. 'aes256-cbc,aes256-gcm'"),
13088
+ max_mtu: z68.number().int().optional(),
13089
+ default_profile: z68.string().optional(),
13090
+ require_client_certificate: z68.boolean().optional(),
13091
+ comment: z68.string().optional(),
13092
+ disabled: z68.boolean().default(false)
13093
+ },
13094
+ async handler(a, ctx) {
13095
+ ctx.info(`Adding OpenVPN server: name=${a.name}`);
13096
+ const cmd = new Cmd("/interface ovpn-server server add").set("name", a.name).opt("port", a.port).opt("protocol", a.protocol).opt("mode", a.mode).opt("netmask", a.netmask).opt("mac-address", a.mac_address).opt("certificate", a.certificate).opt("auth", a.auth).opt("cipher", a.cipher).opt("max-mtu", a.max_mtu).opt("default-profile", a.default_profile).bool("require-client-certificate", a.require_client_certificate).opt("comment", a.comment).flag("disabled", a.disabled).build();
13097
+ const result = await executeMikrotikCommand(cmd, ctx);
13098
+ if (containsRawParserError(result)) {
13099
+ return "Failed to add OpenVPN server: this RouterOS build does not support named OpenVPN" + " server instances (the multi-server model requires RouterOS 7.17+). Use set_ovpn_server" + ` to configure the single legacy server instead.
13100
+
13101
+ ${result}`;
13102
+ }
13103
+ if (looksLikeError(result))
13104
+ return `Failed to add OpenVPN server: ${result}`;
13105
+ const details = await executeMikrotikCommand(`/interface ovpn-server server print detail where name="${a.name}"`, ctx);
13106
+ return details.trim() ? `OpenVPN server '${a.name}' added successfully:
13107
+
13108
+ ${details}` : "OpenVPN server creation completed but unable to verify.";
13109
+ }
13110
+ }),
13111
+ defineTool({
13112
+ name: "list_ovpn_servers",
13113
+ title: "List Named OpenVPN Servers",
13114
+ annotations: READ,
13115
+ description: "`list_ovpn_servers` \u2014 READ / list / show / inspect all named OpenVPN server instances" + " (`/interface ovpn-server server print detail`) on the RouterOS 7.17+ multi-server model," + " optionally filtered by partial name (name_filter). Returns each server's name, port, protocol," + " certificate, profile and disabled state. Pass a name_filter to fetch one server's full detail" + " (this doubles as get-by-name). The `.id`/name values feed update_ovpn_server," + " remove_ovpn_server, enable_ovpn_server and disable_ovpn_server. For the legacy single-server" + " menu use get_ovpn_server; for outbound tunnels use list_ovpn_clients.",
13116
+ inputSchema: {
13117
+ name_filter: z68.string().optional().describe("Partial name match")
13118
+ },
13119
+ async handler(a, ctx) {
13120
+ ctx.info("Listing OpenVPN servers");
13121
+ const filters = [];
13122
+ if (a.name_filter)
13123
+ filters.push(`name~"${a.name_filter}"`);
13124
+ const result = await executeMikrotikCommand(`/interface ovpn-server server print detail${whereClause(filters)}`, ctx);
13125
+ return isEmpty(result) ? "No named OpenVPN servers found (the device may use the legacy single-server menu \u2014 try get_ovpn_server)." : `OPENVPN SERVERS:
13126
+
13127
+ ${result}`;
13128
+ }
13129
+ }),
13130
+ defineTool({
13131
+ name: "update_ovpn_server",
13132
+ title: "Update Named OpenVPN Server",
13133
+ annotations: WRITE_IDEMPOTENT,
13134
+ description: "Modify a named OpenVPN server instance (`/interface ovpn-server server set [find name=...]`) on" + " the RouterOS 7.17+ multi-server model \u2014 change port, protocol, mode, certificate, auth/cipher," + " netmask, max_mtu, default_profile, mac_address, comment or require_client_certificate without" + " recreating it. To toggle only the enabled state use enable_ovpn_server / disable_ovpn_server." + " To create a server use add_ovpn_server; to remove one use remove_ovpn_server. For the legacy" + " single-server menu use set_ovpn_server. Returns the updated server's detail.",
13135
+ inputSchema: {
13136
+ name: z68.string().describe("Existing OpenVPN server instance name"),
13137
+ port: z68.number().int().optional(),
13138
+ protocol: z68.enum(["tcp", "udp"]).optional(),
13139
+ mode: z68.enum(["ip", "ethernet"]).optional(),
13140
+ netmask: z68.number().int().optional(),
13141
+ mac_address: z68.string().optional(),
13142
+ certificate: z68.string().optional(),
13143
+ auth: z68.string().optional(),
13144
+ cipher: z68.string().optional(),
13145
+ max_mtu: z68.number().int().optional(),
13146
+ default_profile: z68.string().optional(),
13147
+ require_client_certificate: z68.boolean().optional(),
13148
+ comment: z68.string().optional()
13149
+ },
13150
+ async handler(a, ctx) {
13151
+ ctx.info(`Updating OpenVPN server: name=${a.name}`);
13152
+ const base = `/interface ovpn-server server set [find name="${a.name}"]`;
13153
+ const cmd = new Cmd(base).opt("port", a.port).opt("protocol", a.protocol).opt("mode", a.mode).opt("netmask", a.netmask).opt("mac-address", a.mac_address).opt("certificate", a.certificate).opt("auth", a.auth).opt("cipher", a.cipher).opt("max-mtu", a.max_mtu).opt("default-profile", a.default_profile).bool("require-client-certificate", a.require_client_certificate).opt("comment", a.comment).build();
13154
+ if (cmd === base)
13155
+ return "No updates specified.";
13156
+ const count = await executeMikrotikCommand(`/interface ovpn-server server print count-only where name="${a.name}"`, ctx);
13157
+ if (count.trim() === "0")
13158
+ return `OpenVPN server '${a.name}' not found.`;
13159
+ const result = await executeMikrotikCommand(cmd, ctx);
13160
+ if (looksLikeError(result))
13161
+ return `Failed to update OpenVPN server: ${result}`;
13162
+ const details = await executeMikrotikCommand(`/interface ovpn-server server print detail where name="${a.name}"`, ctx);
13163
+ return `OpenVPN server '${a.name}' updated successfully:
13164
+
13165
+ ${details}`;
13166
+ }
13167
+ }),
13168
+ defineTool({
13169
+ name: "remove_ovpn_server",
13170
+ title: "Remove Named OpenVPN Server",
13171
+ annotations: DESTRUCTIVE,
13172
+ description: "Permanently delete a named OpenVPN server instance (`/interface ovpn-server server remove" + " [find name=...]`) on the RouterOS 7.17+ multi-server model \u2014 verifies existence with a" + " count-only check before deleting. Use list_ovpn_servers to confirm the name. To stop a server" + " without deleting it use disable_ovpn_server. This does not touch the legacy single-server menu" + " (use set_ovpn_server with enabled=false for that) or any OVPN clients. Returns a success or" + " not-found message.",
13173
+ inputSchema: { name: z68.string() },
13174
+ async handler(a, ctx) {
13175
+ ctx.info(`Removing OpenVPN server: name=${a.name}`);
13176
+ const count = await executeMikrotikCommand(`/interface ovpn-server server print count-only where name="${a.name}"`, ctx);
13177
+ if (count.trim() === "0")
13178
+ return `OpenVPN server '${a.name}' not found.`;
13179
+ const result = await executeMikrotikCommand(`/interface ovpn-server server remove [find name="${a.name}"]`, ctx);
13180
+ if (looksLikeError(result))
13181
+ return `Failed to remove OpenVPN server: ${result}`;
13182
+ return `OpenVPN server '${a.name}' removed successfully.`;
13183
+ }
13184
+ }),
13185
+ defineTool({
13186
+ name: "enable_ovpn_server",
13187
+ title: "Enable Named OpenVPN Server",
13188
+ annotations: WRITE_IDEMPOTENT,
13189
+ description: "Enable a disabled named OpenVPN server instance (`/interface ovpn-server server enable" + " [find name=...]`) on the RouterOS 7.17+ multi-server model, so it starts accepting clients." + " Use list_ovpn_servers to confirm the name. To deactivate use disable_ovpn_server; to delete" + " use remove_ovpn_server. For the legacy single-server menu use set_ovpn_server with" + " enabled=true. Returns a success or error message.",
13190
+ inputSchema: { name: z68.string() },
13191
+ async handler(a, ctx) {
13192
+ ctx.info(`Enabling OpenVPN server: name=${a.name}`);
13193
+ const count = await executeMikrotikCommand(`/interface ovpn-server server print count-only where name="${a.name}"`, ctx);
13194
+ if (count.trim() === "0")
13195
+ return `OpenVPN server '${a.name}' not found.`;
13196
+ const result = await executeMikrotikCommand(`/interface ovpn-server server enable [find name="${a.name}"]`, ctx);
13197
+ if (looksLikeError(result))
13198
+ return `Failed to enable OpenVPN server: ${result}`;
13199
+ return `OpenVPN server '${a.name}' enabled successfully.`;
13200
+ }
13201
+ }),
13202
+ defineTool({
13203
+ name: "disable_ovpn_server",
13204
+ title: "Disable Named OpenVPN Server",
13205
+ annotations: WRITE_IDEMPOTENT,
13206
+ description: "Disable an active named OpenVPN server instance (`/interface ovpn-server server disable" + " [find name=...]`) on the RouterOS 7.17+ multi-server model, stopping it without deleting its" + " configuration. Use list_ovpn_servers to confirm the name. To re-activate use" + " enable_ovpn_server; to delete use remove_ovpn_server. For the legacy single-server menu use" + " set_ovpn_server with enabled=false. Returns a success or error message.",
13207
+ inputSchema: { name: z68.string() },
13208
+ async handler(a, ctx) {
13209
+ ctx.info(`Disabling OpenVPN server: name=${a.name}`);
13210
+ const count = await executeMikrotikCommand(`/interface ovpn-server server print count-only where name="${a.name}"`, ctx);
13211
+ if (count.trim() === "0")
13212
+ return `OpenVPN server '${a.name}' not found.`;
13213
+ const result = await executeMikrotikCommand(`/interface ovpn-server server disable [find name="${a.name}"]`, ctx);
13214
+ if (looksLikeError(result))
13215
+ return `Failed to disable OpenVPN server: ${result}`;
13216
+ return `OpenVPN server '${a.name}' disabled successfully.`;
13217
+ }
13218
+ }),
13073
13219
  defineTool({
13074
13220
  name: "create_ovpn_client",
13075
13221
  title: "Create OpenVPN Client Interface",
@@ -17023,6 +17169,16 @@ ${details}`;
17023
17169
  // src/tools/routing-table.ts
17024
17170
  import { z as z91 } from "zod";
17025
17171
  var UNSUPPORTED14 = "Routing tables are not available on this device (requires RouterOS v7 with the routing package).";
17172
+ function fibToken(fib, onSet = false) {
17173
+ if (fib === undefined)
17174
+ return;
17175
+ if (fib)
17176
+ return "fib";
17177
+ return onSet ? "!fib" : undefined;
17178
+ }
17179
+ function buildAddRoutingTableCommand(a) {
17180
+ return new Cmd("/routing table add").set("name", a.name).raw(fibToken(a.fib)).opt("comment", a.comment).flag("disabled", a.disabled).build();
17181
+ }
17026
17182
  var routingTableTools = [
17027
17183
  defineTool({
17028
17184
  name: "list_routing_tables",
@@ -17072,7 +17228,7 @@ ${result}`;
17072
17228
  },
17073
17229
  async handler(a, ctx) {
17074
17230
  ctx.info(`Adding routing table: ${a.name}`);
17075
- const cmd = new Cmd("/routing table add").set("name", a.name).bool("fib", a.fib).opt("comment", a.comment).flag("disabled", a.disabled).build();
17231
+ const cmd = buildAddRoutingTableCommand(a);
17076
17232
  const result = await executeMikrotikCommand(cmd, ctx);
17077
17233
  if (commandUnsupported(result))
17078
17234
  return UNSUPPORTED14;
@@ -17099,8 +17255,7 @@ ${details}`;
17099
17255
  ctx.info(`Updating routing table: ${a.name}`);
17100
17256
  const base = `/routing table set [find name="${a.name}"]`;
17101
17257
  const cmd = new Cmd(base);
17102
- if (a.fib !== undefined)
17103
- cmd.bool("fib", a.fib);
17258
+ cmd.raw(fibToken(a.fib, true));
17104
17259
  if (a.comment !== undefined)
17105
17260
  cmd.set("comment", a.comment);
17106
17261
  if (a.disabled !== undefined)
@@ -21692,7 +21847,7 @@ var moduleCatalog = [
21692
21847
  label: "OpenVPN",
21693
21848
  slug: "openvpn",
21694
21849
  group: "VPN & Tunneling",
21695
- description: "OpenVPN server + clients (`/interface ovpn-*`).",
21850
+ description: "OpenVPN servers \u2014 legacy single + RouterOS 7.17 multi-server \u2014 and clients (`/interface ovpn-*`).",
21696
21851
  tools: openvpnTools
21697
21852
  },
21698
21853
  {
@@ -23613,7 +23768,7 @@ function registerPrompts(server) {
23613
23768
  // package.json
23614
23769
  var package_default = {
23615
23770
  name: "@usex/mikrotik-mcp",
23616
- version: "3.15.0",
23771
+ version: "3.17.0",
23617
23772
  description: "MCP server for MikroTik RouterOS \u2014 660+ tools over SSH for firewall, NAT, routing, DHCP, DNS, WireGuard, wireless, QoS and more.",
23618
23773
  keywords: [
23619
23774
  "ai",
package/dist/index.js CHANGED
@@ -13082,6 +13082,152 @@ ${result}`;
13082
13082
  ${details}`;
13083
13083
  }
13084
13084
  }),
13085
+ defineTool({
13086
+ name: "add_ovpn_server",
13087
+ title: "Add Named OpenVPN Server",
13088
+ annotations: WRITE,
13089
+ description: "Add a named inbound OpenVPN server instance (`/interface ovpn-server server add`) \u2014 the" + " RouterOS 7.17+ multi-server model, where several OVPN servers can run side by side, each on" + " its own port/certificate/profile. Provide a unique name; port defaults to 1194. Supports" + " protocol (tcp/udp), ip or ethernet mode, certificate, auth/cipher algorithm lists, netmask," + " max_mtu, default_profile, mac_address (ethernet mode) and require_client_certificate. For the" + " legacy single-server (selector-less) menu on older RouterOS use set_ovpn_server. To remove a" + " named server use remove_ovpn_server; to list them use list_ovpn_servers. For outbound tunnels" + " use create_ovpn_client. Returns the created server's detail including its name.",
13090
+ inputSchema: {
13091
+ name: z69.string().describe("Unique name for the new OpenVPN server instance"),
13092
+ port: z69.number().int().default(1194),
13093
+ protocol: z69.enum(["tcp", "udp"]).optional(),
13094
+ mode: z69.enum(["ip", "ethernet"]).optional(),
13095
+ netmask: z69.number().int().optional(),
13096
+ mac_address: z69.string().optional().describe("Server MAC for ethernet mode"),
13097
+ certificate: z69.string().optional(),
13098
+ auth: z69.string().optional().describe("Comma-separated, e.g. 'sha256,sha1'"),
13099
+ cipher: z69.string().optional().describe("Comma-separated, e.g. 'aes256-cbc,aes256-gcm'"),
13100
+ max_mtu: z69.number().int().optional(),
13101
+ default_profile: z69.string().optional(),
13102
+ require_client_certificate: z69.boolean().optional(),
13103
+ comment: z69.string().optional(),
13104
+ disabled: z69.boolean().default(false)
13105
+ },
13106
+ async handler(a, ctx) {
13107
+ ctx.info(`Adding OpenVPN server: name=${a.name}`);
13108
+ const cmd = new Cmd("/interface ovpn-server server add").set("name", a.name).opt("port", a.port).opt("protocol", a.protocol).opt("mode", a.mode).opt("netmask", a.netmask).opt("mac-address", a.mac_address).opt("certificate", a.certificate).opt("auth", a.auth).opt("cipher", a.cipher).opt("max-mtu", a.max_mtu).opt("default-profile", a.default_profile).bool("require-client-certificate", a.require_client_certificate).opt("comment", a.comment).flag("disabled", a.disabled).build();
13109
+ const result = await executeMikrotikCommand(cmd, ctx);
13110
+ if (containsRawParserError(result)) {
13111
+ return "Failed to add OpenVPN server: this RouterOS build does not support named OpenVPN" + " server instances (the multi-server model requires RouterOS 7.17+). Use set_ovpn_server" + ` to configure the single legacy server instead.
13112
+
13113
+ ${result}`;
13114
+ }
13115
+ if (looksLikeError(result))
13116
+ return `Failed to add OpenVPN server: ${result}`;
13117
+ const details = await executeMikrotikCommand(`/interface ovpn-server server print detail where name="${a.name}"`, ctx);
13118
+ return details.trim() ? `OpenVPN server '${a.name}' added successfully:
13119
+
13120
+ ${details}` : "OpenVPN server creation completed but unable to verify.";
13121
+ }
13122
+ }),
13123
+ defineTool({
13124
+ name: "list_ovpn_servers",
13125
+ title: "List Named OpenVPN Servers",
13126
+ annotations: READ,
13127
+ description: "`list_ovpn_servers` \u2014 READ / list / show / inspect all named OpenVPN server instances" + " (`/interface ovpn-server server print detail`) on the RouterOS 7.17+ multi-server model," + " optionally filtered by partial name (name_filter). Returns each server's name, port, protocol," + " certificate, profile and disabled state. Pass a name_filter to fetch one server's full detail" + " (this doubles as get-by-name). The `.id`/name values feed update_ovpn_server," + " remove_ovpn_server, enable_ovpn_server and disable_ovpn_server. For the legacy single-server" + " menu use get_ovpn_server; for outbound tunnels use list_ovpn_clients.",
13128
+ inputSchema: {
13129
+ name_filter: z69.string().optional().describe("Partial name match")
13130
+ },
13131
+ async handler(a, ctx) {
13132
+ ctx.info("Listing OpenVPN servers");
13133
+ const filters = [];
13134
+ if (a.name_filter)
13135
+ filters.push(`name~"${a.name_filter}"`);
13136
+ const result = await executeMikrotikCommand(`/interface ovpn-server server print detail${whereClause(filters)}`, ctx);
13137
+ return isEmpty(result) ? "No named OpenVPN servers found (the device may use the legacy single-server menu \u2014 try get_ovpn_server)." : `OPENVPN SERVERS:
13138
+
13139
+ ${result}`;
13140
+ }
13141
+ }),
13142
+ defineTool({
13143
+ name: "update_ovpn_server",
13144
+ title: "Update Named OpenVPN Server",
13145
+ annotations: WRITE_IDEMPOTENT,
13146
+ description: "Modify a named OpenVPN server instance (`/interface ovpn-server server set [find name=...]`) on" + " the RouterOS 7.17+ multi-server model \u2014 change port, protocol, mode, certificate, auth/cipher," + " netmask, max_mtu, default_profile, mac_address, comment or require_client_certificate without" + " recreating it. To toggle only the enabled state use enable_ovpn_server / disable_ovpn_server." + " To create a server use add_ovpn_server; to remove one use remove_ovpn_server. For the legacy" + " single-server menu use set_ovpn_server. Returns the updated server's detail.",
13147
+ inputSchema: {
13148
+ name: z69.string().describe("Existing OpenVPN server instance name"),
13149
+ port: z69.number().int().optional(),
13150
+ protocol: z69.enum(["tcp", "udp"]).optional(),
13151
+ mode: z69.enum(["ip", "ethernet"]).optional(),
13152
+ netmask: z69.number().int().optional(),
13153
+ mac_address: z69.string().optional(),
13154
+ certificate: z69.string().optional(),
13155
+ auth: z69.string().optional(),
13156
+ cipher: z69.string().optional(),
13157
+ max_mtu: z69.number().int().optional(),
13158
+ default_profile: z69.string().optional(),
13159
+ require_client_certificate: z69.boolean().optional(),
13160
+ comment: z69.string().optional()
13161
+ },
13162
+ async handler(a, ctx) {
13163
+ ctx.info(`Updating OpenVPN server: name=${a.name}`);
13164
+ const base = `/interface ovpn-server server set [find name="${a.name}"]`;
13165
+ const cmd = new Cmd(base).opt("port", a.port).opt("protocol", a.protocol).opt("mode", a.mode).opt("netmask", a.netmask).opt("mac-address", a.mac_address).opt("certificate", a.certificate).opt("auth", a.auth).opt("cipher", a.cipher).opt("max-mtu", a.max_mtu).opt("default-profile", a.default_profile).bool("require-client-certificate", a.require_client_certificate).opt("comment", a.comment).build();
13166
+ if (cmd === base)
13167
+ return "No updates specified.";
13168
+ const count = await executeMikrotikCommand(`/interface ovpn-server server print count-only where name="${a.name}"`, ctx);
13169
+ if (count.trim() === "0")
13170
+ return `OpenVPN server '${a.name}' not found.`;
13171
+ const result = await executeMikrotikCommand(cmd, ctx);
13172
+ if (looksLikeError(result))
13173
+ return `Failed to update OpenVPN server: ${result}`;
13174
+ const details = await executeMikrotikCommand(`/interface ovpn-server server print detail where name="${a.name}"`, ctx);
13175
+ return `OpenVPN server '${a.name}' updated successfully:
13176
+
13177
+ ${details}`;
13178
+ }
13179
+ }),
13180
+ defineTool({
13181
+ name: "remove_ovpn_server",
13182
+ title: "Remove Named OpenVPN Server",
13183
+ annotations: DESTRUCTIVE,
13184
+ description: "Permanently delete a named OpenVPN server instance (`/interface ovpn-server server remove" + " [find name=...]`) on the RouterOS 7.17+ multi-server model \u2014 verifies existence with a" + " count-only check before deleting. Use list_ovpn_servers to confirm the name. To stop a server" + " without deleting it use disable_ovpn_server. This does not touch the legacy single-server menu" + " (use set_ovpn_server with enabled=false for that) or any OVPN clients. Returns a success or" + " not-found message.",
13185
+ inputSchema: { name: z69.string() },
13186
+ async handler(a, ctx) {
13187
+ ctx.info(`Removing OpenVPN server: name=${a.name}`);
13188
+ const count = await executeMikrotikCommand(`/interface ovpn-server server print count-only where name="${a.name}"`, ctx);
13189
+ if (count.trim() === "0")
13190
+ return `OpenVPN server '${a.name}' not found.`;
13191
+ const result = await executeMikrotikCommand(`/interface ovpn-server server remove [find name="${a.name}"]`, ctx);
13192
+ if (looksLikeError(result))
13193
+ return `Failed to remove OpenVPN server: ${result}`;
13194
+ return `OpenVPN server '${a.name}' removed successfully.`;
13195
+ }
13196
+ }),
13197
+ defineTool({
13198
+ name: "enable_ovpn_server",
13199
+ title: "Enable Named OpenVPN Server",
13200
+ annotations: WRITE_IDEMPOTENT,
13201
+ description: "Enable a disabled named OpenVPN server instance (`/interface ovpn-server server enable" + " [find name=...]`) on the RouterOS 7.17+ multi-server model, so it starts accepting clients." + " Use list_ovpn_servers to confirm the name. To deactivate use disable_ovpn_server; to delete" + " use remove_ovpn_server. For the legacy single-server menu use set_ovpn_server with" + " enabled=true. Returns a success or error message.",
13202
+ inputSchema: { name: z69.string() },
13203
+ async handler(a, ctx) {
13204
+ ctx.info(`Enabling OpenVPN server: name=${a.name}`);
13205
+ const count = await executeMikrotikCommand(`/interface ovpn-server server print count-only where name="${a.name}"`, ctx);
13206
+ if (count.trim() === "0")
13207
+ return `OpenVPN server '${a.name}' not found.`;
13208
+ const result = await executeMikrotikCommand(`/interface ovpn-server server enable [find name="${a.name}"]`, ctx);
13209
+ if (looksLikeError(result))
13210
+ return `Failed to enable OpenVPN server: ${result}`;
13211
+ return `OpenVPN server '${a.name}' enabled successfully.`;
13212
+ }
13213
+ }),
13214
+ defineTool({
13215
+ name: "disable_ovpn_server",
13216
+ title: "Disable Named OpenVPN Server",
13217
+ annotations: WRITE_IDEMPOTENT,
13218
+ description: "Disable an active named OpenVPN server instance (`/interface ovpn-server server disable" + " [find name=...]`) on the RouterOS 7.17+ multi-server model, stopping it without deleting its" + " configuration. Use list_ovpn_servers to confirm the name. To re-activate use" + " enable_ovpn_server; to delete use remove_ovpn_server. For the legacy single-server menu use" + " set_ovpn_server with enabled=false. Returns a success or error message.",
13219
+ inputSchema: { name: z69.string() },
13220
+ async handler(a, ctx) {
13221
+ ctx.info(`Disabling OpenVPN server: name=${a.name}`);
13222
+ const count = await executeMikrotikCommand(`/interface ovpn-server server print count-only where name="${a.name}"`, ctx);
13223
+ if (count.trim() === "0")
13224
+ return `OpenVPN server '${a.name}' not found.`;
13225
+ const result = await executeMikrotikCommand(`/interface ovpn-server server disable [find name="${a.name}"]`, ctx);
13226
+ if (looksLikeError(result))
13227
+ return `Failed to disable OpenVPN server: ${result}`;
13228
+ return `OpenVPN server '${a.name}' disabled successfully.`;
13229
+ }
13230
+ }),
13085
13231
  defineTool({
13086
13232
  name: "create_ovpn_client",
13087
13233
  title: "Create OpenVPN Client Interface",
@@ -17035,6 +17181,16 @@ ${details}`;
17035
17181
  // src/tools/routing-table.ts
17036
17182
  import { z as z92 } from "zod";
17037
17183
  var UNSUPPORTED14 = "Routing tables are not available on this device (requires RouterOS v7 with the routing package).";
17184
+ function fibToken(fib, onSet = false) {
17185
+ if (fib === undefined)
17186
+ return;
17187
+ if (fib)
17188
+ return "fib";
17189
+ return onSet ? "!fib" : undefined;
17190
+ }
17191
+ function buildAddRoutingTableCommand(a) {
17192
+ return new Cmd("/routing table add").set("name", a.name).raw(fibToken(a.fib)).opt("comment", a.comment).flag("disabled", a.disabled).build();
17193
+ }
17038
17194
  var routingTableTools = [
17039
17195
  defineTool({
17040
17196
  name: "list_routing_tables",
@@ -17084,7 +17240,7 @@ ${result}`;
17084
17240
  },
17085
17241
  async handler(a, ctx) {
17086
17242
  ctx.info(`Adding routing table: ${a.name}`);
17087
- const cmd = new Cmd("/routing table add").set("name", a.name).bool("fib", a.fib).opt("comment", a.comment).flag("disabled", a.disabled).build();
17243
+ const cmd = buildAddRoutingTableCommand(a);
17088
17244
  const result = await executeMikrotikCommand(cmd, ctx);
17089
17245
  if (commandUnsupported(result))
17090
17246
  return UNSUPPORTED14;
@@ -17111,8 +17267,7 @@ ${details}`;
17111
17267
  ctx.info(`Updating routing table: ${a.name}`);
17112
17268
  const base = `/routing table set [find name="${a.name}"]`;
17113
17269
  const cmd = new Cmd(base);
17114
- if (a.fib !== undefined)
17115
- cmd.bool("fib", a.fib);
17270
+ cmd.raw(fibToken(a.fib, true));
17116
17271
  if (a.comment !== undefined)
17117
17272
  cmd.set("comment", a.comment);
17118
17273
  if (a.disabled !== undefined)
@@ -21704,7 +21859,7 @@ var moduleCatalog = [
21704
21859
  label: "OpenVPN",
21705
21860
  slug: "openvpn",
21706
21861
  group: "VPN & Tunneling",
21707
- description: "OpenVPN server + clients (`/interface ovpn-*`).",
21862
+ description: "OpenVPN servers \u2014 legacy single + RouterOS 7.17 multi-server \u2014 and clients (`/interface ovpn-*`).",
21708
21863
  tools: openvpnTools
21709
21864
  },
21710
21865
  {
@@ -22016,7 +22171,7 @@ function selectToolModules(filter = {}, catalog = moduleCatalog) {
22016
22171
  // package.json
22017
22172
  var package_default = {
22018
22173
  name: "@usex/mikrotik-mcp",
22019
- version: "3.15.0",
22174
+ version: "3.17.0",
22020
22175
  description: "MCP server for MikroTik RouterOS \u2014 660+ tools over SSH for firewall, NAT, routing, DHCP, DNS, WireGuard, wireless, QoS and more.",
22021
22176
  keywords: [
22022
22177
  "ai",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usex/mikrotik-mcp",
3
- "version": "3.15.0",
3
+ "version": "3.17.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",
package/schemas/README.md CHANGED
@@ -7,7 +7,7 @@ edit by hand — regenerate instead.
7
7
  | File | Contents |
8
8
  | -------------------- | ------------------------------------------------------------------------------------------ |
9
9
  | `config.schema.json` | The runtime configuration object (env vars / CLI flags). |
10
- | `tool-catalog.json` | Every one of the 715 tools: `name`, `risk`, `title`, `description`, and input JSON Schema. |
10
+ | `tool-catalog.json` | Every one of the 721 tools: `name`, `risk`, `title`, `description`, and input JSON Schema. |
11
11
  | `tools/<name>.json` | The input JSON Schema for a single tool. |
12
12
 
13
13
  `risk` is derived from the MCP tool annotations:
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "version": "3.14.0",
3
+ "version": "3.16.0",
4
4
  "generated": "by scripts/gen-schemas.ts — do not edit by hand",
5
- "toolCount": 715,
5
+ "toolCount": 721,
6
6
  "tools": [
7
7
  {
8
8
  "name": "list_interfaces",
@@ -14539,6 +14539,235 @@
14539
14539
  "additionalProperties": false
14540
14540
  }
14541
14541
  },
14542
+ {
14543
+ "name": "add_ovpn_server",
14544
+ "title": "Add Named OpenVPN Server",
14545
+ "risk": "write",
14546
+ "annotations": {
14547
+ "destructiveHint": false,
14548
+ "openWorldHint": false
14549
+ },
14550
+ "description": "Add a named inbound OpenVPN server instance (`/interface ovpn-server server add`) — the RouterOS 7.17+ multi-server model, where several OVPN servers can run side by side, each on its own port/certificate/profile. Provide a unique name; port defaults to 1194. Supports protocol (tcp/udp), ip or ethernet mode, certificate, auth/cipher algorithm lists, netmask, max_mtu, default_profile, mac_address (ethernet mode) and require_client_certificate. For the legacy single-server (selector-less) menu on older RouterOS use set_ovpn_server. To remove a named server use remove_ovpn_server; to list them use list_ovpn_servers. For outbound tunnels use create_ovpn_client. Returns the created server's detail including its name.",
14551
+ "inputSchema": {
14552
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
14553
+ "type": "object",
14554
+ "properties": {
14555
+ "name": {
14556
+ "type": "string",
14557
+ "description": "Unique name for the new OpenVPN server instance"
14558
+ },
14559
+ "port": {
14560
+ "default": 1194,
14561
+ "type": "integer",
14562
+ "minimum": -9007199254740991,
14563
+ "maximum": 9007199254740991
14564
+ },
14565
+ "protocol": {
14566
+ "type": "string",
14567
+ "enum": ["tcp", "udp"]
14568
+ },
14569
+ "mode": {
14570
+ "type": "string",
14571
+ "enum": ["ip", "ethernet"]
14572
+ },
14573
+ "netmask": {
14574
+ "type": "integer",
14575
+ "minimum": -9007199254740991,
14576
+ "maximum": 9007199254740991
14577
+ },
14578
+ "mac_address": {
14579
+ "description": "Server MAC for ethernet mode",
14580
+ "type": "string"
14581
+ },
14582
+ "certificate": {
14583
+ "type": "string"
14584
+ },
14585
+ "auth": {
14586
+ "description": "Comma-separated, e.g. 'sha256,sha1'",
14587
+ "type": "string"
14588
+ },
14589
+ "cipher": {
14590
+ "description": "Comma-separated, e.g. 'aes256-cbc,aes256-gcm'",
14591
+ "type": "string"
14592
+ },
14593
+ "max_mtu": {
14594
+ "type": "integer",
14595
+ "minimum": -9007199254740991,
14596
+ "maximum": 9007199254740991
14597
+ },
14598
+ "default_profile": {
14599
+ "type": "string"
14600
+ },
14601
+ "require_client_certificate": {
14602
+ "type": "boolean"
14603
+ },
14604
+ "comment": {
14605
+ "type": "string"
14606
+ },
14607
+ "disabled": {
14608
+ "default": false,
14609
+ "type": "boolean"
14610
+ }
14611
+ },
14612
+ "required": ["name", "port", "disabled"],
14613
+ "additionalProperties": false
14614
+ }
14615
+ },
14616
+ {
14617
+ "name": "list_ovpn_servers",
14618
+ "title": "List Named OpenVPN Servers",
14619
+ "risk": "read",
14620
+ "annotations": {
14621
+ "readOnlyHint": true,
14622
+ "idempotentHint": true,
14623
+ "openWorldHint": false
14624
+ },
14625
+ "description": "`list_ovpn_servers` — READ / list / show / inspect all named OpenVPN server instances (`/interface ovpn-server server print detail`) on the RouterOS 7.17+ multi-server model, optionally filtered by partial name (name_filter). Returns each server's name, port, protocol, certificate, profile and disabled state. Pass a name_filter to fetch one server's full detail (this doubles as get-by-name). The `.id`/name values feed update_ovpn_server, remove_ovpn_server, enable_ovpn_server and disable_ovpn_server. For the legacy single-server menu use get_ovpn_server; for outbound tunnels use list_ovpn_clients.",
14626
+ "inputSchema": {
14627
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
14628
+ "type": "object",
14629
+ "properties": {
14630
+ "name_filter": {
14631
+ "description": "Partial name match",
14632
+ "type": "string"
14633
+ }
14634
+ },
14635
+ "additionalProperties": false
14636
+ }
14637
+ },
14638
+ {
14639
+ "name": "update_ovpn_server",
14640
+ "title": "Update Named OpenVPN Server",
14641
+ "risk": "write-idempotent",
14642
+ "annotations": {
14643
+ "destructiveHint": false,
14644
+ "idempotentHint": true,
14645
+ "openWorldHint": false
14646
+ },
14647
+ "description": "Modify a named OpenVPN server instance (`/interface ovpn-server server set [find name=...]`) on the RouterOS 7.17+ multi-server model — change port, protocol, mode, certificate, auth/cipher, netmask, max_mtu, default_profile, mac_address, comment or require_client_certificate without recreating it. To toggle only the enabled state use enable_ovpn_server / disable_ovpn_server. To create a server use add_ovpn_server; to remove one use remove_ovpn_server. For the legacy single-server menu use set_ovpn_server. Returns the updated server's detail.",
14648
+ "inputSchema": {
14649
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
14650
+ "type": "object",
14651
+ "properties": {
14652
+ "name": {
14653
+ "type": "string",
14654
+ "description": "Existing OpenVPN server instance name"
14655
+ },
14656
+ "port": {
14657
+ "type": "integer",
14658
+ "minimum": -9007199254740991,
14659
+ "maximum": 9007199254740991
14660
+ },
14661
+ "protocol": {
14662
+ "type": "string",
14663
+ "enum": ["tcp", "udp"]
14664
+ },
14665
+ "mode": {
14666
+ "type": "string",
14667
+ "enum": ["ip", "ethernet"]
14668
+ },
14669
+ "netmask": {
14670
+ "type": "integer",
14671
+ "minimum": -9007199254740991,
14672
+ "maximum": 9007199254740991
14673
+ },
14674
+ "mac_address": {
14675
+ "type": "string"
14676
+ },
14677
+ "certificate": {
14678
+ "type": "string"
14679
+ },
14680
+ "auth": {
14681
+ "type": "string"
14682
+ },
14683
+ "cipher": {
14684
+ "type": "string"
14685
+ },
14686
+ "max_mtu": {
14687
+ "type": "integer",
14688
+ "minimum": -9007199254740991,
14689
+ "maximum": 9007199254740991
14690
+ },
14691
+ "default_profile": {
14692
+ "type": "string"
14693
+ },
14694
+ "require_client_certificate": {
14695
+ "type": "boolean"
14696
+ },
14697
+ "comment": {
14698
+ "type": "string"
14699
+ }
14700
+ },
14701
+ "required": ["name"],
14702
+ "additionalProperties": false
14703
+ }
14704
+ },
14705
+ {
14706
+ "name": "remove_ovpn_server",
14707
+ "title": "Remove Named OpenVPN Server",
14708
+ "risk": "destructive",
14709
+ "annotations": {
14710
+ "destructiveHint": true,
14711
+ "idempotentHint": true,
14712
+ "openWorldHint": false
14713
+ },
14714
+ "description": "Permanently delete a named OpenVPN server instance (`/interface ovpn-server server remove [find name=...]`) on the RouterOS 7.17+ multi-server model — verifies existence with a count-only check before deleting. Use list_ovpn_servers to confirm the name. To stop a server without deleting it use disable_ovpn_server. This does not touch the legacy single-server menu (use set_ovpn_server with enabled=false for that) or any OVPN clients. Returns a success or not-found message.",
14715
+ "inputSchema": {
14716
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
14717
+ "type": "object",
14718
+ "properties": {
14719
+ "name": {
14720
+ "type": "string"
14721
+ }
14722
+ },
14723
+ "required": ["name"],
14724
+ "additionalProperties": false
14725
+ }
14726
+ },
14727
+ {
14728
+ "name": "enable_ovpn_server",
14729
+ "title": "Enable Named OpenVPN Server",
14730
+ "risk": "write-idempotent",
14731
+ "annotations": {
14732
+ "destructiveHint": false,
14733
+ "idempotentHint": true,
14734
+ "openWorldHint": false
14735
+ },
14736
+ "description": "Enable a disabled named OpenVPN server instance (`/interface ovpn-server server enable [find name=...]`) on the RouterOS 7.17+ multi-server model, so it starts accepting clients. Use list_ovpn_servers to confirm the name. To deactivate use disable_ovpn_server; to delete use remove_ovpn_server. For the legacy single-server menu use set_ovpn_server with enabled=true. Returns a success or error message.",
14737
+ "inputSchema": {
14738
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
14739
+ "type": "object",
14740
+ "properties": {
14741
+ "name": {
14742
+ "type": "string"
14743
+ }
14744
+ },
14745
+ "required": ["name"],
14746
+ "additionalProperties": false
14747
+ }
14748
+ },
14749
+ {
14750
+ "name": "disable_ovpn_server",
14751
+ "title": "Disable Named OpenVPN Server",
14752
+ "risk": "write-idempotent",
14753
+ "annotations": {
14754
+ "destructiveHint": false,
14755
+ "idempotentHint": true,
14756
+ "openWorldHint": false
14757
+ },
14758
+ "description": "Disable an active named OpenVPN server instance (`/interface ovpn-server server disable [find name=...]`) on the RouterOS 7.17+ multi-server model, stopping it without deleting its configuration. Use list_ovpn_servers to confirm the name. To re-activate use enable_ovpn_server; to delete use remove_ovpn_server. For the legacy single-server menu use set_ovpn_server with enabled=false. Returns a success or error message.",
14759
+ "inputSchema": {
14760
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
14761
+ "type": "object",
14762
+ "properties": {
14763
+ "name": {
14764
+ "type": "string"
14765
+ }
14766
+ },
14767
+ "required": ["name"],
14768
+ "additionalProperties": false
14769
+ }
14770
+ },
14542
14771
  {
14543
14772
  "name": "create_ovpn_client",
14544
14773
  "title": "Create OpenVPN Client Interface",
@@ -0,0 +1,65 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "add_ovpn_server",
4
+ "type": "object",
5
+ "properties": {
6
+ "name": {
7
+ "type": "string",
8
+ "description": "Unique name for the new OpenVPN server instance"
9
+ },
10
+ "port": {
11
+ "default": 1194,
12
+ "type": "integer",
13
+ "minimum": -9007199254740991,
14
+ "maximum": 9007199254740991
15
+ },
16
+ "protocol": {
17
+ "type": "string",
18
+ "enum": ["tcp", "udp"]
19
+ },
20
+ "mode": {
21
+ "type": "string",
22
+ "enum": ["ip", "ethernet"]
23
+ },
24
+ "netmask": {
25
+ "type": "integer",
26
+ "minimum": -9007199254740991,
27
+ "maximum": 9007199254740991
28
+ },
29
+ "mac_address": {
30
+ "description": "Server MAC for ethernet mode",
31
+ "type": "string"
32
+ },
33
+ "certificate": {
34
+ "type": "string"
35
+ },
36
+ "auth": {
37
+ "description": "Comma-separated, e.g. 'sha256,sha1'",
38
+ "type": "string"
39
+ },
40
+ "cipher": {
41
+ "description": "Comma-separated, e.g. 'aes256-cbc,aes256-gcm'",
42
+ "type": "string"
43
+ },
44
+ "max_mtu": {
45
+ "type": "integer",
46
+ "minimum": -9007199254740991,
47
+ "maximum": 9007199254740991
48
+ },
49
+ "default_profile": {
50
+ "type": "string"
51
+ },
52
+ "require_client_certificate": {
53
+ "type": "boolean"
54
+ },
55
+ "comment": {
56
+ "type": "string"
57
+ },
58
+ "disabled": {
59
+ "default": false,
60
+ "type": "boolean"
61
+ }
62
+ },
63
+ "required": ["name", "port", "disabled"],
64
+ "additionalProperties": false
65
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "disable_ovpn_server",
4
+ "type": "object",
5
+ "properties": {
6
+ "name": {
7
+ "type": "string"
8
+ }
9
+ },
10
+ "required": ["name"],
11
+ "additionalProperties": false
12
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "enable_ovpn_server",
4
+ "type": "object",
5
+ "properties": {
6
+ "name": {
7
+ "type": "string"
8
+ }
9
+ },
10
+ "required": ["name"],
11
+ "additionalProperties": false
12
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "list_ovpn_servers",
4
+ "type": "object",
5
+ "properties": {
6
+ "name_filter": {
7
+ "description": "Partial name match",
8
+ "type": "string"
9
+ }
10
+ },
11
+ "additionalProperties": false
12
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "remove_ovpn_server",
4
+ "type": "object",
5
+ "properties": {
6
+ "name": {
7
+ "type": "string"
8
+ }
9
+ },
10
+ "required": ["name"],
11
+ "additionalProperties": false
12
+ }
@@ -0,0 +1,57 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "update_ovpn_server",
4
+ "type": "object",
5
+ "properties": {
6
+ "name": {
7
+ "type": "string",
8
+ "description": "Existing OpenVPN server instance name"
9
+ },
10
+ "port": {
11
+ "type": "integer",
12
+ "minimum": -9007199254740991,
13
+ "maximum": 9007199254740991
14
+ },
15
+ "protocol": {
16
+ "type": "string",
17
+ "enum": ["tcp", "udp"]
18
+ },
19
+ "mode": {
20
+ "type": "string",
21
+ "enum": ["ip", "ethernet"]
22
+ },
23
+ "netmask": {
24
+ "type": "integer",
25
+ "minimum": -9007199254740991,
26
+ "maximum": 9007199254740991
27
+ },
28
+ "mac_address": {
29
+ "type": "string"
30
+ },
31
+ "certificate": {
32
+ "type": "string"
33
+ },
34
+ "auth": {
35
+ "type": "string"
36
+ },
37
+ "cipher": {
38
+ "type": "string"
39
+ },
40
+ "max_mtu": {
41
+ "type": "integer",
42
+ "minimum": -9007199254740991,
43
+ "maximum": 9007199254740991
44
+ },
45
+ "default_profile": {
46
+ "type": "string"
47
+ },
48
+ "require_client_certificate": {
49
+ "type": "boolean"
50
+ },
51
+ "comment": {
52
+ "type": "string"
53
+ }
54
+ },
55
+ "required": ["name"],
56
+ "additionalProperties": false
57
+ }