trackmcp
Back to directory
gensecaihq

pfsense-mcp-server

View on GitHub

Model Context Protocol (MCP) server for pfSense firewall management. Control firewall rules, VPNs, DNS, DHCP and diagnostics in natural language from Claude Desktop, Claude Code or any MCP client — 333 wire-format-verified tools for the pfSense REST API, with safety guardrails, config backup and rollback on every change.

94 stars PythonOthers Updated Aug 31, 2026
claudegenaimcpmcp-serverpfsensepfsense-firewallhacktoberfestclaude-codeclaude-desktopcybersecurityfastmcpfirewallfirewall-managementllmmodel-context-protocolnetwork-automationnetwork-securitypfsense-apipythonrest-api

Documentation


text
You:     Block all traffic from 203.0.113.5 on WAN
Claude:  ✓ created block rule  →  ✓ applied changes  →  rollback: restore_config_backup(revision_id=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 — with a confirmation gate, config backup, and rollback on every destructive action.

Letting an AI touch a production firewall is only safe if the plumbing is right, so that's where the work went: every tool's wire format is verified against the pfSense REST API schema by a contract-test layer, and every change runs through a guardrail pipeline. 572 tests plus a wire-protocol E2E suite in CI on Python 3.11–3.13.

> [!TIP]

> Jump to the Quick Start — about two minutes with `uvx`, no clone required. And if this saves you a trip through the pfSense web UI, a ⭐ helps others find it.

Contents

Why this exists ·

Quick start ·

What you can do ·

Safety ·

Supported versions ·

Authentication ·

Deployment ·

Configuration ·

Testing ·

MCP compliance ·

Architecture ·

Contributing

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
  • Config backup before every delete/reboot — with a one-line rollback command (and an explicit warning if a backup point can't be captured)
  • Rate limiting on every mutating tool prevents runaway AI loops 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: Python 3.11+, pfSense with REST API v2 package installed

Option A — run without cloning (uvx):

bash
uvx --from git+https://github.com/gensecaihq/pfsense-mcp-server pfsense-mcp-server

Option B — clone for development:

bash
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 to `~/Library/Application Support/Claude/claude_desktop_config.json`.

Using the installed entry point (Option A):

json
{
  "mcpServers": {
    "pfsense": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/gensecaihq/pfsense-mcp-server", "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):

json
{
  "mcpServers": {
    "pfsense": {
      "command": "python3.11",
      "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"
      }
    }
  }
}

About that 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

333 tools across every major pfSense subsystem:

DomainToolsWhat You Can Do
Firewall Rules9Create, update, delete, reorder rules. Bulk block IPs. View compiled pf ruleset.
Aliases5Manage host/network/port/URL aliases. Add and remove addresses.
NAT16Port forwards, outbound NAT, 1:1 NAT — full lifecycle management.
VPN51OpenVPN servers and clients, IPsec tunnels, WireGuard peers — CRUD, status, apply.
Routing16Gateways, gateway groups, static routes, default gateway management.
DNS24Unbound resolver and dnsmasq forwarder: host overrides, domain overrides, access lists.
DHCP17Leases, static mappings, address pools, custom options, server config.
Certificates15Certs, CAs, CRLs — generate, renew, export PKCS12.
Users12User accounts, groups, LDAP/RADIUS auth server config.
Interfaces14Interface config, VLANs, bridges, groups.
System44Status, settings, diagnostics, state table, config history, reboot, ping.
Services14Start/stop/restart services. NTP, cron, SSH, service watchdog.
Logs3Firewall log analysis with parsed IPv4/IPv6 filterlog data.
Traffic Shaping12Shapers, queues, and limiters for bandwidth management.
Schedules8Time-based firewall rule scheduling.
Virtual IPs5CARP, ProxyARP, and IP Alias management.
Troubleshooting10Diagnose connectivity, blocked traffic, VPN, DHCP, DNS, HA. Full health report.
Packages49HAProxy, ACME/Let's Encrypt, BIND DNS, FreeRADIUS.
Utility9HATEOAS navigation, object ID management, guardrail status.

Safety First

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

code
"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": "restore_config_backup(revision_id=42, confirm=True)"
  }

Every one of the 202 mutating tools carries a guardrail, enforced at registration by a meta-test so a new tool can't ship ungated: the 52 destructive (delete/reboot/halt) tools require `confirm=True`, and the other 150 (create/update/apply/manage/export/service-control) are rate-limited, audited, and allowlist-checked. Sensitive parameters (passwords, keys, PSKs, bind passwords, tokens) are redacted in the audit log and in echoed API error responses.

You can also:

  • Pass `dry_run=True` to preview any destructive operation without executing
  • Pass `verify_descr="Allow HTTPS"` to verify you're deleting the right rule (guards against ID shifts)
  • Set `MCP_READ_ONLY=true` to expose only the 131 read-only tools (search, get, diagnose)
  • Set `MCP_ALLOWED_TOOLS=search_firewall_rules,get_firewall_log` to restrict to specific tools

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

Supported pfSense Versions

VersionREST API packageStatus
pfSense CE 2.9.0v2.10.2 (latest)Supported
pfSense CE 2.8.1v2.10.2 (latest)Verified
pfSense Plus 26.07v2.10.2 (latest)Supported
pfSense Plus 26.03.1v2.10.2 (latest)Supported
pfSense Plus 26.03v2.10.2 (latest)Verified
pfSense Plus 25.11.1v2.10.2 (latest)Supported
pfSense Plus 25.11v2.7.3 (legacy)Verified
pfSense CE 2.8.0v2.7.3 (legacy)Supported
pfSense Plus 24.11v2.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`):

MethodConfigBest For
Basic Auth`AUTH_METHOD=basic` + username/passwordQuick setup, local users
API Key`AUTH_METHOD=api_key` + key from System > REST API > KeysAutomation, service accounts
JWT`AUTH_METHOD=jwt` + username/passwordShort-lived tokens, auto-refresh

Deployment Options

stdio (default) — for Claude Desktop and Claude Code:

bash
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:

bash
python3 -m src.main -t streamable-http --port 3000

Docker — hardened container with read-only filesystem:

bash
docker compose up

Container security: non-root user (`mcp:1000`), read-only filesystem, all capabilities dropped, `noexec` tmpfs, `no-new-privileges`. In HTTP mode the container health check probes an unauthenticated `/health` endpoint (the `/mcp` endpoint requires a 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

VariableRequiredDefaultDescription
`PFSENSE_URL`YespfSense 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

All configuration options

VariableDefaultDescription
`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_API_KEY`Bearer token for HTTP transport (required)
`MCP_ALLOWED_ORIGINS`localhostComma-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_CRITICAL``2`Max critical ops per 300 seconds
`MCP_ALLOWED_TOOLS`allComma-separated tool allowlist
`MCP_ROLLBACK_BUFFER``50`Rollback entries kept in memory

Testing

bash
python3 -m pytest tests/ -v          # 572 tests
python3 -m pytest tests/ --cov=src   # with coverage (~48%)

The suite includes a wire-contract layer (`tests/contract/`) that asserts every tool's payload against the real pfSense REST API v2.10.2 schema (distilled from the upstream OpenAPI spec), so a wrong field name or type is a failing test rather than a silent misconfiguration. CI runs on Python 3.11/3.12/3.13 with `pip-audit` dependency scanning.

On top of the in-process suite, an end-to-end protocol smoke test drives the

server over the real MCP wire protocol with the official

MCP Inspector CLI — on

both transports, in CI on every push:

bash
make test-e2e            # or: ./scripts/inspector_smoke.sh  (needs node/npx, jq)

It verifies the initialize handshake, the 333-tool listing with annotations,

the guardrail confirm-gate over the wire, read-only mode, and HTTP bearer-auth

plus Origin enforcement — no pfSense instance required.

MCP Specification Compliance

Compliant with MCP 2025-11-25 — the newest revision with stable SDK support — and negotiates down to older revisions per connection, so existing clients keep working:

  • `ToolAnnotations` on all 333 tools (readOnlyHint, destructiveHint, idempotentHint)
  • `serverInfo.version` and `instructions` provided
  • Origin header validation (MUST requirement)
  • Bearer token auth with timing-safe comparison
  • Default bind to localhost per spec SHOULD
  • stdio and Streamable HTTP transports

The stateless 2026-07-28 revision

The newest revision, MCP 2026-07-28 (published 28 July 2026), is the protocol's largest overhaul yet: it removes the `initialize` handshake and protocol-level sessions entirely — every request is self-contained, so remote MCP servers become ordinary stateless HTTPS endpoints — and adds an official extensions system, tighter OAuth 2.0/OIDC alignment, and a formal feature-lifecycle policy with a minimum twelve-month deprecation window.

SDK support ships in fastmcp 4, currently in beta. This codebase is verified ready: the full test suite and the MCP Inspector wire-protocol smoke test pass on the fastmcp 4 beta (4.0.0b2 / mcp SDK 2.0, checked continuously by a non-blocking CI job), the server holds no session state by design, and it uses none of the features 2026-07-28 deprecates (Roots, Sampling, MCP Logging). Adopting the stateless protocol when fastmcp 4 is stable is a dependency-pin change; fastmcp 4 servers negotiate the protocol era per connection, keeping today's handshake-era clients fully supported.

Project Structure

code
src/
  main.py              Entry point (transports, read-only filter, key validation)
  server.py            FastMCP instance + API client
  client.py            pfSense REST API v2 HTTP client (retry/backoff, pooling)
  guardrails.py        Risk classification, confirm gate, rate limit, audit, redaction
  helpers.py           Validation, parsing, pagination, safety guards
  models.py            Data models
  middleware.py        HTTP bearer auth + Origin validation + /health
  tools/               34 tool modules (333 tools)
scripts/
  generate_contract.py Regenerate the wire contract from an OpenAPI spec
  generate_token.py    Generate a secure MCP_API_KEY bearer token
  inspector_smoke.sh   End-to-end MCP protocol smoke test (MCP Inspector CLI)
tests/                 572 tests (incl. tests/contract/ wire-contract suite)

See ARCHITECTURE.md for the request lifecycle, guardrail

model, and wire-contract layer; SECURITY.md for disclosure and

hardening; and RELEASE_AUDIT.md for the audit and roadmap.

Contributing

We need real-world testing across diverse pfSense environments. See CONTRIBUTING or:

1. Fork and create a feature branch

2. Run `python3 -m pytest tests/ -v`

3. Submit a PR

Ideas: integration tests against real pfSense, additional package support (Snort, Suricata), Ollama local LLM bridge, multi-instance management.

License

MIT

Acknowledgments

  • jaredhendrickson13 / pfrest — pfSense REST API v2 package
  • JeremiahChurch — modular rewrite (PR #5), log endpoint OOM safeguards (PR #6)
  • shawnpetersen — API v2 endpoint discovery (PR #3)
  • aemitic — DELETE-body fix (PR #9), firewall `ipprotocol` for IPv6/dual-stack (PR #10), `logconfigchanges` (PR #11)
  • pbhorjee — live-status diagnostics fix (PR #21), firewall-log freshness + exact-IP filtering (PR #23)
  • hossamnagy — resilient startup on transient preflight failure (PR #14)
  • bill-mccormick-dg — independent DELETE-body fix (PR #16)
  • w1ld3r — DELETE and remote-syslog bug reports (#12, #13)
  • tvlc — WebGUI port type-mismatch report (#7)
  • renanwilliam — uvx/pipx packaging request (#8)
  • Netgate — pfSense
  • FastMCP — MCP framework

Frequently asked questions

What is pfsense-mcp-server?

pfsense-mcp-server is Model Context Protocol (MCP) server for pfSense firewall management. Control firewall rules, VPNs, DNS, DHCP and diagnostics in natural language from Claude Desktop, Claude Code or any MCP client — 333 wire-format-verified tools for the pfSense REST API, with safety guardrails, config backup and rollback on every change.

How do I install pfsense-mcp-server?

Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.

Is pfsense-mcp-server open source?

Yes — it is hosted on GitHub at https://github.com/gensecaihq/pfsense-mcp-server and has 94 stars.

Related MCP tools

OpenOSINTOpenOSINT

AI-powered OSINT agent with interactive REPL, MCP server, and CLI. 19 tools. Works with Claude, GPT-4, or local models. For authorized security research only.

1,523 Python
ai-agentanthropicclaude+16
riponcmprojectmem

Open-source coding agent memory. Records issues, attempts, fixes and decisions, then warns your agent before it repeats an approach that already failed. Native MCP server for Claude Code, Cursor, Antigravity and Codex. 100% local, no cloud, no telemetry. MIT.

796 Python
ai-agentsai-memoryai-tools+17
taylorwilsdongoogle_workspace_mcp

Control Gmail, Google Calendar, Docs, Sheets, Slides, Chat, Forms, Tasks, Search & Drive with AI - Comprehensive Google Workspace MCP Server & CLI Tool

3,117 Python
aigmailgoogle-calendar+17
jgravellejcodemunch-mcp

Cut AI token costs 95%+ on code exploration. The leading MCP server for precise, symbol-level GitHub code retrieval via tree-sitter AST. Works with Claude Code, Cursor & any MCP client. 313B+ tokens saved.

2,651 Python
claudeclaude-codeai-coding+17
IvanMurzakUnity-MCP

AI Skills, MCP Tools, and CLI for Unity Engine. Full AI develop and test loop. Use cli for quick setup. Efficient token usage, advanced tools. Any C# method may be turned into a tool by a single line. Works with Claude Code, Gemini, Copilot, Cursor and any other absolutely for free.

4,137 C#
aiai-integrationgame-development+16
mukul975cve-mcp-server

Production-grade MCP server giving Claude 27 security intelligence tools across 21 APIs — CVE lookup, EPSS scoring, CISA KEV, MITRE ATT&CK, Shodan, VirusTotal, and more.

1,383 Python
cisa-kevclaude-aicve+15

Run your own MCP server? See who uses it and what to fix.

Measure it with TrackMCP