Skip to main content
Glama
shernandez47832

pfSense MCP Server

๐Ÿ›ก๏ธ pfSense MCP Server

Manage your pfSense firewall in plain English โ€” from Claude Desktop, Claude Code, or any MCP client.

332 tools across every subsystem ยท wire-format verified against the pfSense REST API ยท safety guardrails on every change

Release CI MCP 2025-11-25 pfSense API v2.10.2 Python 3.11โ€“3.13 Tests License: MIT PRs welcome


You:     Block all traffic from 203.0.113.5 on WAN
Claude:  โœ“ created block rule  โ†’  โœ“ applied changes  โ†’  rollback point: config revision 42

You:     Why can't 192.168.1.50 reach the internet?
Claude:  ran diagnostics โ†’ gateway WAN_DHCP is down, and a block rule on LAN matches this host

You:     Add a WireGuard peer for my laptop and show me the config
Claude:  โœ“ created peer on tun_wg0  โ†’  here's the client config to import

pfSense MCP Server connects Claude Desktop, Claude Code, and any other MCP client to your pfSense firewall. Ask questions, diagnose issues, and change configuration through conversation. Every destructive action needs explicit confirmation, and the server records the config revision it can be rolled back to.

Letting an AI change a production firewall is only safe if the details are right, and that's where the work went:

  • A contract-test layer checks every tool's request format against the pfSense REST API schema.

  • Every change goes through a multi-layer guardrail pipeline.

  • CI runs 661 tests on Python 3.11โ€“3.13, plus an end-to-end MCP protocol test.

Latest release: v1.1.0 ยท Changelog

TIP

Jump to theQuick Start. Setup takes about two minutes with uvx, and you don't need to clone anything. If this project is useful to you, a โญ helps others find it.

Contents

Why this exists ยท Quick start ยท What you can do ยท Safety ยท Supported versions ยท Authentication ยท Deployment ยท Configuration ยท Testing ยท MCP compliance ยท Known limitations ยท Architecture ยท Contributing

Related MCP server: magicsword-mcp

Why This Exists

Managing a pfSense firewall means clicking through web UI tabs, remembering field names, and hoping you don't fat-finger a rule that locks you out. With this MCP server, you describe what you want in plain English and the AI handles the REST API calls, validates inputs, and warns you before anything destructive happens.

What makes it different:

  • Every destructive operation requires explicit confirmation and shows you exactly what will happen

  • The config revision is captured before every high-risk change. The response gives the revision ID to restore from Diagnostics โ€บ Backup & Restore โ€บ Config History in the webGUI, or warns explicitly if no revision could be captured.

  • Rate limits on every tool that changes configuration stop a runaway AI loop from flooding your firewall

  • Positive input validation (IP/port/MAC/CIDR) plus path-traversal/XSS screening, and secrets redacted from logs and API error responses

  • Wire-format verified against the pfSense REST API v2.10.2 schema by a contract-test layer, so tools send exactly what the API expects

Quick Start

Prerequisites:

IMPORTANT

This project isnot published on PyPI. A different, unrelated project uses the PyPI name pfsense-mcp-server, so never run pip install pfsense-mcp-server. Install from Git or from the release assets as shown below.

Option A: run without cloning (uvx):

uvx --from git+https://github.com/gensecaihq/pfsense-mcp-server@v1.1.0 pfsense-mcp-server

Option B: clone for development:

git clone https://github.com/gensecaihq/pfsense-mcp-server.git
cd pfsense-mcp-server
pip install -r requirements.txt
cp .env.example .env
# Edit .env: set PFSENSE_URL, AUTH_METHOD, and credentials

Connect to Claude Desktop. Add the server to claude_desktop_config.json:

  • macOS: ~/Library/Application Support/Claude/

  • Windows: %APPDATA%\Claude\

Using the installed entry point (Option A):

{
  "mcpServers": {
    "pfsense": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/gensecaihq/pfsense-mcp-server@v1.1.0", "pfsense-mcp-server"],
      "env": {
        "PFSENSE_URL": "https://192.168.1.1",
        "AUTH_METHOD": "basic",
        "PFSENSE_USERNAME": "admin",
        "PFSENSE_PASSWORD": "your-password",
        "PFSENSE_VERSION": "CE_2_8_1",
        "PFSENSE_CA_FILE": "/path/to/pfsense-ca.pem"
      }
    }
  }
}

Or running from a clone (Option B):

