The difference matters. A blocklist fails on the command nobody thought of; a whitelist fails closed. Here the read path only permits explicit patterns, writes go through a separate execution path that is off by default, and shell metacharacters are blocked outright so nothing gets chained onto a permitted command. The other thing to notice is the per-device DHCP tool — lease, static reservation and log history in one answer is exactly the shape of the question "why does this laptop keep dropping off".
An MCP server that connects to an OpenWRT router over SSH and lets an assistant read its state. The security model is the design: every command is matched against an explicit read-only whitelist, and the four write tools plus the one destructive tool do not run at all unless you set a flag.
- 24 tools in total — 19 read, 4 write, 1 destructive — each labelled with its risk level
- System state: board info, memory, uptime and release, a unified context snapshot covering system, WiFi, DHCP and health, and server introspection listing its own tools and collectors — `get_router_info`, `get_router_context`, `describe_router_capabilities`
- Network reads: WiFi radios, SSIDs and connected clients, active DHCP leases, a connectivity diagnosis running ping, DNS and gateway tests, plus individual ping, traceroute, DNS lookup and a scan of neighbouring WiFi networks — `get_router_wifi_status`, `get_router_dhcp_leases`, `diagnose_router_connectivity`, `ping_host`, `traceroute_host`, `nslookup_host`, `wifi_scan`
- Security and configuration reads: iptables, nftables or fw4 rules, and UCI configuration sections — `get_router_firewall_rules`, `read_router_uci_config`
- Diagnostics and inventory: recent system logs, filtered log search, and installed OPKG packages — `get_router_logs`, `search_router_logs`, `list_router_packages`
- Device-level DHCP work: static reservations, DHCP events in the logs, and a full per-device view combining lease, reservation and log history — `get_dhcp_static_leases`, `search_dhcp_logs`, `get_device_dhcp_details`
- Writes behind `ENABLE_WRITE_OPERATIONS`: set and commit a UCI value, restart an interface, reload network services — and a reboot marked destructive — `uci_set`, `uci_commit`, `restart_interface`, `reload_network`, `reboot_device`
- Audit logging of every executed command with timestamps, on by default
An OpenWRT router with SSH enabled and an SSH key pair — generate one and copy the public key to the router; password login is supported through `OPENWRT_PASSWORD` but discouraged. Two variables are required: `OPENWRT_HOST` and `OPENWRT_SSH_KEY`. Python 3.14+ for a local install (`pip install -e ".[dev]"`, then run `openwrt-mcp`), or the published Docker image. Three ports are used — health, MCP over SSE, and a REST API — and all of them bind to `127.0.0.1` by default; Docker port forwarding requires setting `MCP_UNSAFE_PUBLIC_ACCESS_CONFIRMED`. Optional host key verification is available via `OPENWRT_KNOWN_HOSTS`.
One command plus a key — pip install -e ".[dev]", then supply credentials
