@usex/mikrotik-mcp 4.10.0 → 4.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usex/mikrotik-mcp",
3
- "version": "4.10.0",
3
+ "version": "4.12.0",
4
4
  "description": "MCP server for MikroTik RouterOS — 780+ tools over SSH for firewall, NAT, routing, DHCP, DNS, WireGuard, wireless, QoS and more.",
5
5
  "keywords": [
6
6
  "ai",
@@ -85,7 +85,7 @@
85
85
  "@modelcontextprotocol/ext-apps": "^1.7.4",
86
86
  "@modelcontextprotocol/sdk": "^1.29.0",
87
87
  "@tikoci/centrs": "^0.1.0",
88
- "figlet": "^1.11.0",
88
+ "figlet": "^1.11.1",
89
89
  "gradient-string": "^3.0.0",
90
90
  "ipaddr.js": "^2.4.0",
91
91
  "ssh2": "^1.17.0",
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: setup-port-scan-detection
3
+ title: Set up port-scan detection (detect + tag, never block)
4
+ description: Pick a device, present the six port-scan signatures, let the user choose which to enable, validate the trust list, then install them into a trust-excluding detect-portscan jump-gate — snapshotted and applied under Safe Mode. Detects and tags scanners; never blocks.
5
+ arguments:
6
+ - name: device
7
+ description: Which configured device to protect (config key or label from list_mikrotik_devices). Omit to discover the devices and let the user choose.
8
+ required: false
9
+ - name: trusted_list_name
10
+ description: The existing management/trusted address-list on that device (e.g. Trust-IP). Omit to discover it and confirm with the user — it must already exist and contain the address you manage the device from.
11
+ required: false
12
+ ---
13
+
14
+ You are setting up **port-scan detection** on a MikroTik router managed by this
15
+ MCP server. These rules **detect and tag** a scanning source into an address list
16
+ (default `port scanners`) — they **never drop or block** anything. Blocking is a
17
+ separate, deliberately out-of-scope concern (see the closing note). The server may
18
+ manage several routers, so establish which one first, and **never enable a
19
+ signature the user did not explicitly choose.**
20
+
21
+ Target device: {{device}}
22
+ Trusted list: {{trusted_list_name}}
23
+
24
+ ## 0. Discover the device (do this FIRST)
25
+
26
+ - Call `list_mikrotik_devices` to enumerate the configured routers (key, label,
27
+ transport target, default).
28
+ - Resolve `{{device}}` against that inventory. If it doesn't match a known key or
29
+ label, STOP and show the list — never substitute a similar name. If it was
30
+ omitted, present the inventory and **ask which device to protect.** Pass that
31
+ device on every subsequent tool call.
32
+
33
+ ## 1. Present the catalog and get an EXPLICIT selection (mandatory)
34
+
35
+ - Call `list_port_scan_detection_signatures` (with the chosen `device` so it also
36
+ reports which signatures are already present). Show the user **all six** with
37
+ their one-line descriptions and exact match syntax:
38
+ - `psd_generic` — "Port scanners to list" — RouterOS built-in PSD heuristic;
39
+ catches ordinary `nmap -sT/-sS` sweeps the flag signatures can't see.
40
+ - `nmap_fin_stealth` — "NMAP FIN Stealth scan" — lone FIN (`nmap -sF`).
41
+ - `syn_fin_scan` — "SYN/FIN scan" — impossible SYN+FIN combo.
42
+ - `syn_rst_scan` — "SYN/RST scan" — impossible SYN+RST combo.
43
+ - `fin_psh_urg_scan` — "FIN/PSH/URG scan" — Nmap `-sX` Xmas scan.
44
+ - `nmap_null_scan` — "NMAP NULL scan" — Nmap `-sN`, no flags set.
45
+ - **Ask the user which specific signature IDs to enable.** Do NOT infer, do NOT
46
+ default to all six, do NOT default to none. Wait for an explicit list. There is
47
+ no select-all. A good default suggestion to offer (but still confirm): all six,
48
+ since they only tag and don't block — but the choice is the user's.
49
+
50
+ ## 2. Validate the trust list (pre-flight, before any write)
51
+
52
+ The detection chain is gated by a single `input` jump that EXCLUDES a trusted
53
+ address-list, so a trusted source is never tagged. That protection is only real if
54
+ the trust list exists and contains your management address:
55
+
56
+ - Determine `{{trusted_list_name}}` — the actual management/trusted list on THIS
57
+ device (commonly `Trust-IP`, but confirm; there is no default). If omitted, call
58
+ `list_address_lists` (`device=<name>`) and ask the user which list holds their
59
+ trusted management addresses.
60
+ - Confirm with `list_address_lists` that the list **exists and is non-empty**. If
61
+ it is missing or empty, STOP: this design protects nothing without it. Guide the
62
+ user to create/populate it with their management address(es) first (e.g.
63
+ `add_address_list_entry list=<trusted_list_name> address=<your-mgmt-IP>`). Do NOT
64
+ auto-create or auto-populate it as part of this flow.
65
+ - **Explicitly ask the human to confirm** that the address they are currently
66
+ managing this device from is in that list. The tool cannot know which IP you
67
+ connect from, so this is a human acknowledgement — you will pass it as
68
+ `confirmed_trusted_list_includes_my_ip=true`, and you may only set it after the
69
+ user has said yes.
70
+
71
+ ## 3. Apply (only after the selection + trust confirmation)
72
+
73
+ - Call `add_port_scan_detection_rules` with:
74
+ - `device` = the chosen device,
75
+ - `rule_types` = **exactly** the signature IDs the user named (non-empty),
76
+ - `trusted_list_name` = the validated list,
77
+ - `address_list_name` (optional, default `"port scanners"`),
78
+ - `address_list_timeout` (optional, default `"2w"`),
79
+ - `confirm=true`,
80
+ - `confirmed_trusted_list_includes_my_ip=true`.
81
+ - The tool: captures a config snapshot (returns a `snapshot_id`), creates the
82
+ `detect-portscan` chain if absent, installs the single trust-excluding jump —
83
+ positioned **before** the input default-deny (or appended after the management
84
+ accepts if there is none), inserts only the not-yet-present signatures, and
85
+ applies everything inside **Safe Mode** (auto-reverts if your session drops).
86
+ - It is **idempotent**: re-running with the same selection adds nothing and reports
87
+ already-present rules. It will refuse if `rule_types` is empty, contains an
88
+ unknown value, or if the trust list is missing/empty.
89
+
90
+ ## 4. Verify management access (do not skip)
91
+
92
+ - Present the tool's result: the `snapshot_id`, which signatures were added vs.
93
+ already present, the jump gate's position relative to the default-deny, and the
94
+ final `detect-portscan` chain.
95
+ - **Instruct the user to verify their management access (SSH/Winbox/whatever they
96
+ use) from a SEPARATE, FRESH connection now**, before considering the change
97
+ final. Safe Mode's auto-revert is the safety net, but confirm no lockout. If
98
+ anything is wrong, roll back with
99
+ `diff_config_snapshots from=<snapshot_id> to=live` and the snapshot tools.
100
+ - If the tool noted this device has **no input default-deny**, mention it as an
101
+ unrelated observation — do not fix it here (out of scope).
102
+
103
+ ## Scope — detection only
104
+
105
+ These rules only populate the `port scanners` list; they do not block it. To turn
106
+ that list into an active drop, use the separate, purpose-built
107
+ `enforce_address_list_blocking` (Security Hardening) after confirming your trusted
108
+ sources are safely excluded — never fold blocking into this detection step. Do not
109
+ enable any signature the user didn't explicitly choose.
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 819 tools: `name`, `risk`, `title`, `description`, and input JSON Schema. |
10
+ | `tool-catalog.json` | Every one of the 821 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": "4.10.0",
3
+ "version": "4.12.0",
4
4
  "generated": "by scripts/gen-schemas.ts — do not edit by hand",
5
- "toolCount": 819,
5
+ "toolCount": 821,
6
6
  "tools": [
7
7
  {
8
8
  "name": "find_tools",
@@ -12780,9 +12780,11 @@
12780
12780
  "type": "string"
12781
12781
  },
12782
12782
  "in_interface": {
12783
+ "description": "Match by inbound interface NAME (e.g. ether1, pppoe-out1) — NOT a chain and NOT an interface list. For an interface list use in_interface_list.",
12783
12784
  "type": "string"
12784
12785
  },
12785
12786
  "out_interface": {
12787
+ "description": "Match by outbound interface NAME (e.g. ether1, pppoe-out1) — NOT a chain and NOT an interface list. For an interface list use out_interface_list.",
12786
12788
  "type": "string"
12787
12789
  },
12788
12790
  "connection_state": {
@@ -13075,9 +13077,11 @@
13075
13077
  "type": "string"
13076
13078
  },
13077
13079
  "in_interface": {
13080
+ "description": "Inbound interface NAME (e.g. ether1) — not a chain; use in_interface_list for a list.",
13078
13081
  "type": "string"
13079
13082
  },
13080
13083
  "out_interface": {
13084
+ "description": "Outbound interface NAME (e.g. ether1) — not a chain; use out_interface_list for a list.",
13081
13085
  "type": "string"
13082
13086
  },
13083
13087
  "connection_state": {
@@ -16015,6 +16019,89 @@
16015
16019
  "additionalProperties": false
16016
16020
  }
16017
16021
  },
16022
+ {
16023
+ "name": "list_port_scan_detection_signatures",
16024
+ "title": "List Port-Scan Detection Signatures",
16025
+ "risk": "read",
16026
+ "annotations": {
16027
+ "readOnlyHint": true,
16028
+ "idempotentHint": true,
16029
+ "openWorldHint": false
16030
+ },
16031
+ "description": "Read-only catalog of the six port-scan detection signatures this fleet can install (psd_generic, nmap_fin_stealth, syn_fin_scan, syn_rst_scan, fin_psh_urg_scan, nmap_null_scan) — each with its id, display name, one-line description and exact RouterOS match syntax. CALL THIS FIRST and show the user all six signatures with their descriptions. Do NOT proceed to add_port_scan_detection_rules until the user has explicitly named which specific signature IDs they want — never infer, never default to all six, never default to none. When `device` is supplied, also reports per signature whether it is already present in that device's detect-portscan chain. (On a multi-device server, target the device with the `device` selector this tool exposes.)",
16032
+ "inputSchema": {
16033
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
16034
+ "type": "object",
16035
+ "properties": {},
16036
+ "additionalProperties": false
16037
+ }
16038
+ },
16039
+ {
16040
+ "name": "add_port_scan_detection_rules",
16041
+ "title": "Add Port-Scan Detection Rules",
16042
+ "risk": "dangerous",
16043
+ "annotations": {
16044
+ "destructiveHint": true,
16045
+ "openWorldHint": false
16046
+ },
16047
+ "description": "Installs the user-selected port-scan detection signatures into a dedicated `detect-portscan` sub-chain, gated by a single input jump that EXCLUDES a trusted address-list (so trusted sources are never tagged). These rules only add the source to an address list — they NEVER drop or block. NEVER call this with a guessed or default set of rule_types: it must only be called with signature IDs the user explicitly chose after seeing list_port_scan_detection_signatures — there is no select-all. Requires `trusted_list_name` (must already exist and be non-empty on the device) and the human acknowledgement `confirmed_trusted_list_includes_my_ip=true`. Captures a config snapshot and applies every write inside Safe Mode (auto-revert on session drop). Idempotent — a second identical run adds nothing. Enforcement/blocking of the tagged list is intentionally out of scope.",
16048
+ "inputSchema": {
16049
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
16050
+ "type": "object",
16051
+ "properties": {
16052
+ "rule_types": {
16053
+ "minItems": 1,
16054
+ "type": "array",
16055
+ "items": {
16056
+ "type": "string",
16057
+ "enum": [
16058
+ "psd_generic",
16059
+ "nmap_fin_stealth",
16060
+ "syn_fin_scan",
16061
+ "syn_rst_scan",
16062
+ "fin_psh_urg_scan",
16063
+ "nmap_null_scan"
16064
+ ]
16065
+ },
16066
+ "description": "REQUIRED, non-empty. The specific signature IDs the user explicitly chose after seeing the catalog. No default, no select-all — unknown values are rejected."
16067
+ },
16068
+ "trusted_list_name": {
16069
+ "type": "string",
16070
+ "minLength": 1,
16071
+ "description": "REQUIRED. The management/trusted address-list on THIS device (no default). Must already exist and contain at least one entry, or the call is refused."
16072
+ },
16073
+ "address_list_name": {
16074
+ "default": "port scanners",
16075
+ "description": "Address list detected scanners are tagged into (default \"port scanners\").",
16076
+ "type": "string"
16077
+ },
16078
+ "address_list_timeout": {
16079
+ "default": "2w",
16080
+ "description": "How long a detected source stays tagged (default \"2w\").",
16081
+ "type": "string"
16082
+ },
16083
+ "confirm": {
16084
+ "type": "boolean",
16085
+ "const": true,
16086
+ "description": "Must be true to write."
16087
+ },
16088
+ "confirmed_trusted_list_includes_my_ip": {
16089
+ "type": "boolean",
16090
+ "const": true,
16091
+ "description": "Human acknowledgement that the address you currently manage this device from is present in trusted_list_name. The tool cannot infer this — it must be explicitly true."
16092
+ }
16093
+ },
16094
+ "required": [
16095
+ "rule_types",
16096
+ "trusted_list_name",
16097
+ "address_list_name",
16098
+ "address_list_timeout",
16099
+ "confirm",
16100
+ "confirmed_trusted_list_includes_my_ip"
16101
+ ],
16102
+ "additionalProperties": false
16103
+ }
16104
+ },
16018
16105
  {
16019
16106
  "name": "setup_port_knock",
16020
16107
  "title": "Set Up Port-Knock Guardian",
@@ -0,0 +1,57 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "add_port_scan_detection_rules",
4
+ "type": "object",
5
+ "properties": {
6
+ "rule_types": {
7
+ "minItems": 1,
8
+ "type": "array",
9
+ "items": {
10
+ "type": "string",
11
+ "enum": [
12
+ "psd_generic",
13
+ "nmap_fin_stealth",
14
+ "syn_fin_scan",
15
+ "syn_rst_scan",
16
+ "fin_psh_urg_scan",
17
+ "nmap_null_scan"
18
+ ]
19
+ },
20
+ "description": "REQUIRED, non-empty. The specific signature IDs the user explicitly chose after seeing the catalog. No default, no select-all — unknown values are rejected."
21
+ },
22
+ "trusted_list_name": {
23
+ "type": "string",
24
+ "minLength": 1,
25
+ "description": "REQUIRED. The management/trusted address-list on THIS device (no default). Must already exist and contain at least one entry, or the call is refused."
26
+ },
27
+ "address_list_name": {
28
+ "default": "port scanners",
29
+ "description": "Address list detected scanners are tagged into (default \"port scanners\").",
30
+ "type": "string"
31
+ },
32
+ "address_list_timeout": {
33
+ "default": "2w",
34
+ "description": "How long a detected source stays tagged (default \"2w\").",
35
+ "type": "string"
36
+ },
37
+ "confirm": {
38
+ "type": "boolean",
39
+ "const": true,
40
+ "description": "Must be true to write."
41
+ },
42
+ "confirmed_trusted_list_includes_my_ip": {
43
+ "type": "boolean",
44
+ "const": true,
45
+ "description": "Human acknowledgement that the address you currently manage this device from is present in trusted_list_name. The tool cannot infer this — it must be explicitly true."
46
+ }
47
+ },
48
+ "required": [
49
+ "rule_types",
50
+ "trusted_list_name",
51
+ "address_list_name",
52
+ "address_list_timeout",
53
+ "confirm",
54
+ "confirmed_trusted_list_includes_my_ip"
55
+ ],
56
+ "additionalProperties": false
57
+ }
@@ -41,9 +41,11 @@
41
41
  "type": "string"
42
42
  },
43
43
  "in_interface": {
44
+ "description": "Match by inbound interface NAME (e.g. ether1, pppoe-out1) — NOT a chain and NOT an interface list. For an interface list use in_interface_list.",
44
45
  "type": "string"
45
46
  },
46
47
  "out_interface": {
48
+ "description": "Match by outbound interface NAME (e.g. ether1, pppoe-out1) — NOT a chain and NOT an interface list. For an interface list use out_interface_list.",
47
49
  "type": "string"
48
50
  },
49
51
  "connection_state": {
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "list_port_scan_detection_signatures",
4
+ "type": "object",
5
+ "properties": {},
6
+ "additionalProperties": false
7
+ }
@@ -28,9 +28,11 @@
28
28
  "type": "string"
29
29
  },
30
30
  "in_interface": {
31
+ "description": "Inbound interface NAME (e.g. ether1) — not a chain; use in_interface_list for a list.",
31
32
  "type": "string"
32
33
  },
33
34
  "out_interface": {
35
+ "description": "Outbound interface NAME (e.g. ether1) — not a chain; use out_interface_list for a list.",
34
36
  "type": "string"
35
37
  },
36
38
  "connection_state": {