191 lines
6.6 KiB
Markdown
191 lines
6.6 KiB
Markdown
# 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
|
|
|
|
- **77+ tools** covering system status, interfaces, firewall rules, aliases, NAT, DHCP, diagnostics, routing, VPN (OpenVPN/IPsec/WireGuard), and DNS resolver
|
|
- **Multi-firewall**: connect to many pfSense boxes dynamically via `pfsense_connect(url, api_key)` — no static firewall in config required
|
|
- **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
|
|
|
|
No static firewall URL/key required — credentials are provided at runtime via `pfsense_connect`.
|
|
|
|
```yaml
|
|
mcp_servers:
|
|
pfsense:
|
|
command: /usr/local/lib/hermes-agent/venv/bin/pfsense-mcp
|
|
timeout: 120
|
|
enabled: true
|
|
env:
|
|
PFSENSE_VERIFY_SSL: "false"
|
|
PFSENSE_ALLOW_WRITES: "false"
|
|
```
|
|
|
|
Then `hermes gateway restart`. Connect to a firewall in chat:
|
|
|
|
```text
|
|
pfsense_connect(url="https://10.77.50.1", api_key="...", name="branch-office")
|
|
pfsense_test_connection()
|
|
pfsense_list_firewall_rules()
|
|
```
|
|
|
|
### Multi-firewall workflow
|
|
|
|
```text
|
|
# Register firewalls (name optional — defaults from IP/hostname)
|
|
pfsense_connect("https://10.77.50.1", "key-a", name="hq")
|
|
pfsense_connect("https://10.77.60.1", "key-b", name="branch")
|
|
|
|
# List and switch
|
|
pfsense_list_targets()
|
|
pfsense_use_target("branch")
|
|
|
|
# Or pass target / inline credentials on any tool
|
|
pfsense_get_system_status(target="hq")
|
|
pfsense_get_gateway_status(url="https://10.77.60.1", api_key="key-b")
|
|
```
|
|
|
|
| Tool | Purpose |
|
|
|------|---------|
|
|
| `pfsense_connect` | Register + activate a firewall (url, api_key, name) |
|
|
| `pfsense_use_target` | Switch active firewall |
|
|
| `pfsense_list_targets` | List registered firewalls |
|
|
| `pfsense_get_active_target` | Show current active target |
|
|
| `pfsense_disconnect_target` | Remove a registered target |
|
|
|
|
Optional env defaults (`PFSENSE_URL`, `PFSENSE_API_KEY`) still work as a fallback when no target is connected.
|
|
|
|
### 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
|