Skip to main content
Glama

mcp-mikrotik

CI Python 3.11 | 3.12 | 3.13 Coverage ≥95% enforced in CI License: GPL-3.0-or-later

A Model Context Protocol server for MikroTik RouterOS devices. It lets an MCP client (Claude Desktop, Claude Code, or any other MCP-compatible LLM tool) read a router's live state - interfaces, routes, DHCP, wireless, VPN, firewall, containers, logs, live traffic - and diagnose it (ping, traceroute, torch), so an operator or an LLM can answer "what's going on with this network" without opening WinBox. For a small, explicit, individually-reviewed set of changes, it can also write - every write is read-only by default, gated behind a central allowlist, and previewed before it's applied.

Philosophy: start read-only, make writes something you opt into and can review, never something an LLM reaches by accident. MIKROTIK_ALLOW_WRITE defaults to false - point this at a fleet and it can only ever read until you deliberately turn writes on. Even then there is no generic "run this RouterOS command" tool: every write is a dedicated, named function mapped to exactly one API path, and every one of them supports confirm=false to preview a change before confirm=true applies it. See "Security model" below for the full mechanism.

This is a from-scratch implementation, not a fork. It exists to correct a set of concrete failures found in an earlier project during a security audit: an unrestricted generic "run any API command" tool, an HTTP transport bound to 0.0.0.0 with no auth, command injection via string-built SSH calls, and no tests. See "Security model" below for how each of those is avoided here.

Status

1.11.0. Every planned tool round through Tier 2 has shipped, plus Tier 3's IPv6 parity item in full (reads in v1.9, writes in v1.10), plus this round's headline feature: the dead-man / lockout-proof write primitive (arm_dead_man/cancel_dead_man) and the wireless RF tuning tools it unlocks (set_wireless_channel/set_wireless_tx_power/ set_wireless_tuning/get_wireless_link_quality) - see "Dead-man / lockout-proof writes" and "Wireless RF tuning" below. The full read-tool inventory (interfaces, VLANs, routing IPv4 and IPv6, DHCP servers/ leases/networks, wireless (raw + normalized link-quality), VPN/WireGuard/ PPP, containers, LTE/5G, USB, hotspot, live traffic, backups, firewall filter/NAT/mangle IPv4 and IPv6, bridge ports & VLAN filtering, SFP/optical monitor, certificates, users/RADIUS, NTP/clock, a heuristic security audit), guarded writes across identity/interfaces/wifi/wireless-RF- tuning/dead-man/bandwidth/DHCP/address-lists (IPv4 and IPv6)/PoE/ containers/failover-routing (IPv4 and IPv6)/Netwatch/DNS/Wake-on-LAN/ firewall-rule-toggle (filter/NAT/mangle, IPv4 and IPv6)/firewall-rule- reorder/WireGuard/hotspot-vouchers/backup/VLANs/PPP-PPPoE-secrets/ NTP-servers, and the production-hardening layers this needs to run unattended against a real fleet - audit journal, correlation IDs, read retry, circuit breaker. See CHANGELOG.md for the full version-by-version history, and ROADMAP.md for what's next (and what's deliberately out of scope, and why).