{
  "mcpServers": {
    "pfsense": {
      "command": "python3",
      "args": ["-m", "src.main"],
      "cwd": "/path/to/pfsense-mcp-server",
      "env": {
        "PFSENSE_URL": "https://192.168.1.1",
        "AUTH_METHOD": "basic",
        "PFSENSE_USERNAME": "admin",
        "PFSENSE_PASSWORD": "your-password",
        "PFSENSE_VERSION": "CE_2_8_1",
        "PFSENSE_CA_FILE": "/path/to/pfsense-ca.pem"
      }
    }
  }
}

Remove PFSENSE_CA_FILE if your pfSense certificate is signed by a public CA.

About the CA file. pfSense ships with a self-signed certificate from its own CA, and Python does not read your OS trust store, so verification fails out of the box. Export the CA at System > Cert. Manager > CAs (the export-certificate icon), save the PEM anywhere readable, and point PFSENSE_CA_FILE at it. A missing or unparseable file is a startup error, never a silent downgrade.

VERIFY_SSL=false also connects, and is fine for a throwaway lab. Understand what it costs: nothing authenticates the firewall, so anything that can intercept the connection can read the API key and act as the firewall. This tool changes firewall rules โ€” treat that credential accordingly.

Start talking to your firewall. Open Claude Desktop and ask:

  • "Show me all blocked traffic in the last hour"

  • "What services are running?"

  • "Create a port forward for port 443 to 192.168.1.50"

  • "Run a full system health check"

What You Can Do

332 tools across every major pfSense subsystem:

Domain

Tools

What You Can Do

Firewall Rules

9

Create, update, delete, reorder rules. Bulk block IPs. View compiled pf ruleset.

Aliases

5

Manage host/network/port/URL aliases. Add and remove addresses.

NAT

16

Port forwards, outbound NAT, 1:1 NAT โ€” full lifecycle management.

VPN

51

OpenVPN servers and clients, IPsec tunnels, WireGuard peers โ€” CRUD, status, apply.

Routing

16

Gateways, gateway groups, static routes, default gateway management.

DNS

23

Unbound resolver and dnsmasq forwarder: host overrides, domain overrides, access lists.

DHCP

17

Leases, static mappings, address pools, custom options, server config.

Certificates

15

Certs, CAs, CRLs โ€” generate, renew, export PKCS12.

Users

12

User accounts, groups, LDAP/RADIUS auth server config.

Interfaces

14

Interface config, VLANs, bridges, groups.

System

43

Status, settings, diagnostics, state table, config history, reboot, ping.

Services

14

Start/stop/restart services. NTP, cron, SSH, service watchdog.

Logs

4

Firewall log analysis with parsed IPv4/IPv6 filterlog data. Raw tail/grep reads of the dhcpd/filter/resolver/system/auth log files.

Traffic Shaping

12

Shapers, queues, and limiters for bandwidth management.

Schedules

8

Time-based firewall rule scheduling.

Virtual IPs

5

CARP, ProxyARP, and IP Alias management.

Troubleshooting

10

Diagnose connectivity, blocked traffic, VPN, DHCP, DNS, HA. Full health report.

Packages

49

HAProxy, ACME/Let's Encrypt, BIND DNS, FreeRADIUS.

Utility

9

HATEOAS navigation, object ID management, guardrail status.

Safety First

AI managing a production firewall needs guardrails. This server has 9 layers:

"Delete firewall rule 5"

  1. CLASSIFY    โ†’ HIGH risk (destructive)
  2. ALLOWLIST   โ†’ tool is permitted
  3. SANITIZE    โ†’ parameters clean (no injection)
  4. RATE LIMIT  โ†’ under 10 deletes/minute
  5. DRY RUN?    โ†’ user can preview first
  6. CONFIRM     โ†’ blocked until confirm=True
  7. BACKUP      โ†’ config revision captured
  8. EXECUTE     โ†’ API call made
  9. AUDIT LOG   โ†’ action recorded with redacted params

Response includes:
  "config_backup": {
    "pre_change_revision_id": 42,
    "rollback_instruction": "To undo this change, restore revision 42 manually in the pfSense webGUI: Diagnostics > Backup & Restore > Config History."
  }

All 201 tools that change configuration carry a guardrail, and a test fails the build if a new one ships without it.

  • Every change tool is rate-limited, audit-logged and checked against the allowlist.

  • High-risk tools (51): deletes, disconnects, reboot, halt and bulk block are also blocked until the caller passes confirm=True.

  • manage_* tools: these require confirm=True for their remove and delete actions.

  • Secrets: passwords, keys, PSKs, bind passwords and tokens are redacted in the audit log and in echoed API error responses.

confirm=True is a parameter the MCP client sends. It is not a separate human-approval step, so keep your client's tool-approval prompts on for destructive tools.

