@usex/mikrotik-mcp 4.24.0 → 5.0.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 (74) hide show
  1. package/README.md +108 -51
  2. package/dist/cli.js +1839 -554
  3. package/dist/index.d.ts +57 -0
  4. package/dist/index.js +1 -1
  5. package/dist/shared/{library-2f8ty72a.js → cli-2dj736ma.js} +34321 -22476
  6. package/dist/shared/{cli-ps0h2mxx.js → cli-vvy7yfyg.js} +1 -1
  7. package/dist/shared/{cli-10wtq3xb.js → library-13dhfdnq.js} +29451 -18574
  8. package/dist/shared/{library-phwm9kqe.js → library-syt5fmtj.js} +1 -1
  9. package/dist/ui/observability.html +70 -62
  10. package/package.json +3 -2
  11. package/policies/baseline.yaml +180 -0
  12. package/prompts/backup-and-document.md +28 -18
  13. package/prompts/build-tunnel-transactionally.md +74 -0
  14. package/prompts/fleet-rollout.md +68 -0
  15. package/prompts/setup-traffic-flow.md +68 -0
  16. package/schemas/README.md +1 -1
  17. package/schemas/config.schema.json +367 -4
  18. package/schemas/tool-catalog.json +3044 -1152
  19. package/schemas/tools/abort_rollout.json +17 -0
  20. package/schemas/tools/abort_transaction.json +17 -0
  21. package/schemas/tools/add_alert_rule.json +45 -0
  22. package/schemas/tools/add_ipv6_route.json +1 -1
  23. package/schemas/tools/add_route.json +3 -2
  24. package/schemas/tools/add_schedule.json +50 -0
  25. package/schemas/tools/add_script.json +1 -1
  26. package/schemas/tools/add_traffic_flow_target.json +36 -0
  27. package/schemas/tools/add_transaction_step.json +21 -0
  28. package/schemas/tools/analyze_flows.json +25 -0
  29. package/schemas/tools/begin_transaction.json +109 -0
  30. package/schemas/tools/block_attacker.json +22 -0
  31. package/schemas/tools/check_policy_snapshot.json +20 -0
  32. package/schemas/tools/commit_transaction.json +13 -0
  33. package/schemas/tools/configure_attack_response.json +12 -0
  34. package/schemas/tools/diff_explanations.json +24 -0
  35. package/schemas/tools/explain_device.json +22 -0
  36. package/schemas/tools/explain_policy_finding.json +17 -0
  37. package/schemas/tools/explain_rule_reachability.json +18 -0
  38. package/schemas/tools/explain_section.json +32 -0
  39. package/schemas/tools/export_policy_report.json +22 -0
  40. package/schemas/tools/flow_top_talkers.json +31 -0
  41. package/schemas/tools/get_alert_history.json +26 -0
  42. package/schemas/tools/get_attack_incident.json +13 -0
  43. package/schemas/tools/get_audit_timeline.json +24 -0
  44. package/schemas/tools/get_device_capabilities.json +7 -0
  45. package/schemas/tools/get_traffic_flow_settings.json +7 -0
  46. package/schemas/tools/list_alert_rules.json +7 -0
  47. package/schemas/tools/list_attack_incidents.json +27 -0
  48. package/schemas/tools/list_attack_responses.json +20 -0
  49. package/schemas/tools/list_policies.json +17 -0
  50. package/schemas/tools/list_schedules.json +12 -0
  51. package/schemas/tools/list_traffic_flow_targets.json +7 -0
  52. package/schemas/tools/mute_alert_rule.json +18 -0
  53. package/schemas/tools/plan_rollout.json +95 -0
  54. package/schemas/tools/refresh_device_capabilities.json +7 -0
  55. package/schemas/tools/remove_alert_rule.json +13 -0
  56. package/schemas/tools/remove_schedule.json +13 -0
  57. package/schemas/tools/remove_traffic_flow_target.json +13 -0
  58. package/schemas/tools/rollout_status.json +12 -0
  59. package/schemas/tools/run_policy_check.json +12 -0
  60. package/schemas/tools/run_schedule_now.json +13 -0
  61. package/schemas/tools/scan_for_attacks.json +21 -0
  62. package/schemas/tools/set_traffic_flow_settings.json +28 -0
  63. package/schemas/tools/simulate_change.json +72 -0
  64. package/schemas/tools/simulate_packet.json +53 -0
  65. package/schemas/tools/simulate_suite.json +71 -0
  66. package/schemas/tools/start_flow_collector.json +14 -0
  67. package/schemas/tools/start_rollout.json +98 -0
  68. package/schemas/tools/stop_flow_collector.json +7 -0
  69. package/schemas/tools/test_alert_channel.json +14 -0
  70. package/schemas/tools/unblock_attacker.json +20 -0
  71. package/schemas/tools/update_alert_rule.json +41 -0
  72. package/schemas/tools/update_route.json +3 -2
  73. package/schemas/tools/validate_policy_file.json +16 -0
  74. package/schemas/tools/verify_transaction.json +13 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usex/mikrotik-mcp",
