A first real job for an MCP gateway: review your OPNsense cluster
Most people meet MCP the same way: you wire up a gateway, you watch a model call a tool, it works, and then comes the awkward pause. It can reach your systems now. What do you actually do with that?
Here is a good first job, because it needs no automation, changes nothing, and produces something you can act on the same afternoon: ask an agent what is wrong with your firewall.
We did it on a live OPNsense HA pair — two boxes that are supposed to be identical and that nobody had diffed field by field in a long time.
That is all of it. No script to write, no field mapping, no pipeline to maintain.
What it takes
Section titled “What it takes”Each firewall is one backend on the gateway, described by a single YAML file that says what the OPNsense API offers — that description is DADL, and it turns into the tools the agent can call. There is no MCP server to write and nothing to install on the firewall itself. The API key lives in the gateway, not in your chat client.
The agent then works in Code Mode: instead of a tool call per question, it writes a short script that runs in the gateway’s sandbox, queries what it needs and returns only its own result. That matters more than it sounds, because only what the script returns ever reaches the model. One firmware endpoint answers with roughly 330 KB — nine hundred packages and a changelog — for the simple question “which plugins are installed here?”. In the sandbox that collapses to five names.
Cost of the whole thing: eight minutes, no SSH session, nothing changed. One caveat worth stating plainly: our key had full access and the agent simply never called anything but read tools. That is a choice, not a guarantee. Every tool in the description carries an access level, so the gateway can expose only the reading ones — for a review, that is the setup to prefer.
What came back
Section titled “What came back”The first result is the boring one, and it is the one you want: the rule sets match. 27 user rules per node, compared field by field — action, interface, direction, protocol, source and destination including negation, ports, logging, gateway, ordering — with zero deviations. Same for the 23 aliases, the NAT rules, the users. Both nodes carry comparable state tables, which is what working state replication looks like; whether a failover actually preserves sessions is something only a failover tells you. 70 virtual IPs, every one of them master on one node and backup on the other, with no address claimed twice.
Then the interesting part.
- A TLS certificate that expired on 3 August 2019 and is still flagged as in use. An ACME client is installed, and the certificate store holds nothing it ever issued.
- A different MTU on the same uplink — one node is set to 1456, the other to 1500. Nothing is wrong today. The difference only becomes visible the day the second node takes over, as the class of path-MTU problem that takes an afternoon to track down.
- Automatic firmware updates at 04:00 — on both cluster nodes. Same job, same time, no offset. Both boxes can therefore pull the same update in the same night, which is the one thing a pair exists to avoid.
- An orphaned test address on one node, described as temporary, bound to that machine’s hardware address and following no failover role.
- Log settings drifting apart: both nodes forward to the same collector, but with different verbosity and different message formats. Whatever parses those logs sees something else after a failover.
- Three accounts, all administrators, no second factor, no source-network restriction on the admin group.
None of this is exotic. It is the sediment every long-lived firewall collects: something set once during a migration, a test that was never cleaned up, a default nobody revisited. It is exactly the sort of thing that is boring to look for and unpleasant to discover during an incident.
Two things to know before you trust a report
Section titled “Two things to know before you trust a report”A review by an agent is still a review, and the same two rules apply as with a human one.
Verify before you act. Findings arrive well formatted and confidently worded, and that formatting is independent of whether they are true. In our first run, the report stated that logs exist only on the boxes and are never shipped anywhere. They are, and always were — the answer sat in a part of an API response the agent had already fetched and had not read to the end. It was caught because somebody who knows the network read the report and objected. Treat each finding as a lead, not a verdict: the cheap version is to check the one screen in the web UI that the finding points at.
Nothing found does not mean nothing is there. This is the half people forget. We ran the review a second time with a stricter brief; that run cleared up the logging question and found several things the first had missed — but it never looked at disk usage at all, and so it never mentioned that one node’s log partition is nearly full. Not an error, not a wrong claim: a place nobody pointed the flashlight.
The practical consequence is small. Ask the report to state its own coverage — which tools it called, and which areas it skipped and why — and read that before the findings. An agent cannot reliably list everything it failed to think of, but it can tell you exactly what it touched, and the gap between that and your estate is the part you still own.
What this does not replace
Section titled “What this does not replace”It is not a penetration test and not a compliance audit. It sees what the API exposes, which is a lot but not everything — whether a certificate is actually being served on the wire is a question you answer with a TLS connection, not with a config flag. And it is a snapshot: it tells you the two nodes differ today, not since when.
What it does replace is the tedious comparison that never makes it into anyone’s week.
Try it on your own pair
Section titled “Try it on your own pair”The OPNsense connector is one YAML file describing the API, behind an Apache-2.0 gateway you run yourself: DADL and ToolMesh. Add both firewalls as backends, create an API key on each, and paste the brief from the top of this post. Then check the first finding by hand before you change anything.
The same brief works against a NetBox that has drifted from reality, an alerting stack full of rules nobody has read in two years, a switch estate, a ticket queue — anything with an API and a description file in front of it. This post is the first of a series that will work through those one at a time, and a follow-up goes a level deeper into wording the brief so the findings hold up.
Questions, corrections and war stories are welcome in GitHub Discussions; if you would rather have this run as a managed instance, we are at [email protected].