The full pytest suite currently has 1794 tests (114 tools), all passing against an in-memory fake device layer (pytest -q), at 100% line coverage (CI enforces a 95% floor) - see "Development & CI" below. Many tools are additionally smoke-tested against real ROS6/ROS7 hardware before release (the v1.10 IPv6 writes are an exception - see CHANGELOG.md's v1.10 entry; v1.11's wireless RF tools were hardware-verified, see CHANGELOG.md's v1.11 entry and docs/api-notes-wireless-rf.md).

Related MCP server: vyos-mcp

Installation

Requirements:

  • Python 3.11+.

  • A MikroTik device reachable over the RouterOS API (not WinBox, not SSH) - plain API port 8728, or api-ssl port 8729. RouterOS 6.49+ (the legacy wireless wifi stack) or 7.x (the wifi package) are both supported; several read/write tools (wireless_registrations, set_wifi_ssid, bgp_sessions) detect which generation a device speaks and use the matching path automatically.

With pip:

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

With uv:

uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"

Either way this installs the mcp-mikrotik console script (see "Running" below) plus .[dev] (pytest/pytest-asyncio/pytest-cov) for running the test suite locally.

Configuration

Configuration comes from environment variables plus an optional devices.yaml file.

  1. Copy the examples:

    cp devices.yaml.example devices.yaml
    cp .env.example .env
  2. Edit devices.yaml with your real devices and credentials. This file is git-ignored - it is never meant to be committed.

  3. Edit .env (or export the variables another way) to control server-wide behaviour:

    Variable

    Default

    Meaning

    MIKROTIK_DEVICES_FILE

    devices.yaml

    Path to the devices YAML file

    MIKROTIK_ALLOW_WRITE

    false

    Enable write tools (see Security model)

    MIKROTIK_LOG_LEVEL

    INFO

    Log level for the server process (stderr); invalid values fall back to INFO with a warning

    MIKROTIK_TIMEOUT

    10

    Fallback connect timeout (seconds) for devices without their own timeout

    MIKROTIK_AUDIT_LOG

    (unset)

    File path for the JSON-lines write-audit journal; unset logs each event via logging (stderr) instead. See "Production features" below.

    MIKROTIK_READ_RETRIES

    2

    Extra retry attempts for read operations on a transient network error

    MIKROTIK_BREAKER_THRESHOLD

    3

    Consecutive connection failures before a device's circuit breaker opens

    MIKROTIK_BREAKER_COOLDOWN

    30

    Seconds a device's circuit stays open before a trial reconnect is allowed

Each device entry supports its own port and use_ssl, since a fleet is commonly a mix of plain API (8728) and api-ssl (8729) devices, and possibly a mix of RouterOS 6.x and 7.x. It can also override timeout (seconds; falls back to MIKROTIK_TIMEOUT, then 10s - useful for devices behind a slow link) and, when use_ssl: true, tls_verify (see "TLS verification for api-ssl" below).

Running

The server speaks MCP over stdio - it is meant to be launched by an MCP client (e.g. configured as a command in Claude Code), not run as a network service:

mcp-mikrotik
# or, without installing the console script:
python -m mcp_mikrotik.server

There is no HTTP transport at all - stdio only. If one is added in a future release, it must default to binding 127.0.0.1 (never 0.0.0.0) and require a bearer token from an environment variable - see the TODO(http-transport) note at the top of src/mcp_mikrotik/server.py.

Connecting an MCP client

Since mcp-mikrotik speaks MCP over stdio, any MCP-compatible client can launch it as a subprocess. For Claude Desktop, add it to claude_desktop_config.json:

{
  "mcpServers": {
    "mikrotik": {
      "command": "mcp-mikrotik",
      "env": {
        "MIKROTIK_DEVICES_FILE": "/absolute/path/to/devices.yaml",
        "MIKROTIK_ALLOW_WRITE": "false"
      }
    }
  }
}

For Claude Code, the equivalent is:

claude mcp add mikrotik --env MIKROTIK_DEVICES_FILE=/absolute/path/to/devices.yaml --env MIKROTIK_ALLOW_WRITE=false -- mcp-mikrotik

Use an absolute path for MIKROTIK_DEVICES_FILE - an MCP client typically launches the server from its own working directory, not this project's. Leave MIKROTIK_ALLOW_WRITE=false (the default) until you've read "Security model" below and deliberately want write tools enabled.

Example interactions

Once connected, an LLM caller uses the tools below directly by name. A few representative exchanges:

  • "What's the status of my core-switch?" → calls system_info and interfaces, summarizes board/RouterOS version/uptime and which interfaces are up or down.

  • "Is there a device on 192.168.88.50?" → calls dhcp_leases (and, if nothing turns up there, arp_table) filtered to that address, to tell a DHCP-assigned host from a statically-addressed one.

  • "Limit the guest on 192.168.88.77 to 5 Mbps." → calls set_client_bandwidth(target="192.168.88.77", max_limit="5M/5M", confirm=false) first, shows the before/after preview, and only calls it again with confirm=true once you confirm - this requires MIKROTIK_ALLOW_WRITE=true on the server.

Tools

Read-only

Tool

Description

list_devices

List configured devices (passwords never included).

system_info

RouterOS identity + resource info (board, version, uptime, CPU/memory).

interfaces

List interfaces; include_disabled to include disabled ones (default: excluded).

list_vlans

List VLAN interfaces (/interface/vlan: name, vlan-id, parent interface, mtu, running, disabled, comment); include_disabled to include disabled ones (default: excluded), same convention as interfaces. See "VLAN management" below.

ip_addresses

List IPv4 addresses.

ip_routes

List the IPv4 routing table; optional limit (capped at 500).

neighbors

List neighbors discovered via CDP/MNDP/LLDP.

dhcp_leases

List DHCP server leases (address, mac, host-name, status, server, comment).

simple_queues

List Simple Queue entries (name, target, max-limit, limit-at, bytes counters, disabled) - see who already has a bandwidth limit and how much traffic they've moved.

address_lists

List firewall address-list entries (list, address, timeout, dynamic, disabled) - see who's currently in which named list.

firewall_nat

List IPv4 firewall NAT rules (chain, action, to-addresses, etc). Read-only - does not add/modify/remove rules.

scheduler

List scheduled tasks (name, on-event, interval, next-run, disabled).

ip_pools

List IP pools (name, ranges).

wireless_registrations

List wireless clients currently associated to the device. Tries the ROS7 wifi registration table first, falls back to the ROS6 wireless one; returns an empty list (not an error) for a device with no radio.

wireguard_peers

List WireGuard VPN peers (name, interface, public-key, endpoint, last-handshake, rx/tx, allowed-address, disabled). Never exposes a private-key or preshared-key, even defensively. Empty list (not an error) with no WireGuard interfaces. See "VPN & routing diagnostics" below.

wireguard_interfaces

List WireGuard tunnel interfaces (name, listen-port, public-key, running, disabled, mtu). Never exposes a private-key - RouterOS's own reply genuinely carries one here (unlike wireguard_peers), always stripped before returning. Empty list (not an error) with no WireGuard interfaces. See "WireGuard management" below.

ppp_active

List active PPP-based VPN server sessions (/ppp/active: name, service - l2tp/pptp/sstp/ovpn/pppoe, caller-id, address, uptime). Empty list (not an error) with no PPP server / no active sessions.

ppp_secrets

List CONFIGURED PPP/PPPoE secrets (/ppp/secret: name, service, profile, remote-address, local-address, disabled, comment, last-logged-out) - the dial-in credentials themselves, as opposed to ppp_active's currently-connected sessions. Never exposes a secret's password, even defensively. Empty list (not an error) with no PPP server. See "PPP/PPPoE secrets" below.

ipsec_active_peers

List active IPsec peers (remote-address, state, uptime, rx/tx, side). Empty list (not an error) for a device that doesn't use IPsec.

bgp_sessions

BGP session status (remote-address/as, state, uptime, prefix-count). Tries ROS7's /routing/bgp/session first, falls back to ROS6's /routing/bgp/peer; empty list (not an error) for a device that doesn't run BGP.

ospf_neighbors

OSPF neighbor adjacencies (address, state, router-id, adjacency). Empty list (not an error) for a device that doesn't run OSPF.

netwatch

List Netwatch host monitors (host, status up/down, interval, since, comment, disabled, plus has-up-script/has-down-script presence booleans - never the raw script body). The key read for diagnosing/building failover. See "VPN & routing diagnostics" below.

dns_cache

List cached DNS records (name, type, data, ttl).

firewall_filter

List IPv4 firewall filter rules (chain, action, etc). Read-only - does not add/modify/remove rules.

firewall_mangle

List IPv4 firewall mangle rules (/ip/firewall/mangle): chain, action, comment, disabled, plus whatever other fields RouterOS returns for a given rule - these vary a lot by action (e.g. mark-connection/mark-packet/mark-routing). Read-only - does not add/modify/remove rules. See "NAT & mangle rule toggle (by comment)" below.

connection_tracking

List active connections from /ip/firewall/connection, FILTERED - at least one of src_address/dst_address/dst_port/protocol is required (a ValidationError otherwise); capped at 100 rows with a truncated flag. See "Connection tracking (filtered)" below.

system_health

System health metrics (voltage, temperature, ...), if the device exposes any; empty list otherwise.

logs

Recent log entries; limit (positive, capped at 500) and optional topics substring filter, applied before the limit cut.

ping

Ping an address from the device; address is validated as IPv4/IPv6/hostname before use.

traceroute

Traceroute to an address from the device; returns the list of hops. address validated like ping's; count/max_hops are capped low (and a fixed short per-hop timeout used internally) so the command can't run long enough to hit RouterOS's own API command timeout. Diagnostic only - not gated by MIKROTIK_ALLOW_WRITE.

arp_table

List the IPv4 ARP table (address, mac-address, interface, dynamic, complete) - cross-reference IP↔MAC for a statically-addressed device that doesn't show up in dhcp_leases.

bridge_hosts

List /interface/bridge/host entries (mac-address, on-interface, bridge, dynamic, local) - find which physical bridge port a MAC is currently on.

interface_traffic

Current rx/tx rate of one interface (/interface/monitor-traffic once=yes); interface is validated for shape before use. A single instantaneous reading, not a stream - see "Physical layer & PoE control" below.

poe_status

PoE configuration + live consumption for every PoE-capable ethernet port on the device (voltage/current/power/poe-out-status); empty list (not an error) for a device with no PoE hardware. See "Physical layer & PoE control" below.

lte_status

Signal/status of one LTE/5G modem interface (/interface/lte/monitor once=yes) - operator, technology (3G/LTE/5G), signal (rsrp/rsrq/sinr/rssi), band, registration-status, cell-id. Empty dict (not an error) with no LTE hardware. See "LTE/5G monitoring" below.

lte_interfaces

List LTE/5G modem interfaces (name, running, disabled, apn-profiles). Empty list (not an error) with no LTE hardware.

containers

List containers (name/tag, status, ram-usage, root-dir, interface, os). Empty list (not an error) with no container package. See "Container management" below.

container_config

Container subsystem configuration (registry-url, tmpdir, ram-high). Empty dict (not an error) with no container package.

usb_devices

USB ports (/system/routerboard/usb) + attached storage (/disk) combined as {"usb_ports": [...], "disks": [...]}; either or both empty (not an error) with no USB hardware. See "USB" below.

list_write_operations

List every guarded write operation and the RouterOS path/action it maps to (metadata only, no gate).

security_audit

Read-only, heuristic security audit: aggregates several config reads into {"findings": [...], "summary": {...}}. See "Security audit" below.

security_events

Recent /log entries filtered to security-relevant ones (login/logout/auth-failure, critical/error topics); limit (positive, capped at 500, default 50) - same shape as logs' own limit. See "Security audit" below.

hotspot_active

List clients currently logged into the RouterOS hotspot (user, address, mac-address, uptime, bytes-in/bytes-out). Empty list (not an error) with no hotspot server / no one logged in. See "Hotspot vouchers" below.

torch

Live traffic snapshot of one interface (/tool/torch once=yes) - optional src_address/dst_address/port filters. Sorted by traffic volume (biggest talkers first) and capped at 50 flows, with truncated/total_matched. See "Live traffic monitoring (torch)" below.

list_backups

List backup files on the device (/file, filtered to *.backup): name, size, creation-time. See "Backup" below.

certificates

List certificates (/certificate): name, common-name, subject/issuer fields, invalid-before/invalid-after (raw), key-size/key-type, fingerprint, expired/trusted flags. Adds a computed daysUntilExpiry from invalid-after when parseable. Never exposes a private-key, even defensively. See "AAA/PKI visibility" below.

users

List RouterOS login accounts (/user): name, group, address (allowed-source restriction), last-logged-in, disabled, comment. /user never exposes a password over the API. Read only - no /user creation/edit (see "Roadmap & non-goals"). See "AAA/PKI visibility" below.

user_active

List currently active RouterOS management login sessions (/user/active: name, address, via, when) - who's logged into the device's own admin interface right now.

radius

List RADIUS server configuration (/radius): service, address, timeout, accounting-port, authentication-port. Never exposes the shared secret, same redaction mechanism as ppp_secrets. See "AAA/PKI visibility" below.

interface_monitor

Link/optical status of one ethernet interface (/interface/ethernet/monitor once=yes): status, rate, full-duplex, auto-negotiation, plus SFP/DDM optics fields when the port has an SFP cage and a module is present. Empty dict (not an error) with no reply. See "SFP/optical monitor, DHCP-server config, bridge VLAN filtering" below.

dhcp_servers

List DHCP server config (/ip/dhcp-server): name, interface, address-pool, lease-time, disabled, authoritative, comment - as opposed to dhcp_leases, which lists what a server has handed out. See "SFP/optical monitor, DHCP-server config, bridge VLAN filtering" below.

dhcp_networks

List DHCP server networks (/ip/dhcp-server/network): address, gateway, dns-server, netmask, domain, comment. See "SFP/optical monitor, DHCP-server config, bridge VLAN filtering" below.

bridge_ports

List bridge port membership (/interface/bridge/port): bridge, interface, pvid, disabled, edge, horizon, learn, comment. See "SFP/optical monitor, DHCP-server config, bridge VLAN filtering" below.

bridge_vlans

List the bridge VLAN filtering table (/interface/bridge/vlan): bridge, vlan-ids, tagged, untagged, comment, plus current-tagged/current-untagged when present - completes the VLAN story for a managed switch (bridge VLAN filtering), distinct from the standalone /interface/vlan interfaces list_vlans/add_vlan manage. See "SFP/optical monitor, DHCP-server config, bridge VLAN filtering" below.

ntp_client

NTP client configuration/status (/system/ntp/client): enabled, mode, plus whichever of ROS7's servers/freq-drift/status/synced-server/synced-stratum or ROS6's primary-ntp/secondary-ntp/server-dns-names the device actually returns - nothing invented. enabled normalized to bool | None. See "NTP client + clock" below.

system_clock

Device clock (/system/clock): time, date, time-zone-name, time-zone-autodetect, gmt-offset, dst-active. time-zone-autodetect/dst-active normalized to bool | None. See "NTP client + clock" below.

ipv6_addresses

List IPv6 addresses (/ipv6/address): address, interface, advertise, disabled, dynamic. Mirrors ip_addresses for IPv6. Empty list (not an error) if the ipv6 package is disabled. See "IPv6 read parity (v1.9)" below.

ipv6_routes

List the IPv6 routing table (/ipv6/route): dst-address, gateway, distance, active, dynamic, disabled. Mirrors ip_routes for IPv6, including its optional limit (capped at 500). Empty list (not an error) if the ipv6 package is disabled. See "IPv6 read parity (v1.9)" below.

ipv6_firewall_filter

List IPv6 firewall filter rules (/ipv6/firewall/filter): chain, action, etc. Mirrors firewall_filter for IPv6. Read-only - does not add/modify/remove rules. Empty list (not an error) if the ipv6 package is disabled. See "IPv6 read parity (v1.9)" below.

ipv6_neighbors

List the IPv6 neighbor discovery table (/ipv6/neighbor): address, mac-address, interface, status, dynamic. Mirrors arp_table for IPv6. Empty list (not an error) if the ipv6 package is disabled. See "IPv6 read parity (v1.9)" below.

ipv6_firewall_address_lists

List IPv6 firewall address-list entries (/ipv6/firewall/address-list): list, address, dynamic, disabled. Mirrors address_lists for IPv6. Empty list (not an error) if the ipv6 package is disabled. See "IPv6 read parity (v1.9)" below.

get_wireless_link_quality

PtP/PtMP link-quality diagnosis: the same registration-table wireless_registrations reads, normalized per peer into signal_strength/signal_to_noise/tx_ccq/rx_ccq/tx_rate/rx_rate/distance/uptime. Optional interface filter. A field the current generation's registration-table doesn't publish (e.g. ROS7's newer /interface/wifi) comes back None, never fabricated. See "Wireless RF tuning + dead-man" below.

Write (guarded)

Every write tool below requires MIKROTIK_ALLOW_WRITE=true and is called twice: once with confirm=false (the default) to get a before/after preview, and again with confirm=true to actually apply it. See "Security model" below for the full guard mechanism.

Tool

Description

set_identity

Set a device's RouterOS identity (hostname).

enable_interface

Enable a network interface by name (disabled=no). Errors if the interface name doesn't exist; never creates one.

disable_interface

Disable a network interface by name (disabled=yes). Errors if the interface name doesn't exist; never creates one.

set_wifi_ssid

Set a wireless interface's SSID. Detects whether the interface lives under the ROS7 wifi package or the ROS6 wireless package and writes to whichever one matches; errors if the interface name isn't found under either. On ROS7, also detects whether the ssid is inline or lives on the interface's referenced configuration profile and writes to the right place - see "ROS7 wifi: configuration-based SSID" below.

set_client_bandwidth

Limit a client's bandwidth via a Simple Queue targeting an IP/subnet (target). Updates the existing queue's max-limit/limit-at if one already targets it, otherwise creates one with a name derived from target. FastTrack gotcha: if the device has a FastTrack firewall rule, fasttracked traffic bypasses queues entirely - this may have no visible effect until FastTrack is adjusted. See "Limiting a client's bandwidth" below.

add_static_dhcp_lease

Create a static DHCP lease pinning an IP address to a mac_address (useful to give a client a stable target before limiting it). Refuses to create a second lease for a MAC that already has one.

remove_simple_queue

Remove a Simple Queue by target or name - undoes a bandwidth limit.

add_to_address_list

Add an IP/subnet address to a named firewall list_name. Only manages the list - see "Blocking/allowing a client via address lists" below for why this alone doesn't block/allow anything. Refuses to create a duplicate list_name+address pair.

remove_from_address_list

Remove the list_name+address entry from a firewall address-list. Same "list only" caveat as add_to_address_list.

set_poe_out

Set a PoE-capable ethernet port's poe-out mode (auto-on/forced-on/off). Errors if interface_name doesn't exist, or exists but isn't PoE-capable; never creates/coerces anything. See "Physical layer & PoE control" below.

start_container

Start a container by name or tag (/container/start). Errors if container doesn't match any container; never creates one. See "Container management" below.

stop_container

Stop a container by name or tag (/container/stop). Errors if container doesn't match any container; never creates one. See "Container management" below.

set_route_distance

Adjust an existing route's distance (failover priority - lower wins). Resolved by the stable dst_address+gateway pair - never a dynamic .id/index. Errors if no route matches, or if more than one still does after that pair (AmbiguousResourceError). See "Failover control" below.

enable_route

Enable a route (disabled=no). Resolved by dst_address, narrowed by optional gateway/comment when more than one route shares it.

disable_route

Disable a route (disabled=yes). Same resolution as enable_route. The returned preview's warning field is non-null whenever the route is the default route (0.0.0.0/0/::/0) - disabling it cuts outbound traffic through that gateway. See "Failover control" below.

add_route

Add a static route (dst_address+gateway required, optional distance/comment). Never refuses a duplicate dst_address - multiple routes sharing one is the normal failover shape. warning is non-null when dst_address is the default route. See "Failover control" below.

remove_route

Remove a static route, resolved by dst_address (narrowed by optional gateway). Refuses outright (raises an error, removes nothing) if the resolved route is dynamic (dynamic=true - connected/DHCP/OSPF/BGP-installed). warning is non-null (not blocking) when removing a static default route. See "Failover control" below.

add_netwatch

Create a Netwatch host monitor (host, optional interval/comment). Never accepts an up-script/down-script - see "Failover control" below. Refuses a duplicate host.

remove_netwatch

Remove a Netwatch host monitor by host (tried first) or comment. Raises AmbiguousResourceError instead of guessing if more than one monitor still matches.

add_static_dns

Create a static DNS entry (/ip/dns/static) resolving name to address. record_type is "A" (default, address a literal IP) or "CNAME" (address is itself the alias target hostname). Refuses a duplicate name+record_type pair. See "DNS management" below.

remove_static_dns

Remove a static DNS entry by name, optionally narrowed by record_type. Errors if more than one row still matches after narrowing (AmbiguousResourceError) - never guesses which one to remove.

clear_dns_cache

Flush the device's DNS resolver cache (/ip/dns/cache/flush, no arguments). Benign (only cached answers are cleared), but still guarded/confirm-gated.

remove_dhcp_lease

Remove a DHCP lease (dynamic OR static) by address or mac_address - typically to force a client to renew its IP. The returned preview's warning field is non-null if the resolved lease is STATIC - removing it deletes the pinned IP↔MAC mapping, not just a renewable entry. See "DHCP lease removal" below.

wake_on_lan

Send a Wake-on-LAN magic packet (/tool/wol) for mac_address, out interface. Benign and targets no existing device row, but still guarded/confirm-gated. See "Wake-on-LAN" below.

enable_firewall_rule

Enable an EXISTING firewall filter rule (disabled=no), resolved by its comment (optionally narrowed by chain). Never creates a rule. See "Firewall rule toggle (by comment)" below.

disable_firewall_rule

Disable an EXISTING firewall filter rule (disabled=yes). Same resolution/never-creates guarantee as enable_firewall_rule.

add_wireguard_interface

Create a WireGuard tunnel interface (name, optional listen_port). RouterOS generates the private key internally - never accepted or returned by this tool. Refuses a duplicate name. See "WireGuard management" below.

add_wireguard_peer

Add a WireGuard peer to an existing interface (remote public_key, allowed_address, optional endpoint_address/endpoint_port/persistent_keepalive/comment). Never accepts a private-key or preshared-key. Errors if interface doesn't exist; refuses a duplicate public_key on the same interface.

remove_wireguard_peer

Remove a WireGuard peer from an interface, resolved by public_key or comment. Errors if more than one peer still matches after narrowing (AmbiguousResourceError) - never guesses which one to remove.

add_hotspot_user

Create a hotspot voucher user (name, password, optional profile/limit_uptime/limit_bytes_total). Refuses a duplicate name. Result always includes username/password/qr_payload - the plaintext password IS in the result (that's the point) but never in the audit journal. See "Hotspot vouchers" below.

create_backup

Create a RouterOS system backup file (name, optional encryption password). Refuses to overwrite an existing .backup file of the same name. password never appears in the result or the audit journal. See "Backup" below.

add_vlan

Create a VLAN interface (/interface/vlan): name, vlan_id (1-4094), parent interface, optional mtu/comment. Refuses a duplicate name. See "VLAN management" below.

remove_vlan

Remove a VLAN interface by name. Errors if no VLAN interface matches.

move_firewall_rule

Reorder an EXISTING firewall filter rule (/ip/firewall/filter move), resolved by its comment (optionally narrowed by chain) - same resolution as enable_firewall_rule/disable_firewall_rule. Never creates or edits a rule's fields - only its position changes, to either immediately before another rule (before_comment) or a given 0-based position. See "Firewall rule reorder (by comment)" below.

add_ppp_secret

Create a PPP/PPPoE secret (name, password, service - one of pppoe/pptp/l2tp/ovpn/sstp/any, default any - optional profile/remote_address/comment). Refuses a duplicate name. password DELIBERATELY appears in the result (echoed back as confirmation) but never in the audit journal - same asymmetry as add_hotspot_user. See "PPP/PPPoE secrets" below.

remove_ppp_secret

Remove a PPP/PPPoE secret by name. Errors if no secret matches, or if more than one somehow does (AmbiguousResourceError). The returned preview's before never includes the secret's password.

enable_nat_rule

Enable an EXISTING firewall NAT rule (disabled=no), resolved by its comment (optionally narrowed by chain - srcnat/dstnat). Never creates a rule. Same pattern as enable_firewall_rule. See "NAT & mangle rule toggle (by comment)" below.

disable_nat_rule

Disable an EXISTING firewall NAT rule (disabled=yes). Same resolution/never-creates guarantee as enable_nat_rule.

enable_mangle_rule

Enable an EXISTING firewall mangle rule (disabled=no), resolved by its comment (optionally narrowed by chain). Never creates a rule. Same pattern as enable_firewall_rule.

disable_mangle_rule

Disable an EXISTING firewall mangle rule (disabled=yes). Same resolution/never-creates guarantee as enable_mangle_rule.

set_ntp_servers

Set the NTP server(s) a device syncs its clock against (/system/ntp/client), servers (1+ IPv4/IPv6 addresses or hostnames). Detects ROS6 vs ROS7 field shape and writes to whichever one matches. Never enables/disables the NTP client itself. See "NTP client + clock" below.

enable_ipv6_firewall_rule

Enable an EXISTING IPv6 firewall filter rule (disabled=no), resolved by its comment (optionally narrowed by chain). Never creates a rule. Mirrors enable_firewall_rule on /ipv6/firewall/filter. See "IPv6 write parity (v1.10)" below.

disable_ipv6_firewall_rule

Disable an EXISTING IPv6 firewall filter rule (disabled=yes). Same resolution/never-creates guarantee as enable_ipv6_firewall_rule.

add_ipv6_route

Add a static IPv6 route (dst_address+gateway required, optional distance/comment). Mirrors add_route on /ipv6/route - never refuses a duplicate dst_address. dst_address/gateway must be IPv6 (an IPv4 value is rejected). warning is non-null when dst_address is the default route (::/0). See "IPv6 write parity (v1.10)" below.

remove_ipv6_route

Remove a static IPv6 route, resolved by dst_address (narrowed by optional gateway). Refuses outright (raises an error, removes nothing) if the resolved route is dynamic (dynamic=true). warning is non-null (not blocking) when removing a static default route (::/0). Mirrors remove_route on /ipv6/route.

add_to_ipv6_address_list

Add an IPv6 address/subnet to a named IPv6 firewall list_name (/ipv6/firewall/address-list). Only manages the list. Refuses to create a duplicate list_name+address pair. address must be IPv6. Mirrors add_to_address_list.

remove_from_ipv6_address_list

Remove the list_name+address entry from an IPv6 firewall address-list. Same "list only" caveat as add_to_ipv6_address_list.

set_wireless_channel

Set a /interface/wireless interface's frequency (+ optional channel_width). LOCKOUT-RISK on a management-path PtP link - arms a dead-man revert by default (arm_deadman=True). Preview's warning always reports whether the target frequency needs a DFS Channel Availability Check. See "Wireless RF tuning + dead-man" below.

set_wireless_tx_power

Set a /interface/wireless interface's tx_power (dBm), forcing tx-power-mode=all-rates-fixed. LOCKOUT-RISK - same dead-man default as set_wireless_channel. Default (max) power can saturate a short link's receiver and worsen CCQ - see "Wireless RF tuning + dead-man" below.

set_wireless_tuning

Set a /interface/wireless interface's adaptive_noise_immunity and/or distance. adaptive_noise_immunity alone is reception-only tuning, never arms a dead-man. A numeric distance is LOCKOUT-RISK (directly sets ACK-timeout/TDMA timing) - arms a dead-man revert by default, same as set_wireless_channel/set_wireless_tx_power.

arm_dead_man

Arm a local, self-removing RouterOS scheduler that reverts revert_commands after minutes unless cancelled first. NOT wireless-specific - the reusable anti-lockout primitive behind every LOCKOUT-RISK write. See "Dead-man / lockout-proof writes" below.

cancel_dead_man

Cancel a dead-man scheduler armed by arm_dead_man, once the change it guards is confirmed good. Can only ever target a scheduler this package itself armed (name shape deadman-<hex>).

Not yet exposed, deliberately: device reboot, backup RESTORE (/system/backup/load

  • same risk class as reboot), and creating/generally modifying a firewall filter, NAT, or mangle rule (only the narrow disabled TOGGLE of an existing, admin-authored rule is exposed for all three - see "Firewall rule toggle (by comment)" and "NAT & mangle rule toggle (by comment)" below). See "Roadmap / non-goals" below for why.

Limiting a client's bandwidth (v0.3)

The typical flow to find and limit a client that's consuming too much of the link:

  1. simple_queues and dhcp_leases / wireless_registrations to see who's on the network and whether they already have a limit.

  2. Optionally, add_static_dhcp_lease to pin a chatty client's IP so its target doesn't drift to a different address on DHCP renewal.

  3. set_client_bandwidth with confirm=false first to preview the max-limit/limit-at it would set (and whether it would create a new queue or update an existing one), then confirm=true to apply it.

  4. remove_simple_queue (by target or name) to lift the limit later.

FastTrack gotcha: RouterOS's own quick-set wizards commonly add a FastTrack rule to /ip/firewall/filter for performance. Fasttracked connections bypass the whole queueing subsystem, including Simple Queue - so a queue created by set_client_bandwidth can silently have zero effect on a client whose traffic is already being fasttracked. If a limit doesn't seem to be taking effect, check firewall_filter for a FastTrack rule and adjust/disable it for the traffic you're trying to limit. mcp-mikrotik does not create or generally modify firewall rules - the only firewall filter write exposed is the narrow disabled toggle of an existing rule (enable_firewall_rule/disable_firewall_rule - see "Firewall rule toggle (by comment)" below).

Blocking/allowing a client via address lists (v0.4)

add_to_address_list/remove_from_address_list manage entries in a named /ip/firewall/address-list - nothing more. Adding an address to a list has no effect on traffic by itself. It only blocks or allows anything if a /ip/firewall/filter (or NAT) rule on the device already references that same list name, e.g.:

/ip firewall filter add chain=forward src-address-list=blocked-clients action=drop

mcp-mikrotik does not create or generally modify that rule for you - the only firewall filter write exposed is the narrow disabled TOGGLE of an existing, admin-authored rule (enable_firewall_rule/disable_firewall_rule

  • see "Firewall rule toggle (by comment)" below, and "Roadmap / non-goals" further below for why rule creation itself still isn't) - use firewall_filter to check whether a rule referencing your list already exists on the device before relying on add_to_address_list to actually block or allow anyone. The typical flow:

  1. Confirm (once, out of band - e.g. via WinBox/CLI, or just by reading firewall_filter) that a filter rule referencing your list name exists, e.g. src-address-list=blocked-clients action=drop on the forward chain.

  2. dhcp_leases / wireless_registrations / neighbors to identify the client's IP.

  3. add_to_address_list with confirm=false first to preview the entry it would add, then confirm=true to apply it. An optional timeout (e.g. "1d") auto-expires the entry instead of blocking/allowing permanently.

  4. address_lists to check current membership; remove_from_address_list to lift a block/allow later.

Physical layer & PoE control (v0.6)

Three tools for the physical/L2 layer, aimed at fleets where devices are powered over PoE from a managed switch (e.g. a MikroTik CRS318-16P-2S+ feeding antennas at different PoE levels - 48V "high" and 24V "low"):

  • arp_table/bridge_hosts (/ip/arp and /interface/bridge/host - see the read-tools table above) to cross-reference an IP to a MAC, and a MAC to the physical bridge port it's on.

  • interface_traffic for a live rx/tx reading on one interface.

  • poe_status for per-port PoE configuration and live consumption (voltage/current/power/poe-out-status) across every PoE-capable port - empty, not an error, on hardware with no PoE at all.

  • set_poe_out to change a port's PoE output mode.

The killer use case: remote power-cycle a locked-up antenna/camera/AP. Rather than a truck roll to physically unplug/replug a device, if it's powered over PoE from a MikroTik switch:

  1. bridge_hosts (or arp_table) to confirm which physical port the stuck device is on, if not already known.

  2. poe_status to see its current poe-out/poe-out-status and confirm it's actually drawing power (voltage/current > 0) before assuming a PoE cycle will help.

  3. set_poe_out with poe_out="off", confirm=false first to preview, then confirm=true to actually cut power to the port.

  4. Wait a few seconds - poe_status again to confirm poe-out-status shows the port is no longer powered.

  5. set_poe_out with poe_out="auto-on" (preview, then confirm) to restore power. forced-on is also available for ports/devices that need power regardless of RouterOS's own PoE detection/negotiation.

Like every other write tool, set_poe_out never creates or coerces anything: it raises ResourceNotFoundError if interface_name doesn't exist on the device at all, or if it exists but has no poe-out field (not PoE-capable hardware, e.g. an SFP+ cage) - see "Security model" below.

LTE/5G monitoring (v0.7)

For devices with a cellular WAN modem (LTE/5G):

  • lte_interfaces to see which LTE interfaces exist on the device (name, running, disabled, apn-profiles).

  • lte_status for one interface's live signal/status - operator (current-operator), technology (access-technology: 3G/LTE/5G), signal quality (rsrp/rsrq/sinr/rssi), band, registration-status, and cell-id. Built the same "monitor-once" way as interface_traffic/ poe_status (/interface/lte/monitor <interface> once=yes) - a single instantaneous reading, not a stream.

Both return empty (an empty list/dict, never an error) on a device with no LTE hardware or package at all - the same convention poe_status/ system_health already use for optional hardware.

Container management (v0.7)

RouterOS 7's container package runs OCI containers directly on the device (e.g. a lightweight metrics agent or a small web dashboard, without a separate host). The typical flow:

  1. containers to see what's deployed (name/tag, status, ram-usage, root-dir, interface, os) and container_config for the subsystem-wide settings (registry-url, tmpdir, ram-high).

  2. start_container/stop_container with confirm=false first to preview, then confirm=true to actually apply it. container matches against a container's name if it has one, falling back to its tag (the image reference, e.g. "grafana/grafana:latest") otherwise - RouterOS only populates name when the container was created with one explicitly.

Unlike enable_interface/set_poe_out (which flip a field synchronously), starting/stopping a container fires a RouterOS action command (/container/start//container/stop) that transitions asynchronously - the preview's after.status reflects the immediate transitional state ("starting"/"stopping"), not a guaranteed final one. Call containers again afterward to see the settled "running"/"stopped" status. See CHANGELOG.md's "How start/stop extends the guard" for how this new action-command shape was added to the write guard without weakening it. Like every other write tool, start_container/stop_container never create a container: an unmatched container raises ResourceNotFoundError. A device with no container package/hardware support at all raises the same ResourceNotFoundError (never a raw device-side error) - the same underlying condition containers() already degrades gracefully from (returns [] rather than erroring).

USB (v0.7)

usb_devices reads /system/routerboard/usb (physical USB ports, on boards that expose them) and /disk (attached storage - USB flash drives, and USB LTE/5G modems that surface as a disk rather than under routerboard/usb) and returns both as {"usb_ports": [...], "disks": [...]}, since which of the two a given USB device shows up under depends on the hardware. Either or both lists come back empty (never an error) on a board with no USB hardware at all.

SFP/optical monitor, DHCP-server config, bridge VLAN filtering (v1.7)

Five read-only tools closing out most of ROADMAP.md's Tier 2 - none of them touch the write guard or require MIKROTIK_ALLOW_WRITE:

  • interface_monitor (/interface/ethernet/monitor once=yes): link status/rate/duplex for any ethernet port, built the same "monitor once" way as interface_traffic/poe_status/lte_status. On a port with an SFP cage AND a module inserted, the reply additionally carries DDM optics fields (sfp-temperature, sfp-supply-voltage, sfp-tx-power, sfp-rx-power, sfp-tx-bias-current, sfp-vendor-name, sfp-vendor-part-number, sfp-wavelength, sfp-module-present) - a plain copper port (the vast majority of ports on most hardware) simply has none of the sfp-* fields at all, and interface_monitor never invents one. Hardware caveat: this project's reference board (a mANTBox) has no SFP cage, so the command path is confirmed but the DDM field values have not been verified against real SFP optics - treat them as unverified until checked on hardware with an actual module.

  • dhcp_servers / dhcp_networks (/ip/dhcp-server, /ip/dhcp-server/network): the DHCP server's own config (address-pool, lease-time, authoritative, and per-subnet gateway/dns-server/domain) - as opposed to the already-shipped dhcp_leases, which only lists what a server has handed out to clients.

  • bridge_ports / bridge_vlans (/interface/bridge/port, /interface/bridge/vlan): together these complete the VLAN story for a managed switch (CRS/hEX-style hardware). The v1.2 VLAN tools (list_vlans/add_vlan/remove_vlan) only ever operate on standalone /interface/vlan interfaces - router-on-a-stick style routing, a different RouterOS mechanism from bridge VLAN filtering, which is how VLANs actually get segmented across a switch's physical ports. bridge_ports shows per-port pvid/edge/horizon/learn config; bridge_vlans shows the vlan-idstagged/untagged port membership table, plus RouterOS's own computed current-tagged/current-untagged when the device's reply carries them.

All boolean-shaped fields these five tools touch are normalized with formatting.coerce_ros_bool (disabled on dhcp_servers/bridge_ports, full-duplex/sfp-module-present on interface_monitor) rather than compared against the string "true"/"false" - librouteros hands a RouterOS boolean back as a Python bool or omits the field entirely, never that string. Enum-shaped RouterOS fields that merely look boolean (auto-negotiation, authoritative, edge, learn - each of which can take a value like "auto" or "after-2sec-delay", not just yes/no) are deliberately left as RouterOS's own raw value instead.

NTP client + clock (v1.8)

The last item ROADMAP.md's Tier 2 named - closed out here. Two read tools plus one guarded write:

  • ntp_client / system_clock (/system/ntp/client, /system/clock): NTP configuration/sync status and the device's own clock. Every field the device's reply actually carries is returned as-is

    • .get-based, nothing invented - only the boolean-shaped ones (enabled, time-zone-autodetect, dst-active) are normalized via formatting.coerce_ros_bool. Clock drift breaks certificate validation (see certificates's daysUntilExpiry), log timestamps, and scheduler timing - check both tools together when diagnosing any of those.

  • set_ntp_servers (WRITE, guarded): sets the NTP server(s) a device syncs against. /system/ntp/client is the SAME RouterOS path on both generations (unlike set_wifi_ssid's genuinely different /interface/wifi vs /interface/wireless menus) - only the FIELD SHAPE differs, detected by reading the row once and checking which field is present: servers (ROS7's single comma-joined list) or primary-ntp (ROS6's fixed two-slot form) - the same "read first, then decide" detection set_wifi_ssid already established.

    • ROS7: writes the full comma-joined servers list.

    • ROS6: has no servers list at all. servers[0] maps to primary-ntp, servers[1] (if given) to secondary-ntp; anything beyond the first two is dropped, with warning naming exactly which ones. Older ROS6 firmware only accepts a literal IP in either slot - a hostname destined for one of those two slots is instead folded into server-dns-names (RouterOS's own DNS-name field for this menu) IF the device's row shows that field exists; if it doesn't, that hostname is NOT applied (never a value RouterOS would likely reject), and warning says so. If nothing at all ends up applicable, the tool raises a validation error rather than silently performing a no-op write.

    • Never enables/disables the NTP client itself - only the server list changes. warning also fires if the client is currently disabled (enabled=no): new servers won't be used until it's enabled separately (out of scope here - see "Roadmap & non-goals" below).

    • Hardware caveat: exercised only against this project's fake RouterOS connection (tests/fakes.py), not real ROS6 hardware - the ROS6 field shapes and the "older firmware rejects a hostname" claim are unverified on an actual device. See CHANGELOG.md.

IPv6 read parity (v1.9)

ROADMAP.md's Tier 3 "IPv6 parity" item, READ-ONLY side. Five read tools, each mirroring an existing IPv4 read field-for-field on the /ipv6/* equivalent of its path:

IPv6 tool

Mirrors

ipv6_addresses

ip_addresses

ipv6_routes

ip_routes (same optional limit, capped at 500)

ipv6_firewall_filter

firewall_filter

ipv6_neighbors

arp_table

ipv6_firewall_address_lists

address_lists

Trap this release specifically guards against: the entire /ipv6/* menu subtree raises if the ipv6 package is disabled on the device - a common, fully supported state, not every deployment runs IPv6. All five tools above use the same skip-if-missing pattern already established for other optional features (wireguard_peers, ppp_active, bgp_sessions, ospf_neighbors, ...): a DeviceCommandError from the /ipv6/* path is caught and an empty list is returned, never propagated as an error. Like the IPv4 reads they mirror (ip_addresses/firewall_filter/ arp_table/...), these tools pass RouterOS's rows through as-is - no server-side boolean coercion. The fixtures/tests use real Python bool values for disabled/dynamic/advertise/active (matching what librouteros actually returns), so the tests exercise the real shape.

IPv6 write parity (v1.10)

The WRITE side of the same ROADMAP.md Tier 3 item, closing it out entirely. Six guarded write tools, each mirroring an existing IPv4 write tool field-for-field on the /ipv6/* equivalent of its path:

IPv6 tool

Mirrors

enable_ipv6_firewall_rule / disable_ipv6_firewall_rule

enable_firewall_rule / disable_firewall_rule

add_ipv6_route / remove_ipv6_route

add_route / remove_route

add_to_ipv6_address_list / remove_from_ipv6_address_list

add_to_address_list / remove_from_address_list

IPv6-only address validation: dst_address/gateway/address on all six tools are validated as IPv6-only (validate_ipv6_dst_address, validate_ipv6_route_gateway, validate_ipv6_target in validation.py) - unlike the IPv4-or-IPv6 validators the IPv4 tools use, these explicitly REJECT an IPv4 match, since /ipv6/* has no IPv4 concept and forwarding one to the device would just surface RouterOS's own rejection instead of a clear client-side error.

The "ipv6 package disabled" trap behaves DIFFERENTLY here than for the v1.9 reads above: those catch DeviceCommandError and return [] (skip-if-missing). These six write tools deliberately do not - a write has no safe "nothing happened" empty-list shape to fall back to, so if the resolution step (reading existing rows to find the target rule/route/entry) hits a disabled ipv6 package, DeviceCommandError propagates as a normal write-tool error instead of being silently swallowed into a result that would look identical to "there was nothing to toggle/remove".

remove_ipv6_route carries remove_route's single most important safety property unchanged: it refuses outright to remove a dynamic route (dynamic=true, via formatting.coerce_ros_bool - never a == "true" string comparison). add_ipv6_route/remove_ipv6_route also carry the same default-route warning their IPv4 counterparts carry, checked against ::/0 instead of 0.0.0.0/0.

Hardware caveat: not verified against real hardware - exercised only against this project's fake RouterOS connection (tests/fakes.py), unlike v1.9's reads (verified on both real ROS6 and ROS7). See CHANGELOG.md.

Dead-man / lockout-proof writes (v1.11)

No other MikroTik MCP server has this. It is this project's answer to a problem every one of them shares: a write to a device reached over its own radio link can cut the path back to that device, permanently, with no remote recovery. ROADMAP.md's "Explicitly NOT on the roadmap" table already names RouterOS's own best anti-lockout mechanism - Safe Mode - as something this API-only, SSH-free project cannot use (it's a CLI-only, interactive feature). The dead-man is the in-architecture answer: build the equivalent of Safe Mode's "abandon changes if I disappear" guarantee purely over the RouterOS API, using RouterOS's own scheduler as the timer.

The pattern, verified live against the single highest-risk case in this project's own fleet - an 8.8km PtP radio link that is the only management path to the far-end device:

  1. Before a risky write, arm a scheduler local to the target device that reverts the change and removes itself once it fires - a ONE-SHOT schedule at an explicit future clock time, not a recurring interval:

    /system scheduler add name=<name> start-date=<date> start-time=<time> \
      interval=00:00:00 policy=read,write,test,policy,reboot \
      on-event=":log warning DEADMAN; <revert-commands>; \
                 /system scheduler remove [find name=\"<name>\"]"

    <date>/<time> are computed as arm-time + N minutes, read from the TARGET DEVICE's own /system/clock - see "Design note" below for why this replaced an earlier interval-only design.

  2. Apply the risky write.

  3. If the write breaks reachability, the device heals itself once the deadline is reached - the on-event script runs entirely on-device, independent of whether the API session (or anything else) can still reach it afterward. Zero further action needed from the operator.

  4. If the write is good, cancel the scheduler before it fires (cancel_dead_man) - the change stays.

Two reusable primitives in guard.py, each going through the exact same allowlist + read-only gate + confirm/preview + audit machinery as every other guarded write here:

  • arm_dead_man(device_name, revert_commands, minutes=3, confirm=false)

    • revert_commands is any non-empty list (max 10) of RouterOS script statements that restore a known-good prior state. name is always generated here ("deadman-<hex>", never caller-supplied) and returned as the handle cancel_dead_man needs. minutes is capped 1-60. revert_commands is a structurally-restricted channel, not a generic command-execution one: every item must match /<path> set [find <field>="<value>"] <field>=<value> ... - the exact "restore one row's fields" shape every internal caller already produces. set is the only verb ever accepted (never remove/add/ reboot/anything else); [find <field>="<value>"] (a single selector with a balanced quote/bracket) is mandatory, never a bare .id. This is a positive allowlist, not a denylist (an earlier denylist-of-verbs version let /ip/route remove [find ...]-style commands and an unbalanced-quote parse-abort vector through - see docs/api-notes-wireless-rf.md for the full account) - plus a fixed set of script-structure-breaking characters ($ ; \ \ { }- not"/ [/], which the [find name="X"]` idiom itself needs) and a redundant verb denylist as extra defense-in-depth layers underneath.

  • cancel_dead_man(device_name, name, confirm=false) - removes the scheduler before it fires. name must match the "deadman-<hex>" shape arm_dead_man itself generates - by construction, before the device is ever read, this can never be pointed at an unrelated scheduler entry (e.g. an admin's own "backup-daily" task).

Not wireless-specific. set_wireless_channel/set_wireless_tx_power (below) are this round's two callers - each arms a dead-man automatically by default (arm_deadman=true) whose revert restores the interface's prior frequency/channel-width or tx-power/tx-power-mode, read before anything changes - but the primitive itself is generic: a future risky write in another domain (a route, a bridge port, a firewall rule) can call arm_dead_man directly with its own revert commands.

Auditing. arm_dead_man/cancel_dead_man are each independently audited exactly like any other guarded write (see "Production hardening" below) - a confirmed set_wireless_channel call that arms a dead-man produces two journal entries (one for the channel change, one for the arm), not one. The dead-man firing on-device is not something this package's own JSON audit journal can observe (it happens autonomously, outside any MCP tool call) - that is exactly what the on-event script's own :log warning statement is for: it lands in RouterOS's own /log, readable afterward via this package's logs/security_events tools.

Design note - one-shot (interval=00:00:00) with an explicit future start-date/start-time, not an interval-only recurring schedule. Verified live (and re-verified after an initial mistake - see docs/api-notes-wireless-rf.md for the full account): an interval-only schedule does not fire immediately on arm, it fires once per interval starting at arm-time+interval, as expected. The real reason one-shot still matters: RouterOS aborts an on-event script entirely at its first unparseable statement, so a broken revert command means the trailing /system scheduler remove never runs either. An interval-only schedule in that situation stays armed and keeps re-firing the same broken on-event every interval, indefinitely, until removed by hand; a one-shot schedule fires exactly once no matter what happens inside it. The deadline itself is computed with real datetime+timedelta arithmetic against the TARGET DEVICE's own clock, so it is midnight/month/year-rollover safe. See docs/api-notes-wireless-rf.md for the full write-up and the real-hardware readings behind every number in this section.

Wireless RF tuning (v1.11)

Three guarded writes on /interface/wireless (RouterOS's legacy wireless menu - see "Which menu, and why" in docs/api-notes-wireless-rf.md for why this round targets it and not ROS7's newer /interface/wifi), plus one read (get_wireless_link_quality, in the read-only table above) - built to diagnose and tune a PtP/PtMP link, not just an access point's SSID (set_wifi_ssid, unchanged, still the only /interface/wifi write tool):

  • set_wireless_channel(interface_name, frequency, channel_width=None, ...)

    • LOCKOUT-RISK: arms a dead-man by default (see above). The preview's warning always reports whether the target frequency needs a DFS Channel Availability Check under the interface's current frequency-mode, read from the device: instant with frequency-mode=superchannel (verified - no DFS/CAC at all), ~60s for most of the DFS range (5250-5725MHz), ~600s for the 5600-5650MHz weather-radar sub-band specifically.

  • set_wireless_tx_power(interface_name, tx_power, ...) - forces tx-power-mode=all-rates-fixed. LOCKOUT-RISK, same dead-man default. Verified today: on a short link, the default (maximum) tx-power saturated the receiver (-27dBm measured) and produced a worse CCQ (34) than a lower power (~8dBm gave -47dBm and CCQ 94). There is no single "right" power - use get_wireless_link_quality before/after to judge the effect on a given link. A brief CCQ/rate dip right after applying is expected (rate re-adaptation), not a failure.

  • set_wireless_tuning(interface_name, adaptive_noise_immunity=None, distance=None, arm_deadman=True, deadman_minutes=3, ...)

    • adaptive_noise_immunity alone is reception-only tuning, confirmed safe (does not drop an already-associated link) - never arms a dead-man. Verified today: "ap-and-client-mode" measurably helps when signal is good but CCQ is poor (interference, not distance).

    • A numeric distance (unlike the named "dynamic"/"indoors" modes) directly sets the ACK-timeout/TDMA timing - LOCKOUT-RISK, confirmed this can silently drop an already-associated link on a mismatch. Arms a dead-man by default, same mechanism as set_wireless_channel/set_wireless_tx_power. Verified today: an explicit distance (e.g. 9 for a ~9km link) beats "dynamic" for ACK timeout on a long PtP link.

All three: errors if interface_name doesn't exist on /interface/wireless

  • never creates one. get_wireless_link_quality normalizes the same registration-table wireless_registrations already reads into signal_strength/signal_to_noise/tx_ccq/rx_ccq/tx_rate/rx_rate/ distance/uptime per peer - the numbers that actually diagnose a PtP link, rather than a raw, generation-dependent row shape.

VPN & routing diagnostics (v0.8)

Six read-only tools for VPN, routing-protocol, and failover diagnostics

  • none of them touch the write guard or require MIKROTIK_ALLOW_WRITE:

  • VPN sessions/peers: wireguard_peers (WireGuard), ppp_active (PPP-based VPN servers - l2tp/pptp/sstp/ovpn/pppoe), ipsec_active_peers (IPsec). Each covers a different RouterOS VPN mechanism; a device that doesn't use a given one returns an empty list, not an error. wireguard_peers never returns a private key, even defensively - see "Security model" below.

  • Routing-protocol status: bgp_sessions (tries ROS7's /routing/bgp/session first, falls back to ROS6's /routing/bgp/peer - the same generation split wireless_registrations already handles for wifi) and ospf_neighbors. Empty list (not an error) for a device that doesn't run the protocol.

  • netwatch: /tool/netwatch, RouterOS's own mechanism for watching a gateway or peer's reachability (commonly used to drive an up/down script

    • e.g. flipping a failover route). This is the key diagnostic read for understanding whether/how a device's own failover behavior is configured. The up-script/down-script fields are surfaced only as has-up-script/has-down-script presence booleans, never the raw script body - a Netwatch script can contain arbitrary RouterOS commands (route changes, credential changes, ...) that don't belong in a read tool's output.

These six were the read-only foundation v0.8 shipped for failover tooling; v0.9 (below) adds the corresponding write tools.

Failover control (v0.9)

Five guarded write tools - set_route_distance, enable_route/ disable_route, add_netwatch/remove_netwatch - are the atomic building blocks for adjusting a RouterOS failover setup. Deliberately small, composable steps, not one black-box "do a failover" command: an LLM caller (or a human operator) combines them, previewing each one before applying it. add_route/remove_route (v1.5, below) extend the same /ip/route family with the two writes that were still missing: creating and removing a route outright, rather than only adjusting one already on the device.

Recommended flow:

  1. netwatch (read) and ip_routes (read) to see the current setup - which gateways are being watched, and which routes/distances currently determine which one wins.

  2. add_netwatch (confirm=false first to preview, then confirm=true) to start watching a gateway/peer's reachability, if not already monitored. This tool never accepts an up-script/down-script parameter (see below) - it only creates the observable host/status/interval/comment row. RouterOS's own up/down-script mechanism (configured manually, out-of-band, on the device - WinBox/CLI) is what actually reacts to a Netwatch status change; this package deliberately does not create or modify a script for you, e.g. by generating one that calls set_route_distance/disable_route on transition - see "Netwatch scripts are never accepted" below for why.

  3. To actually switch which route wins, either:

    • set_route_distance (preview, then confirm) to change a route's priority (lower distance wins) relative to another route with the same dst-address - the non-destructive way to fail over: both routes stay present and enabled, only their relative priority changes.

    • disable_route/enable_route (preview, then confirm) to take a route out of/back into consideration entirely.

  4. ip_routes (read) again afterward to confirm the routing table now reflects what you intended.

RISK - the default route. disable_route's returned preview carries a non-null warning field whenever the route being disabled is the default route (dst-address = 0.0.0.0/0 or ::/0) - disabling it cuts all outbound traffic that relies on that gateway, not just traffic to one destination. This is set on both the confirm=false preview and the confirm=true applied result, so a caller reading only applied/after still cannot miss it. Always read the warning field before calling again with confirm=true - and prefer set_route_distance over disable_route/enable_route for the default route specifically when possible: changing which of two already-enabled default routes has the lower distance fails over without ever leaving the device with zero enabled default routes at any point in between.

Route resolution: stable identifiers, never an index. All three route tools resolve the target row by its dst-address, narrowed by gateway and/or comment when more than one route shares that dst-address - exactly the failover shape (e.g. two 0.0.0.0/0 routes to different gateways). Never by a RouterOS .id (reassigned as routes are added/ removed elsewhere on the device) or a list index (even less stable). If nothing matches, ResourceNotFoundError. If more than one route still matches after narrowing, AmbiguousResourceError - the tool never guesses; the caller must add (or correct) gateway/comment.

Netwatch resolution: same rigor as routes. remove_netwatch resolves its target by host (tried first if both are given), falling back to comment, exactly like the route tools above - never a RouterOS .id. add_netwatch itself refuses to create a second monitor for a host that already has one, but a device can still end up with more than one row sharing a host/comment via manual (WinBox/CLI) configuration outside this tool; if so, remove_netwatch raises AmbiguousResourceError instead of removing the first match - never a silent guess.

Netwatch scripts are never accepted. add_netwatch has no up_script/down_script parameter at all - not validated-and-rejected, genuinely absent from the tool's signature - because a Netwatch script body can run arbitrary RouterOS commands (route changes, credential changes, ...), exactly the class of caller-controlled-arbitrary-command vector this package's write guard exists to rule out (see "Security model" below and guard.py's module docstring). Configure up/down scripts manually on the device (WinBox/CLI) once the monitor exists. The read-only netwatch tool already only ever surfaces has-up-script/has-down-script as presence booleans, never a script body, for the same reason.

Static route add/remove (v1.5)

add_route/remove_route close out the route family started in v0.9, reusing the same _resolve_route machinery set_route_distance/ enable_route/disable_route already use - a route is always identified by its stable dst-address (+ optional gateway, and for add_route's disambiguating siblings comment), never a RouterOS .id/list index.

The default-route warning fires in both directions. Exactly like disable_route, both add_route and remove_route set a non-null warning field - on both the confirm=false preview and the confirm=true applied result - whenever dst_address is the default route (0.0.0.0/0/::/0): adding/overriding it redirects all outbound traffic through the new gateway; removing it cuts outbound traffic that relies on the old one. Always read warning before calling again with confirm=true.

add_route never refuses a duplicate dst_address. Unlike add_vlan/add_static_dns, two (or more) routes sharing a dst-address is the normal failover shape - a second 0.0.0.0/0 pointing at a backup gateway is exactly what this tool is for, so it never raises ResourceAlreadyExistsError.

SAFETY GUARANTEE - remove_route refuses to remove a dynamic route, outright. If the resolved row's dynamic field is "true" (a connected/DHCP/OSPF/BGP-installed route - RouterOS creates these itself, an operator did not), remove_route raises an error before building any preview and without ever calling the write primitive - this is a hard refusal, not merely a warning (contrast remove_dhcp_lease, which warns but still allows removing a static lease). Removing a device's connected/ dynamic route can sever the network entirely, so this tool only ever manages static, admin-created routes; if removing a dynamic route is genuinely intended, do it manually on the device (WinBox/CLI).

DNS management (v0.10)

add_static_dns/remove_static_dns manage /ip/dns/static - typical uses:

  • Block a malicious/unwanted domain: add_static_dns with address set to 0.0.0.0 (or another sinkhole address) - any client that resolves the blocked name through this device's DNS server gets that address instead of the real one.

  • Internal DNS override: point an internal hostname at a specific internal IP, or (record_type="CNAME") alias one hostname to another.

record_type selects what address means: "A" (default) is a literal IPv4/IPv6 address; "CNAME" means address is itself another hostname (the alias target), written to RouterOS's cname field - a CNAME row has no address field of its own on the device.

Resolution: name+record_type, never a dynamic index. add_static_dns refuses to create a second row for the same name+record_type pair (ResourceAlreadyExistsError) - this also means RouterOS round-robin DNS (two "A" records sharing a name but pointing at different addresses) is not something this tool creates; add the second record manually on the device if that's genuinely intended. remove_static_dns resolves by name, narrowed by record_type if given; if more than one row still matches after narrowing (e.g. an existing round-robin pair), AmbiguousResourceError - the tool never guesses which one to remove.

clear_dns_cache (/ip/dns/cache/flush) is unrelated to /ip/dns/static - it clears cached upstream DNS answers, not any configured entry. Benign (cached answers repopulate on the next resolution) but still a guarded, confirm-gated write, like every other tool here.

DHCP lease removal (v0.10)

remove_dhcp_lease removes an existing /ip/dhcp-server/lease row by address or mac_address (mac_address is tried first if both are given - the more stable identifier, since an address can be reused by a different lease over time). The typical use is forcing a client to renew its IP: the existing lease is deleted, and the client is offered a new one on its next DHCP exchange.

This removes EITHER a dynamic or a static lease. RouterOS's dynamic field on the resolved row tells them apart. Removing a DYNAMIC lease is the ordinary case above. Removing a STATIC lease (one pinned by add_static_dhcp_lease) is also allowed - not blocked outright - but it deletes the pinned IP↔MAC mapping itself, not just a renewable entry, so the returned preview's warning field is non-null whenever the resolved lease is static, on both the confirm=false preview and the confirm=true applied result. Always check warning before calling again with confirm=true.

Wake-on-LAN (v0.10)

wake_on_lan sends a /tool/wol magic packet for mac_address, out interface. Unlike every other write tool in this package, there is nothing existing on the device to resolve or verify first - mac_address/ interface are validated for shape only (this does NOT check that interface exists on the device; RouterOS itself rejects an unknown interface name at send time). Benign - it never changes device configuration - but still guarded/confirm-gated like every other write tool, so an LLM caller can't wake a machine "by accident".

Firewall rule toggle (by comment) (v0.11)

Creating or generally modifying a firewall filter rule stays out of scope (see "Roadmap / non-goals" below): a single wrong rule - e.g. one that blocks the API port itself - can lock out all remote management access to the device, with no way to recover it over the same connection. That risk can't be designed away from inside the tool itself, so instead of exposing rule authorship, v0.11 exposes only the narrowest safe operation on top of an existing rule: flipping its disabled field.

The intended workflow (the community-suggested design this round follows): an admin creates a rule ahead of time, on the device itself, reviews it once, and leaves it disabled -

/ip firewall filter add chain=forward src-address-list=attacker-x \
  action=drop comment="Bloqueio_Ataque_X" disabled=yes
  • and an LLM caller later enables it via enable_firewall_rule when it detects the condition the rule exists to guard against:

enable_firewall_rule(device_name="core-switch", comment="Bloqueio_Ataque_X", confirm=false)  # preview
enable_firewall_rule(device_name="core-switch", comment="Bloqueio_Ataque_X", confirm=true)   # apply

If something goes wrong, the admin knows exactly which rule was toggled - the same one they already wrote and reviewed, never a rule this package authored on its own judgment. disable_firewall_rule reverses it the same way.

Resolution: comment, never a dynamic index. Both tools resolve the target rule by its comment - a STABLE, admin-controlled identifier - optionally narrowed by chain if two rules share the same comment on different chains. A comment that matches no rule raises ResourceNotFoundError (never falls back to creating one); a comment that still matches more than one rule after narrowing raises AmbiguousResourceError - the tool never guesses which one to toggle. The returned preview's before/after are the full matched rule (every field RouterOS returned for it - chain/action/etc, not just disabled), so the caller can confirm WHICH rule this is before ever passing confirm=true.

NAT & mangle rule toggle (by comment) (v1.4)

enable_nat_rule/disable_nat_rule and enable_mangle_rule/ disable_mangle_rule extend the exact pattern above to the other two firewall menus: /ip/firewall/nat (already read-only since v0.4 via firewall_nat) and /ip/firewall/mangle (read-only tool firewall_mangle added this same round). Same reasoning, same guarantees, same resolution:

  • Never creates a rule. An admin creates the NAT/mangle rule ahead of time, on the device itself, reviews it once, and leaves it disabled; an LLM caller later enables it via enable_nat_rule/enable_mangle_rule when it detects the condition the rule exists to guard against - e.g. a port-forward left disabled until a maintenance window, or a traffic-mark rule staged for a QoS change. Why this matters just as much here as for filter: disabling the wrong NAT rule can cut a whole LAN's Internet access (e.g. the srcnat/masquerade rule), and mangle rules commonly feed routing/QoS decisions downstream - creation/free-form edit stays out of scope for the same lockout reasoning "Firewall rule toggle (by comment)" above explains for filter (see ROADMAP.md's "Explicitly NOT on the roadmap").

  • Resolution: comment, never a dynamic index, optionally narrowed by chain (NAT: srcnat/dstnat; mangle: prerouting/postrouting/ forward/input/output, or a custom jump-target chain on either menu - chain is shape-only, not a fixed enum, same as filter's). A comment matching no rule raises ResourceNotFoundError; one still matching more than one rule after narrowing raises AmbiguousResourceError - never guesses which one to toggle.

  • Implementation note: both pairs share the exact same guard.py helper the filter pair (v0.11) already used (_set_firewall_rule_disabled), generalized with a resource_label parameter so ResourceNotFoundError/AmbiguousResourceError name the right menu ("Firewall filter rule" / "Firewall NAT rule" / "Firewall mangle rule") - the resolution logic itself was already path-agnostic, so nothing about it changed for filter.

enable_nat_rule(device_name="core-switch", comment="rdp-forward-maintenance", confirm=false)  # preview
enable_nat_rule(device_name="core-switch", comment="rdp-forward-maintenance", confirm=true)   # apply

Connection tracking (filtered) (v0.11)

connection_tracking reads RouterOS's connection tracking table (/ip/firewall/connection) - useful to see what a client is actually talking to right now, e.g. while investigating the traffic a set_client_bandwidth/add_to_address_list decision was based on.

A filter is mandatory - on a production router, the full table can be large enough to blow straight past an LLM caller's context/token budget on its own (a community-reported gotcha this tool is built to avoid). Calling it with none of src_address/dst_address/dst_port/protocol set raises a ValidationError instead of returning everything.

The result is also hard-capped at 100 rows regardless of how many match: truncated is true whenever more rows matched than were returned, and total_matched always reports the real, pre-truncation count - so a caller always knows whether it's seeing everything or should narrow the filter further.

Each returned entry: protocol, src-address/src-port and dst-address/dst-port (RouterOS packs address+port into one field, e.g. "192.0.2.1:80" - this tool splits them apart), tcp-state (populated for TCP connections), timeout, and the assured/confirmed/seen-reply flags - RouterOS's own closest equivalent to a generic "connection state" for this table.

Security audit (v0.12)

Two read-only tools, both in src/mcp_mikrotik/security.py, built for the "analyze this router's security" use case: an LLM caller reads config and recent logs and reports what it sees, rather than an operator manually walking every menu.

security_audit(device_name) runs eight independent, defensive checks and returns {"findings": [{"severity", "category", "title", "detail", "recommendation"}, ...], "summary": {"high", "medium", "low", "info"}} - findings sorted by severity (high first), summary always including all four keys (0 for a severity with no findings):

  1. Insecure management services (/ip/service): telnet/ftp/www/ api enabled (cleartext/non-SSL protocols) - high if telnet/ftp is also open to any address (address empty or 0.0.0.0/0), medium if www/api is, low if enabled but restricted to a narrower range. winbox enabled and open to any address is its own medium finding. ssh/api-ssl/www-ssl are never flagged - they're the secure counterparts a caller is expected to prefer.

  2. Firewall input chain has no final drop/reject (/ip/firewall/filter chain=input): a conservative heuristic based on rule order alone - if the LAST enabled rule on chain=input isn't action=drop/reject (or there are no enabled input rules at all), a medium finding recommends reviewing whether unmatched management traffic is actually blocked. This does not claim certainty - RouterOS's real evaluation semantics (jump chains, address-list matches, etc.) are richer than one rule's position can prove; see security.py's _check_firewall_input_drop docstring.

  3. SNMP community open (/snmp/community): a community named public (RouterOS's default) or with no addresses restriction (empty/ 0.0.0.0/0) - medium.

  4. DNS resolver open to remote requests (/ip/dns allow-remote-requests=yes) - medium; can be abused for DNS amplification/reflection if not also restricted by the firewall.

  5. RouterOS outdated (/system/package/update): installed version differs from the latest available - low. Skipped (no finding) if the device hasn't checked for updates yet.

  6. Open wireless/wifi (no security at all): ROS6 /interface/wireless/security-profiles with mode=none, or ROS7 /interface/wifi/security with no passphrase AND no authentication-types configured (802.1X/EAP setups legitimately have no passphrase, so only BOTH absent counts) - high.

  7. Users with a write/full policy (/user): an info finding counting how many configured accounts have a write/full group - visibility, not a vulnerability by itself.

  8. Certificate expired or expiring soon (/certificate, v1.6): high if a certificate is expired, medium if it expires within 30 days. Trusts RouterOS's own expired flag (via coerce_ros_bool) OR a negative daysUntilExpiry computed from invalid-after - either is sufficient on its own, so a device that only reliably exposes one of the two still gets a correct answer; a certificate with neither available contributes no finding. See "AAA/PKI visibility" below.

Each check is defensive: it reads its own menu(s) and, if that menu doesn't exist on this device/RouterOS generation (DeviceCommandError), contributes no findings instead of failing - the same "empty/skipped, not an error" convention system_health/poe_status/wireless_registrations already use. One check being unavailable never stops the rest of the audit.

NEVER a scanner, NEVER definitive. Every check here is a best-effort read of a handful of RouterOS menus - it can both under-report (a real misconfiguration this module doesn't know to look for) and, for check #2 specifically, over-report on an unusual-but-intentional ruleset. Findings exist to prompt a human/LLM review, not to be treated as ground truth.

No finding ever contains a secret. /ip/service, /snmp/community, /interface/wireless/security-profiles, /interface/wifi/security, and /user can all carry a password/passphrase/community-string-shaped field - no check ever copies a raw row (or a credential field from one) into a finding; each finding's text is built from a fixed template referencing only non-secret fields (name, mode, address restriction, boolean presence checks, counts). See tests/test_security.py's test_run_security_audit_never_leaks_a_secret (unit-level, every secret-bearing menu populated with a distinctive marker value while multiple checks are made to fire) and test_server.py's test_security_audit_* (the same guarantee exercised through the actual MCP tool call).

security_events(device_name, limit=50) filters /log down to security-relevant entries: topic account (RouterOS's own topic for login/logout/authentication-failure events), critical/error topics, and a generic system,info entry whose message looks like a login/logout. Filtering happens client-side (the same reasoning logs' topics filter already documents) and is applied BEFORE the limit cut, so a caller always gets the most recent limit MATCHING entries - limit is capped at 500, same shape as logs' own limit. Useful to correlate access attempts/anomalies without reading the entire (often much larger) unfiltered log via logs.

Both tools are read-only - neither is gated by MIKROTIK_ALLOW_WRITE, and neither changes anything on the device.

AAA/PKI visibility (v1.6)

Four read-only tools closing out most of ROADMAP.md's Tier 2 - certificate expiry, users/AAA, and RADIUS - all in src/mcp_mikrotik/server.py.

certificates(device_name) lists /certificate: name, common-name, subject/issuer fields (if present), invalid-before/invalid-after (raw RouterOS date strings), key-size/key-type, fingerprint, and RouterOS's own expired/trusted flags returned as-is (use formatting.coerce_ros_bool if you need to branch on them rather than just display them).

A computed daysUntilExpiry (negative once past due) is added from invalid-after whenever it can be parsed. RouterOS's own date rendering varies by version/locale - formatting.parse_ros_datetime handles the two confirmed shapes ("2027-01-15 12:00:00" and "jan/15/2027 12:00:00", the latter matched against a fixed English month-abbreviation table rather than strptime's locale-dependent %b, since RouterOS always renders it in English regardless of the server process's own locale) and is DEFENSIVE BY DESIGN: an unrecognized/unparseable date never raises - daysUntilExpiry is simply omitted and the raw invalid-after string is left untouched.

SECURITY: /certificate's own API reply never carries a private key (RouterOS only returns certificate metadata over the API) - a private-key field is nonetheless stripped defensively before returning (strip_sensitive_fields), the same mechanism ppp_secrets/ wireguard_interfaces already use, in case a future RouterOS version or firmware quirk ever adds one.

security_audit's check #8 (see "Security audit" above) uses this exact same expiry logic (formatting.days_until) to flag an expired or soon-to-expire certificate as a finding, so the read tool and the audit check can never disagree about what "expiring soon" means.

users(device_name) lists /user: name, group, address (an allowed-source restriction, if the account has one), last-logged-in (if RouterOS exposes it), disabled, comment. /user's own API reply never carries a password at all - RouterOS doesn't expose it over the API - so there's nothing to strip here, unlike ppp_secrets/radius. This is a READ only: creating or editing a /user login stays deliberately out of scope for this package - see "Roadmap & non-goals" below for why a router login is a different risk class from a service credential like a PPP secret or hotspot user.

user_active(device_name) lists /user/active: name, address, via (e.g. api/winbox/ssh/web), when - who is currently logged into the device's own management right now, as opposed to users' CONFIGURED accounts.

radius(device_name) lists /radius: service, address, timeout, accounting-port, authentication-port, and whatever other fields RouterOS returns for a given entry.

SECURITY: RouterOS's own /radius reply carries the plaintext shared secret - this is ALWAYS stripped before returning (strip_sensitive_fields), the exact mechanism ppp_secrets uses for /ppp/secret's password and wireguard_interfaces uses for a tunnel interface's private-key. A RADIUS shared secret never leaves this process via this tool. See tests/test_server.py's test_radius_never_exposes_secret.

All four tools return an empty list (never an error) if their menu is unavailable on a given device/RouterOS generation - the same convention every other optional read in this package uses.

WireGuard management (v0.13)

The most security-sensitive round in this package's history: WireGuard uses private keys. The absolute rule this round is built around: no tool, error message, preview, or audit journal entry may ever contain one. Private keys stay on the router - period.

Four tools, all covering /interface/wireguard and /interface/wireguard/peers:

  • wireguard_interfaces (read) - lists tunnel interfaces (name, listen-port, public-key, running, disabled, mtu). RouterOS's own reply for this menu genuinely carries a private-key field - always stripped before returning. wireguard_peers (v0.8) is unchanged in shape but now also strips a peer's preshared-key (a real, optional field on that menu) the same way.

  • add_wireguard_interface (write, guarded) - creates a tunnel interface (name, optional listen_port). RouterOS generates the private key internally when the interface is created - there is no private_key parameter on this tool at all, so there is no code path through which a caller could ever supply (or receive back) one. The confirm=false preview's after only describes what will be created (name/listen-port) - it never invents a public-key, since RouterOS hasn't generated the key pair yet at preview time. Only the confirm=true applied result re-reads the newly created interface and reports its real public-key (safe to share - it's what a remote peer needs to connect to you), with private-key always stripped. Refuses to create a second interface sharing name.

  • add_wireguard_peer (write, guarded) - registers a remote peer on an existing interface: its public_key (validated as a 44-character base64 WireGuard key), allowed_address (a comma-separated list of CIDR ranges, e.g. "10.0.0.2/32,10.0.0.3/32"), and optional endpoint_address/endpoint_port/persistent_keepalive/comment. Has no private_key or preshared_key parameter either - the remote peer's own private key (and any preshared key) are entirely out of this tool's scope. interface must already exist (create it first with add_wireguard_interface); refuses to add a duplicate peer (same public_key already registered on the same interface).

  • remove_wireguard_peer (write, guarded) - removes a peer from an interface, resolved by public_key or comment. Errors if more than one peer still matches after narrowing (AmbiguousResourceError) - never guesses which one to remove.

Typical flow to stand up a site-to-site or road-warrior tunnel:

  1. add_wireguard_interface (confirm=false to preview, then confirm=true) to create the tunnel interface on this device. wireguard_interfaces to read back its real public-key - give that to the remote peer, out of band, so it can configure its own side.

  2. add_wireguard_peer (confirm=false then confirm=true) to register the remote side's public_key and the traffic (allowed_address) routed through it.

  3. wireguard_peers to check last-handshake/rx/tx counters once the remote side connects, confirming the tunnel is actually passing traffic.

  4. remove_wireguard_peer to revoke a peer later (e.g. a decommissioned site or a compromised key).

How the private-key/preshared-key redaction is enforced (belt-and-suspenders, two independent layers):

  1. formatting.strip_sensitive_fields (with formatting.WIREGUARD_SENSITIVE_FIELDS = {"private-key", "preshared-key"}) is applied to every row these tools ever return - both read tools (wireguard_interfaces/wireguard_peers, in server.py) and every write tool's before/after preview (in guard.py's _redact_wireguard_row, applied before a WritePreview is ever constructed - see next point for why that ordering matters).

  2. The audit journal never gets a chance to see one either. The write-guard's _audited decorator (v0.5) journals exactly whatever a guard.py function returns - so if redaction happened only in server.py (one layer up, after guard.py returns), a private-key would already be sitting in the audit journal (a file on disk, or a log line) by the time server.py got a chance to strip it. Every WireGuard write function in guard.py therefore redacts its own before/after before constructing the WritePreview the decorator will log. audit._SENSITIVE_KEY (extended this round to also match private, on top of the existing pre.?shared term that already covers preshared-key) is a second, independent line of defense on top of that, not a substitute for it.

See tests/test_guard.py's WireGuard section, tests/test_guard_audit.py's test_add_wireguard_interface_confirmed_call_never_leaks_private_key_into_journal, and tests/test_server.py's test_add_wireguard_interface_never_leaks_private_key_anywhere for the tests proving all of this: a fake device (tests/fakes.py) simulates RouterOS generating a real key pair - including a distinctively-marked private-key - on interface creation, and every test asserts that marker never reaches the tool's return value, the audit journal (before and after), or any other log line.

Hotspot vouchers (v0.14)

hotspot_active (read) lists who's currently logged into the RouterOS hotspot (/ip/hotspot/active) - user, address, mac-address, uptime, bytes-in/bytes-out. add_hotspot_user (write, guarded) creates a new voucher - a visitor login, not a device/API credential:

add_hotspot_user(name="visitor-42", password="Xk7mQ2p9", limit_uptime="02:00:00")

profile (an existing /ip/hotspot/user/profile name, e.g. to cap shared bandwidth), limit_uptime (a RouterOS duration), and limit_bytes_total (a positive integer byte quota) are all optional. Refuses to create a duplicate name - it never resets an existing voucher's password.

QR/voucher payload. The tool result always also includes username, password, and qr_payload - a plain string the caller renders as a QR code itself (this package deliberately does not generate a QR image - that would mean pulling in an imaging dependency for something a caller's own UI layer can do in a couple of lines). The format chosen for qr_payload is "<username>:<password>" - a plain, self-describing credential pair. Two alternatives were considered and rejected:

  • A login URL (http://<hotspot>/login?username=..&password=..) would need a reliably-known hotspot LAN address, which this package has no way to determine for an arbitrary device/deployment - and RouterOS's actual captive-portal login is normally a POST carrying additional session-specific tokens (chap-id/chap-challenge), so a bare GET URL with a plaintext password wouldn't even reliably authenticate.

  • A WIFI:T:WPA;S:<ssid>;P:<pass>;; payload is for auto-joining a WPA wireless network - a different credential (and a different protocol layer) than a hotspot LOGIN (walled-garden HTTP auth), which can just as easily run over a wired port.

username:password makes no claim about network topology or login mechanics that could turn out to be wrong for a given deployment. A caller integrating with a specific captive portal is free to build its own login URL (or its own QR format) from username/password plus its own known portal address.

The deliberate password asymmetry. Unlike every secret this package has handled before (a device password, a WireGuard private-key - never returned to any caller at all), a voucher's plaintext password is present in the tool's own result on both confirm=false (preview) and confirm=true (applied) - the caller needs it to hand to a visitor. It must still never reach the audit journal. No new redaction code was needed for that: audit._SENSITIVE_KEY already matches "password" case-insensitively at any depth of the journaled {"before": ..., "after": ...} summary (it's what already protects a device's own connection password - see the "Audit journal" bullet under "Production features" below), so the exact same after dict returned to the caller gets its password key silently dropped before audit.record() ever sees it. See tests/test_guard_audit.py's test_add_hotspot_user_password_never_in_audit_journal and tests/test_server.py's test_add_hotspot_user_password_in_result_but_never_in_audit_journal for the proof, at both the guard layer and the full MCP tool-call boundary.

Live traffic monitoring (torch) (v0.14)

torch answers "who is consuming bandwidth on this interface right now" - a single live snapshot via RouterOS's own real-time traffic monitor (/tool/torch interface=<interface> once=yes), built the same "once" monitor-style way as interface_traffic/poe_status/lte_status. interface is validated for shape before use; optional src_address/ dst_address/port filters are forwarded to RouterOS itself, narrowing the snapshot before it ever leaves the device - use them on a busy interface instead of fetching every flow and filtering client-side.

Regardless of how many flows RouterOS reports for the requested instant, the result's flows list is sorted by total traffic (tx+rx, biggest talkers first) and hard-capped at 50 entries - truncated is true whenever more flows matched than were returned, and total_matched always reports the real (pre-cap) count, the same "cap it, tell the caller how much was cut" shape connection_tracking (v0.11) already established. Diagnostic only - torch never changes device state, so (like ping/ traceroute) it is not gated by MIKROTIK_ALLOW_WRITE.

Backup (v0.14)

create_backup (write, guarded) creates a RouterOS system backup file (/system/backup/save name=<name>) - the device's full configuration (interfaces, firewall, users, ...) as one binary .backup file on its own storage. list_backups (read) lists existing ones - use it after create_backup to confirm a new backup landed and see its real size/creation-time.

create_backup refuses to overwrite an existing .backup file of the same name (ResourceAlreadyExistsError) - RouterOS's own /system/backup/save would otherwise silently overwrite one. An optional password encrypts the backup file itself (unrelated to any device/API credential) - it is redacted before the write's preview is ever constructed (the same "redact before constructing the preview" rule v0.13's WireGuard round established for private/preshared keys), so it never reaches the caller or the audit journal, either.

Backup restore is deliberately not exposed - see "Roadmap / non-goals" below: loading a backup overwrites a device's entire running configuration and reboots it, the same risk class as a remote reboot, with no meaningful before/after preview and no rollback if the wrong file (or the right file, at the wrong time) is loaded.

VLAN management (v1.2)

list_vlans (read) lists /interface/vlan rows, excluding disabled ones by default - same include_disabled convention as interfaces. add_vlan (write, guarded) creates one: name (the new RouterOS interface name, e.g. "vlan100"), vlan_id (1-4094, the IEEE 802.1Q tag), and interface (the parent it rides on top of, e.g. "bridge1"/"ether2" - not verified to exist here; RouterOS itself rejects an unknown parent at write time). mtu/comment are optional. It refuses to create a duplicate name (ResourceAlreadyExistsError) rather than silently reconfiguring an existing VLAN interface. remove_vlan (write, guarded) removes one by name, erroring (ResourceNotFoundError) if it doesn't exist.

add_vlan(device_name="core-switch", name="vlan100", vlan_id=100, interface="bridge1", confirm=false)  # preview
add_vlan(device_name="core-switch", name="vlan100", vlan_id=100, interface="bridge1", confirm=true)   # apply

Firewall rule reorder (by comment) (v1.2)

move_firewall_rule (write, guarded) reorders an existing /ip/firewall/filter rule - it never creates or otherwise edits a rule's fields (chain/action/etc); only its position in the chain's evaluation order changes. Same philosophy as enable_firewall_rule/ disable_firewall_rule (v0.11) above: authoring or generally modifying a firewall rule stays out of scope (a wrong rule can lock out remote management with no way to recover it over the same connection), so this only exposes the narrow, safe operation of moving an admin-authored rule that already exists.

Resolution: comment, never a dynamic index - the same STABLE, admin-controlled identifier enable_firewall_rule/disable_firewall_rule resolve a rule by, optionally narrowed by chain if more than one rule shares that comment. A comment that matches no rule raises ResourceNotFoundError; one that still matches more than one rule after narrowing raises AmbiguousResourceError - never guesses which one to move.

Destination: exactly one of two ways to say where. before_comment moves the rule to appear immediately before an existing rule identified by its own comment (resolved the same way, and also subject to AmbiguousResourceError if it isn't unique); position moves it to a 0-based index among the other rules (i.e. after the rule being moved is taken out of consideration) - a position at or beyond the end of that list moves it to the very end. Supplying both, or neither, raises ValidationError.

move_firewall_rule(device_name="core-switch", comment="Bloqueio_Ataque_X", position=0, confirm=false)  # preview
move_firewall_rule(device_name="core-switch", comment="Bloqueio_Ataque_X", position=0, confirm=true)   # apply

The returned preview's before/after report the rule's comment/chain plus its current vs. new position - not the full row (unlike enable_firewall_rule/disable_firewall_rule's preview), since no field on the rule itself is changing, only where it sits in the list.

PPP/PPPoE secrets (v1.3)

ppp_secrets (read) lists /ppp/secret rows - the CONFIGURED dial-in credentials (name, service, profile, remote-address, local-address, disabled, comment, last-logged-out) - as opposed to the pre-existing ppp_active, which lists currently-CONNECTED sessions. add_ppp_secret (write, guarded) creates a new one - a dial-in service credential, not a device/API login:

add_ppp_secret(name="fiber-customer-42", password="Xk7mQ2p9", service="pppoe", profile="default-encryption")

service (default "any") restricts which PPP service the secret may authenticate for - one of "pppoe"/"pptp"/"l2tp"/"ovpn"/"sstp"/ "any". profile (an existing /ppp/profile name, e.g. to assign an address pool or rate limit) and remote_address (a literal IP handed to the client on connect) and comment are all optional. Refuses to create a duplicate name. remove_ppp_secret (write, guarded) removes one by name, erroring (ResourceNotFoundError) if it doesn't exist, or (AmbiguousResourceError) if more than one row somehow shares that name - never guessing which one to remove.

Same risk class, same precedent as add_hotspot_user (v0.14). A /ppp/secret only grants network/dial-in access - it can never touch the router's own configuration, unlike a /user login (which is deliberately not on this package's roadmap - see "Roadmap & non-goals" below). So add_ppp_secret follows add_hotspot_user's password handling exactly: the plaintext password DELIBERATELY appears in this tool's own result (the caller supplied it and gets it echoed back as confirmation of exactly what was written), but never reaches the audit journal - audit._SENSITIVE_KEY already matches "password", so no new redaction code was needed. See tests/test_guard_audit.py's test_add_ppp_secret_password_never_in_audit_journal for the proof.

remove_ppp_secret redacts the opposite way: it looks up an EXISTING row first, and that row's own password field is stripped in guard.py - before the returned preview is ever constructed - so it can never leak into the tool's result or the audit journal either. See tests/test_guard.py's test_remove_ppp_secret_preview_never_includes_password for the proof.

ppp_secrets never returns a password field at all, the same formatting.strip_sensitive_fields mechanism wireguard_interfaces uses for a tunnel interface's private-key.

Security model

This section is the single consolidated reference for every control this package applies - to every read, and especially to every write. The philosophy is simple: read-only by default, writes are opt-in, allowlisted, previewed, and audited. No tool in this package ever accepts an arbitrary RouterOS API path or a free-form command.

Three independent controls apply to every write tool, all centralized in src/mcp_mikrotik/guard.py:

  1. Read-only by default. MIKROTIK_ALLOW_WRITE defaults to false. With writes disabled, any write tool returns a clear error and never touches the device - the gate is checked before any read or write call is made.

  2. Central allowlist, no generic command tool. There is no tool that accepts an arbitrary API path or command. Each write operation is a dedicated, named function (e.g. set_identity, enable_interface) mapped to exactly one API path and action in guard.ALLOWLIST. There is no code path by which a caller can reach an API path outside that table. As of v0.7, action isn't limited to update/add/remove: start_container/stop_container use start/stop to represent RouterOS's /container/start//container/stop ACTION commands - but the dispatch mechanism (getattr(client, op.action)) and the fixed, individually-reviewed MikrotikClient method it can ever reach are unchanged; see CHANGELOG.md's "How start/stop extends the guard". v0.10 adds a second such pair: clear_dns_cache/wake_on_lan use flush/wol for RouterOS's /ip/dns/cache/flush//tool/wol ACTION commands - same getattr(client, op.action) dispatch, same fixed reviewed MikrotikClient.flush/.wol methods, the only difference from start/stop being that neither targets a specific row/.id (there is no "list" to pick one row from - both are standalone, one-shot commands, dispatched via the connection's callable form like ping, not the path(*segments)(cmd, **{".id": id}) form start/stop use). set_wifi_ssid and set_client_bandwidth are the two exceptions to "one tool, one allowlist entry": because RouterOS exposes wifi under different paths depending on generation (ROS7 /interface/wifi vs ROS6 /interface/wireless) - and, on ROS7, the ssid itself lives in one of two different places depending on whether the interface references a named configuration (see "ROS7 wifi: configuration-based SSID" below) - set_wifi_ssid is backed by three fixed, reviewed allowlist entries (set_wifi_ssid_ros7/set_wifi_ssid_ros7_configuration/ set_wifi_ssid_ros6), and the guard function picks between them by reading the device: which path has a matching interface name, and then, for a ROS7 match, whether that interface's ssid is inline or lives on its referenced configuration profile. Likewise, set_client_bandwidth either updates an existing Simple Queue or creates a new one, so it is backed by set_client_bandwidth_update/set_client_bandwidth_add, and the guard function picks between them by checking whether a queue already targets the given target. In both cases the choice is made entirely by the guard function reading the device - never by accepting a path or an add-vs-update decision from the caller.

  3. Explicit confirm with before/after preview. Every write tool takes a confirm: bool parameter. With confirm=False (the default), the tool computes and returns what would change - a before/after structure - without applying anything. Only confirm=True applies the change.

Since v1.11, a fourth control applies specifically to LOCKOUT-RISK writes (today: set_wireless_channel/set_wireless_tx_power, and set_wireless_tuning when given a numeric distance - a bad frequency/ power/ACK-timeout on a management-path radio link can cut the only route back to the device): the dead-man. A confirm=True apply arms a local, self-removing RouterOS scheduler before the write, which reverts it automatically once its deadline is reached unless explicitly cancelled (cancel_dead_man) - see "Dead-man / lockout-proof writes" below for the full mechanism. This is this project's in-architecture answer to giving up RouterOS's own Safe Mode (see "Explicitly NOT on the roadmap" in ROADMAP.md) in exchange for staying API-only.

ROS7 wifi: configuration-based SSID

Confirmed against real ROS7 hardware (a mANTBox): in the standard production layout, a /interface/wifi interface references a named configuration (e.g. configuration=cfg1) and has no writable ssid field of its own - writing one directly there is rejected by RouterOS ("unknown parameter ssid"). The ssid instead lives on the referenced /interface/wifi/configuration row.

set_wifi_ssid resolves this automatically: for a ROS7 match, it checks the interface's own configuration field, looks up the matching /interface/wifi/configuration row by name, and reads/writes the ssid there (backed by the set_wifi_ssid_ros7_configuration allowlist entry). The before/after preview always reflects the ssid's real location - it is never synthesized on a field that doesn't actually exist on the device. Only a wifi interface with no named configuration at all (rare/legacy) keeps a genuinely inline ssid field, written directly on /interface/wifi as before. If neither shape is recognized (a configuration name that doesn't resolve, or an interface with neither an inline ssid nor a configuration reference), the tool raises a clear error rather than sending a write RouterOS would itself reject.

On top of the write guard:

  • Never creates the target. Write tools that operate on a named resource (enable_interface/disable_interface/set_wifi_ssid/remove_simple_queue/ remove_from_address_list/set_poe_out/start_container/stop_container/ set_route_distance/enable_route/disable_route/remove_route/remove_netwatch/ enable_firewall_rule/disable_firewall_rule/add_wireguard_peer/ remove_wireguard_peer) look it up first - by name, by the v0.9 route tools' stable dst-address (+gateway/comment) identifier described in "Failover control" above, by the v0.11 firewall rule tools' comment (+chain) described in "Firewall rule toggle (by comment)" above, or, for the v0.13 WireGuard peer tools, by public-key/comment scoped to a given interface (described in "WireGuard management" above). If nothing matches, the tool raises a clear error instead of creating one - a typo can never silently provision something new. set_poe_out additionally requires the matched interface to actually have a poe-out field (i.e. be PoE-capable hardware) - a name that exists but isn't a PoE port raises the same clear error rather than doing nothing silently. add_wireguard_peer additionally requires its interface to already exist as a WireGuard tunnel - it never creates one (use add_wireguard_interface first). The v0.9 route tools, the v0.11 firewall rule tools, and the v0.13 remove_wireguard_peer additionally never resolve by a RouterOS .id or a list index (both can shift as rows are added/removed elsewhere on the device); if an identifier still matches more than one row after narrowing, AmbiguousResourceError is raised instead of guessing which one to touch.

  • Never silently duplicates. add_static_dhcp_lease checks for an existing lease on the given mac_address first, add_to_address_list checks for an existing entry with the same list_name+address pair first, add_netwatch checks for an existing monitor on the given host first, add_wireguard_interface checks for an existing interface with the given name first, and add_wireguard_peer checks for an existing peer with the same public_key on the same interface first - each raising ResourceAlreadyExistsError instead of creating a second one - both for confirm=false previews and confirm=true applies.

  • Structured API, not shell commands. All device communication goes through librouteros's structured API (path().select()/.add()/.update()/.remove(), and the callable form for one-off commands like ping). Nothing in this codebase builds a command by concatenating strings from user input, so command injection is ruled out by construction rather than by input filtering.

  • Input validation on top, for its own sake. ping's address is still validated against an IPv4/IPv6/hostname pattern before use, purely to reject garbage input early with a clear error - not as an injection defense (see previous point).

  • No secrets in output. Device.to_public_dict() is the only device representation ever returned to a tool caller, and it omits the password field entirely. Passwords are never logged. Since v0.8, wireguard_peers strips a private-key field from every row via formatting.strip_sensitive_fields before returning it - defensively, since RouterOS's own /interface/wireguard/peers reply doesn't carry one in the first place (see "VPN & routing diagnostics" above). Since v0.12, security_audit never copies a raw row (or a credential-shaped field from one) into a finding - every finding's text comes from a fixed template referencing only non-secret fields, even though several of the menus it reads (/ip/service, /snmp/community, wireless/wifi security profiles, /user) can carry a password/passphrase/community-string field

    • see "Security audit" above. Since v0.13, wireguard_interfaces and every WireGuard write tool (add_wireguard_interface/add_wireguard_peer/ remove_wireguard_peer) apply the same redaction to a genuinely secret-bearing menu - a tunnel interface's private-key and a peer's preshared-key - before a write's before/after preview is ever constructed, so guard.py's own audit journal (which logs exactly what a write function returns) can never carry one either; see "WireGuard management" above for the full two-layer redaction (guard.py first, audit._SENSITIVE_KEY as a second, independent line of defense).

  • Structured errors. All errors raised inside the package derive from MikrotikMCPError (see src/mcp_mikrotik/exceptions.py) and are caught at the tool boundary in server.py. The exception is deliberately re-raised, not turned into an {"error": ...} result dict: MCP itself turns an exception propagating out of a tool into a proper isError tool result carrying just that exception's (already-safe) message, and letting the framework do that keeps every tool's declared return type honest (a successful logs call always returns list[dict], never sometimes a dict-shaped error instead). Unexpected exceptions are logged server-side and re-raised as a generic internal-error message, never as a raw traceback.

Production hardening: audit log, correlation IDs, retries, circuit breaker

The remaining layers around the write-guard mechanism above, aimed at running mcp-mikrotik unattended against a real fleet. None of them can weaken or bypass the read-only gate, the central allowlist, or the confirm/preview flow - every write still goes through guard.py exactly as described in "Security model", and the circuit breaker in particular never skips guard.py's read-only gate/allowlist check: that check runs first, entirely before MikrotikClient ever attempts a connection.

  • Audit journal. Every guarded write call (guard.py, one of the ALLOWLIST operations) emits exactly one structured JSON-lines event - whether it previewed (confirm=false), applied (confirm=true), or failed at any point, however early (even a write blocked by the read-only gate before the device is ever touched). Each event has a timestamp, correlation_id, device_name, tool, operation (the ALLOWLIST key), action (add/update/remove/start/stop/flush/wol/save - see v0.7's start_container/stop_container, v0.10's clear_dns_cache/ wake_on_lan, and v0.14's create_backup), confirm, outcome (preview/applied/error), and a summary of the before/after change plus that write's warning (e.g. disable_route's default-route callout, remove_dhcp_lease's static-lease callout - see WritePreview.warning in guard.py), or the error. summary.warning is null for every write that carries no special risk. Never includes a device password or any field that looks like a secret - see src/mcp_mikrotik/audit.py's _sanitize(). Destination is MIKROTIK_AUDIT_LOG (a file path, appended to) if set, otherwise a plain INFO-level line via the standard logger (stderr). Writing the journal is always best-effort: a bad path or a permissions error is logged as a warning and never blocks or fails the write it is describing. Read tools are never journaled - only guarded writes are.

  • Correlation IDs. Every MCP tool call (read or write) gets a short, unique id (uuid4().hex[:12]) for its duration - see src/mcp_mikrotik/correlation.py. It is bound once per call in server.py's _safe wrapper, appears in every audit journal entry a write call produces, and is prefixed onto the server-side log line if the call fails - so one id lets you grep everything one tool call did, end to end, without changing the shape of any error message returned to the caller.

  • Read retry. path/ping/traceroute (every read primitive in src/mcp_mikrotik/client.py) automatically retry on a transient network error - a fresh connection attempt failing, or an in-flight command failing because of an underlying OSError (a dropped socket, a timeout) - with a short backoff (0.5s, then 1s). Up to MIKROTIK_READ_RETRIES extra attempts (default 2). A command rejected by RouterOS itself (a LibRouterosError, not an OSError) is never retried - it would just be rejected again. Writes never retry, regardless of this setting: update/add/remove/start/stop aren't guaranteed idempotent, so retrying one could duplicate or reapply a change.

  • Circuit breaker. Each device gets its own in-memory, thread-safe breaker (client.CircuitBreaker, one instance per pooled MikrotikClient

    • see ClientPool). After MIKROTIK_BREAKER_THRESHOLD consecutive connection failures (default 3), the circuit opens: for the next MIKROTIK_BREAKER_COOLDOWN seconds (default 30), any call to that device - read or write - fails immediately with a clear circuit open for '<device>', retry after <t>s error, without attempting a connection at all. A single successful connection resets the failure count and closes the circuit. This is scoped purely to the connection step - it never decides whether a write is allowed (that's the read-only gate/allowlist in guard.py, always checked first) - it exists to stop a dead device (e.g. an antenna that fell over) from costing a full connect timeout on every single tool call.

TLS verification for api-ssl

RouterOS's api-ssl typically serves a self-signed certificate, so the default tls_verify: true (which validates against the system trust store, or an explicit tls_ca_cert if given) will fail out-of-the-box for most fleets. Two ways to make an SSL device work:

  • Set tls_ca_cert: /path/to/ca.pem on the device entry, if you provision RouterOS with a certificate you can pin, keeping full verification.

  • Set tls_verify: false on that specific device to skip certificate/hostname validation entirely. This is a deliberate, explicit, per-device trade-off (it drops MITM protection on that connection) - it is never the default, and it is opt-in per device, not global. See devices.yaml.example.

Development & CI

pip install -e ".[dev]"
pytest -q

The test suite never talks to a real router: tests/fakes.py provides an in-memory fake that implements the same minimal interface MikrotikClient expects from a librouteros connection, and it is injected via a client_factory parameter on build_server(). It currently has 1298 tests, zero of which touch a real device or the network, at 100% line coverage.

CI (.github/workflows/ci.yml, GitHub Actions) runs on every push to main and every pull request, as three separate jobs that must all pass before a change is considered mergeable:

  • test - the full pytest suite against a matrix of Python 3.11, 3.12, and 3.13, with coverage measured (pytest --cov=mcp_mikrotik --cov-fail-under=95). The 95% floor is deliberately a little below the repo's actual coverage (100%, with two narrow # pragma: no cover exceptions - see CONTRIBUTING.md's "Test coverage") so a PR isn't blocked on a fraction-of-a-percent of genuinely hard-to-reach code, while still failing the build if coverage regresses meaningfully.

  • lint - ruff check . (lint) and ruff format --check . (formatting), configured in pyproject.toml's [tool.ruff].

  • typecheck - mypy src/mcp_mikrotik, configured in pyproject.toml's [tool.mypy]. librouteros ships no type stubs, so it's covered instead by client.py's own RouterosConnection/RouterosPath Protocols, which the rest of the codebase is type-checked against.

Run all three locally before opening a PR - see CONTRIBUTING.md for the exact commands, plus the full checklist a PR is reviewed against (the security-model rules every write tool must follow, and the step-by-step guide for adding a new tool, read or write). See ROADMAP.md for what's next and why - candidate tools are filtered through the same security-model invariants before landing there.

Roadmap & non-goals

Delivered through 1.0

Every tool round originally planned for this project has shipped - see CHANGELOG.md for the full version-by-version detail:

  • Core read tools + guarded writes (v0.1-v0.4): device/interface/route reads, set_identity, enable_interface/disable_interface, set_wifi_ssid, set_client_bandwidth, add_static_dhcp_lease, remove_simple_queue, add_to_address_list/remove_from_address_list.

  • Production hardening (v0.5): audit journal, correlation IDs, read retry, circuit breaker - see "Security model" above.

  • Physical layer, LTE, containers, USB (v0.6-v0.7): set_poe_out, lte_status/lte_interfaces, start_container/stop_container + containers/container_config, usb_devices.

  • VPN/routing diagnostics + failover control (v0.8-v0.9): wireguard_peers, ppp_active, ipsec_active_peers, bgp_sessions, ospf_neighbors, netwatch (read), plus the guarded failover write tools set_route_distance/enable_route/disable_route/ add_netwatch/remove_netwatch - see "Failover control" above. Netwatch up/down-script configuration itself remains deliberately out of scope (manual, on the device) - see "Netwatch scripts are never accepted" above for why.

  • DNS/DHCP/Wake-on-LAN write tools (v0.10): add_static_dns/ remove_static_dns, clear_dns_cache, remove_dhcp_lease, wake_on_lan - see "DNS management", "DHCP lease removal", and "Wake-on-LAN" above. Only the two simplest static DNS record types ("A"/"CNAME") are exposed; other RouterOS record types (AAAA/MX/TXT/NS/...) remain a future decision, not silently widened here.

  • Firewall rule toggle + connection tracking (v0.11): enable_firewall_rule/disable_firewall_rule (a disabled TOGGLE only, on an existing, admin-authored rule resolved by comment - never rule creation or any other field) and connection_tracking (mandatory filter, hard-capped at 100 rows) - see "Firewall rule toggle (by comment)" and "Connection tracking (filtered)" above.

  • Security audit + security-relevant log events (v0.12): security_audit, security_events - see "Security audit" above. Both are read-only and heuristic: security_audit does not (and will not) auto-remediate anything it finds - every finding exists to inform a human/LLM decision, not to be acted on automatically. Widening its check list (e.g. NAT exposure, more RouterOS-version-specific CVE checks) is a future decision, not silently expanded here.

  • WireGuard VPN management (v0.13): wireguard_interfaces, add_wireguard_interface, add_wireguard_peer, remove_wireguard_peer - see "WireGuard management" above.

  • Hotspot vouchers, live traffic monitoring, and backup (v0.14): hotspot_active, torch, list_backups, add_hotspot_user, create_backup - see "Hotspot vouchers", "Live traffic monitoring (torch)", and "Backup" above.

  • 1.0.0: no new tools - a polish/consolidation round (ambiguity handling on remove_netwatch, the audit journal carrying a write's warning, and this README).

Non-goals

These are deliberately not exposed, not because they're technically hard, but because the standard guard/confirm/preview mechanism isn't sufficient protection for them on its own - see the comment above ALLOWLIST in guard.py:

  • Device reboot (/system/reboot): there's no meaningful before/after preview for a reboot, and a bad batch reboot across a fleet has no dry-run or rollback. Would need its own confirmation/cooldown policy first.

  • Backup RESTORE (/system/backup/load): same risk class as reboot - loading a backup overwrites the device's entire running configuration and reboots it, with no meaningful before/after preview and no rollback. create_backup/list_backups only ever create/list backup files; restoring one stays a manual, on-device (WinBox/CLI) operation until it has its own confirmation/cooldown policy.

  • Firewall filter rule CREATION or general modification (any ip/firewall/filter write other than the disabled toggle): a single wrong rule (e.g. one that blocks the API port itself) can lock out all remote management access to the device, with no way to recover it over the same connection. Would need staged/rollback support (e.g. RouterOS safe mode) before it belongs in the allowlist - enable_firewall_rule/disable_firewall_rule sidestep that risk entirely by only ever touching a rule an admin already wrote and reviewed themselves, never authoring one.

  • A generic "run this RouterOS command/path" tool: this is not a gap to be filled later - it is the exact failure mode this project exists to avoid (see "Status" above). Every write will always be a dedicated, named, individually-reviewed function in guard.ALLOWLIST, never an arbitrary path+action a caller supplies.

Post-1.0 ideas

  • Further write tools are added by extending guard.ALLOWLIST with one new named operation and function each - see the comment block at the top of guard.py. Do not add a generic write tool.

  • A second entrypoint that periodically polls devices and pushes metrics to Firebase is planned to reuse MikrotikClient/get_client from client.py. Not implemented yet - see the TODO(collector) note at the bottom of client.py.

License

GPL-3.0-or-later - see LICENSE.

This project imports librouteros (GPL-2.0-or-later) in-process, so the combined work is distributed under the GPL. Versions up to 1.11.0 were published as Apache-2.0; from the next release on, the whole project is GPL-3.0-or-later.

Available Tools

114 tools
add_hotspot_userA

Create a hotspot voucher user (/ip/hotspot/user add) for a visitor - name/password are the login credentials; profile (an existing hotspot user profile), limit_uptime (a RouterOS duration, e.g. "01:00:00"), and limit_bytes_total (a positive integer byte quota) are all optional.

QR/VOUCHER: the result always also includes username, password (the plaintext voucher credentials - THIS IS THE POINT: the visitor needs them), and qr_payload - a plain STRING the caller renders as a QR code itself; this package deliberately does NOT generate a QR IMAGE (no extra imaging dependency). Format chosen for qr_payload: "<username>:<password>" - a plain, self-describing credential pair, NOT a login URL and NOT a WIFI: payload. Two alternatives were considered and rejected: a login URL (http://<hotspot>/login?username=..&password=..) would need a reliably-known hotspot LAN address, which this package has no way to determine for an arbitrary device/deployment - and RouterOS's actual captive-portal login is normally a POST with additional session-specific tokens (chap-id/chap-challenge), so a bare GET URL with a plaintext password wouldn't even reliably work; a WIFI: payload is for auto-joining a WPA network, which is a different credential than a hotspot LOGIN (walled-garden HTTP auth) entirely. username:password makes no claim about network topology or login mechanics that could be wrong for a given deployment - a caller integrating with a specific captive portal can build its own login URL from these two fields plus its own known portal address.

PASSWORD IN THE JOURNAL: unlike every secret this package has handled before (a device password, a WireGuard private-key), this tool's password is DELIBERATELY present in its result - but still never written to the audit journal. See guard.add_hotspot_user's docstring for exactly how that asymmetry holds.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a preview (including qr_payload) without changing anything; call again with confirm=True to actually create it. Errors clearly (without creating anything) if name already exists on the device - it never creates a duplicate or resets an existing voucher's password.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
confirmNo
profileNo
passwordYes
device_nameYes
limit_uptimeNo
limit_bytes_totalNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses the write-guard requirement, the preview-vs-commit semantics, that duplicates are never created and existing passwords are never reset, and the deliberate password/journal asymmetry. This is unusually rich behavioral disclosure for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and dense with useful facts, but the QR/VOUCHER section spends a full paragraph on two rejected alternatives and their rationale. That design discussion is informative but longer than an agent needs to call the tool, so it dilutes conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded multi-param write tool, nothing essential is missing: creation semantics, guard, preview flow, error behavior, and result fields (username, password, qr_payload) are all addressed. An output schema exists, so the return-value coverage is a bonus rather than a requirement.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does: name/password as login credentials, profile as an existing hotspot user profile, limit_uptime as a RouterOS duration with an example, and limit_bytes_total as a positive integer byte quota. confirm is covered in the workflow and the optional/required split is clear.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Create a hotspot voucher user') with the underlying RouterOS path (`/ip/hotspot/user add`) and the target audience (a visitor). It is unambiguous against siblings like hotspot_active, which reads rather than creates users.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states prerequisites (blocked unless MIKROTIK_ALLOW_WRITE=true) and the exact two-call workflow: confirm=False for a preview, confirm=True to create. It also spells out the name-collision behavior, so an agent knows the intended call sequence and the failure mode.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_ipv6_routeA

Add a static IPv6 route (/ipv6/route add): dst_address and gateway are required, distance (failover priority - lower wins) and comment are optional. Mirrors add_route on the IPv6 menu - never refuses a duplicate dst_address, multiple routes sharing one is the normal failover shape.

dst_address/gateway must be IPv6 (an IPv4 address/subnet in either is rejected before the device is ever touched - /ipv6/route has no IPv4 concept).

RISK: adding/overriding the default route (dst_address="::/0") redirects all outbound IPv6 traffic through the new gateway. The returned preview's warning field is non-null whenever this is the case - always check it before calling again with confirm=true.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview (including the warning field) without changing anything; call again with confirm=True to actually apply it. Also errors clearly if the ipv6 package is disabled on the device.

ParametersJSON Schema
NameRequiredDescriptionDefault
commentNo
confirmNo
gatewayYes
distanceNo
device_nameYes
dst_addressYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so richly: it discloses the MIKROTIK_ALLOW_WRITE=true gate, the confirm preview workflow, that duplicates are never refused (failover shape), the non-null `warning` on default-route override, and a distinct error when the ipv6 package is disabled. This is exactly the behavioral detail an agent needs before a mutating call.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose and command, then groups parameters, then flags RISK and the write guard in their own blocks. Every sentence adds a constraint or behavior; nothing is padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded write tool with a 6-parameter schema, 0% schema coverage and an output schema, it covers validation rules, risk, gating, error conditions, and even references the preview's `warning` field rather than re-explaining return values. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate and largely does: it marks dst_address/gateway as required IPv6-validated values, explains distance as failover priority where lower wins, notes comment as optional, and describes confirm's preview-vs-apply semantics. Only device_name is left undefined, a minor gap against otherwise thorough coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Add a static IPv6 route'), ties it to the underlying RouterOS command, and explicitly distinguishes it from the IPv4 sibling by noting it 'Mirrors add_route on the IPv6 menu.' An agent can route IPv4 vs IPv6 intent without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context: use this for IPv6 (the IPv4 counterpart is add_route) and follow the confirm=False-preview-then-confirm=True sequence. It stops short of explicitly stating when-not to use it (e.g. vs remove_ipv6_route or ipv6_routes), so it is strong but not exhaustive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_netwatchA

Create a Netwatch host monitor (/tool/netwatch add): host (a plain IPv4/IPv6 address), optional interval (a RouterOS duration, e.g. "10s"/"00:00:10") and optional comment.

SECURITY: this tool does NOT accept an up-script/down-script - a Netwatch script body can run arbitrary RouterOS commands (route or credential changes, ...), so it is deliberately outside what this guarded write tool will ever send to a device. Configure up/down scripts manually on the device once the monitor exists (WinBox/CLI)

  • see README's "Failover control" section. The read-only netwatch tool already only ever surfaces has-up-script/has-down-script as presence booleans, never a script body, for the same reason.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly (without creating anything) if a monitor for host already exists - it never creates a duplicate.

ParametersJSON Schema
NameRequiredDescriptionDefault
hostYes
commentNo
confirmNo
intervalNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden, and it does: guarded write blocked unless MIKROTIK_ALLOW_WRITE=true, dry-run default, does-nothing-on-duplicate error path, and an explicit security rationale for the deliberately absent up-script/down-script capability. This is disclosure well beyond a typical mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose and command, then clearly partitioned into SECURITY and WRITE sections, so a skimming agent can find the guard and confirm rules quickly. It is longer than strictly necessary — the security paragraph restates the script restriction twice — but every section carries actionable information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded mutation tool with an output schema already present, the description supplies everything an agent needs before calling: prerequisites, confirm workflow, duplicate handling, and the security boundary. Return-format details are correctly left to the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across five parameters, so the description must compensate; it explains `host` (plain IPv4/IPv6), `interval` (RouterOS duration with concrete examples "10s"/"00:00:10"), `comment`, and fully documents `confirm`'s preview/apply semantics. Only `device_name` goes unexplained, a minor gap given it is a required target selector.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource plus the underlying CLI command (`/tool/netwatch add`), immediately distinguishing it from the read-only `netwatch` sibling that also appears in the tool list. An agent knows exactly what gets created (a Netwatch host monitor) and against what input (a host address).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing: use this to create a monitor, use the read-only `netwatch` tool to inspect script presence, and configure up/down scripts manually on the device rather than through this tool. It also states the two-step invocation contract (confirm=False for preview, confirm=True to apply), which is the key usage decision for this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_ppp_secretA

Create a PPP/PPPoE secret (/ppp/secret add) - name/password are the dial-in login credentials for a PPPoE/PPTP/L2TP/OpenVPN/SSTP service. service (default "any") restricts which PPP service the secret may authenticate for - one of "pppoe"/"pptp"/"l2tp"/"ovpn"/ "sstp"/"any". profile (an existing /ppp/profile name, e.g. to assign an address pool or rate limit), remote_address (a literal IP handed to the client on connect), and comment are all optional.

PASSWORD IN THE RESULT: like add_hotspot_user's voucher password, this tool's password is DELIBERATELY present in its result (the caller supplied it and gets it echoed back as confirmation) - but still never written to the audit journal. See guard.add_ppp_secret's docstring for exactly how that asymmetry holds.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a preview without changing anything; call again with confirm=True to actually create it. Errors clearly (without creating anything) if name already exists on the device - it never creates a duplicate or resets an existing secret's password.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
commentNo
confirmNo
profileNo
serviceNoany
passwordYes
device_nameYes
remote_addressNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does so well: it discloses the write gate (server must run with MIKROTIK_ALLOW_WRITE=true), the preview/confirm dry-run behavior, duplicate-name error semantics ('never creates a duplicate or resets an existing secret's password'), and the deliberate password-echo-in-result-but-not-audit asymmetry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded and well organized into purpose / password-handling / write-gating paragraphs, but it leans on cross-references ('See guard.add_ppp_secret's docstring', the add_hotspot_user comparison) that carry little value for an agent selecting and invoking the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 8-parameter guarded write with an output schema, the description covers everything an agent needs: prerequisites, confirmation flow, failure modes, and an explanation of the surprising password field in the result. Return values need not be described since an output schema exists.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description must compensate and largely does: it defines the login semantics of name/password, supplies the enum values for `service` that the schema itself lacks (pppoe/pptp/l2tp/ovpn/sstp/any), and explains `profile`, `remote_address`, `comment`, and `confirm`. Only `device_name` is left implicit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Create a PPP/PPPoE secret') and even names the underlying RouterOS path `/ppp/secret add`, which clearly distinguishes it from the sibling readers `ppp_secrets`/`ppp_active` and the writer `remove_ppp_secret`.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives strong when-to-use context: it is a guarded WRITE requiring MIKROTIK_ALLOW_WRITE=true, and it prescribes the two-step flow (confirm=False for preview, confirm=True to commit). It stops short of explicitly routing the agent to siblings (e.g. use ppp_secrets to inspect, remove_ppp_secret to delete) when this tool is the wrong choice.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

address_listsA

List firewall address-list entries (/ip/firewall/address-list): list, address, timeout, dynamic, disabled. See who's currently in which named list (e.g. a "blocked-clients" list a firewall rule drops), before adding/removing entries with add_to_address_list / remove_from_address_list.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full behavioral burden. It does disclose the returned fields and the read-before-write relationship with the add/remove tools, which is useful readable context. But it is silent on whether this is read-only (implied by 'list'), pagination, performance on large lists, or device_name targeting/auth requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose and resource path, then the returned fields, then the related tools. Well-structured and mostly tight. The quoted example ('blocked-clients') costs a few words but is justified as illustrative context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value shape need not be explained in detail, and the description still helpfully names the fields. It correctly situates the tool in the read/write workflow with its add/remove siblings. The gap is that the single required parameter (device_name) is undocumented given 0% coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

One required parameter (device_name) with 0% schema description coverage. The description never explains what device_name means or that the tool operates against a specific router. For a required parameter with zero schema documentation, the description should compensate but does not.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (list) and resource (firewall address-list entries), names the concrete RouterOS path /ip/firewall/address-list, and enumerates the fields returned (list, address, timeout, dynamic, disabled). This distinguishes it from plausible siblings like ipv6_firewall_address_lists and firewall_filter.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides a clear use case — 'See who's currently in which named list... before adding/removing entries' — and routes the agent to the mutation siblings add_to_address_list / remove_from_address_list. It gives the pre-read context explicitly. No explicit when-not-to-use is stated, which keeps it below 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_routeA

Add a static route (/ip/route add): dst_address and gateway are required, distance (failover priority - lower wins) and comment are optional. Never refuses a duplicate dst_address

  • multiple routes sharing one is the normal failover shape.

RISK: adding/overriding the default route (dst_address="0.0.0.0/0" or "::/0") redirects all outbound traffic through the new gateway. The returned preview's warning field is non-null whenever this is the case - always check it before calling again with confirm=true.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview (including the warning field) without changing anything; call again with confirm=True to actually apply it.

ParametersJSON Schema
NameRequiredDescriptionDefault
commentNo
confirmNo
gatewayYes
distanceNo
device_nameYes
dst_addressYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden and delivers: write-tool classification, the server-enforced write guard, the confirm-gated preview/apply pattern, override risk on default routes, the warning field signal, and duplicate-route tolerance.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the operation, followed by risk, followed by write-guard behavior. Sectioned with caps headers. The paragraph form is a bit dense but every sentence carries weight; no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists (preview shape with warning field is referenced), the description covers what an agent needs to invoke safely. Missing only a brief mention of device_name's purpose. For a mutation tool with zero annotations, this is unusually complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate. It identifies required params (dst_address, gateway), optional params (distance with semantics of failover priority - lower wins, comment), and the confirm flag behavior. device_name is not explained, preventing a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Add a static route') with the underlying command, required fields, and key distinguishing behavior (accepts duplicate dst_address as normal failover). Distinguishes from siblings like set_route_distance, enable_route, remove_route, and add_ipv6_route.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly describes the two-step workflow (confirm=False for preview, confirm=True to apply), states the guard condition (MIKROTIK_ALLOW_WRITE=true), and directs the agent to check the preview's warning field before applying. This is a complete when/when-not spec.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_static_dhcp_leaseA

Create a static DHCP lease (/ip/dhcp-server/lease), pinning address to mac_address. Useful to give a client a stable, predictable IP - e.g. before limiting it with set_client_bandwidth.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly (without creating anything) if a lease for mac_address already exists on the device - it never creates a duplicate.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNo
addressYes
commentNo
confirmNo
device_nameYes
mac_addressYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description carries the full burden and does so: it declares this a WRITE tool, states it is blocked unless MIKROTIK_ALLOW_WRITE=true, explains the default no-op preview mode, and specifies non-duplicate error behavior when a lease already exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short, front-loaded paragraphs with no filler; purpose leads and the safety/invocation caveats follow. Marginally longer than strictly necessary but every sentence carries useful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists so return values need not be described, and the description covers the guard, the preview workflow, and the duplicate-lease failure mode an agent must anticipate before calling.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across 6 parameters, so the description must compensate. It explains address, mac_address, and the confirm flag semantics well, and the resource path implies server, but comment and device_name are never explained, leaving a measurable gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Create a static DHCP lease (/ip/dhcp-server/lease)') and pins the outcome ('pinning address to mac_address'), which distinguishes it from remove_dhcp_lease and the read-only dhcp_leases sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives the use case (stable, predictable IP) and names the downstream sibling it enables ('before limiting it with set_client_bandwidth'), plus the two-step confirm=False then confirm=True invocation condition. An agent knows exactly when and how to call it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_static_dnsA

Create a static DNS entry (/ip/dns/static add) resolving name to address.

record_type is "A" (default) or "CNAME": for "A", address is a literal IPv4/IPv6 address; for "CNAME", address is itself another hostname (the alias target), written to RouterOS's cname field. Useful to block a malicious domain (point it at 0.0.0.0) or set up an internal DNS override.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly (without creating anything) if a row already matches this exact name+record_type pair - it never creates a duplicate.

ParametersJSON Schema
NameRequiredDescriptionDefault
ttlNo
nameYes
addressYes
commentNo
confirmNo
device_nameYes
record_typeNoA

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description carries the full burden and does so well: it declares this is a WRITE tool gated behind MIKROTIK_ALLOW_WRITE=true, explains that confirm=False returns a before/after preview while confirm=True applies, and discloses the duplicate-detection error behavior. This is exactly the mutability, safety-gate, and side-effect context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and command, then layered with type semantics, safety gating, and error behavior. Every sentence earns its place, though the multi-paragraph form is slightly longer than strictly necessary for a 7-param tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Since an output schema exists, return values need not be described, and the description covers mutation semantics, safety gating, and idempotency thoroughly. The only shortfall is the unaddressed ttl/comment/device_name parameters, which matters for a tool with 0% schema coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it does add real meaning for name, address, record_type, and confirm (including how CNAME writes to the `cname` field). However, ttl, comment, and device_name are never mentioned, leaving nearly half the parameters undocumented anywhere.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource and even names the underlying RouterOS command (`/ip/dns/static add`), then clarifies the two record types and their distinct address semantics. An agent can distinguish it from the sibling `remove_static_dns` and from generic DNS reads like `dns_cache` without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete when-to-use scenarios (block a malicious domain via 0.0.0.0, internal DNS override) and spells out the two-step confirm workflow. It does not explicitly name an alternative tool or say when NOT to use it (e.g., use `add_static_dhcp_lease` instead for leases), so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_to_address_listA

Add address (an IP or subnet) to a named firewall address-list (/ip/firewall/address-list).

IMPORTANT: this only manages the list - it does NOT create or modify any firewall rule. Adding an address here only blocks or allows traffic if a /ip/firewall/filter (or NAT) rule on the device already references list_name (e.g. src-address-list=list_name, action=drop). See README's "Blocking/allowing a client via address lists" section.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly (without creating anything) if this exact list_name+address pair already exists on the device - it never creates a duplicate.

ParametersJSON Schema
NameRequiredDescriptionDefault
addressYes
commentNo
confirmNo
timeoutNo
list_nameYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully carries the behavioral burden: it discloses the write guard, the two-phase preview/apply workflow, idempotency (refuses duplicate list_name+address pairs without creating anything), and error behavior. It goes well beyond what the schema conveys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Content is front-loaded with the core action, then scoping, then the write guard. It is a bit long with uppercase IMPORTANT and a README pointer, but each block adds decision-relevant information rather than padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded mutation tool with no annotations but an output schema, the description covers the prerequisite, confirmation flow, no-op/duplicate behavior, and the crucial caveat that rules must already reference the list. Nothing needed to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across 6 parameters, so the description must compensate. It clarifies `address` as an IP or subnet and explains `confirm`'s default-false preview semantics and `list_name`'s role in rule matching, but leaves `comment`, `timeout`, and `device_name` entirely undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a precise verb and resource ('Add `address` ... to a named firewall address-list (/ip/firewall/address-list)') and explicitly scopes it away from related concepts, noting it does NOT create or modify firewall rules. This lets an agent distinguish it from siblings like remove_from_address_list, address_lists, and firewall_filter without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit preconditions (server must run with MIKROTIK_ALLOW_WRITE=true) and a concrete call sequence: confirm=False for a preview, then confirm=True to apply. It also routes the agent to the README section for the rule-referencing scenario, covering when the effect actually materializes.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_to_ipv6_address_listA

Add address (an IPv6 address or subnet) to a named IPv6 firewall address-list (/ipv6/firewall/address-list). Mirrors add_to_address_list on the IPv6 menu.

IMPORTANT: this only manages the list - it does NOT create or modify any firewall rule. Adding an address here only blocks or allows traffic if an /ipv6/firewall/filter rule on the device already references list_name. See README's "Blocking/allowing a client via address lists" section.

address must be IPv6 (an IPv4 address/subnet is rejected before the device is ever touched).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly (without creating anything) if this exact list_name+address pair already exists on the device - it never creates a duplicate. Also errors clearly if the ipv6 package is disabled on the device.

ParametersJSON Schema
NameRequiredDescriptionDefault
addressYes
commentNo
confirmNo
timeoutNo
list_nameYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it declares this is a WRITE tool gated behind MIKROTIK_ALLOW_WRITE=true, describes the dry-run/apply confirm pattern and its default, and discloses two specific error behaviors (duplicate list_name+address pair, disabled ipv6 package) with the guarantee that no duplicate is ever created.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then structured with IMPORTANT/behavioral blocks that are easy to scan. It is on the longer side and the guard/duplicate/error notes are dense, but nearly every sentence adds decision-relevant information rather than restating the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded 6-parameter mutation tool with no annotations, it covers purpose, safety gating, dry-run semantics, error conditions, and the key conceptual caveat about firewall rules. An output schema exists, so return-value explanation is correctly omitted, leaving nothing an agent needs in order to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate. It explains `address` (IPv6 only, IPv4 rejected before touching the device), `list_name` (the referenced list), and `confirm` (False=preview, True=apply), but leaves `comment`, `timeout`, and `device_name` unexplained. The critical and non-obvious parameters are covered, so it substantially closes the gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: adds an IPv6 address/subnet to a named IPv6 firewall address-list at `/ipv6/firewall/address-list`. It explicitly distinguishes itself from the IPv4 sibling (`add_to_address_list`) and by extension from `remove_from_ipv6_address_list`, so an agent can route correctly without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-not guidance: 'this only manages the *list* - it does NOT create or modify any firewall rule,' and notes traffic is only affected if an existing filter rule references `list_name`. It also spells out the two-step confirm workflow (preview with confirm=False, apply with confirm=True) and names the IPv4 counterpart it mirrors.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_vlanA

Create a VLAN interface (/interface/vlan add): name (the new RouterOS interface name, e.g. "vlan100"), vlan_id (1-4094, the IEEE 802.1Q tag), interface (the parent interface it rides on top of, e.g. "bridge1"/"ether2" - not verified to exist here; RouterOS itself rejects an unknown one at write time). mtu/comment are optional.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually create it. Errors clearly (without creating anything) if name already exists on the device - it never creates a duplicate.

ParametersJSON Schema
NameRequiredDescriptionDefault
mtuNo
nameYes
commentNo
confirmNo
vlan_idYes
interfaceYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does so well: it discloses the write guard (MIKROTIK_ALLOW_WRITE=true), the confirm-gated preview, duplicate-name rejection, and the fact that the parent interface existence is not validated by the tool. This is exactly the mutation-safety context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and the underlying CLI command, then walks through parameters, then the guard. Slightly dense but every clause (interface-not-verified, duplicate rejection, confirm semantics) adds real value. Could be tightened by not repeating 'call again' phrasing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers all required params, the write-guard behavior, the preview/commit flow, duplicate-name handling, and the incomplete validation caveat. Output schema exists for the return shape, so the description needn't explain the response. A 7-param write tool with 0% schema coverage is fully specified.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate and it does: it defines name, vlan_id range (1-4094, IEEE 802.1Q tag), interface (parent interface with examples bridge1/ether2), and marks mtu/comment as optional. The only parameter not described is confirm, which is covered under behavioral transparency.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (create a VLAN interface), gives the underlying RouterOS command (/interface/vlan add), and names each required parameter. Siblings like add_wireguard_interface or add_static_dhcp_lease are clearly distinct, and remove_vlan is the inverse operation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the confirm=False / confirm=True workflow explicitly, and that the tool is blocked unless MIKROTIK_ALLOW_WRITE=true. It does not name a direct alternative for VLAN creation (there isn't one), but does route the agent through the preview-then-commit pattern.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_wireguard_interfaceA

Create a WireGuard tunnel interface (/interface/wireguard add).

RouterOS generates the interface's private-key internally - this tool never accepts (or returns) one. The confirm=False preview's after only describes what will be created (name, listen-port if given) - it does not invent a public-key, since RouterOS hasn't generated the key pair yet at preview time. The confirm=True applied result re-reads the created interface and reports its real public-key, with private-key always stripped. See README's "WireGuard management" section.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to preview without changing anything; call again with confirm=True to actually create it. Errors clearly if name already exists - never creates a duplicate.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
confirmNo
device_nameYes
listen_portNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so richly: write-gating, private-key never accepted or returned, the preview's limited `after` payload, the real public-key surfaced only on apply with private-key stripped, and the duplicate-name error path. This goes well beyond what any structured field discloses.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the creation action followed by behavioral caveats in short paragraphs; mostly tight, though the key-handling and README reference add some redundancy beyond what a caller strictly needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with an output schema, it covers the critical behavioral surface (write gate, two-phase confirm, key handling, idempotency). The one meaningful hole is the undocumented required `device_name`, which leaves the call-site context partially incomplete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must define all four parameters. It explains the semantics of `confirm` thoroughly and touches `name` (existence check) and `listen-port`, but `device_name` - a REQUIRED parameter - is never mentioned anywhere, leaving an agent unable to know what it means or what to supply.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ('Create a WireGuard tunnel interface'), mapping to a clear RouterOS operation, and is distinguishable from siblings like wireguard_interfaces (list) and add_wireguard_peer by naming the exact resource created.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states this is a guarded WRITE tool blocked unless MIKROTIK_ALLOW_WRITE=true, and prescribes the two-step confirm=False preview then confirm=True apply flow. It does not name an alternative tool for listing/inspecting existing interfaces, leaving that routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_wireguard_peerA

Add a WireGuard peer (/interface/wireguard/peers add) to an existing tunnel interface.

public_key is the REMOTE peer's own public key (base64, 44 chars). allowed_address is a comma-separated list of CIDR ranges routed through this peer (e.g. "10.0.0.2/32,10.0.0.3/32"). endpoint_address/endpoint_port (the peer's reachable address/port, if any) and persistent_keepalive (a RouterOS duration, e.g. "25s") are optional.

Does NOT accept a private-key or preshared-key parameter - the remote peer's own private key, and any preshared key, are entirely out of this tool's scope.

interface must already exist - create it first with add_wireguard_interface; errors clearly if it doesn't. Refuses to add a duplicate peer (same public_key already registered on the same interface) - never creates a duplicate.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to preview without changing anything; call again with confirm=True to actually add it.

ParametersJSON Schema
NameRequiredDescriptionDefault
commentNo
confirmNo
interfaceYes
public_keyYes
device_nameYes
endpoint_portNo
allowed_addressYes
endpoint_addressNo
persistent_keepaliveNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden and does so well: it discloses write gating, two-step confirmation, duplicate detection/refusal, dependency on an existing interface, and explicit scope exclusions for private and preshared keys. No annotation contradiction exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but appropriately structured for a write tool with many parameters: it front-loads the action, then key parameter meanings, then constraints and write-gating flow. Each paragraph addresses a distinct decision or parameter, with no obvious filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 9 parameters, no annotations, and 0% schema description coverage, it covers most decision-critical behavior and most parameters. However, it leaves the required device_name and optional comment unexplained, and an output schema exists so return values need not be covered. The remaining gaps are minor but real.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains public_key format (base64, 44 chars), allowed_address CIDR list with example, endpoint_address/endpoint_port as optional, persistent_keepalive as a RouterOS duration, and confirm semantics, but it does not explain the required device_name or optional comment parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Add a WireGuard peer' with the exact RouterOS command path. It distinguishes the tool from sibling add_wireguard_interface by requiring an existing interface, and from list/remove WireGuard tools, so an agent can select it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states prerequisites ('interface must already exist - create it first with add_wireguard_interface'), duplicate refusal behavior, write gating via MIKROTIK_ALLOW_WRITE=true, and the confirm=False preview / confirm=True commit flow. It also names what the tool does not accept, further constraining usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

arm_dead_manA

Arm a local, self-removing RouterOS scheduler on device_name that reverts a change after minutes (1-60) unless cancelled first (cancel_dead_man) - the anti-lockout primitive behind every LOCKOUT-RISK write in this package (set_wireless_channel/ set_wireless_tx_power use it automatically by default). See README's "Dead-man / lockout-proof writes" section for the full design and the real-hardware incident that validated it.

NOT wireless-specific: revert_commands is any non-empty list (max 10 items) of RouterOS script statements that restore a known-good prior state - a route, a bridge port, a firewall rule, anything - run in order when the dead-man fires, after logging a warning (visible in logs/security_events) and before the scheduler removes itself. Build each command from state you already read from the device, not free-form text.

The returned preview's after["name"] (also after more broadly) is the exact scheduler that would be armed (or was armed, if confirm=True) - pass that name to cancel_dead_man once the change it guards is confirmed good.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to preview the exact scheduler that would be armed without touching the device; call again with confirm=True to actually arm it.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
minutesNo
device_nameYes
revert_commandsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and meets it: it discloses the write-guard (MIKROTIK_ALLOW_WRITE=true), the dry-run default, the self-removing scheduler lifecycle, that revert commands run in order after a logged warning visible in logs/security_events, and that commands must be built from read state, not free text.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and generally well structured, but the mid-paragraph clarification about the preview's after['name'] is wordy and slightly redundant, and the README pointer is a mild detour. Still efficient for the amount of behavior it must convey.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description needn't enumerate return fields, yet it still points the agent at the returned preview's after['name'] for the cancel flow. Given the write-guard, dry-run semantics, and command constraints, nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it does: minutes is bounded (1-60), revert_commands is any non-empty list of max 10 ordered RouterOS statements, confirm controls preview-vs-arm, and device_name is the target. All four parameters gain meaning beyond their bare titles.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Arm a local, self-removing RouterOS scheduler') and immediately scopes it as the anti-lockout primitive behind LOCKOUT-RISK writes. It cleanly distinguishes itself from cancel_dead_man, which it names as the counterpart.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use it (guarding LOCKOUT-RISK writes), how the two-step confirm flow works (confirm=False to preview, confirm=True to arm), and when to cancel (once the guarded change is confirmed good via the returned name). No inference required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

arp_tableA

List the IPv4 ARP table (/ip/arp): address, mac-address, interface, dynamic, complete.

Use this to cross-reference an IP to a MAC (or vice versa) for a statically-addressed device that never shows up in dhcp_leases (it never requested a DHCP lease, so it has no lease entry - but it does get an ARP entry once it has exchanged traffic with the device).

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations the description carries the full burden, and it does well: it discloses the non-obvious behavioral fact that a device only gets an ARP entry after exchanging traffic. It does not state read-only nature explicitly (implied by 'List') nor pagination, so not a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the resource and column list, then the usage rationale. The parenthetical aside is slightly verbose but each sentence carries signal; no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists, so return values need not be explained, and the description still enumerates expected columns. For a one-param read tool with no annotations, the guidance on when it beats dhcp_leases makes it essentially complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

One required parameter (device_name) with 0% schema description coverage. The description does not explain the device_name parameter at all, leaving the agent to infer it targets a specific device. Baseline is 4 for zero-param tools, but here the single param is unexplained, so 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the IPv4 ARP table (/ip/arp)') and even enumerates the returned columns. The explicit '/ip/arp' path and IPv4 qualifier distinguish it from ipv6_neighbors and ip_addresses.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit when-to-use scenario: cross-referencing IP to MAC for a statically-addressed device that will never appear in dhcp_leases. Naming the sibling dhcp_leases and the exclusion condition is exactly the routing guidance an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bgp_sessionsA

List BGP session status: remote-address/remote-as, state (established/idle/...), uptime, prefix-count.

RouterOS exposes this under two different paths depending on generation, the same split wireless_registrations already handles for wifi: ROS7's routing package (/routing/bgp/session) or ROS6's (/routing/bgp/peer). This tries ROS7 first, falls back to ROS6, and returns an empty list - rather than raising - for a device that doesn't run BGP at all.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full disclosure burden and does well: it explains the ROS7/ROS6 path split, the fallback order, and that a non-BGP device yields an empty list instead of an error. That error-suppression detail is exactly the kind of behavior an agent must know to interpret an empty result correctly. It stops short of covering permissions or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the return contents in sentence one, then the generation-handling caveat. The ROS6/ROS7 paragraph is slightly long and references a sibling (wireless_registrations) that is tangentially relevant, but nothing is wasted outright.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no prose explanation, and the description still covers the runtime quirks (generation split, empty-list fallback) an agent needs. Only the device_name parameter lacks any descriptive detail.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description should ideally compensate, but it never mentions device_name or its expected format (e.g. hostname vs IP). The single parameter is self-describing by name, which keeps this at a minimum-viable 3 rather than lower.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('List BGP session status') and enumerates the returned fields (remote-address/remote-as, state, uptime, prefix-count), so the agent knows exactly what this tool produces. It is distinguishable from siblings such as ospf_neighbors or ip_routes by resource, though it never names those alternatives explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains internal path-fallback behavior (ROS7 first, ROS6 second) which implicitly tells the agent this is the single entry point for BGP data regardless of RouterOS generation. It does not, however, state when to prefer this over a generic interface monitor or neighbor tool, nor any prerequisites beyond device_name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bridge_hostsA

List /interface/bridge/host entries: mac-address, on-interface (the physical bridge port), bridge, dynamic, local.

Use this to find which physical port of a bridge a given MAC is currently learned on - e.g. to identify which PoE-capable ethernet port a locked-up device is plugged into, before using poe_status/ set_poe_out on it (see "Physical layer & PoE control" in the README).

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It usefully clarifies field semantics (on-interface = the physical bridge port) and that entries are 'currently learned' dynamic state, but it omits read-only status, pagination/result-size behavior, and any device-side requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the resource and returned fields, followed by a use-case sentence that earns its place. The trailing README pointer is mildly meta but the whole is tight and readable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read tool with an output schema present, the description is largely complete: purpose, output fields, and usage are all covered. The only real gap is the undocumented device_name parameter, which an agent must infer from the schema title alone.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter device_name has 0% schema description coverage and is never mentioned in the description, which spends its words on the returned fields instead. The schema does the documenting here, and the description adds nothing to compensate for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('List /interface/bridge/host entries') and enumerates the fields returned (mac-address, on-interface, bridge, dynamic, local), making clear this is the L2 MAC-learning table. This cleanly distinguishes it from L3 tables like arp_table/neighbors and from bridge_ports/bridge_vlans.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete usage guidance ('find which physical port of a bridge a given MAC is currently learned on') and routes the agent to follow-up tools (poe_status/set_poe_out). It does not, however, state when NOT to use it or name a competing tool for the same lookup, so it falls short of explicit alternative routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bridge_portsA

List bridge port membership (/interface/bridge/port): bridge, interface, pvid, disabled, edge, horizon, learn, comment. Only disabled is normalized to bool | None (formatting.coerce_ros_bool) - edge/learn are RouterOS enums (e.g. auto/yes/no/yes-discover/no-discover), not strict booleans, so they are left as RouterOS's own raw value rather than coerced.

Use this (with bridge_vlans below) to see which physical port of a managed switch's bridge a VLAN actually applies to - bridge_hosts only shows the MAC table, not port/VLAN configuration.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and delivers real behavioral detail: it discloses that only `disabled` is coerced to `bool | None` while `edge`/`learn` are left as raw RouterOS enums, naming the coercion helper. It omits auth/rate-limit context, but for a read-only list tool that gap is minor.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose and routing guidance, and each sentence carries information. It is slightly over-detailed in naming the internal `formatting.coerce_ros_bool` helper and the raw `/interface/bridge/port` path, which cost a little space without adding agent-facing value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-shape explanation is not required, and the description still adds field-level normalization semantics plus clear sibling routing. The only real gap is that the required `device_name` argument is left entirely to the schema's type declaration.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter `device_name` has 0% schema description coverage and the description never explains it, so it does not compensate for the gap. The description instead spends its words on return-field semantics, which belong to the payload rather than the argument.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ('List bridge port membership') and names the exact RouterOS path it maps to. It also implicitly separates itself from bridge_hosts and bridge_vlans by stating what those tools do not cover.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to use this together with `bridge_vlans` to determine which physical port a VLAN applies to, and states the negative case: `bridge_hosts` only shows the MAC table, not port/VLAN configuration. Both the alternative and the exclusion condition are named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

bridge_vlansA

List bridge VLAN filtering table entries (/interface/bridge/vlan): bridge, vlan-ids, tagged, untagged, comment, plus current-tagged/current-untagged when the device's reply carries them (RouterOS's own computed effective port lists - not present on every ROS6/ROS7 version, so only added when actually present, never invented).

This is the honest completion of the VLAN story for a MANAGED SWITCH (CRS/hEX-style hardware): the v1.2 list_vlans/add_vlan/ remove_vlan tools operate on standalone /interface/vlan interfaces (router-on-a-stick style routing), which is a DIFFERENT RouterOS mechanism from bridge VLAN filtering - a switch that segments traffic by VLAN across bridge ports needs THIS table, not /interface/vlan. See bridge_ports above for per-port pvid/edge/learn config.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral burden and does a good job: it discloses that `current-tagged`/`current-untagged` are conditionally present, version-dependent, and never invented. It does not discuss authentication, rate limits, or pagination, but for a read-only list tool with an output schema this is a minor gap. No contradiction with structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the table and fields, then explains the sibling distinction and caveats. It is somewhat verbose with parentheticals and line breaks, but most sentences carry useful information and nothing is egregiously redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a list tool with an output schema, the description is complete: it identifies the exact table, return columns, version-dependent fields, and the key sibling distinction for managed-switch VLAN filtering. An agent has enough context to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is one required parameter (`device_name`) and schema description coverage is 0%, so the description is expected to compensate. Instead, it never explains what `device_name` means, what values are accepted, or where to obtain it. The parameter is conventional, but the definition itself provides no additional semantic guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List') and resource ('bridge VLAN filtering table entries') and gives the RouterOS path `/interface/bridge/vlan`. It explicitly distinguishes this tool from the similarly named `list_vlans`/`add_vlan`/`remove_vlan` siblings, which operate on a different RouterOS mechanism.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly states when to use this tool ('a switch that segments traffic by VLAN across bridge ports needs THIS table, not `/interface/vlan`') and names the alternatives that should not be used for this purpose. It also routes the agent to `bridge_ports` for related per-port configuration.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cancel_dead_manA

Cancel a dead-man scheduler armed by arm_dead_man (or automatically by set_wireless_channel/set_wireless_tx_power), once the change it guards is confirmed good - removes it from /system/scheduler before it can fire and revert.

name MUST be the exact "deadman-" handle arm_dead_man returned (after["name"], or a wireless write's dead_man["name"])

  • by construction this can never target an unrelated scheduler entry (e.g. an admin's own "backup-daily" task).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to preview what would be cancelled; call again with confirm=True to actually cancel it. Errors clearly if name doesn't match an armed scheduler - which can mean it already fired and self-removed (it wasn't cancelled in time), or was already cancelled.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so well: it discloses that this is a WRITE tool, that it is blocked unless MIKROTIK_ALLOW_WRITE=true, that confirm defaults to false, and what cancellation or failure implies. The name-safety guarantee and self-removal behavior are important operational details beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads purpose, then explains the critical name handle, then write gating and confirm semantics, then error cases. The length is justified by the write-guard and handle-safety requirements, and every section adds useful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Complete enough for a write tool with no annotations and an output schema: it covers safety gating, confirmation, name semantics, and error conditions. The only notable gap is that device_name is not described, though its meaning is relatively inferable from sibling tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must define parameters. It thoroughly explains name as the exact deadman-<hex> handle from arm_dead_man and confirm as preview/execute, but it never explains device_name even though that parameter is required.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: cancel a dead-man scheduler armed by arm_dead_man or wireless setters. It clearly distinguishes this tool from siblings by naming the related arm_dead_man and automatic arming paths.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use guidance: cancel once the guarded change is confirmed good, before it fires and reverts. It also explains the confirm=False preview vs confirm=True execution flow and the error meaning if the handle is already gone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

certificatesA

List certificates (/certificate): name, common-name, subject/issuer fields (if present), invalid-before/invalid-after (raw RouterOS date strings, kept as-is), key-size/key-type, fingerprint, and RouterOS's own flags (expired, trusted) - all returned exactly as the device sends them (booleans may come back as Python bool or be omitted entirely; see formatting.coerce_ros_bool for a caller that needs to branch on expired/trusted rather than just display them).

Adds a computed daysUntilExpiry (int, negative once past due) from invalid-after whenever it can be parsed - see formatting.parse_ros_datetime's docstring for the two RouterOS date shapes handled ("2027-01-15 12:00:00" and "jan/15/2027 12:00:00"). RouterOS's own date rendering varies by version/locale; parsing is DEFENSIVE and never raises - a row whose invalid-after doesn't match either known shape simply has no daysUntilExpiry key added, with the raw invalid-after string left untouched so a caller can still see it.

SECURITY: /certificate's own API reply never carries a private key (RouterOS only returns certificate metadata over the API) - a private-key field is nonetheless stripped defensively before returning, in case a future RouterOS version or firmware quirk ever adds one (same strip_sensitive_fields mechanism ppp_secrets/ wireguard_interfaces use). See test_certificates_strips_private_key_defensively.

See also security_audit's certificate-expiry check (v1.6), which flags an expired or soon-to-expire (<=30 days) certificate as a finding using this same expiry logic.

Returns an empty list (never an error) for a device with no certificates configured.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so thoroughly: it discloses defensive date parsing that never raises, the conditional `daysUntilExpiry` key, the stripping of `private-key` even though the API doesn't return it, boolean coercion caveats, and that an empty list is returned (never an error) for devices with no certificates. This is rich, non-redundant behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is quite long and dense, with some repetition (e.g., multiple mentions of defensive handling). It is front-loaded with the field list but the security and parsing details, while useful, could be tightened. Every sentence does earn its place by adding behavioral context, but the overall length is borderline excessive for a list tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (custom parsing, security stripping, conditional fields) and the presence of an output schema (which is not described here, appropriately), the description is complete enough for an agent to call the tool correctly. It covers return value nuances, edge cases, and security behavior without needing to explain the output schema's structure.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the single parameter `device_name` is undocumented in the schema, but the description doesn't explicitly explain it either. However, with 1 parameter, the baseline is 4, and the description's focus on returned fields and behavior partially compensates by clarifying scope. It does not add parameter-specific meaning beyond the name.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it lists certificates from `/certificate`, a specific verb+resource, and enumerates the returned fields. It does not explicitly distinguish itself from siblings like `security_audit` (which it mentions) or `ppp_secrets`/`wireguard_interfaces` (which it references only for a shared mechanism), but the core purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit guidance on when to use this tool versus alternatives. The mention of `security_audit`'s expiry check is informative but framed as a 'see also' rather than a routing rule. An agent is left to infer that this is purely a read/list tool separate from audit operations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

clear_dns_cacheA

Flush the device's DNS resolver cache (/ip/dns/cache/flush) - no arguments, clears every cached DNS answer at once.

Benign (only cached answers are cleared - repopulated on the next resolution - never device configuration), but still guarded/ confirm-gated like every other write tool here.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to preview the current cached-entry count without changing anything; call again with confirm=True to actually flush it.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses that only cached answers are cleared (never config), that results repopulate on next resolution, that the operation is confirm-gated, and that it is blocked without the write env flag.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Content is front-loaded (what it does, then safety, then the guard/confirm mechanics) and every sentence earns its place. Slightly verbose with parenthetical asides and line breaks, but no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained. Given the guard requirement, the confirm flow, and the benign-but-gated nature of the write, the agent has everything needed to invoke this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it does for the key parameter: confirm=False previews while confirm=True executes, including the default. It implies no-argument clearing of the whole cache, and device_name is self-evident for a multi-device server.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Flush the device's DNS resolver cache') and even names the underlying endpoint `/ip/dns/cache/flush`. An agent can distinguish this from the read-only sibling `dns_cache` without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly describes the two-step flow: call with confirm=False (default) to preview cached-entry count, then confirm=True to flush. It also states the prerequisite that the server must run with MIKROTIK_ALLOW_WRITE=true, so when-not-to-use is covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

connection_trackingA

List active connections from RouterOS's connection tracking table (/ip/firewall/connection) - FILTERED. At least ONE of src_address, dst_address, dst_port, protocol is REQUIRED.

WHY a filter is mandatory (unlike every other read tool in this package): on a production router, the full connection-tracking table can be large enough to blow past an LLM caller's context/token budget on its own. Calling this with no filter at all raises a ValidationError instead of returning the whole table.

Filtering happens in Python after reading the table - the same reasoning logs' topics filter already documents (RouterOS's structured API doesn't expose a query-by-field read here either). src_address/dst_address match a row's IP, ignoring the port RouterOS packs into the same field (e.g. "192.0.2.1:80" -> address "192.0.2.1"); dst_port matches the destination's port component. protocol is a RouterOS protocol name (e.g. "tcp"/"udp"/"icmp", case-insensitive) or a numeric IP protocol number (0-255).

Regardless of how many rows match, the result is capped at MAX_CONNTRACK_LIMIT (100) entries - truncated is true whenever more rows matched than were returned, and total_matched always reports the real (pre-truncation) match count, so a caller always knows whether it's seeing everything that matched.

Each returned entry: protocol, src-address/src-port, dst-address/dst-port (address and port split apart - see formatting.split_address_port), tcp-state (populated for TCP connections), timeout, and the assured/confirmed/seen-reply flags - RouterOS's own closest equivalent to a generic "connection state" for this table.

ParametersJSON Schema
NameRequiredDescriptionDefault
dst_portNo
protocolNo
device_nameYes
dst_addressNo
src_addressNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so: it discloses the ValidationError on unfiltered calls, that filtering is done client-side in Python (not via RouterOS query-by-field), the MAX_CONNTRACK_LIMIT=100 cap, the truncated flag and total_matched pre-truncation semantics, and the exact fields returned per row. Nothing behavioral is left inferred.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and the filter requirement, and every sentence (the WHY, the parsing rules, the truncation contract, the return shape) carries distinct information. It is on the long side with a few parenthetical asides, but there is no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read tool with five parameters, a mandatory-filter rule, a hard result cap, and an output schema present, the description covers the precondition, the parsing semantics, the truncation contract and even the per-row field list. An agent has everything needed to call it correctly and interpret the response.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate and does: src_address/dst_address match only the IP portion of RouterOS's packed 'addr:port' field, dst_port matches the destination port component, and protocol accepts either a case-insensitive RouterOS protocol name or a numeric 0-255 IP protocol number.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List active connections from RouterOS's connection tracking table /ip/firewall/connection') and immediately marks the scope as FILTERED, which distinguishes it from the many unfiltered read siblings like ip_routes or firewall_filter.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly gives the when-to-use precondition — at least one of src_address/dst_address/dst_port/protocol is REQUIRED — and explains why (context/token budget risk versus every other read tool in the package), plus what happens if violated (ValidationError). That is a complete usage rule, not an implied one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

container_configB

Container subsystem configuration (/container/config): registry-url, tmpdir, ram-high, etc - a single-row menu. Returns an empty dict (never an error) for a device with no container package.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It does add genuine value by disclosing the empty-dict/never-error behavior for devices without a container package, but it says nothing about permissions, auth requirements, or explicitly confirming the operation is read-only.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact clauses with the identity of the resource front-loaded and no filler. Slightly dense in the parenthetical but every part contributes.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation, and the no-container edge case is covered. However, the undocumented required parameter and absent usage/routing guidance leave clear gaps for a tool with zero annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description never mentions the required 'device_name' parameter or its expected format/scope. Although the single parameter is largely self-evident from its name, the description fails to compensate for the total documentation gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource ('Container subsystem configuration at /container/config') and enumerates representative fields (registry-url, tmpdir, ram-high), which is more than a tautology. It also implies read semantics via 'single-row menu'. It does not explicitly distinguish itself from the sibling 'containers' tool, so it falls short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use or when-not-to-use guidance, and no alternative is named. The closest sibling, 'containers', is never contrasted with this config view, leaving the agent to infer which to call.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

containersB

List containers (/container): name/tag, status, ram-usage, root-dir, interface, os, etc. Returns an empty list (never an error) for a device with no container package/hardware support at all.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It usefully discloses that an unsupported device returns an empty list rather than an error, but it does not cover permissions, pagination, or other operational constraints. For a read-only list tool this is adequate but incomplete.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is front-loaded and short, starting with the tool's core action. The second sentence adds a useful edge case without bloating the description. It is appropriately sized for a simple listing tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the description does not need to document return values in detail. The main gap is that device_name is never explained despite 0% schema coverage. Given the simple one-parameter shape, the description is minimally adequate but not complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description should compensate for the undocumented device_name parameter. It only implies that device_name identifies a device and does not add format, source, or constraints. The return-field list does not clarify the parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: "List containers". It also names the endpoint and summarizes returned fields, so an agent can identify it as a read-only container listing. It does not explicitly differentiate itself from sibling tools such as container_config, start_container, or stop_container.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit guidance on when to use this tool versus container_config or the start/stop container tools. The unsupported-device behavior is an edge case, not usage direction. The agent must infer that this is the listing tool from the name and verb alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_backupA

Create a RouterOS system backup file (/system/backup/save name=<name>) - captures the device's full configuration into one binary .backup file on its own storage. Use list_backups afterward to confirm it landed and see its real size/creation-time.

password, if given, is RouterOS's own backup-FILE encryption option (unrelated to any device/API credential) - forwarded to the device, but NEVER included in the returned preview, and never journaled. See guard.create_backup's docstring for how that redaction is enforced.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a preview of the file that would be created without changing anything; call again with confirm=True to actually create it. Errors clearly (without creating anything) if a .backup file matching name already exists on the device - it never silently overwrites one.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
confirmNo
passwordNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so thoroughly: it discloses that this is a guarded WRITE operation blocked unless `MIKROTIK_ALLOW_WRITE=true`, that `confirm` controls preview vs execution, that existing files cause an error instead of being overwritten, and that `password` is a file-encryption option never returned or journaled. These are exactly the behavioral traits an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the purpose and command, then walks through follow-up, parameter caveats, and write-guard behavior. It is appropriately sized for a guarded write tool with no annotations, though the reference to `guard.create_backup`'s docstring is a slight indirection that could be trimmed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that an output schema exists, the description need not explain return values, and it focuses on behavior: guard requirements, confirmation workflow, no-overwrite policy, and password redaction. The only missing piece is any guidance on `device_name`, but otherwise it is complete for a write tool of this complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains `password` (RouterOS file encryption, never exposed) and `confirm` (preview versus actual creation) in detail, and implies `name` as the file identifier, but `device_name` is not described at all. Two and a half of four parameters are given meaning, leaving a notable gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action (create a RouterOS system backup) and the exact resource (binary `.backup` file on device storage), even including the underlying command. It also distinguishes itself from `list_backups`, which is the follow-up verification tool, so an agent can tell the two apart without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear invocation guidance: use `confirm=False` for a preview, then `confirm=True` to execute, and check results with `list_backups`. There is no explicit 'when not to use' alternative for creation, but the write guard and the no-overwrite behavior implicitly set the context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dhcp_leasesC

List DHCP server leases (address, mac, host-name, status, server, comment).

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

C2.8/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. 'List' implies a read-only operation, but it never states whether the call requires elevated permissions, whether results are paginated, or how leases are ordered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler; the field enumeration is compact. It earns its place, though the field list partly duplicates what the output schema already provides.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained (and the parenthetical is therefore somewhat redundant). The real gap is the undocumented required device_name parameter and the absence of any behavioral notes for a tool with no annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single required parameter device_name is undocumented in both schema and description. The parenthetical lists return fields, not the parameter's meaning or expected format.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('List') and resource ('DHCP server leases') and enumerates the returned fields, which cleanly separates it from siblings like dhcp_servers and dhcp_networks. It does not explicitly name those siblings, but the resource is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use this versus dhcp_servers, dhcp_networks, or remove_dhcp_lease, and no stated prerequisites. The agent is left to infer usage entirely from the name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dhcp_networksA

List DHCP server networks (/ip/dhcp-server/network): address, gateway, dns-server, netmask, domain, comment - the per-subnet options a DHCP server (see dhcp_servers) hands out to clients on lease. No boolean fields here to normalize.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the burden; it implies a read-only listing via 'List' and explains what the returned records mean (per-subnet options handed out on lease). However, it says nothing about permissions, pagination, or failure behavior, and the trailing note about booleans is opaque rather than informative.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with verb and resource, and the field enumeration is efficient. The closing sentence 'No boolean fields here to normalize' is an internal note that adds little value to an agent and slightly dilutes the otherwise tight phrasing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value detail is not required in the description; purpose, path, and record content are covered. The only real omission is any mention of the sole required parameter, which keeps it short of fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is one parameter (`device_name`) with 0% schema description coverage, and the description never mentions it. The gap is mitigated because the parameter name and title are self-explanatory and the tool is obviously device-scoped, but the description adds no semantics beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (DHCP server networks) with the exact API path `/ip/dhcp-server/network`, then enumerates the returned fields. It also distinguishes itself from the sibling `dhcp_servers` by describing these as the per-subnet options the server hands out, so an agent can separate the two without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the resource description (per-subnet lease options) and the cross-reference to `dhcp_servers`, but there is no explicit when-to-use / when-not-to-use guidance or any stated prerequisites. Adequate but leaves routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dhcp_serversA

List DHCP server CONFIG (/ip/dhcp-server) - as opposed to dhcp_leases, which lists the leases a server has handed out. Each entry keeps every field RouterOS returns (name, interface, address-pool, lease-time, authoritative, comment, ...), with disabled normalized to bool | None (formatting.coerce_ros_bool

  • never a == "true" string-equality trap, see that helper's docstring). authoritative is left as RouterOS's own raw value (it can be "yes"/"no"/"after-2sec-delay"/... - not a strict boolean - so it is not coerced).

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the behavioral burden, and it does add real value: it discloses that every RouterOS field is returned and that `disabled` is normalized to `bool | None` while `authoritative` is left raw. It never states the operation is read-only/has no side effects, nor does it cover pagination or auth, leaving gaps for a zero-annotation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core sentence is well front-loaded, but the text is bloated with internal implementation references (`formatting.coerce_ros_bool`, 'see that helper's docstring', the '== "true" string-equality trap') that are not useful to a tool-selecting agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the lengthy field-normalization narrative is partly redundant, while the one input parameter receives no explanation. Adequate but with a clear gap on the parameter side.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single required parameter `device_name` has 0% schema description coverage and is never mentioned in the description. The description's detail is entirely about returned fields (output), so it does not compensate for the undocumented input parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (DHCP server config at `/ip/dhcp-server`) and explicitly distinguishes itself from the sibling `dhcp_leases`. An agent can pick the right tool without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The contrast with `dhcp_leases` ('as opposed to... which lists the leases a server has handed out') gives clear routing guidance for the most likely confusion. It does not, however, state when not to use it or any prerequisite/auth context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

disable_firewall_ruleA

Disable an EXISTING firewall filter rule (/ip/firewall/filter set disabled=yes), resolved by its comment - optionally narrowed by chain if more than one rule shares that comment.

Same "never creates a rule" guarantee and comment-based resolution as enable_firewall_rule - see its docstring and README's "Firewall rule toggle (by comment)" section.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly if no rule matches comment (narrowed by chain), or if more than one still does (AmbiguousResourceError).

ParametersJSON Schema
NameRequiredDescriptionDefault
chainNo
commentYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden and does so thoroughly. It discloses that this is a WRITE tool, that it never creates a rule, that it is guarded by an environment variable, that it supports a preview/apply workflow, and that it can fail on missing or ambiguous matches.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The most important details, the exact action and resolution mechanism, are front-loaded, and the write guard/confirm workflow follows logically. It is somewhat long and defers to an external README/docstring for part of the guarantee, but there is little wasted text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the presence of an output schema, the description need not explain return values, and it covers the critical invocation context: write guard, confirmation flow, resolution semantics, and error cases. It is complete enough for an agent to call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it clearly explains `comment` (resolution key), `chain` (optional narrowing), and `confirm` (default false preview, true apply). It does not explain `device_name`, which is a required parameter and therefore leaves one meaningful gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'Disable an EXISTING firewall filter rule' with the exact RouterOS command path. It distinguishes itself from sibling tools like `enable_firewall_rule` by the opposite action and the shared comment-based resolution model.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states the required server flag MIKROTIK_ALLOW_WRITE=true and gives a two-step workflow: call with confirm=False for a preview, then confirm=True to apply. It also documents failure conditions (`AmbiguousResourceError` when multiple rules match), leaving no ambiguity about when and how to invoke it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

disable_interfaceA

Disable a network interface by name (sets disabled=yes).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly if interface_name does not exist on the device - it is never created.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
device_nameYes
interface_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: write guard, two-phase preview/apply semantics, default confirm value, and the failure mode when the interface is absent ('it is never created'). It stops short of describing reversibility (use enable_interface) or any output shape, but the safety-critical behavior is disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose, then the operational constraints. Every clause earns its place, though the multi-line formatting is slightly looser than a tight two-sentence form.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation, and the description covers the guard, the two-phase confirm, and the key failure mode. The only real gap is the semantics of device_name.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It fully explains confirm's default and two-phase meaning and the not-found behavior of interface_name, but device_name is never described, leaving one of three parameters undocumented in both places.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Disable a network interface by name') and even names the underlying change ('sets disabled=yes'), which cleanly distinguishes it from the sibling enable_interface without opening its schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit operating flow: blocked unless MIKROTIK_ALLOW_WRITE=true, call with confirm=False for a preview, then confirm=True to apply. It does not name enable_interface as the reversing alternative, so the when-not/undo side is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

disable_ipv6_firewall_ruleA

Disable an EXISTING IPv6 firewall filter rule (/ipv6/firewall/ filter set disabled=yes), resolved by its comment - optionally narrowed by chain if more than one rule shares that comment. Mirrors disable_firewall_rule on the IPv6 menu.

Same "never creates a rule" guarantee and comment-based resolution as enable_ipv6_firewall_rule.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly if no rule matches comment (narrowed by chain), or if more than one still does (AmbiguousResourceError). Also errors clearly if the ipv6 package is disabled on the device.

ParametersJSON Schema
NameRequiredDescriptionDefault
chainNo
commentYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses the MIKROTIK_ALLOW_WRITE=true gate, the two-phase confirm preview/apply behavior, the specific error cases (AmbiguousResourceError, no match, disabled ipv6 package), and the no-creation guarantee.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the verb/resource and command, then behavior. Slightly verbose with a couple of redundant 'Errors clearly' clauses, but nearly every sentence carries actionable information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded mutation tool with an output schema already covering return values, the description supplies everything needed: precondition (write flag), safety flow (confirm), resolution semantics, and error conditions. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate; it explains comment (resolution key), chain (optional narrowing when comments collide), and confirm (preview vs. apply). device_name is left implicit, which is a minor gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (disable) and resource (an EXISTING IPv6 firewall filter rule), and names the exact underlying command. It distinguishes itself from siblings by noting it mirrors disable_firewall_rule on the IPv6 menu and contrasts with enable_ipv6_firewall_rule.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context for use, including the confirm=False preview-then-confirm=True workflow and the never-creates guarantee. The alternative for re-enabling is named, but it doesn't broadly explain when to prefer this over other remediation tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

disable_mangle_ruleA

Disable an EXISTING firewall mangle rule (/ip/firewall/mangle set disabled=yes), resolved by its comment - optionally narrowed by chain.

Same "never creates a rule" guarantee and comment-based resolution as enable_mangle_rule.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly if no rule matches comment (narrowed by chain), or if more than one still does (AmbiguousResourceError).

ParametersJSON Schema
NameRequiredDescriptionDefault
chainNo
commentYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses the write guard (env var gate), the default confirm=False preview vs confirm=True apply behavior, the 'never creates a rule' guarantee, and the exact error conditions (no match, or AmbiguousResourceError on multiple matches). That is well beyond what the schema provides.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and the resolution key, then the guard, then the confirm flow. The parenthetical RouterOS command adds concrete context rather than filler, though the paragraph structure is slightly rambling compared to a tight two-sentence form.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists, return values need not be described. The remaining obligations for a guarded write tool — preconditions, confirmation protocol, ambiguity errors, and the no-create guarantee — are all present, so an agent can call it correctly without further discovery.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate. It explains comment (the resolution key), chain (optional narrowing of the match), and confirm (preview vs apply). device_name is left unexplained, which is the only gap, but the semantics of the risky parameters are fully covered.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Disable an EXISTING firewall mangle rule'), gives the underlying RouterOS command, and explicitly distinguishes itself from its counterpart 'enable_mangle_rule' and from creation behavior. An agent can pick it out of the large sibling list immediately.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear usage context: it operates on an existing rule resolved by comment, may be narrowed by chain, and carries the explicit 'blocked unless MIKROTIK_ALLOW_WRITE=true' precondition plus a two-step confirm flow. It does not spell out when to prefer it over e.g. disable_firewall_rule or disable_nat_rule, but the domain is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

disable_nat_ruleA

Disable an EXISTING firewall NAT rule (/ip/firewall/nat set disabled=yes), resolved by its comment - optionally narrowed by chain (srcnat/dstnat).

Same "never creates a rule" guarantee and comment-based resolution as enable_nat_rule.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly if no rule matches comment (narrowed by chain), or if more than one still does (AmbiguousResourceError).

ParametersJSON Schema
NameRequiredDescriptionDefault
chainNo
commentYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations at all, the description carries the full burden and does so well: it discloses the write guard, the dry-run/confirm flow, the safety guarantee ('never creates a rule'), and the specific failure mode (`AmbiguousResourceError`) when multiple rules match.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose, then the guard, then the invocation flow; each sentence carries distinct information. It is slightly longer than strictly necessary due to the back-reference to `enable_nat_rule`, but nothing is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value explanation is unnecessary, and the description covers the remaining gaps: guard condition, preview/apply flow, resolution rules, and error cases. An agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate; it explains `comment` (the resolution key), `chain` (srcnat/dstnat narrowing), and `confirm` (default false, preview vs apply). It only leaves `device_name` implicit, which is a minor gap for a 4-parameter tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Disable an EXISTING firewall NAT rule'), names the underlying operation (`/ip/firewall/nat set disabled=yes`), and specifies resolution semantics (by `comment`, optionally narrowed by `chain`). It also distinguishes itself from the sibling `enable_nat_rule` it is paired with.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly explains the two-step invocation pattern (confirm=False for preview, confirm=True to apply) and the enabling precondition (MIKROTIK_ALLOW_WRITE=true). It also states when errors occur (no match, ambiguous match), which tells the agent what input guarantees are needed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

disable_routeA

Disable a route (/ip/route set disabled=yes), resolved by dst_address - narrowed by gateway/comment when more than one route shares that dst_address. Errors clearly if nothing matches, or if the match is still ambiguous after narrowing.

RISK: disabling the default route (dst_address="0.0.0.0/0" or "::/0") cuts all outbound traffic that relies on this gateway. The returned preview's warning field is non-null whenever this is the case - always check it before calling again with confirm=true.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview (including the warning field) without changing anything; call again with confirm=True to actually apply it.

ParametersJSON Schema
NameRequiredDescriptionDefault
commentNo
confirmNo
gatewayNo
device_nameYes
dst_addressYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so thoroughly. It discloses the write guard, the preview/apply confirm flow, the specific risk of disabling the default route, and the returned warning field to check before confirming. It also describes error behavior on no match or ambiguity, leaving little behavioral uncertainty.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well front-loaded with purpose, then risk, then write-guard mechanics. Every sentence earns its place: resolution logic, error behavior, destructive warning, and confirm flow. It is appropriately sized for a guarded write operation with real risk.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity, the low schema description coverage, and the presence of an output schema, the description is complete enough. It covers purpose, resolution, error cases, destructive risk, the warning field, and the confirm/guard flow. An agent has everything needed to call it safely and correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It meaningfully explains dst_address as the resolution key, gateway and comment as narrowing filters for ambiguous matches, and confirm as the preview/apply switch. It does not explain device_name, though that parameter is largely self-evident from context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Disable a route') and even gives the underlying command ('/ip/route set disabled=yes'). It explains the resolution key (dst_address) and narrowing logic (gateway/comment), which clearly distinguishes it from sibling route operations like enable_route, add_route, or remove_route.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear procedural guidance: call with confirm=False for a preview, then confirm=True to apply, and notes the write guard requiring MIKROTIK_ALLOW_WRITE=true. It also describes error conditions when nothing matches or the match is ambiguous. However, it does not explicitly name alternative tools (e.g., enable_route) or state when not to use this tool, so it stops short of full alternative routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dns_cacheB

List cached DNS records on the device (name, type, data, ttl).

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It discloses the returned field set and that records come from the device cache, but says nothing about required access, whether the cache is per-interface/per-VRF, or whether listing is side-effect free (the safe read profile is left implicit).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One front-loaded sentence that names the action, the resource, and the returned fields with zero filler. Nothing to trim.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, and this is a simple single-parameter read tool. The remaining gap is that the sole parameter and the device scoping are never described, but for a listing tool of this complexity the description is close to sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description never mentions the single required parameter 'device_name' — no format, no expectation of device identifier style. The parameter is self-explanatory by name, but the description adds no meaning over the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('List') and resource ('cached DNS records on the device') plus the returned columns, so the agent knows exactly what it retrieves. It never names the sibling it could be confused with (clear_dns_cache, add_static_dns), but the read-listing verb makes it distinguishable without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use statement, no prerequisite, and no mention of alternatives such as clear_dns_cache or add_static_dns. The only guidance an agent gets is what it can infer from the tool name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

enable_firewall_ruleA

Enable an EXISTING firewall filter rule (/ip/firewall/filter set disabled=no), resolved by its comment - optionally narrowed by chain if more than one rule shares that comment.

SAFE BY DESIGN: this NEVER creates a rule. Intended workflow: an admin creates a rule ahead of time on the device with a descriptive comment (e.g. comment="Bloqueio_Ataque_X"), reviews it once, and leaves it disabled; an LLM caller later enables it via this tool when it detects the condition the rule exists to guard against. If it goes wrong, the admin knows exactly which rule was toggled - the same one they already wrote and reviewed. See README's "Firewall rule toggle (by comment)" section.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview - the FULL matched rule, not just its disabled field, so you can confirm WHICH rule this is - without changing anything; call again with confirm=True to actually apply it. Errors clearly if no rule matches comment (narrowed by chain), or if more than one still does (AmbiguousResourceError)

  • never guesses which one to toggle.

ParametersJSON Schema
NameRequiredDescriptionDefault
chainNo
commentYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does so thoroughly: it discloses the server-side write gate (MIKROTIK_ALLOW_WRITE=true), the confirm=False dry-run default vs confirm=True apply, the AmbiguousResourceError, and the no-match error. These are exactly the behavioral traits an agent needs and cannot infer from the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and CLI command, then structured into rationale, safety gate, and error behavior. It is somewhat long and uses emphasis formatting, but nearly every sentence earns its place given the safety-critical nature.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded write tool with no annotations and 0% schema coverage, the description covers target selection, the write-enable prerequisite, the two-step confirm flow, and failure modes, leaving nothing an agent needs to call it correctly. Output schema exists, so return-value detail is appropriately omitted.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains that `comment` resolves the target rule, `chain` optionally narrows when comments collide, and `confirm` toggles preview vs apply (with default). Each of the four parameters gets meaningful semantics beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Enable an EXISTING firewall filter rule'), gives the underlying CLI command, and explicitly distinguishes itself from creation. The sibling set includes disable_firewall_rule and firewall_filter, so stating 'EXISTING' and 'NEVER creates a rule' sharpens the boundary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit intended workflow (admin pre-creates a disabled rule with a descriptive comment, LLM enables it later on detection), states the alternative meaning of chain narrowing, and rules out ambiguous cases. This is model when-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

enable_interfaceA

Enable a network interface by name (sets disabled=no).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly if interface_name does not exist on the device - it is never created.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
device_nameYes
interface_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it discloses the write guard, the dry-run/apply confirm flow, that the interface is never created, and that a missing interface errors clearly. This is exactly the behavioral context an agent needs before mutating state.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then guard and confirm semantics in compact sentences. No filler; every clause adds actionable detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described. Between the purpose, guard, confirm flow, and error behavior, nothing needed to invoke this tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate. It explains confirm (preview vs apply) and interface_name (must exist, never created), covering the two semantically critical params; device_name is left implicit but is self-evident.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (enable) and resource (network interface) plus the concrete effect (sets disabled=no). This cleanly distinguishes it from the sibling disable_interface and enable_route/enable_firewall_rule tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly lays out the two-step workflow: call with confirm=False for a preview, then confirm=True to apply. Also states the preconditions (MIKROTIK_ALLOW_WRITE=true) and the failure case (interface must exist). No inference required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

enable_ipv6_firewall_ruleA

Enable an EXISTING IPv6 firewall filter rule (/ipv6/firewall/filter set disabled=no), resolved by its comment - optionally narrowed by chain if more than one rule shares that comment. Mirrors enable_firewall_rule on the IPv6 menu - see its docstring and README's "Firewall rule toggle (by comment)" section for the full admin-creates/LLM-enables workflow.

SAFE BY DESIGN: this NEVER creates a rule.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview - the FULL matched rule, not just its disabled field - without changing anything; call again with confirm=True to actually apply it. Errors clearly if no rule matches comment (narrowed by chain), or if more than one still does (AmbiguousResourceError) - never guesses which one to toggle. Also errors clearly (does not return an empty result) if the ipv6 package is disabled on the device - see "IPv6 write parity (v1.10)" in the README.

ParametersJSON Schema
NameRequiredDescriptionDefault
chainNo
commentYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations were provided, so the description carries the full burden — and it does. It discloses the write guard (MIKROTIK_ALLOW_WRITE=true required), the preview-vs-apply confirm semantics, the fact that the preview returns the FULL matched rule, and the exact error conditions (no match, AmbiguousResourceError, ipv6 package disabled). This is well beyond typical disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded and well organized with headers (SAFE BY DESIGN, WRITE tool), but the block is long relative to what an agent needs, and some cross-references (README sections, docstring pointer) are verbose. Every sentence does carry content, so the size is defensible but not tight.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

A write tool with no annotations and 0% schema coverage, but the description covers the safety gate, confirm semantics, resolution ambiguity, and failure modes thoroughly. With an output schema present, return-value explanation is not required, so nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains that `comment` is the resolution key and `chain` only narrows it when multiple rules share a comment, and that `confirm` toggles between preview and apply. It does not explain `device_name`, but for a 4-param tool with 0% coverage this covers the risky ones well.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource (enable an EXISTING IPv6 firewall filter rule), pinpoints the underlying routeros path, and explains the resolution key (comment, optionally narrowed by chain). It explicitly distinguishes itself from siblings by naming enable_firewall_rule and disable_ipv6_firewall_rule's counterpart set.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly gives when-to-use (enable an existing rule, mirroring the admin-creates/LLM-enables workflow), how to use safely (confirm=False preview then confirm=True), and when-not (never creates a rule). It even cross-references the README section for the full workflow.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

enable_mangle_ruleA

Enable an EXISTING firewall mangle rule (/ip/firewall/mangle set disabled=no), resolved by its comment - optionally narrowed by chain (e.g. prerouting/postrouting/forward/input/output) if more than one rule shares that comment.

Same "never creates a rule" guarantee and comment-based resolution as enable_firewall_rule - extended to /ip/firewall/mangle.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview - the FULL matched rule, not just its disabled field - without changing anything; call again with confirm=True to actually apply it. Errors clearly if no rule matches comment (narrowed by chain), or if more than one still does (AmbiguousResourceError) - never guesses which one to toggle.

ParametersJSON Schema
NameRequiredDescriptionDefault
chainNo
commentYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations to lean on, the description carries the full burden and does so well: it discloses the MIKROTIK_ALLOW_WRITE gate, the never-creates guarantee, the before/after preview semantics (full matched rule, not just disabled), and AmbiguousResourceError behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and resolution mechanism before behavioral details. It is somewhat long, but every sentence adds operational value; the only slack is the borderline-redundant restatement of the sibling guarantee.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 4 params, a write guard, and an existing output schema (so return values need not be explained), the description covers everything needed to call it correctly and safely: guard, preview flow, resolution rules, and failure modes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate: it explains comment as the resolution key, chain as an optional narrowing filter with example values, and confirm's preview/apply meaning. Only device_name is left implicit, which is minor and self-evident.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (enable an existing /ip/firewall/mangle rule) and the exact underlying operation (set disabled=no). It distinguishes itself from sibling enable_firewall_rule and clarifies resolution-by-comment, so an agent can tell it apart from the firewall/NAT mangle variants.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly ties the confirm flag to a workflow: confirm=False for a preview, confirm=True to apply. It also states when the tool errors (no match, or ambiguity) and that it never guesses, which directly guides correct invocation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

enable_nat_ruleA

Enable an EXISTING firewall NAT rule (/ip/firewall/nat set disabled=no), resolved by its comment - optionally narrowed by chain (srcnat/dstnat) if more than one rule shares that comment.

Same "never creates a rule" guarantee and comment-based resolution as enable_firewall_rule (see its docstring and README's "Firewall rule toggle (by comment)" section) - extended to /ip/firewall/nat.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview - the FULL matched rule, not just its disabled field - without changing anything; call again with confirm=True to actually apply it. Errors clearly if no rule matches comment (narrowed by chain), or if more than one still does (AmbiguousResourceError) - never guesses which one to toggle.

ParametersJSON Schema
NameRequiredDescriptionDefault
chainNo
commentYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and delivers: a hard write guard (MICROTIK_ALLOW_WRITE=true), a two-step confirm preview/apply flow, the non-destructive resolution behavior, and explicit error semantics. This is well beyond what any structured field provides.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and constraint, and the guard/confirm mechanics are gathered in a clearly labeled block. It is slightly verbose with a cross-reference to the sibling docstring and README, but no sentence is wasted and the structure aids scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values needn't be explained, and the description still notes the preview returns the full matched rule. For a guarded mutation tool with four parameters, the write guard, confirm flow, and error modes are all covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate. It explains `comment` (the resolution key), `chain` (srcnat/dstnat narrowing when comments collide), and `confirm` (preview vs apply). However, `device_name` is never described, leaving one of four parameters ambiguous.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('enable') and resource ('an EXISTING firewall NAT rule'), with the underlying operation (`/ip/firewall/nat set disabled=no`) made explicit. It clearly distinguishes itself from siblings by clarifying it 'never creates a rule' and frames itself as the NAT counterpart to `enable_firewall_rule`.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit about when it applies (existing rule resolved by comment, optionally narrowed by chain) and the exact workflow: confirm=False for a preview, confirm=True to apply. It also names the failure conditions (no match, AmbiguousResourceError) and states it never guesses, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

enable_routeA

Enable a route (/ip/route set disabled=no), resolved by dst_address - narrowed by gateway/comment when more than one route shares that dst_address (e.g. two default routes to different gateways, the standard failover shape). Errors clearly if nothing matches, or if the match is still ambiguous after narrowing.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it.

ParametersJSON Schema
NameRequiredDescriptionDefault
commentNo
confirmNo
gatewayNo
device_nameYes
dst_addressYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations to lean on, the description carries the full burden and does so well: it declares this is a WRITE tool, states the MIKROTIK_ALLOW_WRITE=true gate, and documents the two-phase confirm=False preview / confirm=True apply flow plus error behavior. That is exactly the safety context an agent needs before mutating a route.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short paragraphs, front-loaded with purpose and resolution logic, then the write-guard semantics. Nearly every clause earns its place, though the failover-shape example is mildly illustrative rather than essential.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter write tool with an output schema available, the description covers resolution logic, ambiguity handling, the write gate, and the confirm workflow. Nothing an agent needs to invoke it correctly is missing, and return values are handled by the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it does for the load-bearing parameters: dst_address is the resolver, gateway/comment narrow an ambiguous match, and confirm drives the preview-vs-apply behavior. Only device_name is left implicit, which keeps it from a top score.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Enable a route'), names the underlying operation, and identifies the key selector (dst_address) that distinguishes it from disable_route/add_route/remove_route/set_route_distance. An agent can pick it out of the sibling list without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the resolution/narrowing workflow (dst_address primary, gateway/comment to disambiguate) and what happens on no-match or ambiguity, which is real routing guidance. It does not explicitly name the sibling to use instead for the opposite operation (disable_route), so it stops short of full alternative routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

firewall_filterB

List IPv4 firewall filter rules (chain, action, etc). Read-only - does not add/modify/remove rules.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden, and it does disclose the key trait that this is read-only and never adds/modifies/removes rules. It stops there, saying nothing about permissions, pagination, or volume of results on a device with large rulesets.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the resource and followed by the safety constraint; nothing is padded or redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation, and the read-only statement is a useful addition. However, for a required-parameter query tool the agent still lacks guidance on obtaining a valid device_name and on how this differs from the other firewall listing tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single required parameter device_name carries no documentation in either schema or description. The description's "(chain, action, etc)" refers to output fields rather than explaining what device_name should contain or where to obtain it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ("List IPv4 firewall filter rules") and disambiguates from the IPv6 counterpart by naming IPv4 explicitly. The parenthetical "(chain, action, etc)" hints at the returned fields, though it does not explicitly route the agent against firewall_nat or firewall_mangle siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use guidance or alternatives are offered; the agent gets no hint that ipv6_firewall_filter exists for IPv6 rules or that firewall_nat/firewall_mangle cover other firewall tables. It only signals the read-only nature, not when this tool is the right pick.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

firewall_mangleA

List IPv4 firewall mangle rules (/ip/firewall/mangle): chain (e.g. prerouting/postrouting/forward/input/output, or a custom jump-target chain), action (e.g. mark-connection/mark-packet/ mark-routing), comment, disabled, plus whatever other fields RouterOS returns for a given rule (protocol, src/dst-address, etc - these vary per rule/action, same as firewall_filter/firewall_nat

  • not every rule has every field, and this returns each row as-is rather than assuming a fixed shape). Read-only - does not add/ modify/remove rules. See "NAT & mangle rule toggle (by comment)" below for the guarded enable_mangle_rule/disable_mangle_rule pair.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so the description carries the burden and does well: it discloses the read-only nature, the absence of a fixed row shape, and defers mutation to the guarded pair. It does not mention pagination, rate limits, or permissions, which keeps it short of 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with verb+resource, but the middle parenthetical rambles about variable fields and cross-references siblings in a slightly repetitive way. It earns its length mostly, but could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists, the description need not enumerate returns, yet it helpfully warns that rows vary per rule so the agent isn't surprised. Combined with the routing hint to the toggle pair, the definition is complete enough for a read-only list tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

One parameter (device_name) at 0% schema coverage; the description doesn't explain it, but the sole parameter is self-evident and the description compensates by describing the rule fields returned. Baseline for a single obvious param is acceptable at 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (IPv4 firewall mangle rules, with RouterOS path), and explicitly distinguishes itself from firewall_filter/firewall_nat while pointing to the enable/disable_mangle_rule pair. An agent can route correctly without opening other schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly marks the tool as read-only and points to the guarded toggle pair as the mutation alternative. It does not, however, say when to prefer mangle listing over, e.g., firewall_filter or firewall_nat for a given diagnostic task.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

firewall_natA

List IPv4 firewall NAT rules (/ip/firewall/nat): chain, action, to-addresses, etc. Read-only - does not add/modify/remove rules.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations at all, the description carries the full behavioral burden and does the most important part: it explicitly declares 'Read-only - does not add/modify/remove rules', which substitutes for a readOnlyHint and prevents misuse. It stops short of noting the device context needed for the call or any output shape, but the key safety trait is disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact lines, front-loaded with verb/resource and immediately followed by the read-only caveat. No filler sentences; every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation, and the read-only guarantee is present. However, for a tool whose only parameter is required and undocumented, the description should at least say what device_name refers to; that omission leaves the definition incomplete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single required parameter device_name is neither documented in the schema nor mentioned in the description. At low coverage the description is expected to compensate, and it does not, leaving the one required argument entirely unexplained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb ('List') plus a precise resource ('IPv4 firewall NAT rules') and the underlying path (/ip/firewall/nat), which cleanly separates it from sibling collection tools like firewall_filter, firewall_mangle and connection_tracking. The mention of 'chain, action, to-addresses' confirms what the listing contains.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The read-only framing implicitly signals this is the inspection counterpart to mutating siblings such as enable_nat_rule/disable_nat_rule, but the description never names an alternative or states when to prefer it. Usage is inferable rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

hotspot_activeA

List clients currently logged into the RouterOS hotspot (/ip/hotspot/active): user, address, mac-address, uptime, bytes-in/bytes-out - who is on the hotspot right now, and how much they've each moved this session.

Returns an empty list (never an error) for a device with no hotspot server configured, or simply no one logged in right now - same convention as ppp_active/ipsec_active_peers for an optional feature with no active sessions.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does disclose a meaningful trait: it returns an empty list rather than an error when no hotspot server exists or no one is logged in. It does not cover auth requirements, pagination, or rate limits, but the key error-vs-empty behavior is well communicated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose and returned fields, then a second paragraph for the error convention. The heavy backtick formatting is slightly noisy, but every sentence earns its place and the size is appropriate for the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list tool with an output schema, the definition covers purpose, returned fields, and the empty-vs-error convention that an agent needs. Remaining gaps (auth, pagination) are minor given the output schema and the simple single-parameter surface.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description should compensate for the single `device_name` parameter, and it does not mention it at all. The parameter is trivially self-descriptive, so the practical risk is low, but the description adds no semantics beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List clients currently logged into the RouterOS hotspot'), names the exact API path `/ip/hotspot/active`, and enumerates the returned fields (user, address, mac-address, uptime, bytes-in/out). It is clearly distinguishable from siblings like ppp_active and ipsec_active_peers, which cover different session types.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The reference to ppp_active/ipsec_active_peers is about the empty-list convention, not about when to prefer one tool over another, so alternative-selection guidance is only implied. The description conveys usage context (who is on the hotspot right now) but names no exclusions or prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

interface_monitorA

Link/optical status of one ethernet interface (/interface/ethernet/monitor once=yes) - status (link-ok/ no-link), rate, full-duplex (coerced to bool | None - see formatting.coerce_ros_bool), auto-negotiation (RouterOS's raw value - a "done"/"incomplete"-style state, not a strict boolean, so left as-is), plus SFP/DDM optics fields WHEN the port has an SFP cage and a module is present: sfp-temperature, sfp-supply-voltage, sfp-tx-power, sfp-rx-power, sfp-tx-bias-current, sfp-vendor-name, sfp-vendor-part-number, sfp-wavelength, sfp-module-present (also coerced to bool | None).

A plain copper port (the vast majority) has NONE of the sfp-* fields in RouterOS's reply at all - each is only added to the result when the device's reply actually carries it (.get/in checks throughout, nothing invented). The reference hardware this project was verified against (a mANTBox) has no SFP cage, so the command path itself is confirmed but the DDM field VALUES are not yet verified against real SFP optics - see ROADMAP.md.

interface is validated for shape (validate_interface_name) before it is ever sent to the device - existence isn't checked separately, so a typo'd/unknown interface name simply produces whatever error RouterOS itself returns. Returns an empty dict if the device answers with nothing (same "once" convention as interface_traffic/poe_status/lte_status).

ParametersJSON Schema
NameRequiredDescriptionDefault
interfaceYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so thoroughly: it discloses field coercion (full-duplex / sfp-module-present to bool | None), that auto-negotiation is left as RouterOS's raw non-boolean state, that sfp-* fields appear only when the device reply carries them (nothing invented), that an empty dict is returned when the device answers nothing, and that DDM values are unverified against real optics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and primary field list are front-loaded, and the density is justified by the number of returned fields and their coercion quirks. It is still on the verbose side (ROADMAP.md and mANTBox asides, heavy backtick/parenthetical nesting) but no sentence is purely filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be spelled out, yet the description still covers error behavior, the empty-dict case and validation semantics. The only real gap is `device_name` semantics and any guidance on which device to target, which is minor for a read-only status tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for both parameters. The description compensates for `interface` by explaining it is shape-validated via validate_interface_name and that existence is not checked (typos surface as raw RouterOS errors), but it says nothing at all about `device_name`, leaving half the required parameters undocumented in both schema and text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource ('Link/optical status of one ethernet interface') and enumerates the exact fields returned, so an agent can immediately distinguish it from siblings like interface_traffic, poe_status or interfaces. The scope (single interface, status read) is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the reader infers this is a one-shot status read for a specific interface, and the reference to the 'same once convention as interface_traffic/poe_status/lte_status' hints at the family it belongs to. There is no explicit statement of when to prefer this over alternatives (e.g. interface_traffic for throughput, interfaces for enumeration) and no exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

interfacesC

List network interfaces on a device.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes
include_disabledNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

C2.8/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It only states the basic action and resource, omitting details like whether the device must exist, if live data is retrieved, or if special permissions are required. This is minimal transparency for a tool with two parameters.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that front-loads the purpose. While it could benefit from slightly more detail, it avoids unnecessary verbiage. It earns a high score for conciseness but loses a point for extreme brevity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an existing output schema (which reduces the need to explain return values), the description fails to provide context about required parameters, acceptable formats, or the scope of the listing. For a tool with no annotations, this leaves significant gaps in understanding.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the tool description does not explain any parameters. The two parameters (device_name and include_disabled) are left entirely to the schema, which lacks descriptions. The description adds no value to parameter understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'List network interfaces on a device' clearly states the action (list) and resource (network interfaces) and the scope (on a device). It effectively distinguishes this tool from siblings like ip_addresses and ip_routes by specifying a different resource type.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives, no prerequisites, and no indications of when not to use it. Sibling tools are listed but not compared or differentiated in context of use.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

interface_trafficA

Current rx/tx traffic rate of one interface (/interface/monitor-traffic interface= once=yes).

interface is validated for shape (validate_interface_name) before it is ever sent to the device - existence isn't checked separately here (unlike the guarded write tools), so a typo'd/unknown interface name simply produces whatever error RouterOS itself returns.

Returns a single reply dict - typically rx-bits-per-second/ tx-bits-per-second and rx-packets-per-second/tx-packets-per-second - or an empty dict if the device returned nothing. once=yes makes this a single instantaneous reading, not a continuous stream, so the call always returns promptly.

ParametersJSON Schema
NameRequiredDescriptionDefault
interfaceYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations, so the description carries the burden and does well: it discloses validation behavior (shape-only, existence not checked, RouterOS errors surface as-is), the once=yes prompt-return semantics, and the empty-dict case. Missing only auth/permission or rate-limit context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded purpose, then two tight paragraphs on interface validation and return shape. Parenthetical command example is useful; slight redundancy across sentences but no wasted fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values needn't be explained, yet the description still clarifies the typical fields and empty-dict edge case. Combined with validation and timing semantics, the agent has enough to call correctly; only auth context is absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and both properties lack descriptions, so the description must compensate. It explains `interface` validation semantics and the device_name requirement is implicit; no param format details (e.g., name syntax) are given, keeping it above baseline but not full.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource+scope: 'Current rx/tx traffic rate of one interface', with a concrete RouterOS command and explicit instant-reading semantics. Distinguishable from siblings like interface_monitor and torch by the 'one interface / single instantaneous reading' framing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use vs alternatives. It hints at scope (one interface, single reading) which implicitly contrasts with torch or interface_monitor, but never names an alternative or states exclusions, so the agent must infer routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ip_addressesC

List IPv4 addresses configured on a device.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, and the description only states 'List IPv4 addresses configured on a device.' It does not disclose behavioral traits such as authorization requirements, error handling for missing devices, or whether the operation is safe. For a simple read tool, more transparency would be beneficial.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no superfluous words. It is perfectly concise and front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having an output schema and low complexity, the description omits parameter details and usage guidance. With 0% schema description coverage, the tool definition is incomplete for an agent to understand how to use it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage for its single required parameter 'device_name', and the description does not explain what device_name refers to or provide any additional semantic meaning. The agent receives no help beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists IPv4 addresses on a device, using a specific verb and resource. It distinguishes itself from siblings like 'interfaces' and 'ip_routes' by focusing on IPv4 addresses.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives like 'interfaces' or 'system_info'. The description lacks any context on prerequisites or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ip_poolsB

List IP pools (/ip/pool): name, ranges. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral burden; it does disclose the key trait 'Read-only,' which correctly signals a safe, non-mutating operation. It adds nothing further — no permission requirements, scope, or pagination behavior — so it is adequate but thin for the full burden it must bear.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely compact and front-loaded: verb+resource first, returned fields second, safety trait last. Every fragment carries information, though the endpoint path is marginal.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value explanation is unnecessary, and 'Read-only' covers the safety profile. However, the undocumented required parameter and lack of any scope or when-to-use context leave the definition minimally complete for a device-scoped list tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single required parameter device_name has 0% schema description coverage, and the description never mentions it. The agent gets no indication of what device_name identifies or its expected format, leaving the one parameter the tool requires entirely undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List), resource (IP pools), the backing endpoint (/ip/pool), and the returned fields (name, ranges). An agent can distinguish it from siblings like ip_addresses or ip_routes by resource name, though the description never explicitly contrasts them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Aside from 'Read-only,' there is no when-to-use guidance, no prerequisites, and no mention of alternatives among the many ip_* siblings. The agent must infer the use case from the resource name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ip_routesB

List the IPv4 routing table of a device.

limit, if given, caps the number of rows returned (capped at 500); omit it to get the full table, mirroring logs' limit parameter.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the limit cap of 500 rows, there is no disclosure of behavioral traits such as required permissions, rate limits, or side effects. The description does not compensate for missing annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with purpose, and no wasted words. The explanation of the limit parameter is efficient and clear.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the existence of an output schema, return values need not be explained. However, the missing explanation for device_name and lack of behavioral context leave the description incomplete for an agent that must choose and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds meaning to the limit parameter (caps rows, cap at 500, omit for full table) but does not explain the required device_name parameter. With 0% schema coverage, the description should clarify all parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists the IPv4 routing table of a device, using specific verb and resource. This purpose distinguishes it from sibling tools like interfaces or neighbors.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains the limit parameter's behavior but provides no guidance on when to use this tool versus alternatives, nor any prerequisites or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ipsec_active_peersA

List active IPsec peers (/ip/ipsec/active-peers): remote-address, state, uptime, rx/tx byte counters, side (initiator/responder).

Returns an empty list (never an error) for a device that doesn't use IPsec at all - a completely normal state.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and delivers a genuinely useful behavioral trait: it returns an empty list rather than an error for non-IPsec devices, which prevents an agent from misreading a normal state as a failure. It still omits any mention of permissions or result-size/count behavior, which keeps it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences, purpose front-loaded with the path, and the caveat immediately after. The awkward line wrapping and the field enumeration could be trimmed slightly, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values do not strictly need spelling out, yet the description usefully summarizes them and adds the empty-list semantics. The only real gap is the undocumented device_name input.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description never mentions the sole parameter (device_name) or what value it expects (device name vs. address vs. identifier). With low coverage the description should compensate, and it does not.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb ('List') plus exact resource ('active IPsec peers') and the RouterOS path (/ip/ipsec/active-peers), with the returned fields enumerated. An agent can distinguish this from wireguard_peers, ppp_active, and bgp_sessions without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the monitoring/listing nature of the tool and the note that an empty result is normal, but there is no explicit when-to-use statement, no prerequisites, and no routing toward the sibling tools that cover other tunnel types (wireguard_peers, ppp_active).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ipv6_addressesA

List IPv6 addresses configured on a device (/ipv6/address): address, interface, advertise, disabled, dynamic, plus whatever other fields RouterOS's own reply carries (e.g. its global/ link-local classification). Mirrors ip_addresses for IPv6.

Returns an empty list (never an error) if the ipv6 package is disabled on the device - see "IPv6 read parity (v1.9)" in the README.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden, and it does disclose a genuinely important edge case: an empty list is returned (never an error) when the ipv6 package is disabled, plus a pointer to the README. It also notes the reply carries fields beyond those listed. It omits auth requirements and pagination, so not a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the verb+resource before the field enumeration and the edge-case note. The field list is slightly verbose but each item (address, interface, advertise, disabled, dynamic) earns its place by previewing the payload.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value documentation is not strictly required, yet the description helpfully previews the fields anyway and covers the disabled-package edge case. For a single-param read tool this is nearly complete; only auth/permission expectations are unstated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description would need to compensate for the single `device_name` parameter, and it says nothing about it. The parameter name is self-evident and the tool is single-param, so the gap is minor rather than severe.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List IPv6 addresses configured on a device'), names the underlying RouterOS path (`/ipv6/address`), and explicitly distinguishes itself from its IPv4 counterpart ('Mirrors `ip_addresses` for IPv6'). An agent can place this among the ipv6_* siblings without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'Mirrors `ip_addresses` for IPv6' line gives clear context for choosing this over the IPv4 sibling, and the resource is unambiguous relative to ipv6_routes/ipv6_neighbors. However there is no explicit when-not or alternative routing, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ipv6_firewall_address_listsA

List IPv6 firewall address-list entries (/ipv6/firewall/address-list): list, address, dynamic, disabled. Mirrors address_lists for IPv6.

Returns an empty list (never an error) if the ipv6 package is disabled on the device - see "IPv6 read parity (v1.9)" in the README.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses a non-obvious behavioral trait: returns an empty list (never an error) if the IPv6 package is disabled, which prevents false error handling. However, it does not mention read-only semantics, permissions, or rate limits, leaving some gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the tool's purpose and scope in the first sentence. Three sentences total, each contributing useful information without redundancy. The reference to the README at the end is a minor addition but not wasteful.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is a simple read/list operation with an output schema, so return values are covered separately. The description explains purpose, sibling differentiation, and one behavioral edge case, but it completely omits any explanation of the required `device_name` parameter, which is a notable gap for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the only parameter `device_name` has no description in the schema. The description says 'on the device' which hints at the parameter's purpose but provides no format, constraints, or examples. It does not compensate for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (IPv6 firewall address-list entries), names the exact API path, and explicitly distinguishes itself from the IPv4 sibling `address_lists`. An agent can identify the tool's scope without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description says it mirrors `address_lists` for IPv6, which implicitly tells the agent to use this tool for IPv6 instead of the IPv4 version. It also notes the empty-list behavior when the IPv6 package is disabled, which is a usage condition. No explicit when-not-to-use guidance is given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ipv6_firewall_filterA

List IPv6 firewall filter rules (/ipv6/firewall/filter): chain, action, etc. Mirrors firewall_filter for IPv6. Read-only - does not add/modify/remove rules.

Returns an empty list (never an error) if the ipv6 package is disabled on the device - see "IPv6 read parity (v1.9)" in the README.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does meaningful work: it declares the operation read-only and explicitly says it does not add/modify/remove rules, and it discloses the non-obvious edge case that a disabled `ipv6` package yields an empty list rather than an error. It stops short of describing pagination or return shape, but the safety profile and the key quirk are covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the verb and resource, followed by the sibling mapping, the read-only guarantee, and the empty-list edge case. Every sentence adds distinct information with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value details need not be spelled out, and the description still volunteers the most important output behavior (empty list vs. error). For a single-parameter read tool this is fully sufficient to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for the single `device_name` parameter, and the description adds no syntax, format, or sourcing guidance for it. The parameter name is largely self-explanatory, so the gap is not severe, but the description does not compensate for the coverage deficit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List IPv6 firewall filter rules') and explicitly names the sibling it parallels ('Mirrors `firewall_filter` for IPv6'), letting an agent distinguish it from the IPv4 version and from the ipv6_* mutators without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The tool's context is clear from 'Mirrors `firewall_filter` for IPv6', which tells the agent when to pick this over the IPv4 sibling. There is no explicit when-not guidance or mention of the enable/disable_ipv6_firewall_rule siblings that mutate the same ruleset, so it falls short of a full routing statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ipv6_neighborsA

List the IPv6 neighbor discovery table (/ipv6/neighbor): address, mac-address, interface, status, dynamic. IPv6's neighbor- discovery equivalent of arp_table's IPv4 ARP table.

Returns an empty list (never an error) if the ipv6 package is disabled on the device - see "IPv6 read parity (v1.9)" in the README.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does disclose a real behavioral trait: it returns an empty list rather than an error when the ipv6 package is disabled. That is exactly the kind of non-obvious behavior an agent needs. It stops short of describing other traits (e.g. whether it is read-only — though 'List' implies it, or pagination) so a 4 rather than 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and resource, then field list, then the important empty-list caveat. Only the README cross-reference is slightly extraneous, but it earns its place by anchoring versioned behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists so return values needn't be explained, and the description adds the empty-list behavior and the arp_table parallel — the two things structured fields don't convey. Complete enough for an agent to call it correctly; only explicit usage routing is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter (device_name) at 0% schema description coverage. The description doesn't explain device_name, but with a single, self-evidently named required parameter the baseline is 4 and there's little semantic gap to close.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the IPv6 neighbor discovery table') and enumerates the returned fields. Crucially, it names the differentiator against the sibling arp_table, framing this as the IPv6 counterpart to that IPv4 table, so an agent can pick between them without reading schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the arp_table analogy and the field list, but there is no explicit when-to-use or when-not-to-use guidance, and no routing to the IPv4 arp_table for v4 queries. Adequate but leaves selection to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ipv6_routesA

List the IPv6 routing table of a device (/ipv6/route): dst-address, gateway, distance, active, dynamic, disabled. Mirrors ip_routes for IPv6, including its optional limit (capped at 500, same MAX_ROUTE_LIMIT); omit it to get the full table.

Returns an empty list (never an error) if the ipv6 package is disabled on the device - see "IPv6 read parity (v1.9)" in the README.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden, and it delivers real behavioral context beyond the schema: results are capped at 500, omitting limit returns everything, and a disabled ipv6 package yields an empty list rather than an error. It does not cover auth requirements or pagination beyond the cap, but the edge-case behavior is unusually well disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core purpose and the limit semantics are front-loaded in the first two sentences, with the edge-case behavior last. The README reference ('IPv6 read parity (v1.9)') is slightly extraneous pointer text but does not obscure the definition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the return-value enumeration is redundant but harmless, and the description still supplies the two things the structured data cannot: the 500 cap and the empty-list-on-disabled-package behavior. Enough for an agent to call it correctly, with only auth/permission context missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does for the non-obvious parameter: limit is optional, capped at 500 (MAX_ROUTE_LIMIT), and omitting it returns the full table. device_name is left self-explanatory by its name, but its meaning is not elaborated.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (IPv6 routing table, /ipv6/route), enumerates the returned fields, and explicitly relates itself to the sibling ip_routes ('Mirrors ip_routes for IPv6'). An agent can distinguish it from ipv6_addresses, ipv6_neighbors and ip_routes without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operating context: use the optional limit to cap results, omit it for the full table, and the limit is capped at 500. It does not explicitly state when to prefer this over ip_routes or ipv6_addresses beyond the IPv4/IPv6 distinction, so no exclusion criteria are spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_backupsA

List backup files stored on the device (/file, filtered to names ending in .backup): name, size, creation-time.

Reads the same /file menu create_backup's duplicate-name check uses - call this after create_backup to confirm a new backup landed and see its real size. Returns an empty list (never an error) if the device has no backup files at all.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and adds useful behavior: it reads the same /file menu that create_backup's duplicate-name check uses, returns empty list rather than an error when no backups exist, and returns name, size, and creation-time. It still does not describe permission or authentication requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact paragraphs, front-loaded with the tool's purpose and return shape, followed by the usage context and edge-case behavior. Every sentence contributes specific information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple list tool with an output schema and no annotations, the description covers purpose, usage context, return behavior, and the empty-list edge case. The remaining gap is the undocumented device_name parameter, but the tool is otherwise sufficiently described.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single required parameter is device_name, but the description never mentions the parameter, its expected format, or how it maps to 'the device'. Because coverage is low, the description must compensate and it does not.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List backup files stored on the device'), specifies the hidden path filter ('/file', names ending in '.backup'), and names the returned fields. The mention of create_backup is contextual, not tautological.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to call it after create_backup to confirm a new backup landed and see its real size, giving a clear usage context. However, it does not name alternatives or state when not to use this tool, so it falls short of the top-level when/when-not/alternatives standard.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_devicesA

List configured MikroTik devices. Read-only; passwords are never included.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden. It adds that the operation is read-only and passwords are never exposed, which is useful behavioral context. However, it lacks info on rate limits, authentication, or other side effects. Adequate for a simple read tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences that are front-loaded with purpose. Every word earned its place—no redundancy or extraneous content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given zero parameters and an output schema (exists but not shown), the description is largely adequate: it specifies the action, resource, read-only nature, and password safety. Minor gap: does not explicitly state scope (all devices) but it's implied.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, and schema description coverage is 100% (empty). Baseline is 4 per guidelines. The description adds no parameter info because none exist.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'List configured MikroTik devices', specifying the verb (list) and resource (devices). However, it does not explicitly distinguish from siblings like 'interfaces' or 'system_info', which could be ambiguous for an agent.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description includes 'Read-only; passwords are never included' which indicates safety, but provides no guidance on when to use this tool versus alternatives like 'system_info' or 'neighbors'. No explicit when-not or context for selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_vlansA

List VLAN interfaces (/interface/vlan): name, vlan-id, interface (the parent interface it rides on top of), mtu, running, disabled, comment (if set).

Excludes disabled VLAN interfaces by default, like interfaces; pass include_disabled=True to see them too.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes
include_disabledNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does well on the key trait: the default exclusion of disabled interfaces and the opt-in flag to change it. It omits secondary details (permissions, pagination, whether the list is live vs cached), which keeps it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and target, followed by the field list and then the behavioral caveat. The field enumeration is dense but earns its place by previewing the output, though it could be trimmed since an output schema exists.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema is present, so return format is covered and the description reinforces it with concrete fields. The main behavioral nuance (disabled filtering) is disclosed, but the undocumented `device_name` parameter leaves a small gap for a read-only listing tool with no annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for both parameters. It clearly explains `include_disabled` semantics (default false, set True to include disabled), but says nothing about `device_name`, leaving one of two parameters undocumented anywhere.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (VLAN interfaces) plus the underlying endpoint `/interface/vlan`, and enumerates the returned fields. It also positions itself against the sibling `interfaces` by noting the shared default-filtering behavior, so an agent can tell it apart from `bridge_vlans` or generic `interfaces` without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage via the default behavior ('excludes disabled by default, like `interfaces`; pass include_disabled=True to see them') and references a sibling, but it never explicitly states when to choose this tool over alternatives such as `interfaces` or `bridge_vlans`. Context is implied rather than spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_write_operationsA

List every guarded write operation and the RouterOS path/action it maps to.

Read-only: this only surfaces guard.ALLOWLIST's metadata (D3) - it does not perform or preview a write, and is not gated by MIKROTIK_ALLOW_WRITE.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description fully carries the burden. It discloses read-only behavior, metadata-only access, and lack of gating, which is comprehensive for a list operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core purpose, and every sentence adds value without waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no parameters and presence of an output schema, the description fully explains the tool's function and constraints. No missing context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so schema coverage is 100%. The description adds no parameter information, which is acceptable as none exist. Baseline for 0 params is 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists every guarded write operation with RouterOS path/action mapping. The verb 'list' and resource 'guarded write operations' are specific and distinct from sibling tools like 'set_identity' or 'interfaces'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states it is read-only, does not perform or preview writes, and is not gated by MIKROTIK_ALLOW_WRITE. This gives clear context for when to use, though no explicit alternative tool is named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

logsA

Read recent RouterOS log entries (most recent last).

limit must be positive and is capped at 500. topics, if given, is matched as a plain substring against each entry's topics field - no regex, no unbounded scans - and is applied BEFORE the limit cut: the full log is filtered by topics first, then the last limit matching entries are returned (not the last limit raw entries, then filtered - that would silently drop matches).

R1: this reads the whole /log table via librouteros' path().select() and slices in Python rather than asking RouterOS for only the last limit rows. librouteros' structured API doesn't expose a clean "give me only the tail" query for /log (RouterOS's own count-only print flags aren't reachable through path().select() the way a .limit()/offset would be), so a "request fewer rows" optimization here would mean building a fragile ad-hoc workaround for a table that is small in practice (a few hundred to low thousands of rows on RouterOS's own ring buffer). Left as-is; revisit if a real device turns out to have a much larger log buffer than expected.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
topicsNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description fully discloses behavior: it reads the entire /log table, applies topics filter before limit, returns most recent last, and explains the lack of optimization. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The first sentence clearly states the purpose, but the description includes an internal implementation note (R1) that is verbose and may not be necessary for an AI agent to use the tool correctly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the 3 parameters, no schema descriptions, and presence of an output schema, the description adequately explains the behavior for limit and topics. However, it does not cover prerequisites or potential errors, and device_name is not discussed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has no parameter descriptions (0% coverage). The description adds meaning for 'limit' (positive, capped at 500) and 'topics' (plain substring, applied before limit), but does not elaborate on 'device_name' beyond it being required.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reads recent RouterOS log entries with the most recent last. The verb 'Read' and resource 'RouterOS log entries' are specific, and the sibling tools are distinct (interfaces, ping, etc.), so no confusion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not explicitly state when to use this tool versus alternatives. It provides constraints (limit cap, substring matching) and implementation details, but lacks guidance on when not to use it or how it compares to other tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lte_interfacesB

List LTE/5G modem interfaces (/interface/lte): name, running, disabled, apn-profiles, etc. Returns an empty list (never an error) for a device with no LTE hardware/package at all.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full disclosure burden, and it does deliver one high-value, non-obvious trait: a device with no LTE hardware returns an empty list rather than an error. It omits permission/auth requirements, but the empty-result contract is the detail most likely to trip up an agent and it is stated explicitly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler: the capability and its fields come first, with the edge-case behavior second. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter list tool with an output schema already defining the return shape, the description is largely sufficient and even adds field examples beyond the schema's obligation. The only real omission is any hint about what `device_name` should contain.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for the single required `device_name` parameter, and the description never mentions it or clarifies its format (hostname, IP, or inventory identifier). The name is self-evident, so this is not disastrous, but the description compensates for none of the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("List LTE/5G modem interfaces"), gives the RouterOS path `/interface/lte`, and enumerates the returned fields. This is genuinely clear, but it never differentiates itself from the close sibling `lte_status`, which an agent could easily confuse for the same capability.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use statement, no precondition, and no named alternative among siblings (`interfaces`, `list_devices`, `usb_devices`, `lte_status`). The agent is left to infer that this is the right tool for enumerating LTE modems.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lte_statusA

Signal/status of one LTE/5G modem interface (/interface/lte/monitor <interface> once=yes).

Returns a single reply dict - typically operator (current-operator), technology (access-technology: 3G/LTE/5G), signal (rsrp/rsrq/sinr/rssi), band, registration-status, cell-id - or an empty dict if the device has no LTE hardware/package at all, or interface doesn't match one (same "empty, not an error" convention as poe_status/system_health for optional hardware).

interface is validated for shape (validate_interface_name) before it is ever sent to the device.

ParametersJSON Schema
NameRequiredDescriptionDefault
interfaceYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the full burden, and it does disclose meaningful behavior: the return shape and typical keys, the 'empty dict, not an error' convention when hardware is absent or the interface doesn't match, and that `interface` is shape-validated before being sent. It omits read-only/auth considerations, but for an observation tool this is solid disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose and command, then return values, then edge-case behavior, then validation. Well-structured and mostly earns its sentences, though the return-key enumeration is slightly verbose given an output schema exists.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values needn't be spelled out (they are, harmlessly). The empty-dict edge case is covered. The main gap is that `device_name` is never explained, which matters at 0% schema coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so params are undocumented structurally. The description explains `interface` semantics (must match an LTE interface, validated for shape) but says nothing about `device_name`, leaving half the parameters unexplained in both schema and prose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: fetch the signal/status of one LTE/5G modem interface, and even names the underlying command (`/interface/lte/monitor <interface> once=yes`). This is clearly distinguishable from sibling `lte_interfaces` (which lists interfaces) and `interface_monitor` (generic monitoring).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage (query status of a single named interface) and explains the empty-dict convention shared with `poe_status`/`system_health`, but it never explicitly says when to use this instead of `lte_interfaces` or `interface_monitor`. No exclusions or prerequisites are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

move_firewall_ruleA

Reorder an EXISTING firewall filter rule (/ip/firewall/filter move), resolved by its comment - optionally narrowed by chain if more than one rule shares that comment, same resolution enable_firewall_rule/disable_firewall_rule use.

SAFE BY DESIGN: this NEVER creates or otherwise edits a rule's fields - only its position in the chain's evaluation order changes.

Exactly one of before_comment (move the rule to appear immediately before the EXISTING rule with this comment) or position (move the rule to this 0-based index among the OTHER rules - a value at or beyond the end of that list moves it to the very end) must be given.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview (the rule's comment/chain plus its current vs. new position) without changing anything; call again with confirm=True to actually apply it. Errors clearly if no rule matches comment (narrowed by chain), if before_comment is given but matches no rule, or if either still matches more than one rule (AmbiguousResourceError) - never guesses.

ParametersJSON Schema
NameRequiredDescriptionDefault
chainNo
commentYes
confirmNo
positionNo
device_nameYes
before_commentNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: it states the write-guard (MIKROTIK_ALLOW_WRITE=true), the two-phase confirm flow, the exact non-destructive scope (never creates/edits fields, only reorders), and enumerated error conditions including AmbiguousResourceError with an explicit 'never guesses' guarantee.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Content is front-loaded with the core purpose, then grouped under a SAFE BY DESIGN header and a parameter-rules paragraph. It is dense and longer than average, but nearly every sentence carries distinct operational information, with minimal filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter write tool with no annotations and 0% schema coverage, the description covers resolution, placement, safety guard, confirmation flow, and failure modes. An output schema exists, so return-value detail is not required, and nothing critical for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does: it defines comment as the resolution key, chain as an optional narrowing filter, before_comment as a target-relative placement, position as a 0-based index with end-of-list semantics, and confirm as the preview/apply switch.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Reorder an EXISTING firewall filter rule (/ip/firewall/filter move), resolved by its comment.' It explicitly distinguishes itself from siblings by noting the shared resolution logic with enable_firewall_rule/disable_firewall_rule, and clarifies that only position changes, not fields.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear conditions: exactly one of before_comment or position must be supplied, and it explains the confirm=False preview vs confirm=True apply flow. It also names the sibling tools sharing resolution logic. It stops short of stating when reordering is preferable to other firewall operations, but usage context is otherwise explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

neighborsB

List neighbors discovered via RouterOS neighbor discovery (CDP/MNDP/LLDP).

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden. It states 'List' which implies a read operation, but does not disclose any behavioral traits such as potential latency, response format, or limitations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence that is front-loaded with the verb and resource.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the single parameter and no annotations, the description should explain how 'device_name' is used but does not. Existence of an output schema partially compensates.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description adds no meaning to the required parameter 'device_name' beyond its name.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'List' and resource 'neighbors discovered via RouterOS neighbor discovery (CDP/MNDP/LLDP)', clearly differentiating from sibling tools like 'interfaces' or 'ip_addresses'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use or when-not-to-use guidance is provided, but the purpose is straightforward so usage is implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

netwatchA

List Netwatch host monitors (/tool/netwatch): host, status (up/down), interval, since, comment, disabled, plus has-up-script/has-down-script booleans.

Netwatch is the usual way a RouterOS device itself watches a gateway or peer's reachability (e.g. to drive a failover script on down/up) - this is read-only groundwork for future failover tooling; see README's "VPN & routing diagnostics".

The up-script/down-script fields are surfaced only as presence booleans (has-up-script/has-down-script), never as the raw script body, which can contain arbitrary RouterOS commands (e.g. route/credential changes) that don't belong in a read tool's output.

Returns an empty list (never an error) for a device with no Netwatch entries configured.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does so well: it declares read-only behavior, explains that script bodies are deliberately reduced to presence booleans for safety, and states that an empty list is returned (never an error). It omits any auth/pagination detail, but the disclosed behaviors are substantial and beyond schema scope.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the field list and purpose, and the security rationale for the script booleans earns its place. It is slightly verbose with the README reference, but every sentence adds usable context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, yet the description still summarizes them helpfully. For a single-parameter read tool, nothing an agent needs in order to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description adds no meaning for device_name. It is a single, self-explanatory parameter, so the gap is minor, but the description does not compensate for the missing schema documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ("List Netwatch host monitors") and enumerates the returned fields (host, status, interval, since, comment, disabled, script-presence booleans). The action is unambiguously distinct from the add_netwatch/remove_netwatch siblings, which use different verbs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context: Netwatch is how a RouterOS device watches a gateway/peer's reachability, and this tool is read-only groundwork for failover tooling. However, it names no explicit alternative or when-not-to-use condition (e.g., versus ping or ip_routes) that would round this out to a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ntp_clientB

NTP client configuration/status (/system/ntp/client) - a single-row menu, same shape as container_config. Every field RouterOS's own reply carries is returned as-is (.get-based, nothing invented) - only enabled is normalized to bool | None (formatting.coerce_ros_bool).

ROS7 fields: enabled, mode, servers (a comma-joined string of every configured NTP server - left exactly as RouterOS sends it, NOT split into a list; same "no invented shape" convention bridge_vlans' tagged/untagged fields already follow), freq-drift, status, synced-server, synced-stratum.

ROS6 fields: enabled, primary-ntp, secondary-ntp, server-dns-names, mode. See set_ntp_servers for how a write detects and targets whichever of these two shapes a device actually speaks.

Returns an empty dict (never an error) for a device with no NTP client menu at all.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full weight and does well: it discloses that fields are returned as-is ('.get'-based, nothing invented), that only `enabled` is normalized via `formatting.coerce_ros_bool`, that `servers` is deliberately left un-split, and that a device with no NTP client menu returns an empty dict rather than an error. It omits permission/read-only framing, but the error-handling and normalization disclosure is substantive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core point (NTP client config/status, as-is fields, empty dict on absence) is front-loaded, but the body is padded with implementation detail, backticked internal names, and ROS6/ROS7 field enumerations that are verbose for an agent selecting a tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the extensive return-field explanation is partly redundant, but it adds genuine convention context (no invented shape, empty dict on missing menu, sibling write handling) that the schema would not convey. Combined with the clear resource framing, the definition is complete enough to invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single parameter `device_name` is left unexplained in both schema and description. The description's detail is entirely about return shape, not the input parameter, so it fails to compensate for the coverage gap on the one parameter the agent must supply.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the exact resource and endpoint (`/system/ntp/client`, a single-row menu) and its relationship to `container_config`, effectively telling the agent this is the NTP client read surface. It lacks a crisp leading verb ('get/return'), but the resource and read-oriented framing are unambiguous and distinguish it from the `set_ntp_servers` sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It points to `set_ntp_servers` for write behavior, implicitly establishing that this tool is the read counterpart, but never states explicitly 'use this to read NTP client config; use set_ntp_servers to modify it.' Usage is inferred rather than directed, and no exclusions or preconditions are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ospf_neighborsA

List OSPF neighbor adjacencies (/routing/ospf/neighbor): address, state (Full/Down/...), router-id, adjacency.

Returns an empty list (never an error) for a device that doesn't run OSPF at all.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does disclose the most non-obvious trait: a device without OSPF yields an empty list, never an error. It also implies a read-only listing and names the underlying path, but says nothing about permissions, volume, or freshness of the adjacency data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Very short and front-loaded: the action, scope, and returned fields come first, with the empty-list caveat second. The embedded API path and the stray line breaks add minor noise but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read-only listing with an output schema already present, the definition is essentially complete: purpose, scope, and the empty-result edge case are covered, so return formatting need not be restated. Only the device_name semantics and any permission expectations are absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single required parameter device_name is never mentioned in the description, so no format or identification guidance is added. The parameter name is largely self-explanatory, keeping this at a minimum-viable 3 rather than lower.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List OSPF neighbor adjacencies'), pins the exact data source path (/routing/ospf/neighbor), and enumerates returned fields (address, state, router-id, adjacency). This clearly separates it from siblings like bgp_sessions, arp_table/neighbors, and ipv6_neighbors.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the OSPF-specific scope, and the note that non-OSPF devices return an empty list rather than an error is a useful operational cue. However, there is no explicit statement of when to prefer this over related tools (e.g. bgp_sessions or generic neighbor listings) and no prerequisites or device scope guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pingB

Ping an address from a device. address must be a valid IPv4/IPv6 address or hostname.

ParametersJSON Schema
NameRequiredDescriptionDefault
countNo
addressYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, and the description lacks disclosure of behavioral traits such as timeout, result format, permission requirements, or whether the ping is ICMP-based. Minimal transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences, front-loaded with the core purpose, no unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity and the existence of an output schema, the description is adequate but incomplete—lacks detail on the 'count' parameter and output expectations, and no usage guidance.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, and description only adds meaning for 'address' (validity requirement). The other parameters ('count', 'device_name') are not explained, leaving gaps in understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Ping') and the resource ('an address from a device'), distinguishing it from sibling tools like 'interfaces' or 'logs'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides a prerequisite ('address must be valid IPv4/IPv6 or hostname') but no explicit guidance on when to use this tool vs alternatives (e.g., for connectivity checks vs. routing diagnostics).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

poe_statusA

PoE status/consumption per port, for every PoE-capable ethernet port on the device.

Reads /interface/ethernet and keeps only rows that have a poe-out field (i.e. are PoE-capable on this hardware - e.g. the CRS318-16P's high/low PoE ports), then reads /interface/ethernet/poe/monitor once=yes for each one to get its live voltage/current/power/poe-out-status. Each entry looks like {"interface", "poe-out" (configured mode), "poe-out-status", "voltage", "current", "power"} - the monitor fields are omitted for a port whose live monitor call fails (kept resilient rather than failing the whole tool for one bad port).

voltage/current/power are normalized to int | float | None via formatting.coerce_ros_number, never passed through raw: real hardware (CRS318-16P-2S+, ROS6.49.20) mixes int and string-decimal (e.g. "4.7") types for these same three fields within a single monitor reply, and across different ports of the same device - see that helper's docstring. Without this, a caller comparing voltage > 0 (see README's PoE power-cycle walkthrough) could get a string on one port and a number on another.

Returns an empty list (never an error) for a device with no PoE hardware at all - that's a completely normal state, same as wireless_registrations for a wired-only device.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so richly: it names the underlying endpoints read, discloses the per-port read pattern, states the resilience policy (monitor fields omitted rather than failing the whole tool), explains the numeric coercion of voltage/current/power and the cross-port int/string type hazard it prevents, and declares the empty-list-not-error contract for non-PoE hardware.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose sentence, then justified detail. Most of the length earns its place (coercion hazard, resilience contract), though it sprawls into internal references (README walkthrough, helper docstring) and restates the return shape that the output schema already covers.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations and a single self-evident parameter, the description supplies everything an agent needs: what it reads, what the output contains, the type-normalization guarantee, and the failure semantics. It arguably over-delivers by describing the return shape despite an output schema existing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single parameter device_name is never mentioned in the description, so no naming/format convention is added. However, the parameter is a self-evident device identifier in a device-oriented server, so the gap is minor rather than severe.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource and verb scope: 'PoE status/consumption per port, for every PoE-capable ethernet port on the device.' It is immediately distinguishable from set_poe_out (the write sibling) and from interface_monitor, since it declares the exact interface set it enumerates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the description (read live PoE data; safe on non-PoE devices returning an empty list), but there is no explicit 'use this instead of X' or when-not guidance relative to siblings like interface_monitor or interface_traffic. The reader must infer the selection criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ppp_activeA

List active PPP sessions (/ppp/active): name, service (l2tp/pptp/sstp/ovpn/pppoe), caller-id, address, uptime - VPN server sessions currently connected to this device.

Returns an empty list (never an error) for a device with no PPP server configured, or simply no sessions active right now.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It discloses a crucial trait: returns an empty list, never an error, when no PPP server is configured or no sessions are active. That is exactly the kind of non-obvious behavior an agent needs to avoid misinterpreting an empty result as a failure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences: the first describes content and scope, the second preempts the most likely confusion (empty results). Every sentence earns its place and the key constraint is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, and the description covers scope and the empty-list behavior well. The only missing piece is any guidance on the device_name parameter, which is minor for a single required field.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is one parameter (device_name) with 0% schema description coverage, so the description should ideally explain it. It does not explicitly define device_name, but for a single obvious required parameter this is a minor gap, and the baseline for a 1-param tool without description support is still reasonably high.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (list) and resource (active PPP sessions) and enumerates the returned fields (name, service, caller-id, address, uptime). It explicitly scopes to VPN server sessions connected to this device, which differentiates it from siblings like ppp_secrets or user_active.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clarifies the domain ('VPN server sessions currently connected'), which gives an agent clear context for when to reach for this tool. It does not, however, name alternative tools for related queries or state explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ppp_secretsA

List CONFIGURED PPP/PPPoE secrets (/ppp/secret): name, service (pppoe/pptp/l2tp/ovpn/sstp/any), profile, remote-address, local-address (if set), disabled, comment, last-logged-out (if set)

  • the dial-in credentials themselves, as opposed to ppp_active's currently-CONNECTED sessions. See "PPP/PPPoE secrets" below.

SECURITY: RouterOS's own /ppp/secret reply carries each secret's plaintext password - this is ALWAYS stripped before returning (formatting.strip_sensitive_fields), the same mechanism wireguard_interfaces uses for a tunnel interface's private-key. A secret's password never leaves this process via this tool. See test_ppp_secrets_never_exposes_password.

Returns an empty list (never an error) for a device with no PPP package configured at all - same convention as ppp_active.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and it delivers: it discloses that plaintext `password` is always stripped via formatting.strip_sensitive_fields, and that an unconfigured device returns an empty list rather than an error. It omits operational details like authentication requirements or pagination, keeping it just below the top mark.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The returned-field list and the security note are well front-loaded, but the body wastes space on internal references ('See test_ppp_secrets_never_exposes_password', 'See "PPP/PPPoE secrets" below') that add little for an calling agent. The password-stripping rationale is repeated at length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists and the description does not need to explain return format, yet it still documents the returned fields and covers edge cases (empty list, sensitive-field stripping). For a single-parameter read tool this is thorough, with only minor gaps around auth/usage preconditions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single parameter (device_name) is never mentioned in the description. The parameter is self-evident and shared with many siblings, so the meaning is derivable, but the description adds no explicit semantic value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (CONFIGURED PPP/PPPoE secrets at /ppp/secret path), enumerates the returned fields, and explicitly differentiates itself from the sibling `ppp_active` ('currently-CONNECTED sessions'). An agent can distinguish it from the active-session tool without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames the tool against its closest sibling (configured dial-in credentials vs. `ppp_active`'s live sessions), which gives clear when-to-use context. It does not, however, address the sibling mutators (`add_ppp_secret`, `remove_ppp_secret`) or state prerequisites, so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

radiusA

List RADIUS server configuration (/radius): service, address, timeout, accounting-port, authentication-port, and whatever other fields RouterOS returns for a given entry.

SECURITY: RouterOS's own /radius reply carries the plaintext shared secret - this is ALWAYS stripped before returning (formatting.strip_sensitive_fields), the same mechanism ppp_secrets uses for /ppp/secret's password and wireguard_interfaces uses for a tunnel interface's private-key. A RADIUS shared secret never leaves this process via this tool. See test_radius_never_exposes_secret.

Returns an empty list (never an error) for a device with no RADIUS servers configured.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so thoroughly: it discloses that the plaintext RADIUS shared secret is always stripped via `formatting.strip_sensitive_fields`, never leaves the process, and is handled like `ppp_secrets` and `wireguard_interfaces`. It also states that an empty list, not an error, is returned when no RADIUS servers are configured.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition front-loads the listing purpose, then a clearly labeled SECURITY block, then edge-case return behavior. The security detail and test reference make it longer than a bare list description, but the structure is purposeful and not padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value details are largely covered elsewhere, and the description adds important security and empty-list behavior. The main gap is the undocumented `device_name` parameter, which is minor for a single required field but still left entirely to the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for the single required `device_name` parameter, and the description never explains what `device_name` means or how to supply it. The parameter name is fairly self-evident, but the description adds no semantic detail beyond the bare schema field.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Starts with a specific verb, 'List', and a specific resource, 'RADIUS server configuration', and names the RouterOS endpoint `/radius`. No sibling tool exposes RADIUS configuration, so the resource itself distinguishes it from the surrounding list tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies this is the tool for inspecting RADIUS server configuration and notes empty-list behavior for devices with no RADIUS servers. However, it never states when to prefer this tool over alternatives or any prerequisite beyond the required device. There is no sibling RADIUS-list tool, so alternative guidance is less critical, but explicit usage context is still absent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_dhcp_leaseA

Remove a DHCP lease (/ip/dhcp-server/lease remove) by address or mac_address - typically to force a client to renew its IP. At least one of address/mac_address must be given and must match an existing lease (mac_address is tried first if both are given).

Removes EITHER a dynamic or a static lease. If the resolved lease is STATIC (dynamic=false - i.e. it was pinned with add_static_dhcp_lease), the returned preview's warning field is non-null: removing it deletes the pinned IP<->MAC mapping itself, not just a renewable cache entry. Always check warning before calling again with confirm=true. No warning for a dynamic lease - that is this tool's ordinary use case.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a preview (including the warning field) without changing anything; call again with confirm=True to actually remove it. Errors clearly if nothing matches.

ParametersJSON Schema
NameRequiredDescriptionDefault
addressNo
confirmNo
device_nameYes
mac_addressNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does so: it discloses the MIKROTIK_ALLOW_WRITE=true gating, the preview-vs-confirm semantics, the destructive effect on static leases (deleting the pinned IP<->MAC mapping), the warning field signal, and the error behavior when nothing matches.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well front-loaded with the command path and core semantics, but the static-lease warning paragraph is dense and slightly repetitive with the surrounding paragraphs about the warning field. Still, nearly every sentence earns its place given the tool's destructive nature.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing, the description correctly explains the warning field's meaning because it is action-critical context (a signal to not proceed with confirm). Combined with write gating, confirm flow, and match semantics, an agent has everything needed to call this safely.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates by explaining address vs mac_address semantics, the both-given precedence rule, and the meaning of confirm (preview vs actual removal). device_name is implied but never stated, which is the only gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (remove) and resource (DHCP lease) with the exact router command path, and distinguishes itself from siblings like dhcp_leases (read) and add_static_dhcp_lease by naming the pinning tool directly. An agent can route unambiguously.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names when-to-use (force a client to renew its IP), the precondition (at least one of address/mac_address must match an existing lease), the resolution order when both are given, and the two-step confirm flow. Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_from_address_listA

Remove the entry matching list_name+address from a firewall address-list (/ip/firewall/address-list).

Like add_to_address_list, this only manages the list - see that tool's docstring and README's "Blocking/allowing a client via address lists" section for why this alone doesn't guarantee a change in blocking/allowing behavior.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a preview of what would be removed; call again with confirm=True to actually remove it. Errors clearly if no entry matches list_name+address.

ParametersJSON Schema
NameRequiredDescriptionDefault
addressYes
confirmNo
list_nameYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it declares this is a WRITE tool gated behind MIKROTIK_ALLOW_WRITE=true, explains the two-phase confirm/preview protocol, and warns that list membership alone does not guarantee a change in blocking behavior. That is exactly the behavioral context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and match key, then layered with the guard and confirm flow. It is slightly verbose with the README cross-reference, but every sentence adds operative information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need not be described. Given a 4-param write tool with no annotations, the description covers safety gating, the confirm protocol, matching semantics, and error behavior — everything needed to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate and largely does: it explains that `list_name` and `address` form the match key, and that `confirm` defaults to false and controls preview vs. execution. Only `device_name` is left undocumented, but the explanation of the matching and confirm semantics is substantial.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (remove) plus the exact match key (`list_name`+`address`) and the resource path (/ip/firewall/address-list). It also distinguishes itself from the sibling add_to_address_list and implicitly from remove_from_ipv6_address_list.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operational guidance: preview with confirm=False (default) then re-call with confirm=True, plus the condition that errors occur when no entry matches. It cross-references add_to_address_list for context but never states when *not* to use this versus the IPv6 variant or a firewall-rule edit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_from_ipv6_address_listA

Remove the entry matching list_name+address from an IPv6 firewall address-list (/ipv6/firewall/address-list). Mirrors remove_from_address_list on the IPv6 menu.

address must be IPv6 (an IPv4 address/subnet is rejected before the device is ever touched).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a preview of what would be removed; call again with confirm=True to actually remove it. Errors clearly if no entry matches list_name+address. Also errors clearly if the ipv6 package is disabled on the device.

ParametersJSON Schema
NameRequiredDescriptionDefault
addressYes
confirmNo
list_nameYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description carries the full behavioral burden and does so well: it declares this is a WRITE tool, that it is blocked unless MIKROTIK_ALLOW_WRITE=true, the two-step preview/confirm safety pattern, IPv6-only validation that rejects IPv4 before touching the device, and two explicit error conditions (no matching entry, ipv6 package disabled).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Multi-paragraph but front-loaded: the action and match key come first, followed by validation, then the write-guard and confirm workflow. Every block carries information, though the formatting is slightly heavier than strictly needed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need not be described, and the description covers everything else an agent needs: mutation semantics, the environment gate, the confirm two-step, IPv6 validation, and the failure modes. Nothing essential for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it does: it defines `address` as required-IPv6, ties `list_name`+`address` together as the match key, and explains `confirm`'s default-false preview semantics. Only `device_name` is left implicit, which is minor given its obvious meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Remove the entry ... from an IPv6 firewall address-list') with the exact API path, and names its sibling ('Mirrors `remove_from_address_list` on the IPv6 menu'), letting an agent distinguish the IPv6 variant from the IPv4 one without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the operative workflow clearly: call with confirm=False for a preview, then confirm=True to actually remove, plus the MIKROTIK_ALLOW_WRITE gate. It does not explicitly enumerate when to prefer this over add_to_ipv6_address_list or the IPv4 tool, but the IPv6 framing and sibling reference make the context clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_ipv6_routeA

Remove a static IPv6 route (/ipv6/route remove), resolved by dst_address - narrowed by gateway when more than one route shares that dst_address. Mirrors remove_route on the IPv6 menu, INCLUDING its most important safety property. Errors clearly if nothing matches, or if the match is still ambiguous after narrowing.

dst_address/gateway must be IPv6 (an IPv4 address/subnet in either is rejected before the device is ever touched).

SAFETY: refuses outright (raises an error, does not remove anything) if the resolved route is dynamic (dynamic=true - a connected/DHCP/router-advertisement-installed route). Only static, admin-created IPv6 routes can be removed by this tool.

RISK: removing the default route (dst_address="::/0") cuts all outbound IPv6 traffic that relies on this gateway. The returned preview's warning field is non-null whenever this is the case (not blocking - removing a static default route is legitimate).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview (including the warning field) without changing anything; call again with confirm=True to actually apply it. Also errors clearly if the ipv6 package is disabled on the device.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
gatewayNo
device_nameYes
dst_addressYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the entire burden and does so richly: it discloses the dynamic-route refusal, the write-guard (MIKROTIK_ALLOW_WRITE=true), the confirm preview semantics, the disabled-ipv6-package error, and the default-route risk with its non-blocking `warning` field. This is far beyond what the empty annotation set provides.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with SAFETY, RISK, and WRITE sections and the core purpose front-loaded. It is somewhat long with a little repetition around the preview/warning behavior, but nearly every sentence adds operational value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, and the description still references the returned preview's `warning` field, tying behavior to the return value. With safety, guard, error, and format behaviors all covered, nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it covers the meaningful parameters: dst_address and gateway (with narrowing behavior) and confirm (preview vs apply). It also states the IPv6-only format constraint for dst_address/gateway. Only device_name is left unexplained, which is minor.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (remove a static IPv6 route) and ties it to the exact CLI equivalent `/ipv6/route remove`. It explicitly distinguishes itself from its IPv4 counterpart with 'Mirrors `remove_route` on the IPv6 menu', so an agent can place it among siblings without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the resolution logic (resolved by `dst_address`, narrowed by `gateway` when ambiguous) and the confirm=False/confirm=True two-step workflow. It implies rather than states the IPv4-vs-IPv6 routing split against `remove_route`, so it stops just short of explicit when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_netwatchA

Remove a Netwatch host monitor by host or comment (/tool/netwatch remove). At least one of host/comment must be given and must match an existing monitor (host is tried first if both are given).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a preview of what would be removed; call again with confirm=True to actually remove it.

ParametersJSON Schema
NameRequiredDescriptionDefault
hostNo
commentNo
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does it well: it declares this is a WRITE tool, states it is blocked unless MIKROTIK_ALLOW_WRITE=true, and describes the two-phase preview-then-remove confirmation. That is auth gating plus destructive-action semantics disclosed up front.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then the matching constraint, then the write-guard/confirm behavior. No filler sentences, though the parenthetical CLI path is only marginally useful to an agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values needn't be explained, and the description covers the destructive workflow and guard thoroughly. The only real gap is the unexplained required device_name parameter.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains host/comment selection and the confirm default semantics well, but the required device_name parameter is never described, leaving one of four params undocumented in both schema and prose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Remove a Netwatch host monitor') and even names the underlying RouterOS command, letting an agent distinguish it from add_netwatch and the read-only netwatch sibling without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete usage rules: at least one of host/comment must be given, host is tried first when both are present, and the confirm=False→preview / confirm=True→apply workflow. It stops short of explicitly contrasting with siblings like netwatch (read) or add_netwatch, so a 4 rather than a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_ppp_secretA

Remove a PPP/PPPoE secret (/ppp/secret remove) by name.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually remove it. Errors clearly if no secret matches name (ResourceNotFoundError), or if more than one somehow does (AmbiguousResourceError) - never guesses which one to remove. The returned preview's before never includes the secret's password - redacted before the preview is ever built (see guard.remove_ppp_secret's docstring).

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden and does so richly: it discloses the write-guard (MIKROTIK_ALLOW_WRITE), the dry-run/confirm pattern, that it never guesses on ambiguity, that it fails clearly when no match exists, and that the secret's password is redacted from the preview. These are exactly the traits an agent needs beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action, then the guard, then the confirm workflow, then the error/redaction behavior. Information-dense but every clause earns its place; only `device_name` is left unaddressed, and the wording is slightly technical but not bloated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded destructive write tool with 3 parameters, this is complete: it covers the authorization prerequisite, the safe-preview-then-confirm loop, both error modes, and the password-redaction guarantee. An output schema exists, so return-value details need not be repeated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains `name` as the removal key, `confirm` as the commit switch with its default behavior (preview vs. actual removal), which covers the meaning of three of the parameters; `device_name` is implied as the target device but not elaborated.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Remove a PPP/PPPoE secret') and maps it to the underlying RouterOS command `/ppp/secret remove`, with the removal key (`name`). It is clearly distinguishable from the sibling `add_ppp_secret` and from the read tool `ppp_secrets`.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when the tool can run (server must have MIKROTIK_ALLOW_WRITE=true or it is blocked entirely), and prescribes a two-step workflow: first call with confirm=False for a preview, then again with confirm=True to commit. It also names the error conditions (ResourceNotFoundError, AmbiguousResourceError).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_routeA

Remove a static route (/ip/route remove), resolved by dst_address - narrowed by gateway when more than one route shares that dst_address. Errors clearly if nothing matches, or if the match is still ambiguous after narrowing.

SAFETY: refuses outright (raises an error, does not remove anything) if the resolved route is dynamic (dynamic=true - a connected/DHCP/OSPF/BGP-installed route). Only static, admin-created routes can be removed by this tool - removing a device's connected/dynamic route can sever the network.

The returned preview's warning field is non-null (but not blocking) whenever the resolved route's dst_address is the default route (0.0.0.0/0/::/0) - check it before calling again with confirm=true.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview (including the warning field) without changing anything; call again with confirm=True to actually apply it.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
gatewayNo
device_nameYes
dst_addressYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it discloses the write-guard env flag, the dry-run preview semantics, the non-blocking `warning` field on default-route removal, and the hard refusal on dynamic routes with the reason (network severance). These are precisely the behavioral traits an agent needs to avoid a destructive mistake.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose and resolution logic, then uses labeled SAFETY and WRITE sections, so a reader can locate the destructive-operation constraints immediately. The length is justified by the guarded-write complexity and no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations, an output schema (so return values need not be explained), and a guarded write flow, the description covers the safety and confirm semantics thoroughly. The only gap is the unexplained `device_name` parameter, which is a minor omission.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it explains `dst_address` (resolution key), `gateway` (narrowing only when multiple routes share a dst_address), and `confirm` (preview vs apply) clearly. However, `device_name` is never mentioned, leaving one of four parameters undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Remove a static route'), gives the resolution key (`dst_address`) and the narrower (`gateway`), and even cites the underlying RouterOS command. An agent can distinguish it from siblings like add_route, enable_route, disable_route and remove_ipv6_route without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when it refuses (dynamic/connected/DHCP/OSPF/BGP routes), when it is blocked entirely (no MIKROTIK_ALLOW_WRITE), and the two-step workflow (confirm=False preview then confirm=True apply). Error-on-no-match and error-on-ambiguity conditions are also spelled out, leaving little to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_simple_queueA

Remove a Simple Queue by target or by name - undoes a bandwidth limit previously set with set_client_bandwidth. At least one of target/name must be given and must match an existing queue.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a preview of what would be removed; call again with confirm=True to actually remove it.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNo
targetNo
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it flags this as a WRITE tool, discloses the server-side guard (MIKROTIK_ALLOW_WRITE=true), and explains the two-phase confirm=False preview / confirm=True execute behavior. This is exactly the behavioral context an agent needs before calling a destructive operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The action and its selectors lead, followed by the guard and confirm semantics; every sentence earns its place. The awkward line breaks and slight repetition of 'remove a Simple Queue' cost it a point.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a write tool with an output schema (so return values need not be described), no annotations, and 0% schema coverage, the description covers selection rules, the safety guard, and the confirm workflow. Nothing essential for a correct call is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it does for name/target (mutually-at-least-one, must match an existing queue) and confirm (default preview versus actual removal). device_name is left unexplained, which is the only gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Remove) plus resource (Simple Queue) and the two selectors (target or name), and explicitly ties it to the inverse operation set_client_bandwidth. An agent can distinguish it from siblings like simple_queues or set_client_bandwidth without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear preconditions: at least one of target/name must be supplied and must match an existing queue, and it names the counterpart tool that created the queue. It doesn't discuss alternatives for inspecting queues (e.g., simple_queues) before removal, but the usage context is otherwise explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_static_dnsA

Remove a static DNS entry (/ip/dns/static remove) by name, optionally narrowed by record_type ("A"/"CNAME").

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a preview of what would be removed; call again with confirm=True to actually remove it. Errors clearly if nothing matches name (narrowed by record_type), or if more than one row still matches after narrowing (AmbiguousResourceError) - never guesses which one to remove.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
confirmNo
device_nameYes
record_typeNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden and does so thoroughly: it discloses the write guard, preview/confirm semantics, error behavior for zero matches, and AmbiguousResourceError for multiple matches without guessing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core verb, resource, command path, and identifier narrowing in the first sentence. Remaining sentences add valuable guard and error context, with only minor repetition of the name/record_type narrowing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Rich behavioral detail compensates for absent annotations, and the output schema reduces the need to describe return values. The omission of any device_name semantics is the main remaining gap for a required parameter.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains name, record_type, and confirm well, but completely omits device_name, which is a required parameter. This leaves a significant gap for a 4-parameter tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Remove), resource (static DNS entry), and exact RouterOS command path. Identifies the entry by name, optionally narrowed by record_type, which clearly distinguishes it from sibling add_static_dns.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the guarded write flow: blocked unless MIKROTIK_ALLOW_WRITE=true, call with confirm=False for preview, then confirm=True to remove. No alternative sibling tool is named, so it stops short of full when/when-not/alternatives guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_vlanA

Remove a VLAN interface (/interface/vlan remove) by name.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually remove it. Errors clearly if no VLAN interface matches name.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
confirmNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and succeeds: it declares it is a WRITE tool, names the environment guard, describes the preview/commit safety pattern, and the failure mode when `name` matches nothing. This is the behavior an agent needs before calling a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the action and its guard, then the workflow, then the error behavior. Every sentence contributes, though the formatting could be slightly tighter.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded destructive tool with an output schema and no annotations, the description covers safety, workflow, and error handling. The main omission is any mention of `device_name`'s role in targeting the correct device.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and all three parameters are undocumented in the schema, so the description must compensate. It explains `name` (the target VLAN), `confirm` (default false, controls preview vs. commit), and implies `device_name` selects the device, but the semantics of `device_name` are never made explicit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Remove a VLAN interface') and even names the underlying RouterOS command (`/interface/vlan remove`). It is trivially distinguishable from siblings like add_vlan or list_vlans.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit when/when-not conditions: the tool is blocked unless MIKROTIK_ALLOW_WRITE=true, and it prescribes a two-step workflow (confirm=False for preview, confirm=True to commit). No inference is required from the agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_wireguard_peerA

Remove a WireGuard peer (/interface/wireguard/peers remove) from interface, resolved by public_key or comment (public_key tried first if both are given). At least one of the two must be given.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to preview what would be removed without changing anything; call again with confirm=True to actually remove it. Errors clearly if nothing matches, or if more than one peer still matches (AmbiguousResourceError) - never guesses which one to remove.

ParametersJSON Schema
NameRequiredDescriptionDefault
commentNo
confirmNo
interfaceYes
public_keyNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and delivers: it is a WRITE tool, blocked unless MIKROTIK_ALLOW_WRITE=true, defaults to a non-mutating preview, and errors on zero or multiple matches rather than guessing. This is exactly the safety and side-effect context an agent needs before a destructive call.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the command and resolution rule, then the guard/preview behavior, then error semantics. Every sentence earns its place, though it is somewhat longer than strictly necessary.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, annotation-free, 0%-schema-coverage tool, the description covers guardrails, dry-run workflow, resolution, and failure modes; an output schema exists so return values need no explanation. Only device_name's role is left implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it explains the resolution logic for public_key vs comment (priority order, at-least-one rule) and the meaning of confirm's default. device_name and interface are only implicitly covered (interface appears in the command path), leaving one parameter under-explained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Remove a WireGuard peer'), names the underlying RouterOS command path, and specifies how the peer is resolved (public_key or comment). This distinguishes it clearly from siblings like add_wireguard_peer and wireguard_peers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives strong invocation context: at least one of public_key/comment must be supplied, public_key is tried first, and the confirm=False default previews while confirm=True executes. It doesn't name an alternative tool to use instead, but the when/how-to-use guidance is explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

schedulerB

List scheduled tasks (/system/scheduler): name, on-event, interval, next-run, disabled. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and it does disclose the key trait ('Read-only'), which is genuinely useful. However it says nothing about required permissions, pagination, or rate limits on this live device call.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One tight sentence, front-loaded with verb and resource, then the returned fields, then the read-only tag. Nothing is padded and every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Because an output schema exists, return values need not be explained, yet the description helpfully lists them anyway. The only real gap is that device_name is left unexplained, which matters for a device-scoped call.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single required parameter (device_name) has 0% schema description coverage and the description never mentions it, so an agent gets no meaning or format guidance for the only input. The field list it does provide describes output, not the parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List scheduled tasks') and even names the source path (/system/scheduler) plus the fields returned. No sibling covers scheduling, so the tool is distinguishable, but the description does no explicit sibling routing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use or when-not-to-use guidance and no mention of alternatives or prerequisites. Usage is only faintly implied by the read-only list framing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

security_auditA

Read-only security audit of a device's configuration - gives an LLM caller (or operator) a structured list of findings to review, so it can "look at the security of this router" without an operator manually walking every menu.

Aggregates several independent, defensive checks - see src/mcp_mikrotik/security.py for the full list and reasoning: insecure management services (/ip/service: telnet/ftp/www/api enabled, and whether they're open to any address), whether the firewall's input chain ends in a drop/reject rule (heuristic), SNMP community exposure (/snmp/community), an open DNS resolver (/ip/dns allow-remote-requests), outdated RouterOS (/system/package/update), open wireless/wifi networks (no security profile / no passphrase), a count of users with a write/full policy, and (v1.6) an expired or soon-to-expire (<=30 days) certificate (/certificate).

Each check reads its own menu(s) and skips itself (contributing no findings) if that menu doesn't exist on this device/RouterOS generation - one missing/unsupported menu never fails the whole audit. NEVER a scanner, NEVER definitive - this is a heuristic, best-effort read meant to prompt a human decision, not to replace one; see README's "Security audit" section for the full disclaimer.

READ-ONLY: does not change anything on the device, and is not gated by MIKROTIK_ALLOW_WRITE.

NO SECRET IS EVER RETURNED: no finding ever includes a password, passphrase, or SNMP community string - see security.py's module docstring for exactly how each check avoids that.

Returns {"findings": [{"severity", "category", "title", "detail", "recommendation"}, ...], "summary": {"high", "medium", "low", "info"}} - findings sorted by severity (high first), summary always including all four keys (0 for a severity with no findings).

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: read-only, not gated by MIKROTIK_ALLOW_WRITE, no secret/passphrase/community string ever returned, per-check graceful skip on missing menus, and one missing menu never failing the whole audit. This is exactly the behavioral context an agent needs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well front-loaded (purpose first, then checks, then caveats, then READ-ONLY and NO SECRET headers) and structured with clear emphasis. It is somewhat verbose and spends sentences pointing at source files and README sections that an agent cannot use.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a multi-check aggregate audit tool, the description enumerates the checks, the failure mode, the safety profile, and the return shape. With an output schema also present, nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single parameter (device_name) is never mentioned in the description, so the description adds no meaning beyond the schema. However, the parameter is trivially self-describing by name, which keeps this at a minimum-viable 3 rather than lower.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource+scope: 'Read-only security audit of a device's configuration'. It immediately distinguishes itself from siblings like firewall_filter, security_events, and certificates by being an aggregate audit rather than a raw menu dump.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for use ('look at the security of this router' without an operator manually walking every menu) and a firm boundary ('NEVER a scanner, NEVER definitive... meant to prompt a human decision'). It does not explicitly route the agent to or away from specific sibling tools, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

security_eventsA

Recent RouterOS log entries filtered down to security-relevant ones - login/logout/authentication-failure events (topic "account"), "critical"/"error" topic entries, and generic "system,info" rows whose message looks like a login/logout - so a caller can correlate access attempts/anomalies without reading the entire (often much larger) unfiltered log via logs.

Filtering happens in Python, same reasoning logs' topics filter already documents (RouterOS's structured API doesn't expose a query-by-field read here either) - and is applied BEFORE the limit cut, so this returns the most recent limit MATCHING entries (not the last limit raw entries filtered afterward, which would silently drop matches on a busy log).

limit must be positive and is capped at 500 (default 50), the same shape as logs' own limit.

READ-ONLY: not gated by MIKROTIK_ALLOW_WRITE.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does: it discloses that filtering happens in Python (not server-side), that the filter is applied BEFORE the `limit` cut so the most recent matching entries are returned rather than the last raw entries, that `limit` is capped at 500 with a default of 50, and that the tool is READ-ONLY / not gated by MIKROTIK_ALLOW_WRITE. That is precisely the behavioral detail an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The content is valuable but the prose is dense and runs long with nested parentheticals and cross-references. It is front-loaded with purpose but the rationale and limit explanation sprawl; tightening would improve scannability without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, two-parameter tool with an output schema present, the description covers purpose, filtering semantics, limit behavior, and the write-gating status. The output schema means return values need not be explained. The only mild gap is no explicit description of `device_name`, but overall it is complete enough to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It documents `limit` thoroughly (must be positive, capped at 500, default 50) and explains the semantics of the before-filter limit cut. `device_name` is not described in the description (its meaning is inferable from the tool's purpose), which is the one gap preventing a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('RouterOS log entries filtered down to security-relevant ones') and enumerates exactly which entry classes are included (account topic, critical/error, system,info login/logout rows). It explicitly distinguishes itself from the sibling `logs` tool by naming it and explaining that `security_events` exists so callers avoid reading the entire unfiltered log.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage context is clear: use this when you need access-attempt/anomaly correlation without pulling the whole log, and use `logs` when you want everything. The description does not spell out explicit when-NOT-to-use cases (e.g., 'use logs instead if you need non-security topics'), but the implied boundary against `logs` is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_client_bandwidthA

Limit a client's bandwidth via a RouterOS Simple Queue (/queue/simple).

target is the client's IP address or subnet (e.g. "10.0.0.5" or "10.0.0.0/24"). max_limit is a RouterOS rate pair in "upload/download" form (e.g. "10M/5M"); limit_at is the optional guaranteed-rate (CIR) pair in the same form. If a Simple Queue already targets target, its max-limit/limit-at is UPDATED; otherwise a new one is CREATED with a name derived from target - the returned operation field ("set_client_bandwidth_update" vs "set_client_bandwidth_add") tells you which happened (or would happen, with confirm=False).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it.

GOTCHA - FastTrack: if the device has a FastTrack rule in its firewall (common on RouterOS's own quick-set wizards), fasttracked connections bypass queueing entirely, so this queue may have no visible effect on a client whose traffic is already fasttracked - see README's "Security model" section.

ParametersJSON Schema
NameRequiredDescriptionDefault
targetYes
confirmNo
limit_atNo
max_limitYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so: it discloses that this is a guarded WRITE operation, the environment flag required, the preview/apply two-step, the update-vs-create branching behavior, and the operation field that reveals which occurred. It even flags the non-obvious FastTrack caveat that can silently negate the queue's effect.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and required arguments are front-loaded, followed by the confirm workflow and then the FastTrack gotcha. Despite its length, every paragraph adds operational information an agent needs, with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a five-parameter write tool with an output schema, the description covers the mutation semantics, the safety gate, the preview/apply workflow, the branching return indicator, and a critical environmental caveat. Nothing an agent needs in order to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it defines target (IP or subnet with examples), max_limit (upload/download rate pair), limit_at (optional CIR pair), and confirm (default preview behavior). Only device_name goes unexplained, leaving one of five parameters undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource - limiting a client's bandwidth by creating or updating a RouterOS Simple Queue - and names the underlying path (/queue/simple). It is clearly distinguishable from siblings such as remove_simple_queue and simple_queues, which read or delete rather than set.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit usage protocol: call with confirm=False for a preview, then confirm=True to apply, and it warns that the tool is blocked unless MIKROTIK_ALLOW_WRITE=true. It does not explicitly point to sibling alternatives (e.g., remove_simple_queue for teardown), so it falls just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_identityA

Set a device's RouterOS identity (hostname).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
new_nameYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It reveals that the tool is a WRITE operation, guarded by an environment variable, and offers a safe preview mode via confirm=False. This discloses the non-destructive default behavior and the guarded access, which is good for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences: purpose, guard, workflow. No redundant words, front-loaded with key information. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a write tool with 3 parameters, the description covers the guard and workflow. Output schema exists (assumed to document return values), so the description doesn't need to explain that. Missing detail on how to specify device_name, but overall sufficient for an agent to use correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 0% description coverage, so description must compensate. It explains the 'confirm' parameter's role (preview vs apply), but 'device_name' and 'new_name' are only implied by the first sentence. 'new_name' is clearly the hostname, but 'device_name' lacks elaboration on how to specify it. Partial coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Set a device's RouterOS identity (hostname).' This provides a specific verb and resource, and the tool name 'set_identity' aligns perfectly. Siblings like 'interfaces', 'ip_addresses', etc., are distinct in purpose, so no confusion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains the guarded nature (requires MIKROTIK_ALLOW_WRITE=true) and the two-step preview-apply workflow with confirm parameter. While it doesn't explicitly state when not to use, the context signals and sibling tools imply this is the only write tool for identity. Clear context but no alternatives mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_ntp_serversA

Set the NTP server(s) a device syncs its clock against (/system/ntp/client). servers is a list of one or more IPv4/ IPv6 addresses or hostnames.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Never enables/disables the NTP client itself - only the server list changes; the returned preview's warning says so if the client is currently disabled.

Works against either RouterOS generation, detected by reading /system/ntp/client first: ROS7 writes the full servers list; ROS6 has no such list - servers[0]/servers[1] map onto its fixed primary-ntp/secondary-ntp slots instead (extras beyond two are dropped, called out in warning). A hostname destined for one of those two ROS6 slots is folded into server-dns-names if the device has that field, otherwise it is not applied - warning says so. See guard.set_ntp_servers's docstring for the full detection/mapping rules.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
serversYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it discloses the write guard, the two-step preview/apply flow, that only the server list mutates, and the ROS6 vs ROS7 divergence including dropping extras beyond two entries and hostname folding into `server-dns-names`.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose, then the write guard, then the confirm flow, then generation-specific behavior. Dense but every paragraph earns its place; slightly heavy, but proportional to the tool's real complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded write tool with an output schema (so return values need no prose) and 0% schema coverage, the description covers safety, invocation flow, cross-generation differences, and references the docstring for full mapping rules. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate; it explains `servers` (one or more IPv4/IPv6 addresses or hostnames) and `confirm` (default False = preview, True = apply) thoroughly. Only `device_name` is left implicit, which is minor.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb and resource ('Set the NTP server(s) a device syncs its clock against') and even names the underlying RouterOS path `/system/ntp/client`. It is easily separable from read-only siblings like `ntp_client` and `system_clock`.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear when-to-use mechanics: blocked unless MIKROTIK_ALLOW_WRITE=true, call with confirm=False for a preview, then with confirm=True to apply. It also excludes a neighboring behavior ('never enables/disables the NTP client itself'), though it does not name an alternative tool by name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_poe_outA

Set a PoE-capable ethernet port's PoE output mode (/interface/ethernet set [interface_name] poe-out=).

poe_out must be one of "auto-on", "forced-on", "off".

Primary use case: reset a locked-up antenna/camera/AP powered over PoE by cycling its power - call with poe_out="off" (confirm=true), wait for it to actually power down, then call again with poe_out="auto-on" to bring it back up.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly (without changing anything) if interface_name doesn't exist on the device, or exists but isn't PoE-capable - it never creates or coerces anything.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
poe_outYes
device_nameYes
interface_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it declares this is a WRITE tool gated behind MIKROTIK_ALLOW_WRITE=true, explains the confirm preview/apply flow, and specifies failure behavior (errors without changing anything if the interface is missing or non-PoE, never creates or coerces). This is exactly the behavioral context an agent needs for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and command form, then the idiomatic use case, then the safety gate. Every sentence earns its place, though it runs a bit long and the command syntax is arguably redundant for an agent that must call the tool rather than a shell.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded mutation tool with no annotations and a 0%-covered schema, the description supplies the write gate, the confirm lifecycle, the enum values, the canonical use-case procedure, and failure modes. With an output schema present it need not explain returns, so nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does: it defines the allowed poe_out values (auto-on, forced-on, off), explains confirm's default-False preview semantics, and describes error conditions for interface_name. device_name remains undocumented, which is the only gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: set a PoE-capable ethernet port's PoE output mode, including the exact RouterOS command form. It is clearly distinguishable from its closest sibling poe_status (which only reads), and from enable_interface/disable_interface which act on the interface rather than PoE power.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the primary use case (resetting a locked-up PoE device) with the exact procedure: off with confirm=true, wait for power-down, then auto-on. It also explains when to call confirm=False vs confirm=True, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_route_distanceA

Adjust an existing route's distance (failover priority - lower distance wins) via /ip/route set distance=<distance>.

Resolved by the STABLE (dst_address, gateway) pair - never a dynamic .id/list index, which can silently shift as routes are added/removed elsewhere on the device between a preview and the confirmed apply. Errors clearly (without changing anything) if no route matches that pair, or if more than one still does (AmbiguousResourceError) - this never guesses which route to touch.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. See README's "Failover control" section for the recommended step-by-step flow.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
gatewayYes
distanceYes
device_nameYes
dst_addressYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so richly: it discloses the write-guard requirement, the two-phase preview/apply contract, and the failure semantics (errors without changing anything if no route matches, AmbiguousResourceError if multiple match, never guesses). It also explains the stable-key resolution choice and why dynamic ids are avoided.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and the meaning of `distance`, then layered with resolution rules, guard behavior, and workflow. Each paragraph earns its place, though the multi-paragraph format is denser than strictly necessary for a single-field update.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described. Given a 5-param mutation with 0% schema coverage and no annotations, the description covers the action, the safety guard, the preview/apply contract, the identity resolution strategy, and the error modes — nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it does for the key parameters: `distance` (failover priority, lower wins), `confirm` (default False = preview, True = apply), and the `dst_address`/`gateway` pair as the resolution key. `device_name` is left implicit, which is the only gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource ('Adjust an existing route's distance') and even names the underlying RouterOS command. It also defines the domain meaning of `distance` (failover priority, lower wins), which lets an agent distinguish it from siblings like add_route, remove_route, enable_route, and disable_route.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operational context: it is a guarded WRITE tool requiring MIKROTIK_ALLOW_WRITE=true, with a confirm=False preview step followed by confirm=True apply. It points to the README for the full flow. It does not explicitly name a sibling alternative to use instead, so it falls just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_wifi_ssidA

Set a wireless interface's SSID.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Works against either RouterOS generation - it looks for interface_name under the ROS7 wifi package first, then the ROS6 wireless package - and errors clearly if it isn't found under either; it is never created.

On ROS7, a wifi interface running the standard production layout (a named configuration) has no ssid field of its own - the actual write lands on the referenced /interface/wifi/configuration profile instead, resolved automatically. The before/after preview always reflects the real location the ssid is read from and written to.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
new_ssidYes
device_nameYes
interface_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so thoroughly: write gating by environment variable, preview versus apply semantics, ROS generation detection, failure behavior when the interface is not found, and the important ROS7 nuance that the write may actually land on a referenced configuration profile. This is exactly the kind of beyond-schema context an agent needs for a destructive-capable operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action, then immediately surfaces the write guard and confirm pattern before detailing ROS-specific resolution. It is longer than typical but most sentences carry necessary safety or routing information; minor tightening could improve it, preventing a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex write tool with no annotations, a 0%-covered schema, and an output schema, the description is nearly complete: it covers permissions, preview/apply, generation differences, error conditions, and the ROS7 profile redirection. The main remaining gap is the unexplained device_name parameter, which keeps it from a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for four parameters. It explains confirm's default and preview behavior and clarifies how interface_name is resolved on ROS7 and ROS6, but device_name is never explained and new_ssid is only implied by the tool's name. Partial compensation for a low-coverage schema is a 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Set a wireless interface's SSID.' This clearly distinguishes it from sibling wireless tools like set_wireless_channel or set_wireless_tx_power, though it does not explicitly name an alternative. The purpose is unambiguous but lacks the explicit sibling routing that a 5 would require.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives strong operational context: it is a guarded WRITE tool blocked unless MIKROTIK_ALLOW_WRITE=true, and it explains the confirm=False preview then confirm=True apply two-step pattern. It also explains ROS7/ROS6 interface resolution and error behavior, but does not compare when to use this versus sibling wireless tools, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_wireless_channelA

Set a /interface/wireless interface's frequency (MHz) and optionally channel_width.

LOCKOUT-RISK on a PtP link that is itself the management path to the far end: a bad frequency (or a DFS Channel Availability Check stall) can cut the only route back to the device. By default (arm_deadman=True), a confirm=True apply FIRST arms a dead-man (arm_dead_man) that restores the interface's prior frequency/ channel-width after deadman_minutes (1-60, default 3) unless cancelled - call cancel_dead_man(device_name, dead_man["name"]) once the new channel is confirmed good. Set arm_deadman=False only for an interface known NOT to be a management path.

The returned preview's warning ALWAYS reports whether frequency needs a DFS Channel Availability Check under this interface's CURRENT frequency-mode (superchannel: none, instant; otherwise ~60s in the general DFS range 5250-5725MHz, ~600s in the 5600-5650MHz weather-radar sub-band - verified against real hardware). See docs/api-notes-wireless-rf.md.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview (including the DFS warning, without arming anything) without changing anything; call again with confirm=True to actually apply it. Errors if interface_name doesn't exist on /interface/wireless - never creates one. This targets /interface/wireless only - see guard.py's module note for why ROS7's newer /interface/wifi package is out of scope this round.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
frequencyYes
arm_deadmanNo
device_nameYes
channel_widthNo
interface_nameYes
deadman_minutesNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden and does so richly: it discloses the write-guard (MIKROTIK_ALLOW_WRITE=true), the lockout risk on PtP management paths, the dead-man arming behavior and its default, the DFS CAC delay ranges verified against hardware, and that the tool errors rather than creates a missing interface.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but front-loaded with the core action, then organized into risk/behavioral/tool-scope sections. It is dense and every paragraph earns its place, though the density is high enough that it borders on overwhelming for a single tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 7 parameters, 0% schema coverage, and no annotations, this description supplies everything needed to invoke the tool correctly: write guard, confirm flow, dead-man behavior and cleanup, DFS timing, and the interface-not-found failure mode. An output schema exists, so return values need not be explained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate and it does: it explains frequency units (MHz), channel_width is optional, arm_deadman defaults to True, deadman_minutes range (1-60, default 3), and confirm's preview-then-apply semantics. This meaningfully exceeds the bare 0% schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Set) and resource (a /interface/wireless interface's frequency and optional channel_width), naming the exact config path. It explicitly scopes the tool to /interface/wireless and notes that ROS7's /interface/wifi is out of scope, distinguishing it from the many siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when/when-not guidance: call with confirm=False for a preview, confirm=True to apply; set arm_deadman=False only for interfaces known NOT to be a management path; the description also routes the agent to cancel_dead_man after a confirmed apply and references the related sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_wireless_tuningA

Set a /interface/wireless interface's adaptive_noise_immunity ("none"/"client-mode"/"ap-and-client-mode") and/or distance ("dynamic"/"indoors"/an integer number of km). At least one must be given.

adaptive_noise_immunity alone is reception-only tuning - CONFIRMED SAFE against real hardware today (does not drop an already- associated link), never arms a dead-man. CONFIRMED TODAY: with good signal but poor CCQ (interference, not distance), adaptive_noise_immunity="ap-and-client-mode" measurably helped.

A NUMERIC distance (unlike the named "dynamic"/"indoors" modes) directly changes the ACK-timeout/TDMA timing - LOCKOUT-RISK, CONFIRMED LIVE it can silently drop an already-associated link on a mismatch (e.g. too short for the real link length). By default (arm_deadman=True), a numeric distance arms a dead-man (arm_dead_man) that restores the interface's prior distance after deadman_minutes (1-60, default 3) unless cancelled - same mechanism as set_wireless_channel/set_wireless_tx_power. For a long verified PtP link, an explicit distance (e.g. 9 for ~9km) gave a better ACK timeout than leaving it on "dynamic".

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview (including the LOCKOUT-RISK warning for a numeric distance, without arming anything) without changing anything; call again with confirm=True to actually apply it. Errors if interface_name doesn't exist on /interface/wireless

  • never creates one.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
distanceNo
arm_deadmanNo
device_nameYes
interface_nameYes
deadman_minutesNo
adaptive_noise_immunityNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully carries the behavioral burden and does so richly: it flags the LOCKOUT-RISK of a numeric `distance` (silently drops associated links), states that `arm_deadman=True` arms a restoring dead-man, and documents that the tool never creates an interface and errors if it is missing. This is well beyond what any structured field provides.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with the core purpose and every sentence carries operational content, but the heavy ALL-CAPS emphasis and long multi-clause sentences make it denser and more shouty than needed. Slightly more structure would improve scanability without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so returns need not be described, and the description still covers the write guard, the confirm workflow, dead-man behavior, the lockout risk, and the not-found error. For a 7-parameter mutation tool it is complete enough for an agent to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and enums are absent, yet the description supplies the enum-like values for `adaptive_noise_immunity` (none/client-mode/ap-and-client-mode), the accepted forms for `distance` (dynamic/indoors/integer km), the deadman_minutes range (1-60, default 3), arm_deadman's default and effect, and confirm's preview-vs-apply meaning. It compensates almost entirely for the schema gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the exact resource (`/interface/wireless` interface) and the two settings it mutates (`adaptive_noise_immunity` and/or `distance`), with specific syntax for each. It also positions itself against siblings by noting it shares the dead-man mechanism with set_wireless_channel and set_wireless_tx_power.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete when-to-use guidance per parameter: `adaptive_noise_immunity` for good-signal/poor-CCQ interference cases, numeric `distance` for long verified PtP links. It also states the prerequisite (at least one setting must be supplied), the write guard (MIKROTIK_ALLOW_WRITE=true), and the confirm=False/True workflow, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_wireless_tx_powerA

Set a /interface/wireless interface's tx_power (dBm), forcing tx-power-mode=all-rates-fixed.

CONFIRMED AGAINST REAL HARDWARE TODAY: on a short link, the default (maximum) tx-power SATURATES the receiver and PRODUCES A WORSE CCQ than a lower power (measured: -27dBm/CCQ 34 at default, -47dBm/CCQ 94 at ~8dBm). There is no single "right" power for every link - use get_wireless_link_quality before/after to judge the effect.

LOCKOUT-RISK for the same reason as set_wireless_channel - same arm_deadman/deadman_minutes dead-man behavior (default armed), restoring BOTH tx-power-mode and tx-power on revert.

The returned preview's warning always notes that CCQ/rate briefly re-adapt (a few seconds) right after a power change - expected, not a failure.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors if interface_name doesn't exist on /interface/wireless - never creates one.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
tx_powerYes
arm_deadmanNo
device_nameYes
interface_nameYes
deadman_minutesNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so richly: it discloses the write guard (blocked unless MIKROTIK_ALLOW_WRITE=true), the dead-man lockout risk and that revert restores BOTH tx-power-mode and tx-power, the preview-vs-apply confirm semantics, and that it errors rather than creating a missing interface. The counterintuitive saturation behavior is also explained.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and its forced side effect, and the length is justified by the tool's complexity and lack of annotations. It is slightly verbose, with the saturation example and the CCQ re-adaptation note occupying more space than strictly needed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded mutation tool with no annotations, 6 parameters, and 0% schema coverage, the description covers the safety profile, the preview/apply flow, the write gate, the dead-man revert, and the error behavior. An output schema exists, so its note on the preview warning is supplementary rather than a gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it largely does: tx_power (dBm), confirm (preview vs apply), arm_deadman/deadman_minutes (armed by default, revert behavior), and interface_name (errors if absent, never created) are all given meaning. Only device_name is left to inference, which is minor.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource ('Set a /interface/wireless interface's tx_power (dBm)') and adds the critical side effect ('forcing tx-power-mode=all-rates-fixed'), which distinguishes it from siblings like set_wireless_channel and set_wireless_tuning. An agent can identify the operation and its scope without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent: use get_wireless_link_quality before/after to judge effect, and there is no universally correct power. It also spells out the confirm=False preview → confirm=True apply workflow, and names set_wireless_channel as the sibling with the same dead-man lockout behavior. When-to-use and alternatives are both covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

simple_queuesA

List Simple Queue entries (/queue/simple): name, target, max-limit, limit-at, bytes counters, disabled. Use this to see which clients already have a bandwidth limit and how much traffic they've moved (the bytes counter), before deciding who to limit with set_client_bandwidth.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the full behavioral burden. It implies read-only behavior via 'List' and 'see', and mentions the returned fields including bytes counters and disabled status, but it does not state permissions, authentication needs, pagination, or rate limits. Adequate for a simple list tool, but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with no filler. The core purpose and returned fields are front-loaded, and the usage guidance follows immediately, so every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained. The description covers purpose, fields, and usage well, but it omits any mention of the required device_name parameter despite low schema coverage, which is a small completeness gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter, device_name, has 0% schema description coverage and is never mentioned in the description. The description does not compensate by explaining what device_name identifies or its required status, leaving parameter meaning entirely to the schema title.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb (List) and resource (/queue/simple), enumerates the fields returned, and explicitly distinguishes the tool from the mutation sibling set_client_bandwidth. An agent can tell what it does and when it differs from remove_simple_queue or set_client_bandwidth without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear use case (see existing bandwidth limits and traffic before deciding who to limit) and names the alternative tool set_client_bandwidth. However, it does not explicitly state when not to use this tool or any prerequisites, so it falls just short of the top mark.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

start_containerA

Start a container by name or tag (/container/start).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly (without creating anything) if container doesn't match any /container row's name or tag on the device - it is never created.

The after.status in the preview is the status RouterOS sets immediately ("starting"), not a guaranteed final state - the container transitions to "running" asynchronously; use containers again afterward to see the settled status.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
containerYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: it discloses the MIKROTIK_ALLOW_WRITE=true guard, the non-destructive preview default, the error-without-creating behavior on no match, and the asynchronous status transition where 'starting' is not a settled state.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action and path, then layers guard, preview/apply, error, and async caveats in a logical order. Slightly long with dense parentheticals, but every sentence adds decision-relevant information rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a guarded write tool with an output schema present, it supplies everything an agent needs: safety guard, confirm semantics, failure mode, and interpretation of the returned after.status. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate and largely does: it clarifies that `container` matches a `name` or `tag`, and that `confirm` defaults to False for preview vs True to apply. Only `device_name` is left unexplained, which is minor.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Start') and resource ('container') and even cites the underlying RouterOS path (`/container/start`). It is trivially distinguishable from the sibling stop_container and the read-only containers tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the two-phase call pattern (confirm=False preview then confirm=True apply) and when each applies. It does not explicitly route against alternatives like stop_container or containers, but the context is clear enough to invoke correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

stop_containerA

Stop a container by name or tag (/container/stop).

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a before/after preview without changing anything; call again with confirm=True to actually apply it. Errors clearly (without changing anything) if container doesn't match any /container row's name or tag on the device - it is never created.

The after.status in the preview is the status RouterOS sets immediately ("stopping"), not a guaranteed final state - use containers again afterward to see the settled status.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
containerYes
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so well: write guard, dry-run default, error behavior when the target doesn't match, and the caveat that after.status is 'stopping' rather than a guaranteed final state. This is exactly the non-obvious context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action and then layers the guard, the confirm flow, and the error semantics in short paragraphs. Every sentence adds operational value; only mild verbosity around the after.status caveat.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be restated, and the description fills the remaining gaps: authorization guard, dry-run semantics, failure mode, and status-resolution caveat. Nothing an agent needs to call this safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate: it explains that `container` matches a `name` or `tag` and is never auto-created, and that `confirm` defaults to a non-mutating preview. `device_name` is left unexplained, but its meaning is self-evident from the name and the sibling set.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Stop a container by `name` or `tag`') and names the API endpoint it maps to. An agent can distinguish it immediately from the sibling start_container.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly describes the two-phase call pattern (confirm=False for preview, confirm=True to apply) and the precondition that the server must run with MIKROTIK_ALLOW_WRITE=true. It also names the follow-up tool (`containers`) to check settled status.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

system_clockA

Device clock (/system/clock): time, date, time-zone-name, time-zone-autodetect (normalized to bool | None - formatting.coerce_ros_bool), gmt-offset, dst-active (also normalized) - a single-row menu, same shape as container_config/ ntp_client.

Clock drift breaks certificate validation (see certificates' daysUntilExpiry), log timestamps, and scheduler timing - check this alongside ntp_client's status/synced-server when diagnosing any of those. Returns an empty dict (never an error) for a device with no /system/clock menu at all (not expected on any real RouterOS device, but handled the same defensive way every other single-row read here is).

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does disclose two non-obvious behaviors: bool fields are normalized via `formatting.coerce_ros_bool` to `bool | None`, and a device with no `/system/clock` menu returns an empty dict rather than an error. It omits permission/auth requirements and any rate or concurrency notes, which keeps it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The resource path and field list are front-loaded, and each sentence carries diagnostic or behavioral content. It is parenthetical-heavy and denser than necessary, but there is little outright filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-row read with an output schema, this covers what the tool is, the fields it exposes, the diagnostic context, and the empty-dict edge case. Missing auth/permission context is the only notable gap given the absence of annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and the sole parameter (`device_name`) is never mentioned in the description, so the documentation does not compensate for the gap. The parameter is essentially self-explanatory by name, which prevents a lower score, but nothing beyond the schema is added.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the exact resource (`/system/clock`) and enumerates the readable fields (time, date, time-zone-name, gmt-offset, dst-active), so an agent knows precisely what it returns. It stops short of an explicit verb like 'Read/Get', and the distinguishing information is mostly implicit in the field list, but the resource is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a concrete diagnostic trigger: check this alongside `ntp_client`'s `status`/`synced-server` when clock drift is breaking certificate validation, log timestamps, or scheduler timing. That is a clear when-to-use with a named complementary sibling, though it offers no explicit when-not-to-use or exclusion criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

system_healthB

Read system health metrics (e.g. voltage, temperature), if the device exposes them.

Not every RouterOS device/board type has health sensors (e.g. some CHR/virtual instances have none) - in that case this returns an empty list instead of raising.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It usefully discloses that the tool is a read operation and that missing health sensors lead to an empty list instead of an exception. It does not mention authentication requirements or rate limits, but the key non-obvious behavior for this tool is covered well.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short, front-loaded with the core action, and then adds the important caveat about devices without sensors. It avoids unnecessary detail and every sentence contributes useful information. Minor improvement could come from explicitly naming a related tool or parameter source.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter read tool with an output schema, the description adequately explains the return behavior for unsupported devices. However, it leaves device_name semantics undocumented and does not point to a sibling tool for discovering valid device names. Given the rich output schema, return values need not be explained, but the parameter gap reduces completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is one required parameter, device_name, with 0% schema description coverage. The description does not explain what device_name should contain or how to obtain it. The schema provides only a type and title, so the description fails to compensate for the parameter semantics gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource: read system health metrics such as voltage and temperature. It clearly states what the tool does, but it does not explicitly distinguish itself from sibling tools like system_info or interface_monitor. The purpose is clear without being sibling-differentiated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides usage context by noting that not every device exposes sensors and that unsupported devices return an empty list rather than an error. However, it does not state when to prefer this tool over alternatives such as system_info or interface_monitor, nor does it mention prerequisites like needing a valid device_name from list_devices. Usage is implied rather than explicitly guided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

system_infoB

Get RouterOS identity + resource info (board, version, uptime, CPU/memory).

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.1/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided. Description does not explicitly state that the tool is read-only, nor does it mention any prerequisites, side effects, or return format details. It is minimal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence that is clear and front-loaded with the key action ('Get RouterOS identity + resource info'). No wasted words, though could be slightly more complete.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Description lists specific fields to be retrieved (board, version, uptime, CPU/memory), providing good context. However, it fails to document the single parameter, and with an existing output schema, return values are partially covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%. The description does not explain the required 'device_name' parameter at all, leaving the agent guessing about what values are valid.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the tool gets RouterOS identity and resource info (board, version, uptime, CPU/memory). It distinguishes from siblings like 'list_devices' (which only lists names) and 'set_identity' (which modifies identity).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use or when-not-to-use guidance. However, the purpose is straightforward and the sibling tools are sufficiently different, so usage is implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

torchA

Live traffic snapshot of one interface (/tool/torch interface=<interface> once=yes) - RouterOS's own real-time traffic monitor, useful to answer "who is consuming bandwidth on this link RIGHT NOW". interface is validated for shape (validate_interface_name) before it is ever sent to the device - existence isn't checked separately, so a typo'd/unknown interface name simply produces whatever error RouterOS itself returns.

src_address/dst_address (plain IPv4/IPv6 addresses - validate_ip_address) and port (1-65535 - validate_conntrack_dst_port, reused here for the same "TCP/UDP port" shape) are all optional filters forwarded to RouterOS itself, narrowing the snapshot BEFORE it ever leaves the device - use them to cut down volume on a busy interface rather than fetching every flow and filtering client-side.

once=yes makes this a single instantaneous snapshot, not a continuous stream (same "once" convention as interface_traffic/ poe_status/lte_status - see client.MikrotikClient.torch), so the call always returns promptly instead of opening RouterOS's normal interactive torch stream.

VOLUME CAP: regardless of how many flows RouterOS reports for this snapshot, the result's flows list is sorted by total traffic (tx+rx bytes, biggest first - the "top talkers") and hard-capped at MAX_TORCH_LIMIT (50) entries - truncated is true whenever more flows matched than were returned, and total_matched always reports the real (pre-cap) count. RouterOS's own torch field names for a flow's traffic volume aren't perfectly uniform across RouterOS versions/hardware - this sorts by whichever of tx/rx (bits- or bytes-per-second, depending on version) the device actually returned, defaulting a flow with neither to 0 (sorted last) rather than failing the whole call over one unexpected row shape.

ParametersJSON Schema
NameRequiredDescriptionDefault
portNo
interfaceYes
device_nameYes
dst_addressNo
src_addressNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so richly: it discloses the once=yes single-snapshot semantics, the 50-entry MAX_TORCH_LIMIT cap, sort-by-total-traffic behavior, the truncated/total_matched reporting, permissive error behavior on typo'd interfaces, and a defensive fallback for non-uniform RouterOS field names.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The lead sentence front-loads the core purpose and the details are well-organized into distinct paragraphs. It is dense and runs long, with some parenthetical asides (validate_* helpers, the once convention) that border on over-explanation, but nearly every sentence adds actionable information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Even though an output schema exists (so return values needn't be explained), the description goes further by documenting the flows list, sorting, cap, and truncated/total_matched fields. Combined with validation, error, and filter behavior, an agent has everything needed to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate and it does: interface is shape-validated (existence not checked), src_address/dst_address are IPv4/IPv6 via validate_ip_address, and port is 1-65535 with TCP/UDP semantics via validate_conntrack_dst_port. It also explains that these filters are forwarded to RouterOS to narrow before egress.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (live traffic snapshot of one interface) and frames it as RouterOS's real-time traffic monitor answering 'who is consuming bandwidth RIGHT NOW'. It implicitly distinguishes itself from polling-style siblings by stressing it is an instantaneous snapshot, not a continuous stream.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for use (top-talkers on a busy link right now) and explicit advice to use the src/dst/port filters to narrow on-device rather than fetching everything and filtering client-side. It references the 'once' convention shared with interface_traffic/poe_status/lte_status, but never explicitly states when to pick this over interface_traffic.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

tracerouteA

Traceroute to an address from a device; returns the list of hops.

address must be a valid IPv4/IPv6 address or hostname (validated exactly like ping's). count (probes per hop) and max_hops are both capped low (see MAX_TRACEROUTE_COUNT/MAX_TRACEROUTE_MAX_HOPS) and a fixed short per-hop timeout is used internally, so the command can't run long enough to hit RouterOS's own ~60s API command timeout.

Diagnostic only - this never changes device state, so it is not gated by MIKROTIK_ALLOW_WRITE and needs no confirm/preview.

ParametersJSON Schema
NameRequiredDescriptionDefault
countNo
addressYes
max_hopsNo
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it discloses the read-only nature, that it is not gated by MIKROTIK_ALLOW_WRITE, that count/max_hops are capped low, and that a fixed short per-hop timeout keeps it under RouterOS's ~60s API timeout. It does not mention auth/permission requirements beyond the write-gate note.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core behavior is front-loaded in the first sentence, followed by parameter caveats and a behavioral note. Every sentence adds information, though the phrasing is somewhat verbose and the parenthetical constant references may be noise for an agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema covers the return value (hop list), so the description needn't restate it. Combined with parameter caveats, timeout/runaway protection, and the explicit write-gate note, an agent has everything needed to call this diagnostic tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It documents three of four parameters: `address` (valid IPv4/IPv6 or hostname, validated like ping), `count` (probes per hop, capped), and `max_hops` (capped). Only `device_name` is left unexplained, which is largely self-evident.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Traceroute to an address from a device") plus the return shape ("returns the list of hops"). It references the sibling `ping` for validation parity but never explicitly contrasts when to choose traceroute over ping, so differentiation is implied rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clarifies the operational context (not gated by MIKROTIK_ALLOW_WRITE, no confirm/preview needed), which tells the agent how to invoke it. However, it gives no explicit when-to-use vs the `ping` sibling or other diagnostics, leaving the choice to inference from the tool name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

usb_devicesA

USB hardware on a device: physical USB ports (/system/routerboard/usb, if the board exposes them) plus attached storage (/disk - USB flash drives, and USB LTE/5G modems that surface as a disk rather than under routerboard/usb). Combined into one read since which of the two a given USB device shows up under depends on the hardware.

Returns {"usb_ports": [...], "disks": [...]} - either or both lists empty (never an error) if the board doesn't expose that menu/hardware at all.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does well: it states this is a read, that either list may be empty, and that an absent menu/hardware returns empty lists rather than an error. It stops short of noting permission requirements, so not quite a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the resource, then the union rationale, then the return shape. Sentences earn their place, though the return-format sentence partially duplicates the existing output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Because an output schema exists, return values need not be explained; the description instead supplies the non-error/empty-list behavior an agent needs. The only real omission is the unaddressed `device_name` parameter.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single required parameter `device_name` is never mentioned in the description. The agent must infer its meaning and format entirely from the property name.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names the specific resource (USB hardware), the exact menus it reads (`/system/routerboard/usb` and `/disk`), and explains the union because a device's menu depends on hardware. An agent can distinguish this from `lte_interfaces` or `interfaces` without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the 'combined into one read' rationale, but there is no explicit when-to-use or when-not-to-use statement, and no alternative named (there is no obvious sibling for USB enumeration anyway). Adequate minimum but with a clear gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

user_activeA

List currently active RouterOS login sessions (/user/active): name, address, via (e.g. api/winbox/ssh/web), when (session start time) - who is logged into the device's own management right now, as opposed to users' CONFIGURED accounts.

Returns an empty list (never an error) for a device with nobody currently logged in, or if /user/active is unavailable.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations, so the description carries the full burden, and it does well: it discloses the non-obvious behavioral trait that an empty list is returned rather than an error when no one is logged in or when /user/active is unavailable. Missing pagination or permission/read-only notes, which limits this to a 4.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the resource and endpoint, lists the returned fields compactly, then adds the empty-list guarantee in a separate short paragraph. Every sentence earns its place with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained; the description still helpfully summarizes the key fields and, crucially, documents the empty-list/error-absence behavior that an agent needs when interpreting results. Complete for a simple read tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter (device_name) with 0% schema description coverage, but the single required parameter is self-explanatory from its name and the description's framing. The description adds no format or constraint details for device_name, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (list) and resource (active login sessions via /user/active), enumerates the returned fields, and explicitly contrasts with the sibling `users` tool (configured accounts vs. live sessions). An agent can distinguish this from `users` and `hotspot_active` without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames the use case: 'who is logged into the device's own management right now, as opposed to `users`' CONFIGURED accounts,' naming the sibling alternative and the condition that selects it. There is no when-not-to-use guidance, but the differentiation is clear enough for correct selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

usersA

List RouterOS login accounts (/user): name, group, address (an allowed-source restriction, if the account has one), last-logged-in (if RouterOS exposes it), disabled, comment.

/user's own API reply never carries a password at all - RouterOS doesn't expose it over the API, so there is nothing to strip here (unlike ppp_secrets/radius, whose underlying menus DO carry a secret). This is a READ only: creating/editing a /user login stays deliberately out of scope for this package (see ROADMAP.md's "Explicitly NOT on the roadmap" - a router login is a device/API credential, a different risk class from a service credential like a PPP secret or hotspot user).

Returns an empty list (never an error) if /user is unavailable for some reason - /user always exists on RouterOS in practice, but this keeps the same "empty, not an error" convention every other optional read in this package uses.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses that no password is ever returned, that the underlying menu holds no secret, that writes are out of scope, and that an unavailable `/user` yields an empty list rather than an error. It omits auth/permission requirements, which would be useful given the account-listing subject matter.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is well front-loaded with the returned fields, but the ROADMAP.md aside and the risk-class rationale run long for a single-parameter read tool. The core facts are present; the editorial justification could be trimmed without losing agent-relevant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value documentation is unnecessary, and the description compensates with the empty-list-not-error convention and the password disclosure. The main gap is the undocumented `device_name` parameter and unstated access requirements.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is one parameter (`device_name`) with 0% schema description coverage, and the description never mentions it or its expected format. With low coverage the description should compensate for the schema gap, and it does not.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource ('List RouterOS login accounts (`/user`)') and enumerates the fields returned. It is clearly distinguishable from siblings like `user_active`, `ppp_secrets`, and `radius`, which it explicitly contrasts itself against.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly scopes when this tool applies (read-only listing of `/user` accounts) and states that creating/editing logins is deliberately excluded, routing an agent away from expecting a write path here. It does not, however, explicitly say when to prefer this over `user_active` or `security_audit`, leaving some sibling routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wake_on_lanA

Send a Wake-on-LAN magic packet (/tool/wol) for mac_address, out interface.

Benign - it never changes device configuration and targets no existing RouterOS row - but still guarded/confirm-gated like every other write tool here, so an LLM caller can't wake a machine "by accident". Does NOT verify interface exists on the device first; RouterOS itself rejects an unknown interface name at send time.

WRITE tool, guarded: blocked entirely unless the server is running with MIKROTIK_ALLOW_WRITE=true. Call with confirm=False (the default) to get a preview of what would be sent without changing anything; call again with confirm=True to actually send it.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmNo
interfaceYes
device_nameYes
mac_addressYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so thoroughly: it describes the write/guarded nature, the environment gate, the preview-vs-send confirmation flow, and the fact that interface existence is not pre-validated and may fail at send time.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core purpose is front-loaded, and most sentences carry useful operational context. It is somewhat lengthy and includes a line-break-heavy aside, but the information is relevant rather than redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an unannotated write tool with an output schema, the description covers the critical safety and invocation behavior: write gating, confirmation semantics, and post-validation limitations. The main remaining gap is `device_name` semantics, which is left to the schema despite the 0% schema description coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for all four parameters. It meaningfully explains `mac_address`, `interface`, and `confirm`, but omits `device_name` entirely and gives no format details for the MAC or interface values.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: sending a Wake-on-LAN magic packet via `/tool/wol` for a given MAC address and interface. It clearly distinguishes this action from the many read and configuration-write siblings by naming the exact RouterOS operation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear invocation guidance: use `confirm=False` for preview, then `confirm=True` to send, and note that the tool is blocked unless `MIKROTIK_ALLOW_WRITE=true`. It does not name alternatives, but there is no obvious sibling substitute for Wake-on-LAN.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wireguard_interfacesA

List WireGuard tunnel interfaces (/interface/wireguard): name, listen-port, public-key, running, disabled, mtu.

SECURITY: RouterOS's own /interface/wireguard reply carries the interface's private-key - this is ALWAYS stripped before returning (formatting.strip_sensitive_fields with formatting.WIREGUARD_SENSITIVE_FIELDS), the same mechanism wireguard_peers (v0.8) already used defensively for a peer's private-key/preshared-key. A private-key never leaves this process. See test_wireguard_interfaces_never_exposes_private_key.

Returns an empty list (never an error) for a device with no WireGuard package/interfaces at all - same convention as wireguard_peers.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does so well: it discloses that RouterOS returns a private-key which is always stripped via a named mechanism, that a private-key never leaves the process, and that empty results are returned instead of errors, citing a test. It stops short of stating read-only status explicitly or pagination/permission behavior, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core purpose is front-loaded in the first sentence, followed by well-organized security and empty-list notes. It is somewhat verbose, naming internal functions and a test, but each block carries real information rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple list tool with an output schema, the description covers the notable behaviors an agent needs (field set, sensitive-field stripping, never-error empty list). The one gap is the undocumented device_name parameter, which the schema also leaves blank.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for the single required parameter device_name, so the description must compensate and it does not — device_name is never explained (which device, format, or how it is resolved). The field list describes outputs, not the input parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (list WireGuard tunnel interfaces at /interface/wireguard) and enumerates the returned fields, so the agent knows exactly what this returns. It also implicitly distinguishes itself from wireguard_peers by naming that sibling and its different subject matter (peers vs interfaces).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by 'List ... interfaces' and the empty-list convention is clarified, but there is no explicit when-to-use vs alternatives such as wireguard_peers or add_wireguard_interface. The reference to wireguard_peers is about the security mechanism, not about selecting between the two tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wireguard_peersA

List WireGuard VPN peers (/interface/wireguard/peers): name, interface, public-key, endpoint-address/endpoint-port, current-endpoint-address/current-endpoint-port, last-handshake, rx/tx byte counters, allowed-address, disabled.

SECURITY: a private-key field never appears in RouterOS's own /interface/wireguard/peers reply (only /interface/wireguard - the tunnel interfaces themselves - carries one; see wireguard_interfaces below), but this strips it defensively anyway, along with any preshared-key a configured peer may genuinely carry (a real, if optional, RouterOS field on this menu) - see formatting.WIREGUARD_SENSITIVE_FIELDS and test_wireguard_peers_never_exposes_private_key/ test_wireguard_peers_never_exposes_preshared_key.

Returns an empty list (never an error) for a device with no WireGuard package/interfaces at all - same "empty, not an error" convention as wireless_registrations/system_health for optional features.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it discloses the read-only field set, defensively strips private-key/preshared-key, and specifies the empty-list-not-error convention for devices lacking the WireGuard package. It omits auth/permission requirements and pagination behavior, keeping it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The critical content (what it lists, the security stripping, empty-list behavior) is front-loaded, but the middle section is bloated with internal references such as formatting.WIREGUARD_SENSITIVE_FIELDS and test-function names that don't help an agent select or invoke the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value explanation isn't strictly required, yet the description still enumerates fields and fully covers security and the empty-result edge case. The only real gap is the unaddressed device_name argument.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for the single device_name parameter, so the description must compensate, and it never mentions device_name or its expected format/source. The self-explanatory title 'Device Name' partly mitigates, but the description adds no semantic value over the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List WireGuard VPN peers') plus the exact RouterOS menu path and the returned fields. It explicitly distinguishes itself from the sibling wireguard_interfaces ('only /interface/wireguard - the tunnel interfaces themselves - carries one; see wireguard_interfaces below'), so an agent can tell them apart without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when this applies (enumerating configured peers on a device) and points to wireguard_interfaces as the adjacent sibling holding tunnel-level data. It does not, however, state explicit usage conditions or exclusions for choosing among the read-only listing tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wireless_registrationsA

List wireless clients currently associated to the device (mac, signal, interface, uptime).

RouterOS exposes this under two different paths depending on generation: ROS7's wifi package (/interface/wifi/registration-table) or ROS6's wireless package (/interface/wireless/registration-table). This tries ROS7 first, falls back to ROS6, and returns an empty list

  • rather than raising - for a device with no wireless radio at all (or the relevant package not installed), since that is a completely normal, expected state for a wired-only device.

RAW rows, as RouterOS returns them - see get_wireless_link_quality (v1.11) for the same registration-table data normalized into a fixed CCQ/rate/distance shape for PtP/PtMP diagnosis.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations, so the description carries the full behavioral burden, and it does disclose non-obvious traits: dual-path lookup order, silent fallback, and empty-list-instead-of-error semantics for wired-only or missing-package devices. It omits auth/permission requirements and pagination or volume characteristics, which keeps it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and output fields, then the fallback/edge-case rationale. The parenthetical field list and the sibling pointer both earn their place; the multi-line layout is slightly more verbose than needed but not padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return shape needn't be described, and the description still notes the rows are raw RouterOS fields. Combined with the fallback and empty-list semantics, an agent has enough to call this correctly; only parameter naming guidance is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for the single required parameter, and the description only indirectly implies that 'the device' is identified by device_name. It adds no format or naming guidance, so the lone parameter remains under-specified.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource ('List wireless clients currently associated to the device') plus the returned column set (mac, signal, interface, uptime). It also explicitly names the sibling it is not — get_wireless_link_quality — so an agent can distinguish raw vs. normalized registration data without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains the generation-dependent resolution (ROS7 wifi first, ROS6 wireless fallback) and states the expected no-radio case, and it routes clearly to get_wireless_link_quality for normalized diagnosis. It stops short of an explicit 'prefer X when Y' rule for the other ~80 sibling tools, but the context given is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 104 tool updatesv1.11.0
    • Addedadd_hotspot_user
    • Addedadd_ipv6_route
    • Addedadd_netwatch
    • Addedadd_ppp_secret
    • Addedadd_route
    • Addedadd_static_dhcp_lease
    • Addedadd_static_dns
    • Addedadd_to_address_list
    • Addedadd_to_ipv6_address_list
    • Addedadd_vlan
    • Addedadd_wireguard_interface
    • Addedadd_wireguard_peer
    • Addedaddress_lists
    • Addedarm_dead_man
    • Addedarp_table
    • Addedbgp_sessions
    • Addedbridge_hosts
    • Addedbridge_ports
    • Addedbridge_vlans
    • Addedcancel_dead_man
    • Addedcertificates
    • Addedclear_dns_cache
    • Addedconnection_tracking
    • Addedcontainer_config
    • Addedcontainers
    • Addedcreate_backup
    • Addeddhcp_leases
    • Addeddhcp_networks
    • Addeddhcp_servers
    • Addeddisable_firewall_rule
    • Addeddisable_interface
    • Addeddisable_ipv6_firewall_rule
    • Addeddisable_mangle_rule
    • Addeddisable_nat_rule
    • Addeddisable_route
    • Addeddns_cache
    • Addedenable_firewall_rule
    • Addedenable_interface
    • Addedenable_ipv6_firewall_rule
    • Addedenable_mangle_rule
    • Addedenable_nat_rule
    • Addedenable_route
    • Addedfirewall_filter
    • Addedfirewall_mangle
    • Addedfirewall_nat
    • Addedget_wireless_link_quality
    • Addedhotspot_active
    • Addedinterface_monitor
    • Addedinterface_traffic
    • Addedip_pools
    • Addedipsec_active_peers
    • Addedipv6_addresses
    • Addedipv6_firewall_address_lists
    • Addedipv6_firewall_filter
    • Addedipv6_neighbors
    • Addedipv6_routes
    • Addedlist_backups
    • Addedlist_vlans
    • Addedlte_interfaces
    • Addedlte_status
    • Addedmove_firewall_rule
    • Addednetwatch
    • Addedntp_client
    • Addedospf_neighbors
    • Addedpoe_status
    • Addedppp_active
    • Addedppp_secrets
    • Addedradius
    • Addedremove_dhcp_lease
    • Addedremove_from_address_list
    • Addedremove_from_ipv6_address_list
    • Addedremove_ipv6_route
    • Addedremove_netwatch
    • Addedremove_ppp_secret
    • Addedremove_route
    • Addedremove_simple_queue
    • Addedremove_static_dns
    • Addedremove_vlan
    • Addedremove_wireguard_peer
    • Addedscheduler
    • Addedsecurity_audit
    • Addedsecurity_events
    • Addedset_client_bandwidth
    • Addedset_ntp_servers
    • Addedset_poe_out
    • Addedset_route_distance
    • Addedset_wifi_ssid
    • Addedset_wireless_channel
    • Addedset_wireless_tuning
    • Addedset_wireless_tx_power
    • Addedsimple_queues
    • Addedstart_container
    • Addedstop_container
    • Addedsystem_clock
    • Addedsystem_health
    • Addedtorch
    • Addedtraceroute
    • Addedusb_devices
    • Addeduser_active
    • Addedusers
    • Addedwake_on_lan
    • Addedwireguard_interfaces
    • Addedwireguard_peers
    • Addedwireless_registrations
  2. 10 tool updatesv0.1.0
    • First observedinterfaces
    • First observedip_addresses
    • First observedip_routes
    • First observedlist_devices
    • First observedlist_write_operations
    • First observedlogs
    • First observedneighbors
    • First observedping
    • First observedset_identity
    • First observedsystem_info

TDQS

B3.4/5.0

Scored across 114 tools

Disambiguation3/5

Most tools target clearly distinct resources, but the firewall rule toggles overlap heavily: enable_firewall_rule/disable_firewall_rule/enable_nat_rule/disable_nat_rule/enable_mangle_rule/disable_mangle_rule/enable_ipv6_firewall_rule/disable_ipv6_firewall_rule are nine near-identical tools distinguished only by menu, and the IPv6 mirror set (ipv6_addresses vs ip_addresses, add_route vs add_ipv6_route, etc.) requires reading descriptions carefully to pick correctly.

Naming Consistency4/5

Overwhelmingly consistent verb_noun snake_case (add_route, remove_vlan, set_wifi_ssid, list_backups), but several read tools drop the verb entirely (interfaces, neighbors, logs, certificates, users, scheduler, radius, torch, ping, traceroute), mixing noun-only names with the dominant verb_noun pattern.

Tool Count1/5

114 tools is an extreme mismatch for a single LLM-facing server: the nine enumerate/disable rule toggles, the full IPv4/IPv6 duplicated read-and-write surface, and per-feature reads (wireless, wireguard, lte, ppp, container, bgp, ospf, netwatch) collectively make the surface far larger than an agent can reliably navigate.

Completeness4/5

Coverage is genuinely broad - reads for nearly every RouterOS subsystem plus guarded CRUD for routes, VLANs, firewall rules, DNS, DHCP, WireGuard, PPP, hotspot, containers, and netwatch, with IPv6 read/write parity. Gaps exist (no interface creation, no user management, no hotspot profile creation) but these appear intentional and documented.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP server that sends CLI commands to MikroTik RouterOS via SSH. It allows executing any RouterOS CLI command and getting text output back.
    1
    -