Skip to main content
Glama

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 --version

Create an API key

  1. In the OPNsense GUI: System → Access → Users

  2. Edit the user the server should act as (create a dedicated one — see Least privilege)

  3. Under API keys, press +. A apikey.txt downloads containing key and secret. 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.pem

Disable 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=false

Configuration

All configuration is environment-only. Credentials never appear in tool arguments, so they cannot end up in a conversation transcript.

Variable

Default

Purpose

OPNSENSE_URL

https://192.168.1.1

Base URL including scheme

OPNSENSE_API_KEY

(unset)

API key

OPNSENSE_API_SECRET

(unset)

API secret

OPNSENSE_CA_BUNDLE

(unset)

Path to a PEM file; takes precedence over VERIFY_TLS

OPNSENSE_VERIFY_TLS

true

Set false to skip verification

OPNSENSE_TIMEOUT

30

Request timeout in seconds

OPNSENSE_ALLOW_WRITE

false

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.md is 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's uv lookup.

Claude Desktop: install opnsense-mcp-0.1.1.mcpb via Settings -> Extensions. Credentials go to your OS keychain, not a config file. Build it with cp -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.sh rather 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 /mcp

Runs 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

opnsense_get_system_status

Version, uptime, load, memory, temperature, disk. Sections whose endpoint is missing are omitted rather than failing the call

opnsense_get_firmware_status

Pending updates and installed vs latest version

opnsense_list_services

Core and plugin services with running state

opnsense_control_service

write — start / stop / restart

Network

Tool

Notes

opnsense_list_interfaces

Maps config names (lan, opt2) to device names (igb0, vlan0.30). Call this first whenever a question spans rules and diagnostics

opnsense_get_interface_statistics

Cumulative counters, not rates — call twice and difference

opnsense_search_neighbors

ARP and NDP tables, family = ipv4 / ipv6 / both

opnsense_get_routes

Active routing table

opnsense_list_dhcp_leases

Kea with automatic fallback to legacy ISC

Firewall rules

Tool

Notes

opnsense_search_firewall_rules

Rules in evaluation order with action, interface, source, destination

opnsense_get_firewall_rule

Full record by UUID; enum fields flattened from OPNsense's {value, selected} form

opnsense_get_rule_statistics

Per-rule evaluations / packets / bytes / states. unused_only=true finds dead rules — but counters reset on every apply

opnsense_toggle_firewall_rule

write — stages only; nothing is live until applied

opnsense_apply_firewall_changes

write — savepoint / apply / cancel_rollback / revert

Aliases

Tool

Notes

opnsense_search_aliases

Alias configuration

opnsense_get_alias_contents

What the pf table actually holds — the two diverge when a URL table or GeoIP feed fails to refresh

opnsense_find_alias_references

What breaks if this alias changes

opnsense_update_alias_entries

write — add/remove entries; live immediately, per-entry outcomes reported

Live diagnostics

Tool

Notes

opnsense_get_firewall_log

Recent entries filtered by verdict / interface / address / port / protocol

opnsense_query_firewall_states

pf state table — what is happening now

opnsense_get_pf_statistics

State table usage, memory limits, drop counters

opnsense_kill_states

write — drop states matching an address; wildcards rejected

DNS and VPN

Tool

Notes

opnsense_get_dns_overview

Unbound service state, blocklist status, cache counters

opnsense_search_dns_queries

Recent lookups per client; needs Reporting enabled under Services → Unbound DNS

opnsense_get_vpn_status

WireGuard peers and OpenVPN sessions

Escape hatch

Tool

Notes

opnsense_api_request

Any endpoint. GET always allowed; POST needs OPNSENSE_ALLOW_WRITE and confirm=true. Use for NAT (firewall/source_nat, firewall/d_nat), traffic shaping, IDS, certificates, CrowdSec

Command names in the published API reference are snake_case; URLs use camelCase. get_interface_namesgetInterfaceNames.

Resources

  • opnsense://interfaces — the interface map as JSON

  • opnsense://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 permanent

Skipping 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

TLS verification failed

Self-signed WebGUI cert. Set OPNSENSE_CA_BUNDLE or OPNSENSE_VERIFY_TLS=false

HTTP 401/403 on everything

Wrong key/secret, or the key's user has no API access

HTTP 403 on one endpoint only

Missing ACL for that page. Check Effective Privileges

HTTP 404 on an endpoint

Plugin not installed, or this OPNsense release predates it

Returned HTML instead of JSON

OPNSENSE_URL points somewhere that is not the API

Read timeout

Large state tables and log queries are slow. Lower limit or raise OPNSENSE_TIMEOUT

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 -q

Twenty-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 abstract leases controller, so the concrete v4 controller name is an inference

  • dhcpv4/leases/searchLease (ISC fallback) and openvpn/service/searchSessions

  • Request body key shapes: alias_util add/delete (address), killStates (filter), findReferences (alias)

  • diagnostics/firewall/log server-side filter parameters — rather than guess, the tool fetches a window and filters locally, which is why it reports window_size and 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.

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

View all related MCP servers

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.

View all MCP Connectors

Latest Blog Posts

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