You can also:

  • Pass dry_run=True to preview any destructive operation without running it.

  • Pass verify_descr="Allow HTTPS" to check that you're changing or deleting the rule you expect. This guards against rule IDs shifting.

  • Set MCP_READ_ONLY=true to expose only the 131 read-only tools (search, get, diagnose).

  • Set MCP_ALLOWED_TOOLS=create_firewall_rule_advanced,delete_firewall_rule to permit only the listed write tools. Read tools stay available.

See SECURITY.md for the vulnerability-disclosure policy and deployment-hardening guidance.

Supported pfSense Versions

Version

REST API package

Status

pfSense CE 2.9.0

v2.10.2 (latest)

Supported

pfSense CE 2.8.1

v2.10.2 (latest)

Verified

pfSense Plus 26.07

v2.10.2 (latest)

Supported

pfSense Plus 26.03.1

v2.10.2 (latest)

Supported

pfSense Plus 26.03

v2.10.2 (latest)

Verified

pfSense Plus 25.11.1

v2.10.2 (latest)

Supported

pfSense Plus 25.11

v2.7.3 (legacy)

Verified

pfSense CE 2.8.0

v2.7.3 (legacy)

Supported

pfSense Plus 24.11

v2.7.3 (legacy)

Supported

Requires the pfSense REST API v2 package by jaredhendrickson13. Package v2.8.x+ ships builds only for CE 2.8.1 and Plus 25.11.1/26.03/26.03.1; CE 2.9.0 and Plus 26.07 need v2.10.1+; v2.7.3 is the last release with builds for CE 2.8.0 and Plus 24.11/25.11.

Security note: run REST API package v2.10.0+. It fixes a command-injection flaw in the interface-group endpoints (GHSA-w3w4-mvcc-vmgr) and adds core command auto-escaping; v2.9.0 fixed an earlier settings-sync privilege escalation (GHSA-8q8g-9f77-8g8g).

v2.10.0 also marks OpenVPNClient.auth_pass, User.ipsecpsk, and WireGuardPeer.presharedkey as sensitive, so the API no longer returns them by default. This server still sets them normally; if a workflow needs to read one back, add a sensitive-field override in the REST API settings.

Authentication

Three methods supported (configure in .env):

Method

Config

Best For

Basic Auth

AUTH_METHOD=basic + username/password

Quick setup, local users

API Key

AUTH_METHOD=api_key + key from System > REST API > Keys

Automation, service accounts

JWT

AUTH_METHOD=jwt + username/password