3
- "version": "4.24.0",
3
+ "version": "5.0.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",
@@ -30,6 +30,7 @@
30
30
  "workspaces": [],
31
31
  "files": [
32
32
  "dist",
33
+ "policies",
33
34
  "prompts",
34
35
  "schemas"
35
36
  ],
@@ -108,7 +109,7 @@
108
109
  "clsx": "^2.1.1",
109
110
  "gsap": "^3.15.0",
110
111
  "license-checker": "^25.0.1",
111
- "lucide-react": "^1.27.0",
112
+ "lucide-react": "^1.28.0",
112
113
  "radix-ui": "^1.6.7",
113
114
  "react": "^19.2.8",
114
115
  "react-dom": "^19.2.8",
@@ -0,0 +1,180 @@
1
+ version: 1
2
+ name: MikroTik baseline hardening
3
+ # The bundled starter pack. Every rule here is drawn from a check the Security
4
+ # Hardening and Compliance Auditor modules already make, restated in the policy
5
+ # language so the file doubles as a worked example of the schema.
6
+ #
7
+ # Copy it, edit it, and point `policy.paths` at your own copy — these are a
8
+ # starting position, not a standard.
9
+ policies:
10
+ # ── Management plane ─────────────────────────────────────────────────────
11
+ - id: telnet-disabled
12
+ severity: critical
13
+ description: Telnet must be disabled — it carries credentials in clear text.
14
+ remediation: /ip service set telnet disabled=yes
15
+ match: { section: /ip/service, where: { name: telnet } }
16
+ assert: { field: disabled, equals: "yes" }
17
+ tags: [management, cis]
18
+
19
+ - id: ftp-disabled
20
+ severity: high
21
+ description: The FTP service must be disabled unless a device genuinely serves files.
22
+ remediation: /ip service set ftp disabled=yes
23
+ match: { section: /ip/service, where: { name: ftp } }
24
+ assert: { field: disabled, equals: "yes" }
25
+ tags: [management]
26
+
27
+ - id: ssh-strong-crypto
28
+ severity: high
29
+ description: SSH must use strong crypto (disables the legacy ciphers and 1024-bit DH).
30
+ remediation: /ip ssh set strong-crypto=yes
31
+ match: { section: /ip/ssh, settings: true }
32
+ assert: { field: strong-crypto, equals: "yes" }
33
+ tags: [management, crypto]
34
+
35
+ - id: ssh-forwarding-off
36
+ severity: medium
37
+ description: SSH TCP forwarding turns a router into a tunnel endpoint; leave it off unless a jump host needs it.
38
+ remediation: /ip ssh set forwarding-enabled=no
39
+ match: { section: /ip/ssh, settings: true }
40
+ assert:
41
+ none_of:
42
+ - { field: forwarding-enabled, equals: both }
43
+ tags: [management]
44
+
45
+ - id: no-default-admin
46
+ severity: critical
47
+ description: The stock `admin` account must be renamed or removed.
48
+ remediation: Create a named account with full policy, then /user remove admin
49
+ match: { section: /user, where: { name: admin } }
50
+ # Reaching this rule at all means an account literally named `admin` exists.
51
+ assert: { count: { exactly: 0 } }
52
+ on_empty: pass
53
+ tags: [accounts]
54
+
55
+ - id: users-have-comments
56
+ severity: low
57
+ description: Every account should say who it belongs to.
58
+ remediation: /user set <name> comment="owner"
59
+ match: { section: /user }
60
+ assert: { field: comment, present: true }
61
+ tags: [accounts, hygiene]
62
+
63
+ # ── Discovery & neighbour exposure ───────────────────────────────────────
64
+ - id: neighbor-discovery-scoped
65
+ severity: medium
66
+ description: Neighbour discovery must be limited to an interface list, not left on all interfaces.
67
+ remediation: /ip neighbor discovery-settings set discover-interface-list=LAN
68
+ match: { section: /ip/neighbor/discovery-settings, settings: true }
69
+ assert: { field: discover-interface-list, not_in: [all, none] }
70
+ tags: [discovery]
71
+
72
+ - id: mac-server-scoped
73
+ severity: medium
74
+ description: MAC-Telnet must be restricted to a management interface list.
75
+ remediation: /tool mac-server set allowed-interface-list=LAN
76
+ match: { section: /tool/mac-server, settings: true }
77
+ assert:
78
+ none_of:
79
+ - { field: allowed-interface-list, equals: all }
80
+ tags: [discovery, management]
81
+
82
+ - id: bandwidth-server-off
83
+ severity: low
84
+ description: The bandwidth-test server should be disabled when not actively testing.
85
+ remediation: /tool bandwidth-server set enabled=no
86
+ match: { section: /tool/bandwidth-server, settings: true }
87
+ assert: { field: enabled, equals: "no" }
88
+ tags: [services]
89
+
90
+ # ── Firewall ─────────────────────────────────────────────────────────────
91
+ - id: input-chain-has-drop
92
+ severity: critical
93
+ description: The input chain must end in an explicit drop — an implicit accept is not a firewall.
94
+ remediation: /ip firewall filter add chain=input action=drop comment="default deny"
95
+ match: { section: /ip/firewall/filter, where: { chain: input, action: drop } }
96
+ assert: { count: { min: 1 } }
97
+ tags: [firewall, default-deny]
98
+
99
+ - id: no-bare-input-accept
100
+ severity: critical
101
+ description: An input-chain accept must be scoped by address-list, interface list or connection state.
102
+ remediation: Add src-address-list=, in-interface-list= or connection-state= to the rule.
103
+ match: { section: /ip/firewall/filter, where: { chain: input, action: accept } }
104
+ assert:
105
+ any_of:
106
+ - { field: src-address-list, present: true }
107
+ - { field: in-interface-list, present: true }
108
+ - { field: connection-state, contains: established }
109
+ - { field: in-interface, present: true }
110
+ tags: [firewall]
111
+
112
+ - id: no-disabled-firewall-rules
113
+ severity: low
114
+ description: A disabled firewall rule is dead weight that hides intent — delete it or enable it.
115
+ remediation: Remove the rule, or enable it if it is still needed.
116
+ match: { section: /ip/firewall/filter }
117
+ # `none_of` rather than `not_equals`: a missing field fails every value
118
+ # predicate, and most rules simply omit `disabled=`. "must not be yes"
119
+ # (absent counts as fine) is `none_of`; "present and different" is
120
+ # `not_equals`. This is the single most common authoring mistake.
121
+ assert:
122
+ none_of:
123
+ - { field: disabled, equals: "yes" }
124
+ tags: [firewall, hygiene]
125
+
126
+ - id: ipv6-firewall-present
127
+ severity: high
128
+ description: A device with IPv6 addresses must also filter IPv6 — an IPv4-only firewall is half a firewall.
129
+ remediation: /ipv6 firewall filter add chain=input action=drop
130
+ match: { section: /ipv6/firewall/filter, where: { chain: input, action: drop } }
131
+ assert: { count: { min: 1 } }
132
+ on_empty: fail
133
+ tags: [firewall, ipv6]
134
+
135
+ # ── Kernel & routing ─────────────────────────────────────────────────────
136
+ - id: rp-filter-enabled
137
+ severity: high
138
+ description: Reverse-path filtering must be on, so spoofed source addresses are dropped.
139
+ remediation: /ip settings set rp-filter=strict
140
+ match: { section: /ip/settings, settings: true }
141
+ assert: { field: rp-filter, in: [strict, loose] }
142
+ tags: [kernel, anti-spoof]
143
+
144
+ - id: no-ip-forwarding-of-source-routes
145
+ severity: medium
146
+ description: Source-routed packets must not be accepted.
147
+ remediation: /ip settings set accept-source-route=no
148
+ match: { section: /ip/settings, settings: true }
149
+ assert:
150
+ none_of:
151
+ - { field: accept-source-route, equals: "yes" }
152
+ tags: [kernel]
153
+
154
+ # ── Time & logging ───────────────────────────────────────────────────────
155
+ - id: ntp-client-enabled
156
+ severity: medium
157
+ description: NTP must be enabled — every log timestamp and certificate check depends on it.
158
+ remediation: /system ntp client set enabled=yes servers=...
159
+ match: { section: /system/ntp/client, settings: true }
160
+ assert: { field: enabled, equals: "yes" }
161
+ tags: [time]
162
+
163
+ - id: remote-logging-configured
164
+ severity: medium
165
+ description: At least one logging action must ship logs off the device; local logs die with the router.
166
+ remediation: /system logging action add name=remote target=remote remote=<syslog-host>
167
+ match: { section: /system/logging/action, where: { target: remote } }
168
+ assert: { count: { min: 1 } }
169
+ on_empty: fail
170
+ tags: [logging]
171
+
172
+ - id: dns-not-open-resolver
173
+ severity: high
174
+ description: Remote DNS requests must be off, or the router becomes an open resolver for amplification attacks.
175
+ remediation: /ip dns set allow-remote-requests=no (or firewall port 53 on the WAN)
176
+ match: { section: /ip/dns, settings: true }
177
+ assert:
178
+ none_of:
179
+ - { field: allow-remote-requests, equals: "yes" }
180
+ tags: [dns, amplification]
@@ -14,24 +14,34 @@ change is creating a backup/export.
14
14
  written on the router's flash. Give it a descriptive `label` (e.g. `pre-audit`).
