REGENT
MCP server that lets an AI configure your OpenWrt router. You say what the network should do — "give everyone on the cable and Wi-Fi internet" — and it works out which uci and ubus commands that takes, in which order, and which service has to be reloaded before any of it takes effect
[!IMPORTANT]
Nothing changes by default. Until
OPENWRT_ENABLE_WRITE=1is set, every tool that writes is refused and only reading works. Rebooting, flashing, and resetting ask for more than that: each of those calls has to carry its own confirmation. The server opens no network ports — the MCP client starts it and talks to it over stdin and stdout
[!CAUTION]
Disclaimer: This project is provided under the MIT License and hands an AI root access to a live router. A model can misread an instruction, and the safeguards here — the write gate, the confirmations, the rollback timer — reduce that risk without removing it. A bad change can cut your connection, take the network down, or leave a device that needs a physical reset or a reflash to recover. Take a backup first, keep physical access to the router, and never point this at something you cannot afford to lose. The author disclaims all liability for any damage, downtime, or data loss. By using this software you take full responsibility for what it does to your equipment
🔍 Example
The router this was built against stopped passing traffic, and nothing in the web interface looked wrong. Four separate faults were causing it, none of them visible on the page where it was configured.
One call to routerTopology names all four and says what each one breaks:
UPLINK wwan via phy1-sta0, 192.168.1.4/24, gateway 192.168.1.1
SERVES lan 192.168.1.1/24 DHCP OFF
AP HomeNet 2.4 GHz → wwan2
WARNINGS 4
! lan (192.168.1.0/24) is on the same subnet as the uplink — the default
gateway resolves to this router itself and nothing routes out
! access point HomeNet is attached to 'wwan2', which is not up —
clients will associate and get no address
! dhcp is not serving lan — clients there must be configured by hand
! the uplink sits in zone lan, which does not masquerade — replies to
clients have nowhere to return to
- Any one of the four is enough to stop traffic - together they took an afternoon to find by hand, because a router in this state reports itself as healthy
routerShareUplinkrepairs all four in one call - it puts the changes in an order that keeps the router reachable while they are applied, gives a reason for each one, and arms a rollback timer first, in case the repair cuts the connection it is travelling over
🚀 Key Features
- 🩺 A Diagnosis, Not a Dump -
routerTopologyreads the whole configuration in one pass and reports what is broken and why that stops traffic, rather than handing back a listing for you to interpret - 🧠 Whole Recipes, Not Single Commands - "share the uplink with clients" is six changes across three config files, and the wrong order locks you out partway through. That recipe lives in the server, so the model does not have to reassemble it correctly every time
- ⏱️ Insurance Against Lockout - You reach the router through the network the router provides, so a bad change can take away the means of undoing it. Before a risky change the config files are copied aside and a restore is scheduled on the device itself. If the router still answers afterwards the restore is canceled; if it does not, the restore runs and the old settings come back
- 🔒 Three Levels of Access - Reading always works. Changing anything needs the write gate open. Rebooting, flashing, and resetting need the gate and a separate confirmation on each individual call
- 🔑 Secrets Stay In - The router returns Wi-Fi passwords, VPN keys, and subscription links in clear text. They are stripped before anything is sent back to the model, and before anything is written to the command log or read out of the system log
- 📡 Routed Client Mode - Built for the case where the OpenWrt box has no wire of its own: it joins somebody else's router over Wi-Fi as a client, then serves its own LAN and Wi-Fi behind NAT, adding the VPN and ad-blocking that the upstream cannot provide
- 🧪 Testable Without Hardware - Command building and output parsing are pure functions, so all 457 tests run against a fake SSH transport. The fixtures they run on are output copied verbatim from a live router, including while it was broken
🛠️ Using
You never launch the server yourself. The MCP client spawns it, talks to it over stdin and stdout, and shuts it down on exit, so it only has to be registered once. Nothing needs installing first — uvx fetches the package on the first run. After that you describe what you want in ordinary words
-
Register with the client - add this to wherever that client keeps its MCP configuration
{ "mcpServers": { "regent": { "command": "uvx", "args": ["regent-mcp"] } } }
-
Point it at the router - create a
.envin the configuration directory for your systemWindows %APPDATA%\regent\.envLinux, macOS ~/.config/regent/.envOPENWRT_HOST=192.168.1.1
That address is the only required line, since every other setting already holds what a stock OpenWrt answers on
Setting Default OPENWRT_HOSTrequired — the router's address OPENWRT_USERrootOPENWRT_PORT22OPENWRT_KEYthe file named keybeside this.envOPENWRT_ENABLE_WRITEunset, so nothing can be changed OPENWRT_TIMEOUT30seconds per commandOPENWRT_ROLLBACK_DELAY90seconds before an unconfirmed change reverts -
Give it a key of its own - generate it next to that
.env, never reusing a personal onessh-keygen -t ed25519 -f key -N "" -C "regent"
-
Authorize the key on the router - this sends the public half over and appends it in one go. A stock OpenWrt still accepts a password, which is what gets you in the first time
ssh root@192.168.1.1 "mkdir -p /etc/dropbear; cat >> /etc/dropbear/authorized_keys; chmod 600 /etc/dropbear/authorized_keys" < key.pub
Settings are read once when the server starts, so restart the client after editing .env
What is available depends on what you have allowed:
- Read only - Works immediately, nothing to configure
- Change settings - Add
OPENWRT_ENABLE_WRITE=1to.env - Reboot, flash, reset, restore a backup - Needs explicit confirmation on the call as well
🧰 Tools
| Area | Tools |
|---|---|
| Orientation | routerTopology — what the router does and what is wrong with it |
| Changes | routerApplyUci — any change under the watchdog, with a dry run |
| Backups | routerBackups, routerBackupCreate, routerBackupInspect, routerBackupRestore |
| System | routerSystemInfo, routerExec, routerReboot, routerFactoryReset, routerFirmwareUpgrade |
| Network | routerInterfaces, routerDhcpLeases, routerClients |
| Wi-Fi | routerWireless, routerWirelessClients |
| Firewall | routerFirewallZones, routerFirewallRuleset |
| Services | routerServices, routerServiceControl |
| Packages | routerPackages, routerFindPackage, routerInstallPackage, routerRemovePackage |
| Diagnostics | routerLog, routerPing, routerResolve |
| Ads and Trackers | routerAdblockStatus, routerAdblockSources, routerAdblockConfigure, routerAdblockStorage, routerAdblockUseStorage |
| VPN | routerVpnStatus, routerVpnProbeNode |
| Intents | routerJoinUpstreamWifi, routerPlanShareUplink, routerShareUplink |
These cover what gets asked for most, but they do not have to cover everything. routerExec runs an arbitrary command on the router, so a request nobody anticipated still has a way through — it just gives up the guardrails the dedicated tools provide
[!TIP]
Leave
OPENWRT_ROLLBACK_DELAYalone unless you know why you are changing it. It is how many seconds the router waits before undoing a change nobody confirmed, 90 by default, and it is your safety net for when the AI reconfigures the very interface you are connected through
[!WARNING]
Confirmed on one device so far — a TP-Link Archer C59 running OpenWrt 23.05.4. Every parser was checked against what that router prints, including while it was broken. That proves they match its output, not that the output is universal. Package handling will not work on OpenWrt 24.10, where
opkgbecameapk
🔨 Develop
🔧 Requirements
- Python 3.10+
- Essential packages
fastmcp asyncssh python-dotenv typing-extensions pytest pytest-asyncio
⚡️ Quick Setup Guide
- Clone & Open Project
git clone https://github.com/m-o-z-z-i-x/REGENT.git cd REGENT code .
- Set Up Virtual Environment
- In VS Code
- Open terminal (
Ctrl+~) - Run
python -m venv .venv
- Open terminal (
- Restart the terminal so
.venvactivates itself
- In VS Code
- Install Dependencies
pip install -e ".[dev]"
- Generate an SSH Key (one per router — never reuse a personal key)
ssh-keygen -t ed25519 -f keys/key -N "" -C "regent"
- Run the Tests (no router needed)
pytest -q - Try It Against a Real Router - copy
.env.exampleto.env, fill in the address, then point a client at the checkout instead of atuvx, so every edit is live without rebuilding{ "mcpServers": { "regent": { "command": "<project>/.venv/Scripts/python.exe", "args": ["-m", "regent.server"] } } }
A checkout keeps .env, keys/ and logs/ beside the code and prefers them over the configuration directory, so working on the project never reads or writes an installed copy's settings
[!TIP]
Settings are read once at startup, so the MCP client has to be restarted after editing
.envor the code..envcarries everything needed to reach the router — address, user, port, key. The two tunables that do not vary between routers, the command timeout and the rollback delay, sit inregent/config.py, where an environment variable can still override either of them
🌟 Future Roadmap
Done
- Core over SSH - One reused session, with command building and parsing kept apart from it
- Risk Tiers - Read, write, and destructive, each with its own explicit permission
- Watchdog Rollback - Survives the SSH session dying, because that is what it insures against
- Reading the State - Network, Wi-Fi, firewall, packages, diagnostics
- Topology Analysis - With the common faults named, rather than a plain dump
- Safe Arbitrary Changes - Snapshot, rollback, and a reload of whichever service owns the config
- Ad Blocking - Weighed against the router's free memory before it is applied
- VPN - PassWall status and the four faults that make it look like it is working
- Composite Intents - Joining an upstream network and sharing it with clients
- Backups - Create, inspect, and restore the configuration
Planned improvements
- apk Support - Package handling on OpenWrt 24.10 and newer
- Other Devices - Only the Archer C59 is confirmed so far
- Guest Network - A separate isolated Wi-Fi in one call
Suggestions? Open an Issue to discuss new features!
🤝 Contribution
Contributions are welcome! Here's how to help improve the project
- Fork the repository
- Create a feature branch
git checkout -b feature/your-feature-name
- Commit your changes
git commit -m "Add: your feature description"
- Push to your fork
git push origin feature/your-feature-name
- Open a Pull Request to the main branch of this repository
🔗 Acknowledgments
This project would not be possible without these amazing open-source contributions
- OpenWrt - the firmware, and the UCI/ubus interfaces this server drives
- FastMCP by Prefect — the MCP server framework
- AsyncSSH by Ron Frederick — pure-Python asyncio SSH
📈 Repo Activity
🙏 Support
⭐ Love this project? Give it a star!
If you find this tool helpful and want to support its development — consider buying me a coffee!
UQBZVRZFeZI4CepVq_OF5_KiQ_oo62SzmWlGvppfGuyRqUSE
Bitcoin:
bc1qunr4lkes5xdanln8j5l0gm6e7x0kfw2e6z4yve
Monero:
89vPf9GUBdFXmpEhFiBSiQMQbAeWZYCGDZBfr6e45zpNVUQ8cMnYFc8ct5FH3TJvftSbKTgkHzkiPB9QoYKhNhBdLeWvesC
USDT (TRC20):
TCKL4YBLAFEHFesUuGBiB85aywNE38zVSQ
📬 Contacts
All my contact links are available here
📝 License
This project is licensed under the MIT License
Metadata
Release files for regent-mcp 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| regent_mcp-1.0.0.tar.gz | 74.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| regent_mcp-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 131.1 kB
Release files / regent_mcp-1.0.0.tar.gz
| Download URL | regent_mcp-1.0.0.tar.gz |
|---|---|
| Size | 74.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e9eefaa39e7014b24986e7bfb80eff32407787732bd646b2d8b5f437da4e6e41
|
|
BLAKE2b-256 checksum How to use checksums |
ff447dd30b89c0681a1d24a0a6222d1396b7d3b729c1112f1f01b19b5505cc29
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 28, 2026.
Transparency logRelease files / regent_mcp-1.0.0-py3-none-any.whl
| Download URL | regent_mcp-1.0.0-py3-none-any.whl |
|---|---|
| Size | 57.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3b121ff39c220a32e3e2e2d4ed0254adf550d76e9d3087380fd70fdf13d77737
|
|
BLAKE2b-256 checksum How to use checksums |
39cf2fa3ab509017d8226d8f481aa3c8f2722e77d5af710a5a44ce0e54439dd8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 28, 2026.
Transparency log