Short-lived tokens, obtained and renewed automatically (assumes pfSense's default 1-hour lifetime)

Deployment Options

stdio (default) โ€” for Claude Desktop and Claude Code:

python3 -m src.main          # from a clone
pfsense-mcp-server           # via the installed console entry point (pip/uvx/pipx)

HTTP: for remote access and multi-client setups. It requires MCP_API_KEY, and the server refuses to start with an empty, placeholder or short token.

export MCP_API_KEY="$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))')"
python3 -m src.main -t streamable-http --port 3000

The HTTP transport is plain HTTP. Put it behind a TLS-terminating reverse proxy before exposing it beyond localhost.

Docker: a hardened container running the HTTP transport.

cp .env.example .env        # set PFSENSE_URL, credentials, and MCP_API_KEY
docker compose up -d

The published port binds to 127.0.0.1 by default. Set MCP_BIND_ADDR=0.0.0.0 to expose it, but only behind TLS. For a private CA, put the PEM in ./certs/ and set PFSENSE_CA_FILE=/certs/<file>.pem.

Container security:

  • Runs as a non-root user (mcp:1000).

  • Read-only filesystem, a noexec tmpfs, and no-new-privileges.

  • All Linux capabilities dropped.

The health check probes an unauthenticated /health endpoint, because /mcp requires the bearer token.

Behind an MCP gateway โ€” the HTTP transport is a spec-compliant Streamable HTTP endpoint with bearer-token auth, so it can be registered as an MCP-server target behind managed gateways such as AWS Bedrock AgentCore Gateway (use its API-key credential provider to supply the MCP_API_KEY bearer token, and add the gateway's origin to MCP_ALLOWED_ORIGINS). Such gateways add centralized OAuth/IAM in front and translate between protocol revisions, including 2026-07-28. No gateway is required โ€” this is purely an option for environments that already run one.

Configuration

Variable

Required

Default

Description

PFSENSE_URL

Yes

โ€”

pfSense URL (e.g., https://192.168.1.1)

AUTH_METHOD

api_key

api_key, basic, or jwt

PFSENSE_API_KEY

*

โ€”

REST API key

PFSENSE_USERNAME

*

โ€”

pfSense username (for basic/jwt)

PFSENSE_PASSWORD

*

โ€”

pfSense password (for basic/jwt)

PFSENSE_VERSION

CE_2_8_1

Current: CE_2_8_1, CE_2_9_0, PLUS_25_11_1, PLUS_26_03, PLUS_26_03_1, PLUS_26_07. Legacy (still accepted): CE_2_8_0, PLUS_24_11, PLUS_25_11, CE_26_03

VERIFY_SSL

true

false disables certificate checking entirely โ€” prefer PFSENSE_CA_FILE

PFSENSE_CA_FILE

โ€”

PEM file for pfSense's private/self-signed CA, so verification stays on

API_TIMEOUT

30

Request timeout in seconds

MCP_READ_ONLY

false

Only expose read-only tools

MCP_ENABLE_LOG_FILES

true

Set false to remove get_log_file (raw /var/log/* reads via command sink)

Boolean settings accept true/false, 1/0, yes/no or on/off. Any other value stops the server at startup rather than guessing, so a typo can't turn off TLS verification.

Variable

Default

Description

ENABLE_HATEOAS

false

Enable HATEOAS links in API responses

LOG_LEVEL

INFO

DEBUG, INFO, WARNING, ERROR

MCP_TRANSPORT

stdio

stdio or streamable-http

MCP_HOST

127.0.0.1

Bind address for HTTP mode

MCP_PORT

3000

Port for HTTP mode

MCP_BIND_ADDR

127.0.0.1

Docker Compose only: host address the published port binds to

MCP_API_KEY

โ€”

Bearer token for HTTP transport (required)

MCP_ALLOWED_ORIGINS

localhost

Comma-separated allowed origins

MCP_AUDIT_LOG

โ€”

Path to audit log file (JSON lines)

MCP_RATE_LIMIT_DELETE

10

Max deletes per 60 seconds

MCP_RATE_LIMIT_CREATE

20

Max creates per 60 seconds

MCP_RATE_LIMIT_UPDATE

30

Max settings changes (update_*, apply_*, enable_*/disable_*) per 60 seconds

MCP_RATE_LIMIT_CRITICAL

2

Max critical ops per 300 seconds

MCP_ALLOWED_TOOLS

all

Comma-separated allowlist of write tools. Read tools are always available; get_log_file is controlled by MCP_ENABLE_LOG_FILES

MCP_ROLLBACK_BUFFER

50

Rollback entries kept in memory

RESPONSE_FORMAT

json

gcf re-encodes tool results as Graph Compact Format for fewer tokens (requires the gcf extra)

Response Encoding (GCF)

By default the tools return JSON. Setting RESPONSE_FORMAT=gcf returns each eligible tool result as a single Graph Compact Format block instead: the record arrays these read tools produce (firewall rules, aliases, DHCP leases, certificates, DNS records) have their repeated field names factored into one header, cutting the token cost when the result crosses the LLM boundary. Results that are not a single JSON body โ€” or that GCF would not shrink โ€” stay JSON (see below).

Install the optional extra into the server's environment and set the variable:

pip install '.[gcf]'        # from a clone of this repo
export RESPONSE_FORMAT=gcf

# or, with uvx (the extra must go into uvx's isolated tool environment):
RESPONSE_FORMAT=gcf uvx --with 'gcf-python[fastmcp]==2.7.1' \
  --from git+https://github.com/gensecaihq/pfsense-mcp-server pfsense-mcp-server

It is opt-in and conservative โ€” GCF is used only when it is both smaller than the JSON and a verified lossless round-trip, otherwise the JSON is kept, so no record is ever dropped or altered. structuredContent is preserved, so output-schema validation and non-model clients keep receiving JSON. If the gcf extra is not install

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server providing Claude Code with full UniFi network management capabilities -- devices, clients, ports, bandwidth auditing, firewall policies, and traffic rules -- all through natural language.
    29 npm
    1
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables Claude Desktop, Cursor, and other MCP-aware clients to conversationally manage endpoints, query and triage alerts, inspect events, manage policies and intel feeds, mint enrollment tokens, and preview or commit fleet changes.
    21
    623 npm
    Apache 2.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables an MCP client such as Claude Code to inspect and change a stock OpenWrt 25.12+ router over SSH, covering system status, logs, clients, firewall, packages, services, and WireGuard peers. Configuration edits are staged, checked, and armed with an automatic rollback that survives a reboot, all behind deny-by-default per-client grants, an audit log, and masked secrets.
    MIT
  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    Connects MCP clients such as Claude Desktop or Claude Code to a pfSense firewall so users can inspect and change rules, NAT, VPNs, DNS, DHCP, certificates, services, and diagnostics through plain-language conversation. Every destructive action is rate-limited, confirmation-gated, validated against the pfSense REST API wire format, and paired with a captured config revision for rollback.
    -