# pfSense MCP Model Context Protocol server for [pfSense](https://www.pfsense.org/) firewall management via the [REST API v2 package](https://pfrest.org/) (`pfSense-pkg-RESTAPI`). Sibling project to `opnsense-mcp` with the same safety model. ## Features - **55+ tools** covering system status, interfaces, firewall rules, aliases, NAT, DHCP, diagnostics, routing, VPN (OpenVPN/IPsec/WireGuard), and DNS resolver - **Safety guardrails**: writes disabled by default, dry-run mode, WAN any/any rule blocking, required description prefix - **Audit logging**: all mutations logged to JSONL - **`apply` control**: write tools accept `apply=true` to apply immediately, or batch changes and call the apply tool ## Prerequisites pfSense does not ship a REST API. Install the free **REST API v2 package** on the firewall first: ```sh # On the pfSense shell (adjust version to your pfSense release — see pfrest.org) pkg-static add https://github.com/jaredhendrickson13/pfsense-api/releases/latest/download/pfSense-2.8.0-pkg-RESTAPI.pkg ``` Then in the web UI: **System → REST API → Settings** (enable), and **System → REST API → Keys** to generate an API key. ## Quick Start ### 1. Install ```bash pip install -e /path/to/pfsense-mcp ``` Or with the Hermes venv: ```bash /usr/local/lib/hermes-agent/venv/bin/pip install -e /root/projects/pfsense-mcp ``` ### 2. Configure environment ```bash cp .env.example .env ``` | Variable | Default | Description | |----------|---------|-------------| | `PFSENSE_URL` | `https://192.168.1.1` | Firewall base URL | | `PFSENSE_API_KEY` | — | REST API key (preferred) | | `PFSENSE_USERNAME` / `PFSENSE_PASSWORD` | — | Basic auth fallback | | `PFSENSE_VERIFY_SSL` | `false` | Verify TLS certificate | | `PFSENSE_ALLOW_WRITES` | `false` | Enable mutating operations | | `PFSENSE_DRY_RUN` | `false` | Log writes without executing | | `PFSENSE_REQUIRE_DESCRIPTION_PREFIX` | `mcp:` | Prefix for new firewall rules (`descr`) | | `PFSENSE_BLOCK_WAN_INBOUND_ANY` | `true` | Block WAN any→any pass rules | ### 3. Register with Hermes ```yaml mcp_servers: pfsense: command: /usr/local/lib/hermes-agent/venv/bin/pfsense-mcp timeout: 120 enabled: true env: PFSENSE_URL: "https://your-pfsense" PFSENSE_API_KEY: "your-api-key" PFSENSE_VERIFY_SSL: "false" PFSENSE_ALLOW_WRITES: "false" ``` Then `hermes mcp test pfsense` and `hermes gateway restart`. ### 4. Register with Cursor (`~/.cursor/mcp.json`) ```json { "mcpServers": { "pfsense": { "command": "pfsense-mcp", "env": { "PFSENSE_URL": "https://your-pfsense", "PFSENSE_API_KEY": "your-api-key" } } } } ``` ## Tool Categories ### Read-only (always available with valid credentials) | Tool | Description | |------|-------------| | `pfsense_test_connection` | Verify API auth and connectivity | | `pfsense_get_system_status` | CPU, memory, disk, uptime | | `pfsense_get_interface_status` | Live interface status | | `pfsense_list_firewall_rules` | Filter rules (with query filters) | | `pfsense_list_firewall_states` | Active state table | | `pfsense_list_aliases` | Firewall aliases | | `pfsense_list_port_forwards` | Destination NAT rules | | `pfsense_list_dhcp_leases` | DHCP lease table | | `pfsense_get_arp_table` | ARP / IP→MAC | | `pfsense_get_gateway_status` | Gateway health | | `pfsense_get_firewall_log` | Firewall log | | `pfsense_get_openvpn_status` | OpenVPN connected clients | | `pfsense_get_ipsec_status` | IPsec SAs | | `pfsense_list_wireguard_tunnels` | WireGuard (plugin) | | `pfsense_list_dns_host_overrides` | Local DNS records | | `pfsense_get_config_history` | Config change audit trail | ### Write operations (require `PFSENSE_ALLOW_WRITES=true`) | Tool | Description | |------|-------------| | `pfsense_add_firewall_rule` | Add filter rule (descr prefix required) | | `pfsense_toggle_firewall_rule` | Enable/disable rule | | `pfsense_apply_firewall` | Apply pending changes | | `pfsense_add_alias` / `pfsense_update_alias` | Manage aliases | | `pfsense_add_port_forward` | Add destination NAT | | `pfsense_add_dhcp_static_mapping` | DHCP reservation | | `pfsense_add_dns_host_override` | Local DNS record | | `pfsense_add_static_route` | Static route | | `pfsense_service_action` | Start/stop/restart services | | `pfsense_kill_firewall_states` | Kill states by source | | `pfsense_reboot` | Reboot (double confirm) | ### Query filtering List tools accept a `query` parameter with pfSense REST v2 query syntax: ```text query="interface=wan" exact match query="descr__contains=mcp" substring query="ip__startswith=10.77" prefix query="interface=wan,protocol=tcp" multiple conditions ``` ## Differences vs opnsense-mcp | Aspect | OPNsense | pfSense | |--------|----------|---------| | API | Built-in (`/api/module/controller/command`) | Package required (`/api/v2/...`) | | Auth | key+secret basic auth | `X-API-Key` header or basic auth | | IDs | UUIDs | Numeric ids (positional) | | Apply | Savepoint + rollback workflow | `apply=true` param or apply endpoints | | Rule description field | `description` | `descr` | ## Security Notes - Never commit API keys; use environment variables or Hermes secrets. - Start read-only (`PFSENSE_ALLOW_WRITES=false`). - Create a dedicated pfSense user + API key with minimal privileges. - Review the audit log at `PFSENSE_AUDIT_LOG_PATH`. - pfSense numeric ids shift when objects are deleted — always list immediately before mutating by id. ## License MIT