15
15
  2. **Device restore point** — `create_backup` (binary, for full restore) and
16
16
  `create_export` (text `.rsc`, for review/diff). List them with `list_backups`.
17
- 3. **Inventory** — gather the configuration with read tools and organize it:
18
- - System: `get_system_identity`, `get_system_resources`, `get_routerboard`,
19
- `get_installed_packages`.
20
- - L2/L3: `list_interfaces`, `list_vlan_interfaces`, `list_bridges`,
21
- `list_ip_addresses`, `list_ip_pools`.
22
- - Services: `list_dhcp_servers`, `get_dns_settings`, `list_dns_static`,
23
- `list_ip_services`.
24
- - Routing: `list_routes`, `get_routing_table`.
25
- - Security: `list_filter_rules`, `list_nat_rules`, `list_address_lists`,
26
- `list_users`, `list_certificates`.
27
- - VPN/QoS: `list_wireguard_interfaces` + `list_wireguard_peers`,
28
- `list_simple_queues`, `list_queue_trees`.
29
- - Containers: `list_containers` (if the container feature is enabled).
30
- - Automation: `list_schedulers`, `list_scripts`.
17
+ 3. **The write-up** — call `explain_device`. It analyses the configuration on the
18
+ MCP host and returns a finished architecture document: inferred role with the
19
+ signals behind it, topology with a Mermaid diagram, addressing and DHCP
20
+ scopes, the internet path, what each firewall chain does, what is exposed to
21
+ the internet, tunnels, management services, and an explicit list of anything
22
+ it did not recognise.
31
23
 
