opnsense-mcp
Provides tools to manage firewall rules, view network interfaces, manage DHCP leases, and monitor system status on an OPNsense firewall.
Click on "Install 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., "@opnsense-mcpShow me the active DHCP leases"
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.
opnsense-mcp
An MCP server for the OPNsense firewall REST API. It gives an LLM structured, paginated access to rules, aliases, live pf state, logs, interfaces, DNS and VPN status — and keeps every write behind an explicit gate.
Built for a firewall at https://192.168.1.1, but the address is configuration,
not a constant.
Requirements
Python 3.11+
Network reachability to the OPNsense WebGUI port
An OPNsense API key pair
Related MCP server: coreyhines/opnsense-mcp
Install
git clone <this repo> opnsense-mcp && cd opnsense-mcp
python3 -m venv .venv && . .venv/bin/activate
pip install -e .Verify the package loads before wiring it into a client:
opnsense-mcp --versionCreate an API key
In the OPNsense GUI: System → Access → Users
Edit the user the server should act as (create a dedicated one — see Least privilege)
Under API keys, press +. A
apikey.txtdownloads containingkeyandsecret. It is shown once.
TLS
OPNsense ships a self-signed WebGUI certificate, so plain verification fails out of the box. Two options, in order of preference:
Pin the firewall's certificate. Export it from System → Trust → Certificates and point at the PEM file:
export OPNSENSE_CA_BUNDLE=/etc/ssl/opnsense.pemDisable verification. Works, but the API key travels over a path anyone in the middle can read. Acceptable on a trusted management segment; not otherwise:
export OPNSENSE_VERIFY_TLS=falseConfiguration
All configuration is environment-only. Credentials never appear in tool arguments, so they cannot end up in a conversation transcript.
Variable | Default | Purpose |
|
| Base URL including scheme |
| (unset) | API key |
| (unset) | API secret |
| (unset) | Path to a PEM file; takes precedence over |
|
| Set |
|
| Request timeout in seconds |
|
| Master switch for every write tool |
.env.example has the same set with commentary.
On startup the server prints its resolved configuration to stderr (never stdout — stdio transport uses stdout for the protocol itself) and warns about missing credentials, disabled TLS verification, and enabled writes.
Wiring it into a client
Hand it to an agent:
docs/AGENT-SETUP-PROMPT.mdis a paste-ready prompt that does the whole Windows setup with verification gates.Windows: see
docs/WINDOWS.md— Claude Desktop does not inherit your shell PATH, which breaks the bundle'suvlookup.Claude Desktop: install
opnsense-mcp-0.1.1.mcpbvia Settings -> Extensions. Credentials go to your OS keychain, not a config file. Build it withcp -r opnsense_mcp mcpb/ && npx @anthropic-ai/mcpb pack mcpb.Full walkthrough for every surface, including why claude.ai remote connectors are the wrong choice here:
docs/CONNECTING.md.Use
scripts/opnsense-mcp-env.shrather than putting the API secret directly in client config — both Claude Code and Claude Desktop store those values in plaintext.
stdio (Claude Desktop, Claude Code)
{
"mcpServers": {
"opnsense": {
"command": "/path/to/opnsense-mcp/.venv/bin/opnsense-mcp",
"env": {
"OPNSENSE_URL": "https://192.168.1.1",
"OPNSENSE_API_KEY": "…",
"OPNSENSE_API_SECRET": "…",
"OPNSENSE_CA_BUNDLE": "/etc/ssl/opnsense.pem"
}
}
}
}Streamable HTTP (OpenWebUI and other remote clients)
opnsense-mcp --transport streamable-http --host 127.0.0.1 --port 8000 --path /mcpRuns stateless with JSON responses, which is the simpler thing to put behind a proxy. It binds to loopback by default and warns loudly if you bind wider: the server itself has no authentication, so anything that can reach the port can drive your firewall API. For remote access, terminate auth in a reverse proxy in front of it, or reach it over Tailscale/WireGuard rather than exposing the port.
Tools
Twenty-six tools, all prefixed opnsense_. Every collection tool takes limit,
offset and response_format (markdown for reading, json for chaining values
into a follow-up call) and returns total / count / has_more / next_offset.
System
Tool | Notes |
| Version, uptime, load, memory, temperature, disk. Sections whose endpoint is missing are omitted rather than failing the call |
| Pending updates and installed vs latest version |
| Core and plugin services with running state |
| write — start / stop / restart |
Network
Tool | Notes |
| Maps config names ( |
| Cumulative counters, not rates — call twice and difference |
| ARP and NDP tables, |
| Active routing table |
| Kea with automatic fallback to legacy ISC |
Firewall rules
Tool | Notes |
| Rules in evaluation order with action, interface, source, destination |
| Full record by UUID; enum fields flattened from OPNsense's |
| Per-rule evaluations / packets / bytes / states. |
| write — stages only; nothing is live until applied |
| write — savepoint / apply / cancel_rollback / revert |
Aliases
Tool | Notes |
| Alias configuration |
| What the pf table actually holds — the two diverge when a URL table or GeoIP feed fails to refresh |
| What breaks if this alias changes |
| write — add/remove entries; live immediately, per-entry outcomes reported |
Live diagnostics
Tool | Notes |
| Recent entries filtered by verdict / interface / address / port / protocol |
| pf state table — what is happening now |
| State table usage, memory limits, drop counters |
| write — drop states matching an address; wildcards rejected |
DNS and VPN
Tool | Notes |
| Unbound service state, blocklist status, cache counters |
| Recent lookups per client; needs Reporting enabled under Services → Unbound DNS |
| WireGuard peers and OpenVPN sessions |
Escape hatch
Tool | Notes |
| Any endpoint. GET always allowed; POST needs |
Command names in the published API reference are snake_case; URLs use camelCase.
get_interface_names → getInterfaceNames.
Resources
opnsense://interfaces— the interface map as JSONopnsense://aliases— all configured aliases
Safety model
Three layers, because a firewall is the one box where a bad automated change can remove your ability to fix it.
1. Writes fail closed. With OPNSENSE_ALLOW_WRITE unset, every write tool
returns an explanation of how to enable it and issues no HTTP request at all. There
is a test asserting zero requests reach the firewall in that state.
2. Rule changes go through savepoints. OPNsense's savepoint mechanism applies a
change with a 60-second dead-man's switch: if nobody confirms, the firewall reverts
itself. opnsense_apply_firewall_changes wraps it and each response states the next
step:
1. mode='savepoint' → returns a revision
2. make changes → e.g. toggle a rule
3. mode='apply', revision=<from step 1> → 60s auto-revert armed
4. verify you can still reach the firewall
5. mode='cancel_rollback', same revision → change becomes permanentSkipping step 5 is safe. Skipping step 1 is not: an apply with no savepoint cannot be undone remotely.
3. Some endpoints are refused outright, regardless of the write flag: reboot,
halt, factory reset, config revert, snapshot activation, user account changes. Those
need a human who can reach the console. opnsense_kill_states additionally rejects
wildcard filters, so flushing the entire state table is not reachable by accident.
Note the asymmetry that is not a bug: alias edits and state kills are live immediately with no savepoint, because that is how OPNsense implements them. The tool descriptions say so. Blocking an address by adding it to an alias is the fast path; it is also the one with no undo.
Least privilege
Create a dedicated user for the API key rather than reusing an admin account. Grant only the pages the tools you actually want need, then check the result under System → Access → Users → (user) → Effective Privileges.
A useful signal when tuning this: a 403 on one endpoint while other calls succeed
always means a missing privilege, never bad credentials. The error messages say this
explicitly so an agent stops trying to re-authenticate.
Troubleshooting
Symptom | Cause |
| Self-signed WebGUI cert. Set |
| Wrong key/secret, or the key's user has no API access |
| Missing ACL for that page. Check Effective Privileges |
| Plugin not installed, or this OPNsense release predates it |
Returned HTML instead of JSON |
|
Read timeout | Large state tables and log queries are slow. Lower |
Firewall log returns nothing | Only rules with logging enabled produce entries. Absence is not evidence of a block |
DNS query search is empty | Reporting is off under Services → Unbound DNS → Reporting |
Alias contents empty | An alias is only loaded into pf when an enabled rule references it |
Tests
pip install -e ".[dev]"
pytest -qTwenty-two tests run against mocked HTTP (respx) — no firewall required. They cover
the parts that are expensive to debug live: grid pagination arithmetic including the
unaligned-offset page stitch, the write gate, endpoint refusal, path-traversal
rejection, error translation, and graceful degradation when one section of a
multi-endpoint call fails.
Known gaps
Endpoint paths taken from the published OPNsense API reference are solid. The following were inferred and should be confirmed on first run against a live firewall — each has a specific reason it could differ:
kea/leases4/search— the reference documents only the abstractleasescontroller, so the concrete v4 controller name is an inferencedhcpv4/leases/searchLease(ISC fallback) andopenvpn/service/searchSessionsRequest body key shapes:
alias_util add/delete(address),killStates(filter),findReferences(alias)diagnostics/firewall/logserver-side filter parameters — rather than guess, the tool fetches a window and filters locally, which is why it reportswindow_sizeand warns when a narrow filter over a busy firewall returns nothing
Two tools already degrade rather than fail: DHCP leases falls back Kea → ISC, and alias references falls back from the API endpoint to a filter-rule scan, labelling its own reduced coverage in the output.
Not yet wrapped, reachable via opnsense_api_request: NAT rules, traffic shaping,
IDS/Suricata, captive portal, certificates, CrowdSec and other plugin endpoints.
See evaluation.xml for the evaluation harness and what needs filling in.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-quality-maintenanceEnables interaction with Firewalla network security devices for network monitoring, device management, traffic analysis, and security rule configuration through MCP tools.
- AlicenseAqualityAmaintenanceOPNsense firewall operations via API & mcp. Query ARP, DHCP, firewall rules, logs, interfaces, system status, and packet capture via STDIO or SSE.199MIT
- AlicenseAqualityDmaintenanceA secure MCP server for managing OPNsense firewalls through AI assistants. Provides 81 tools across system, firewall, network, DNS, DHCP, VPN, HAProxy, services, diagnostics, and security domains.8110MIT
- Alicense-qualityAmaintenanceEnables AI clients to manage OPNsense firewall, interfaces, DHCP, DNS, routes, and services via natural language through 42 MCP tools.MIT
Related MCP Connectors
Tailscale device, route, DNS, key, user, and ACL management over MCP and CLI.
Crypto transaction firewall and risk tools for MCP agents.
MCP server for Pentest-Tools.com: run scans, manage findings and reports via your preffered LLM.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/aesaganda/opnsense-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server