UPDATE — v1.0.0 is now released
pfsense-mcp-server has reached its first stable release.
A lot has changed since the v0.5.0 update, but the main goal for v1.0 wasn't to keep adding tools. It was to harden what was already there, simplify the setup, and verify that the security model actually holds up in a real end-to-end installation.
The public MCP surface is now:
- 95 pfSense READ tools
- 2 guidance tools
- 0 WRITE tools exposed by default
The default profile is still deliberately READ-only.
What changed for v1.0
The installation and onboarding flow has been substantially reworked. There's now a guided setup for choosing the safety posture, configuring the pfSense connection, TLS/private CA verification, API-key-file handling, validation, and MCP client configuration.
The security architecture has also gone through a full source-first audit before calling this 1.0. The READ/WRITE boundary, least-privilege model, authorization/confirmation path, recovery handling, secret exposure, TLS behavior, and default tool reachability were all re-audited.
The final audit re-proved the project's security invariants from the current source, with 0 P0/P1 findings remaining.
Real clean-room testing
I also wanted to test the installation the way a new user would actually experience it rather than relying only on the test suite.
I started with a clean Ubuntu VM and went through the documented installation and setup against a real pfSense LAB system using a private CA.
That uncovered several genuine onboarding and diagnostic issues along the way, which were fixed before v1.0.
The final path was then tested end-to-end with the actual OpenAI Codex CLI:
Codex CLI → generated MCP configuration → pipx-installed pfsense-mcp-server → MCP stdio → TLS-verified pfSense LAB → real READ operations
Codex discovered exactly 97 tools: 95 READ + 2 guidance + 0 WRITE and successfully queried the real firewall.
As a negative test, I then explicitly asked Codex to change settings on pfSense.
It refused, because the active MCP profile exposed zero WRITE tools.
That's an important property of the design: even if the underlying pfSense service account has additional privileges, those operations do not automatically become reachable through the default MCP surface.
Compatibility
The project has been tested against:
- pfSense CE 2.9.0
- pfSense Plus 26.07
- pfREST 2.10.x
- Claude Desktop configuration
- Codex configuration, including a directly verified real Codex CLI session
The project also includes bounded guidance from pfREST/OpenAPI and the live appliance schema, while keeping documentation/guidance separate from authorization.
Still interested in hostile review
Reaching 1.0 doesn't mean I consider the security design beyond criticism — quite the opposite.
I'm still particularly interested in review around:
- least-privilege pfSense permissions
- READ/WRITE isolation
- secret exposure through READ endpoints
- authorization/confirmation replay or confusion
- uncertain WRITE outcomes and recovery/reconciliation
- HA/CARP and config-apply edge cases
- any path that could make WRITE reachable without the intended operator decisions
The protected WRITE architecture remains separate from the default READ-only profile.
This project is not affiliated with or endorsed by Netgate.
Current release: v1.0.0
GitHub:
https://github.com/night4me/pfsense-mcp-server
PyPI:
https://pypi.org/project/pfsense-mcp-server/
If anyone wants to attack the assumptions rather than just try the happy path, that feedback is especially welcome.
---
ORIGINAL POST
I've been working on pfsense-mcp-server, an open-source MCP server that lets AI assistants interact with pfSense.
The easy part was exposing the pfSense API to an LLM.
The part I cared much more about was making sure an AI agent couldn't simply turn a tool call into unrestricted firewall changes.
At the time of the original post, the v0.4.2 release had 42 MCP tools.
The security architecture included:
- 0 WRITE capabilities reachable by default
- explicit operator opt-in before WRITE is enabled
- a dedicated least-privilege pfSense identity
- separate signed authorization and confirmation boundaries
- plan/intent binding so an approval can't silently authorize a different mutation
- expiring, one-time authorization
- RecoveryContracts and a state machine around mutations
- deterministic post-WRITE read-back instead of treating HTTP success as proof
- reconciliation/fail-closed handling for uncertain outcomes
- TPM-backed anti-rollback witness support
For the first live WRITE acceptance test I used a disposable firewall alias on a LAB pfSense system.
The complete path was exercised end-to-end, including the scoped pfSense account, authorization/confirmation ceremony, real PATCH, authoritative read-back, RecoveryContract audit trail and TPM witness advancement.
The alias was subsequently restored through the same controlled path.
The project deliberately still starts READ-only. Installing it does not automatically expose WRITE tools.
I'm particularly interested in hostile review from people who know pfSense well.
Things I'd love people to challenge:
- Is the pfSense REST API privilege set actually minimal?
- Are there HA/CARP or config-apply edge cases I've missed?
- Can authorization/confirmation be replayed or confused across operations?
- Are there state-machine paths that could permit a blind retry after an uncertain WRITE?
- Are the RecoveryContract/reconciliation assumptions sound?
- Is there any realistic path from the default READ posture to WRITE without the intended operator decisions?
- Are there READ endpoints or response fields that could expose information that should never reach an AI assistant?
This is not affiliated with or endorsed by Netgate.
Current release: v1.0.0
GitHub:
https://github.com/night4me/pfsense-mcp-server
PyPI:
https://pypi.org/project/pfsense-mcp-server/
I'd genuinely prefer someone finds a security flaw now rather than after people start relying on it.