32
- Produce a structured Markdown report: a one-paragraph overview, a table of
33
- interfaces and addressing, the firewall posture, and a "things worth reviewing"
34
- section (defaults left in place, disabled-but-present rules, expiring certs
35
- check `list_certificates` for any expiring within 30 days).
24
+ Do **not** pull `/export` into the conversation to write this by hand. The
25
+ tool's output is a fraction of the size, already analysed, and identical
26
+ across runs which is what lets `diff_explanations` compare two dates later.
27
+ Use `explain_section` when the user asks about one area rather than the whole
28
+ router.
29
+
30
+ 4. **Fill the gaps `explain_device` deliberately leaves.** A configuration export
31
+ describes what is _defined_, never what is _running_, so add the live facts it
32
+ cannot know:
33
+ - `get_system_resources`, `get_routerboard`, `get_installed_packages` — uptime,
34
+ hardware, what is actually installed.
35
+ - `list_certificates` — flag anything expiring within 30 days.
36
+ - `get_wireguard_status`, `list_ipsec_active_peers` — which tunnels are up
37
+ right now, as opposed to merely configured.
38
+ - `list_schedulers`, `list_scripts` — scheduled automation.
39
+ 5. **Things worth reviewing** — run `firewall_audit` and
40
+ `run_security_hardening_audit` and summarise their findings rather than
41
+ re-deriving them by eye. Read the narrative's "what this document does not
42
+ cover" section aloud to the user: that is the part nobody understood, and it
43
+ is where the surprises live.
44
+
45
+ Present the narrative first, then the live facts, then the review section.
36
46
  Reference the snapshot id and backup/export filenames you created so the user
