keenetic-mcp
Provides tools for managing Keenetic routers via their HTTP API (RCI) and optional SSH, including devices, Wi-Fi, port forwarding, KeenDNS, DNS, DHCP, firewall, mesh, storage, logs, and Entware packages.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@keenetic-mcpwho is using the most bandwidth right now?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.

keenetic-mcp
Your Keenetic router, fully controllable by an AI agent β devices, Wi-Fi, port forwarding, KeenDNS, DNS, DHCP, firewall, mesh, storage, logs, and Entware over SSH.
Fork of salatmaster/keenetic-mcp β extended from 18 to 44 tools: full network-service management (port forwarding, KeenDNS, DNS, static DHCP, firewall), mesh and storage monitoring, log and ping diagnostics, and opt-in SSH access for Entware packages and their configs. Same safety model, same zero-install philosophy.
π§ What's inside
π Start | β‘ Quick Start | π¦ Install | π§ Configuration |
π‘ Learn | π₯ Why this server | π‘οΈ Safety model | π¬ How it works |
π§° Features | π Full tool reference | π SSH & Entware | π§© Skills included |
π See it | π¬ In action | π‘ Supported routers | πΊοΈ Roadmap |
π¦ Project | π οΈ Development | π Acknowledgments | π License |
Related MCP server: keenetic-mcp
π₯ Why
Nothing on the router. It talks to the router's own HTTP API (RCI) over your LAN. No USB drive, no Entware, no firmware modification β until you opt in to SSH for Entware work.
Works on any Keenetic. The tool set adapts to what your specific model and firmware actually support.
Safe by construction. Changes are never saved unless you ask, a backup is taken before the first one, and every change is read back and verified before it is reported as done.
Read-only if you want it. One flag and the agent physically cannot change anything β the write tools are never even registered.
Shell access is opt-in, never default.
--sshunlocks Entware package management and file editing with a blocklist for flash writes,rm -rfof system paths and lockout commands.LAN only. No cloud, no telemetry, no outbound connection to anything but your router.
π¬ In action
> who is using the most bandwidth right now?
Three devices are active. Sorted by traffic:
work-laptop wifi:HomeNet -46 dBm 7.7 GB down
living-room-tv wired:Home 3.2 GB down
hallway-camera wifi:HomeNet -48 dBm 5.4 MB down
> forward port 8123 to the home server
Forwarded tcp/8123 on GigabitEthernet1 -> 02:00:00:00:00:10 (home-server).
Applied to the running configuration and verified, but NOT saved.
A reboot discards it. Backup taken before the change:
~/Library/Application Support/keenetic-mcp/backups/β¦txt
> install mc on the router and enable it in cron (with --ssh)
$ opkg install mc
Package mc (4.8.30-1) installed. 41 KB free on /opt.
Wrote /opt/etc/crontab (backup at /opt/etc/crontab.bak-2026-10-18Tβ¦),
md5 verified.β‘ Quick Start
Requirements
Node.js β₯ 20 on the machine that will run the server (your PC, a NAS, a Raspberry Pi β anything on the same LAN as the router)
A Keenetic router on KeeneticOS 5.x (4.x works too, the tool set adapts)
Any MCP client: Claude Code, Codex, Cursor, Claude Desktopβ¦
π¦ Install
git clone https://github.com/ML-senior/keenetic-mcp.git
cd keenetic-mcp
npm install
npm run buildThen run the setup wizard β it finds your router from the default gateway, confirms it really is a Keenetic, checks the password, and stores the password in your operating system keychain (only the address and login go in a settings file):
node dist/index.js initConnect your MCP client
Claude Code
claude mcp add keenetic -- node /path/to/keenetic-mcp/dist/index.jsCursor / Claude Desktop / anything else β add to the MCP config:
{
"mcpServers": {
"keenetic": {
"command": "node",
"args": ["/path/to/keenetic-mcp/dist/index.js"]
}
}
}With SSH/Entware access (see SSH & Entware):
{
"mcpServers": {
"keenetic": {
"command": "node",
"args": ["/path/to/keenetic-mcp/dist/index.js", "--ssh"]
}
}
}Verify it's working
Ask your agent:
> what router do I have, and is the internet up?You should see your model, firmware and the reachability checks. π
βοΈ Configuration
Configuration resolves in this order: environment variable β CLI flag β
stored config (written by init).
Variable | Flag | Default | Purpose |
|
| (wizard finds it) | Router address |
| β |
| Router login |
| β | (keychain) | Router password |
β |
| off | Never register the write tools |
|
|
| Which tools to advertise: |
| β | β | Web UI moved off 80? Put the port in the host: |
β |
|
| Cap on any tool response |
|
| off (on if set up in | Enable the SSH/Entware tools; |
|
|
| Entware dropbear port. |
| β |
| SSH user |
| β | (keychain) | SSH password. The router password is reused only when the SSH user is the router login |
|
| β | Private key file instead of a password ( |
| β | (keychain) | Passphrase for that key |
| β | per-OS state dir | Where backups live |
Environment variables are what you want in a container. The wizard reads passwords from the terminal; nothing ever lands in a log or a tool response.
πͺΆ Fewer tools, fewer tokens
Every request an agent makes carries the description of every tool it can see. All 44 cost about 8k tokens per request; most agents need a fraction:
| Tools | β tokens | For |
| 44 | 7 900 | interactive work with everything at hand |
| 15 | 2 700 | devices, Wi-Fi, port forwarding, KeenDNS, save, log |
| 24 | 3 500 | monitoring and diagnostics; nothing can change |
| 9 | 1 600 | Entware work over SSH (needs SSH enabled) |
Mix them: --tools core,ssh_check,list_*. --read-only still wins, so
--tools core --read-only gives the core read tools only. A bot that only
reports status is best served by --tools read.
{ "command": "node", "args": ["/path/to/keenetic-mcp/dist/index.js", "--tools", "core"],
"env": { "KEENETIC_HOST": "192.168.1.1:8080", "KEENETIC_PASSWORD": "β¦" } }π Full tool reference
44 tools. Read tools are always available; write tools hide in
--read-only mode; SSH tools hide unless shell access is enabled (--ssh or
the SSH step of init) β except ssh_check, which only probes ports.
π Read
Tool | What it returns |
| every device, filtered by active/wired/wireless/blocked, sorted by traffic, name, signal or last seen |
| one device in full: lease, Wi-Fi rate, policy, schedule, traffic |
| WAN links, bridges, access points, VPN tunnels |
| one interface in full, including WireGuard peers |
| radios by band, with client counts |
| reachability, and which check failed |
| routing table, or just the default route |
| connection policies for selective routing |
| model, firmware, CPU, memory, installed components |
| unsaved changes, who changed what and when |
| every bridge, and whether the web interface lists it as a segment |
| download the configuration to a local file |
| static NAT / port forwarding rules |
| KeenDNS web-app mappings and their upstreams |
| static DNS records the router itself serves |
| fixed MAC-to-IP reservations |
| access-lists and firewall settings, parsed from the running config |
| system log, with line count and text filter |
| Mesh controller and extenders, with per-node client counts |
| USB/flash partitions, free space, what uses them |
| Entware binding: which drive, which init script |
| router-side reachability probes for its internet links; says so when no profile is actually probing |
| which SSH servers answer on the router (no login): configured port, 22, 222 and the KeeneticOS one, with advice |
| pings a host from the machine running this server |
βοΈ Change
Tool | What it does |
| rename, block or allow, assign a routing policy, schedule or priority |
| bring an interface up or down |
| remove a VPN tunnel (WireGuard, OpenVPN, β¦); refuses physical, bridge and default-route interfaces; lists the policies that lost it |
| a guest or IoT network the web interface actually lists, with Wi-Fi, DHCP and optional VPN routing |
| remove a segment and everything created with it |
| forward an external TCP/UDP port to a device, addressed by MAC (an IP of a known device is resolved; an unknown IP is refused) |
| publish or withdraw a KeenDNS web-app mapping, with HTTPS redirect and public/private access |
| static DNS records served by the router; refuses to round-robin an existing name |
| fixed MAC-to-IP reservations; refuses an IP already reserved for another MAC |
| reboot, only with |
| make pending changes survive a reboot |
π Shell (opt-in, --ssh)
Tool | What it does |
| run a shell command, get stdout, stderr and the exit code |
| read a file, e.g. an Entware config under |
| write under |
|
|
πͺ€ Escape hatch
Tool | What it does |
| any router API path at all, for whatever the tools above do not cover |
π‘οΈ The safety model
Nothing is saved unless you ask. Changes apply to the running configuration and are discarded on reboot until
save_configis called. The server never calls it on its own.A backup is taken automatically before the first change of a session. The path is in every write response.
Every change is verified. The router accepts some wrong commands silently and changes nothing, so each write is read back and compared before it is reported as successful.
Read-only mode really is read-only. With
--read-only, the write tools are not registered at all rather than registered and refusing, so the agent never sees them.SSH is a deliberate second key. It is off by default, never appears in read-only mode, refuses flash writes /
rm -rfof system paths /reboot/passwdoutright, andssh_write_fileis confined to/opt/and/tmp/with a.bakcopy and an md5 round-trip on every write.Your password goes in the system keychain, not in a config file, and never in a log or a tool response.
LAN only. No cloud, no telemetry, no outbound connection to anything but your router.
π SSH & Entware (opt-in)
The RCI API covers the router's own configuration. For everything that lives inside the router's Linux β Entware packages, their configs, service logs β enable shell access:
node dist/index.js --ssh
# or: KEENETIC_SSH=1 node dist/index.jsKeenetic has two SSH servers, and only one of them is a shell:
Server | Default port | User | What you get |
Entware dropbear | 222 |
| a Linux shell: |
KeeneticOS SSH component | 22 (often moved, e.g. 2022) | the router account | the router CLI ( |
So the defaults are 222 / root, and the router password is never handed to
root. The easiest setup is the wizard β after the router login it asks
whether to enable shell access, then for port, user, and password or key
file, logs in to check it really reached Entware, and stores the secret in
the system keychain (config.json only gets port, user and key path):
node dist/index.js initOr by environment:
KEENETIC_SSH=1 KEENETIC_SSH_PASSWORD=β¦ node dist/index.js # 222, root
KEENETIC_SSH=1 KEENETIC_SSH_KEY=~/.ssh/keenetic node dist/index.js # key auth
KEENETIC_SSH=1 KEENETIC_SSH_PORT=2222 KEENETIC_SSH_PASSWORD=β¦ node dist/index.jsNot sure which port? Ask the agent to run ssh_check: it probes the
configured port, 22, 222 and the port the KeeneticOS server is set to (read from
ip ssh), shows each banner, and says what to set. If nothing answers on 222,
dropbear is not running: opkg install dropbear and
/opt/etc/init.d/S51dropbear start.
Typical flow an agent can now drive end-to-end:
1. get_media / get_opkg_status β is the Entware drive healthy?
2. opkg_manage { action: "update" } β refresh package lists
3. opkg_manage { action: "install", package: "adguardhome" }
4. ssh_read_file / ssh_write_file β edit /opt/etc/β¦ (auto .bak + md5 check)
5. ssh_exec "/opt/etc/init.d/S99x restart" β apply
6. ssh_exec "logread" / get_log β verify from the logsπ§© Skills included
The plugin ships four skills, so the agent knows how your router behaves rather than guessing. One plugin directory serves both Claude Code and Codex: they read different manifests but share the same skills and the same server definition.
keenetic-rci teaches the router's API tree: which paths exist, which ones return 100 KB, and how to recover the exact syntax of a command from the router's own configuration.
keenetic-safe-changes teaches the change workflow: what the router's fail-safe does and does not protect against, which interfaces will cut off your own access, and why the SSH tools are a different risk class.
keenetic-segments covers building an isolated network the router will admit exists. The obvious way produces a guest network that carries traffic perfectly and never appears in the web interface, because a segment is VLAN-backed and the VLAN is the part everyone leaves out.
keenetic-troubleshoot is an ordered diagnostic playbook for "the internet is down", "Wi-Fi is bad" and "one device cannot connect".
π‘ Supported routers
RCI, the API this uses, is a standard part of KeeneticOS rather than a feature of expensive models, so this works across the range. Verified against a Keenetic Ultra (KN-1811) on KeeneticOS 5.1.3.
Models on the current 5.1 branch: Giga (KN-1010), Hero (KN-1011, KN-1012), Start and Starter (KN-1111, KN-1112, KN-1121), Air and Explorer (KN-1613, KN-1621), Extra and Carrier (KN-1713, KN-1714, KN-1721), Ultra and Titan (KN-1810, KN-1811, KN-1812). Older hardware on 4.x and earlier has RCI too; the tool set adapts to the components each router actually has.
The SSH tools work with any Keenetic running Entware with dropbear;
opkg_manage additionally needs Entware installed on a USB drive.
π¬ How it works
Keenetic routers expose RCI, a JSON mirror of their command-line tree, over
HTTP. This server speaks both of the router's authentication schemes: the
classic challenge-response (NDW2) and the three-phase NDW4 handshake introduced
in KeeneticOS 5.x β Argon2id key derivation with SCRAM-style mutual proofs,
where client and server each prove they know the password before a session is
opened. The scheme is picked from the router's WWW-Authenticate header,
exactly the way the web panel picks it, so the same build works against 4.x
and 5.x firmware. One session is kept alive across the agent's questions, and
the answers are shaped so they fit in a model's context: the raw interface
listing alone is 32 KB, and the NAT table is over 100 KB.
Shell access runs over a fresh SSH connection per command β a stateless connect sidesteps every flavour of stale-session bug a long-lived dropbear connection collects, at the cost of a handshake per command that nobody notices at agent speeds.
There is no coherent public documentation for RCI, so docs/rci-api.md is the notes taken while building this: the authentication handshake, the paths that exist, the traps, and how to recover a command's syntax from the router itself.
πΊοΈ Roadmap
Port forwarding, KeenDNS mappings, static DNS, static DHCP, firewall read
Mesh nodes, storage, OPKG status, system log, ping, safe reboot
Opt-in SSH: exec, file read/write with backup + md5 verify, opkg
show/netfilterparsed view (live firewall counters)Wi-Fi site survey and channel analysis
Traffic statistics over time (interface counters sampling)
npm publication under a scoped name
WireGuard peer management (
interface WireguardNwrite tools)
Want one of these? Open an issue.
π οΈ Development
npm install
npm test # no router required
npm run typecheck
npm run buildA checkout reports its version as 0.0.0-dev, because there is no version
written down anywhere in the sources. Put KEENETIC_MCP_VERSION in a .env at
the repository root to say otherwise; the same file can hold KEENETIC_HOST
and KEENETIC_PASSWORD so you do not have to export them. A real environment
variable always wins over that file, and an installed copy never reads one.
Tests run against sanitized fixtures captured from a real router. To refresh them, and to run a read-only smoke test against your own:
KEENETIC_HOST=β¦ KEENETIC_PASSWORD=β¦ npm run capture:fixtures
KEENETIC_TEST_HOST=β¦ KEENETIC_TEST_PASSWORD=β¦ npm run smokeFixtures are anonymized deterministically and a test scans the whole repository for anything that looks like a real MAC address, private IP or key.
Contributing
Fork the repository
Create your feature branch (
git checkout -b feature/amazing-tool)Commit your changes (
git commit -m 'Add amazing tool')Push to the branch (
git push origin feature/amazing-tool)Open a Pull Request
See CONTRIBUTING.md for details.
π Acknowledgments
Project | How it fed this one |
The original project this fork is built on: the RCI client, the safety model, the skills, the test suite | |
The on-router Entware implementation whose documented RCI write shapes (port forwarding, KeenDNS, DNS, DHCP) were ported into the TypeScript tools here | |
Prior art for the RCI authentication handshake |
π License
MIT β see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Context and control for any AI. Agent identity, scoped access, and proof across tools.
Governed personal world model and memory for your AI agent. Pair once, connect over MCP.
Connect any AI agent to 1,000+ apps and 27,000+ actions through one remote MCP server (OAuth).
Gives AI agents a public IPv6 identity, hostname, port forwarding, web fetch, team mesh. Free tier.
Related MCP Servers
- AlicenseAqualityBmaintenanceAn MCP server that lets an AI assistant manage your Keenetic router in plain language β list connected devices, pin static DHCP leases, rename devices, check WAN status, and reboot.10MIT
- AlicenseAqualityAmaintenanceEnables MCP agents to control Keenetic routers via plain language, providing network monitoring, device management, and safe configuration changes with backup and read-only options.18228 npm28MIT
- AlicenseNot gradedqualityBmaintenanceMCP server that bridges AI assistants like Claude Code to Keenetic routers, enabling natural language control of Wi-Fi, devices, VPN, and network segmentation via the router's RCI interface.228 npmMIT
- FlicenseBqualityAmaintenanceEnables AI agents to manage Keenetic routers through the same RCI API used by the router's web interface, working directly over the local network without cloud involvement. It supports reading device statuses and executing configuration changes, with confirm, dry-run, and destructive-action safeguards.23-