37
47
  knows their restore points.
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: build-tunnel-transactionally
3
+ title: Build a site-to-site tunnel as one cross-device transaction
4
+ description: Configure both ends of a tunnel under coordinated Safe Mode — verified while still uncommitted, then committed everywhere or rolled back everywhere. Never a half-built tunnel.
5
+ arguments:
6
+ - name: site_a
7
+ description: Configured device name of the first router (one end of the tunnel).
8
+ required: true
9
+ - name: site_b
10
+ description: Configured device name of the second router (the other end).
11
+ required: true
12
+ - name: tunnel
13
+ description: What to build (e.g. "WireGuard 10.99.0.0/30", "GRE over the existing WAN", "IPsec site-to-site"). If omitted, WireGuard is a good default.
14
+ required: false
15
+ ---
16
+
17
+ Build a tunnel between **{{site_a}}** and **{{site_b}}** as a single
18
+ cross-device transaction, so it either works on both ends or exists on neither.
19
+
20
+ Tunnel to build: {{tunnel}}
21
+
22
+ The failure this avoids: configured end-by-end, a tunnel whose second half fails
23
+ leaves the first half live — and if the failing change was a firewall rule, a
24
+ router you can no longer reach. Under a transaction each device stages its
25
+ changes in its own Safe Mode session; nothing persists until every end has been
26
+ verified.
27
+
28
+ Follow these steps:
29
+
30
+ 1. **Look before you write.** Read both ends: `list_interfaces`,
31
+ `list_ip_addresses`, and for WireGuard `list_wireguard_interfaces` /
32
+ `list_wireguard_peers`. Pick addresses and a port that do not collide with
33
+ anything already configured, and note which device you reach the other
34
+ THROUGH (that one must commit last).
35
+
36
+ 2. **Open the transaction.** Call `begin_transaction` with
37
+ `devices=["{{site_a}}", "{{site_b}}"]`, a `label`, and — this is the part that
38
+ makes it safe — `assertions` that prove the tunnel actually works:
39
+ - `{"kind": "ping", "from": "{{site_a}}", "to": "<{{site_b}} tunnel address>"}`
40
+ - `{"kind": "wireguard-peer-handshake", "device": "{{site_a}}", "peer": "<{{site_b}} public key>"}`
41
+ (WireGuard only)
42
+ - `{"kind": "reachable", "device": "{{site_b}}"}` — cheap insurance that the
43
+ far end is still answering after its own changes.
44
+ Set `jump_host` if one router is reached through the other; the tool warns
45
+ when it is not committed last.
46
+
47
+ 3. **Queue every command.** One `add_transaction_step` per RouterOS command,
48
+ naming the participant it runs on. Nothing executes yet. Cover both ends
49
+ completely: interface, addresses, peer/keys, the firewall rule that permits
50
+ the tunnel port, and the route(s) over it.
51
+
52
+ 4. **Prepare and verify.** Call `verify_transaction`. This snapshots each device,
53
+ applies its steps inside Safe Mode, and runs the assertions against the
54
+ still-uncommitted fleet. If anything fails, everything is rolled back
55
+ automatically and the result is `ABORTED` — nothing changed anywhere. Report
56
+ which assertion failed and fix the plan before retrying.
57
+
58
+ 5. **Commit.** Only after a clean verify, call `commit_transaction`. Read the
59
+ terminal state out loud:
60
+ - `COMMITTED` — both ends persisted; confirm with a final `ping` and
61
+ `get_wireguard_status`.
62
+ - `ABORTED` — nothing changed; safe to retry.
63
+ - `PARTIAL` — **tell the user immediately and stop**. Name each device's state
64
+ and the snapshot id in the report; the fix is a manual restore
65
+ (`diff_config_snapshots <id> live`, then `config_reconcile` or
66
+ `restore_backup`), not another blind attempt.
67
+
68
+ 6. **If you need to back out** at any point before commit, call
69
+ `abort_transaction` — it closes every Safe Mode session and RouterOS reverts
70
+ the staged changes.
71
+
72
+ Be explicit about the limits when you report: this is a best-effort distributed
73
+ commit, not a database transaction. Commits are sequential, so there is a
74
+ seconds-long window where one end is committed and the other is not.
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: fleet-rollout
3
+ title: Roll one change out across the fleet, safely
4
+ description: Apply the same change to many routers as canary → wave → fleet, with a health gate and soak between waves and automatic revert of everything already changed on the first failure.
5
+ arguments:
6
+ - name: change
7
+ description: What to change on every device (e.g. "set the NTP servers to 10.0.0.1 and 10.0.0.2", "add the management address-list entry", "disable the telnet service").
8
+ required: true
9
+ - name: targets
10
+ description: Which devices — a list of names, "all", or a tag (e.g. "branch"). If omitted, ask before selecting anything.
11
+ required: false
12
+ ---
13
+
14
+ Roll this change out across the fleet: **{{change}}**
15
+
16
+ Targets: {{targets}}
17
+
18
+ This is the highest-blast-radius thing in the toolbox: one mistake, applied
19
+ automatically to every router. The structure that makes it safe is
20
+ canary → wave → fleet with a health gate between waves — use it, and show your
21
+ work before executing.
22
+
23
+ Follow these steps:
24
+
25
+ 1. **Turn the request into exact commands.** Work out the RouterOS commands for
26
+ the change and check them against one device's current config first (a `get_*`
27
+ or `list_*` read). A rollout applies the same commands everywhere, so a
28
+ command that depends on a device-specific name (an interface, a list) is a
29
+ trap — say so rather than rolling it out.
30
+
31
+ 2. **Preview with `plan_rollout`.** It contacts nothing. Show the human:
32
+ - which devices matched (and, for a selector, which were excluded and why),
33
+ - the wave split — the canary is the device that will find the problem,
34
+ - the exact commands, and the estimated duration.
35
+ Order matters for an explicit list: put the router you reach the others
36
+ THROUGH **last**, so a change that severs its path cannot strand the rest.
37
+
38
+ 3. **Get agreement before executing.** Do not call `start_rollout` on your own
39
+ initiative for a fleet-wide change. Present the plan and ask.
40
+
41
+ 4. **Execute with `start_rollout confirm=true`.** Defaults worth stating out
42
+ loud when you do:
43
+ - `soakSeconds=30` — the wait after each wave's health check. A change that
44
+ breaks connectivity ten seconds later must not already be on every router.
45
+ - `onFailure=halt-and-revert` — the first failed gate stops the rollout and
46
+ restores every device it already changed, newest first.
47
+ Raise the soak for anything touching routing, firewall or interfaces; those
48
+ break with a delay.
49
+
50
+ 5. **Read the terminal state out loud.** Each one means something different:
51
+ - `COMPLETED` — every device applied the change.
52
+ - `HALTED and REVERTED` — a gate failed; the fleet is back where it started.
53
+ Report WHICH device and why, especially if the failure was on an untouched
54
+ device (that means the change broke something fleet-wide).
55
+ - `HALTED` (`halt-and-hold`) — changed devices are still changed, on purpose,
56
+ for inspection.
57
+ - `COMPLETED WITH FAILURES` — `continue` was set; list what failed.
58
+ - `NEEDS ATTENTION` — **stop and tell the user immediately.** A revert itself
59
+ failed; the report names the device and the snapshot id. The fix is a manual
60
+ restore (`diff_config_snapshots <id> live`, then `config_reconcile`), not
61
+ another rollout.
62
+
63
+ 6. **Verify a sample afterwards.** Read the changed setting back from the canary
64
+ and from one device in the last wave. A rollout that reports success and a
65
+ device that actually has the setting are two different facts.
66
+
67
+ To stop a rollout in flight: `abort_rollout` — it reverts everything this
68
+ rollout changed, regardless of `onFailure`.
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: setup-traffic-flow
3
+ title: Set up continuous traffic analytics (NetFlow/IPFIX)
4
+ description: Enable /ip traffic-flow, point the router at this host's collector, and start answering "who is using my bandwidth" continuously — cheap flow metadata, no packet payload.
5
+ arguments:
6
+ - name: collector_address
7
+ description: The IP address of THIS MCP host as the router sees it (e.g. 192.168.88.50). If omitted, work it out from the router's neighbour/ARP table or ask.
8
+ required: false
9
+ - name: interfaces
10
+ description: Which interfaces to sample (e.g. "ether1", "bridge"). Defaults to all.
11
+ required: false
12
+ ---
13
+
14
+ Set up continuous traffic-flow analytics for this MikroTik device.
15
+
16
+ Collector address: {{collector_address}}
17
+ Interfaces to sample: {{interfaces}}
18
+
19
+ **Explain this before you do it.** Traffic Flow makes the router export a
20
+ continuous stream of flow records — source and destination address, ports,
21
+ protocol, byte and packet counts — to a collector over UDP. It carries **no
22
+ packet payload**, which is exactly why it is cheap and privacy-preserving next
23
+ to the packet sniffer, but it is still a description of who on the network talks
24
+ to whom, sent continuously to a host. Say where it will be sent, and confirm the
25
+ address is one the user controls.
26
+
27
+ Follow these steps:
28
+
29
+ 1. **Look before you write.** `get_traffic_flow_settings` and
30
+ `list_traffic_flow_targets` — flow export may already be on and pointed
31
+ somewhere. If a target already exists that is NOT this host, mention it
32
+ rather than silently adding a second.
33
+
34
+ 2. **Work out the collector address.** It must be this MCP host's address _as
35
+ the router sees it_ — not `127.0.0.1`, which would make the router export to
36
+ itself. If it was not supplied, look at the router's `/ip address` and
37
+ neighbour tables to find the management subnet, and confirm the choice with
38
+ the user rather than guessing.
39
+
40
+ 3. **Start the receiver first.** `start_flow_collector` (default UDP 2055).
41
+ Starting the exporter before the collector just throws the first minutes of
42
+ data away.
43
+
44
+ 4. **Point the device at it.** `add_traffic_flow_target` with
45
+ `dst_address=<collector>`, `port=2055`, `version=9`. Use **9 or ipfix** —
46
+ v5 is IPv4-only and has no template mechanism, so IPv6 flows would be missing
47
+ entirely. A short `v9_template_timeout` (e.g. `30s`) makes the first decoded
48
+ flows appear sooner.
49
+
50
+ 5. **Enable export.** `set_traffic_flow_settings` with `enabled=true` and the
51
+ requested `interfaces` (default all). Mention the two timeouts:
52
+ `active_flow_timeout` (default 30m) is how long a long-lived flow is held
53
+ before being reported — lower it if the user wants fresher numbers and can
54
+ accept more export traffic.
55
+
56
+ 6. **Wait for the first template, then verify.** v9/IPFIX exporters send the
57
+ template periodically and data records are undecodable until it arrives, so
58
+ the first minute or two can legitimately be empty. Then run
59
+ `flow_top_talkers` — if it is still empty, its output names the reason
60
+ (collector not running, nothing received, templates pending, decode errors);
61
+ act on that rather than guessing.
62
+
63
+ 7. **Report what they now have.** Top talkers for the last window, and where to
64
+ look next: `analyze_flows` for the full report, the dashboard's **Flows**
65
+ page for the live view.
66
+
67
+ To undo all of this later: `remove_traffic_flow_target`,
68
+ `set_traffic_flow_settings enabled=false`, `stop_flow_collector`.
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 833 tools: `name`, `risk`, `title`, `description`, and input JSON Schema. |
10
+ | `tool-catalog.json` | Every one of the 885 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: