{
  "markdown": "# mcp-pfsense\n\n[![PyPI](https://img.shields.io/pypi/v/mcp-pfsense)](https://pypi.org/project/mcp-pfsense/)\n[![Python](https://img.shields.io/pypi/pyversions/mcp-pfsense)](https://pypi.org/project/mcp-pfsense/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nMCP server for managing **pfSense firewalls** through AI assistants like Claude, ChatGPT, and Copilot.\n\n> **Requires**: [pfrest](https://github.com/pfrest/pfSense-pkg-RESTAPI) package installed on your pfSense instance (provides the REST API).\n\n## Features\n\n**19 tools** across 7 categories:\n\n| Category | Tools | Description |\n|----------|-------|-------------|\n| **System** | `get_system_status`, `get_interfaces` | Version, CPU, memory, uptime, temperature, network interfaces |\n| **Firewall** | `list_firewall_rules`, `add_firewall_rule`, `delete_firewall_rule`, `list_firewall_aliases` | Rule management with interface filtering, alias listing |\n| **DHCP** | `list_dhcp_leases`, `list_dhcp_static_mappings`, `add_dhcp_static_mapping`, `delete_dhcp_static_mapping` | Active leases, IP reservations |\n| **DNS** | `list_dns_host_overrides`, `add_dns_host_override`, `delete_dns_host_override` | Unbound DNS Resolver host overrides |\n| **Pending changes** | `get_pending_changes`, `apply_changes` | See what is staged per subsystem (firewall, dhcp, dns) and apply it |\n| **Monitoring** | `get_gateway_status`, `get_arp_table`, `list_services` | Gateway health, connected devices, service status |\n| **Services** | `restart_service` | Restart any pfSense service |\n\n### Safety\n\n- **Two-step confirmation** for destructive operations (delete rules, delete mappings, restart services, apply changes): the tool returns a warning on first call and only executes when called again with `confirm=true`.\n- **Writes are staged, not live.** Like the pfSense WebGUI, `add_*` and `delete_*` store the change in the config but do not activate it. The tool response says so (`applied: false`, plus a `pending` note). Activate with `apply_changes(subsystem, confirm=true)` — which reloads that subsystem, including anything a human left staged in the WebGUI — or pass `apply=true` on the write itself when you explicitly want a one-shot change. Nothing the assistant does reaches the packet filter without one of those two explicit steps.\n- `delete_dhcp_static_mapping` takes the mapping's `interface` (its `parent_id` in `list_dhcp_static_mappings`) and `mapping_id`; a mapping is addressed by both.\n\n## Installation\n\n```bash\n# Using uvx (recommended)\nuvx mcp-pfsense\n\n# Using pip\npip install mcp-pfsense\n```\n\n### Prerequisites\n\n1. **pfSense** with [pfrest](https://github.com/pfrest/pfSense-pkg-RESTAPI) package installed\n2. A user account with API access (typically `admin`)\n\n## Configuration\n\nSet environment variables:\n\n| Variable | Required | Default | Description |\n|----------|----------|---------|-------------|\n| `PFSENSE_HOST` | Yes | — | pfSense hostname or IP |\n| `PFSENSE_PASSWORD` | Yes | — | API user password |\n| `PFSENSE_USERNAME` | No | `admin` | API username |\n| `PFSENSE_PORT` | No | `443` | API port |\n| `PFSENSE_SCHEME` | No | `https` | `http` or `https` |\n| `PFSENSE_VERIFY_SSL` | No | `false` | Verify SSL certificate |\n\n### Claude Desktop\n\nAdd to `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"pfsense\": {\n      \"command\": \"uvx\",\n      \"args\": [\"mcp-pfsense\"],\n      \"env\": {\n        \"PFSENSE_HOST\": \"10.10.10.1\",\n        \"PFSENSE_PASSWORD\": \"your-password\"\n      }\n    }\n  }\n}\n```\n\n### Claude Code\n\n```bash\nclaude mcp add pfsense -- uvx mcp-pfsense\n```\n\nThen set environment variables in your shell or `.env` file.\n\n## Usage Examples\n\nOnce connected, ask your AI assistant:\n\n- *\"What's the pfSense system status?\"*\n- *\"Show me all firewall rules on the LAN interface\"*\n- *\"List active DHCP leases\"*\n- *\"Add a DNS entry for nas.home.lan pointing to 10.10.10.50\"*\n- *\"What devices are connected to the network?\"* (ARP table)\n- *\"Show gateway health and latency\"*\n- *\"Create a firewall rule to allow TCP port 8080 on LAN\"*\n- *\"Reserve IP 10.10.10.60 for MAC aa:bb:cc:dd:ee:20\"*\n\n## API Compatibility\n\n- **pfSense**: 2.7.x and 2.8.x\n- **pfrest**: REST API v2 — any v2.x release, except `list_dhcp_static_mappings`, which needs **v2.7.0 or later** (it uses the `/services/dhcp_server/static_mappings` collection endpoint added in that release).\n- **Python**: 3.11+\n\nThe endpoint, parameters and encoding each tool uses are pinned by `tests/test_client_endpoints.py` and `tests/test_wire_format.py`, derived from the pfrest v2 endpoint definitions. Versions before 0.2.0 called several endpoints that do not exist in pfrest v2 (see Troubleshooting).\n\n> **Note**: pfrest runs on nginx (port 80 by default), separate from the pfSense WebGUI (lighttpd on port 443). If your pfrest is configured on a non-standard port, set `PFSENSE_PORT` and `PFSENSE_SCHEME` accordingly.\n\n## Troubleshooting\n\n### Only `get_system_status` and `get_arp_table` work; everything else returns 400/404\n\nmcp-pfsense 0.1.1 and earlier called singular endpoints for listing (`/interface`, `/firewall/rule`, `/firewall/alias`) and legacy paths that pfrest v2 does not serve (`/status/dhcp_leases`, `/services/dhcpd/static_mapping`, `/services/unbound/host_override`, `/status/gateway`, `/status/service` for GET). Upgrade to 0.2.0 or later.\n\n### `403` on `list_services` or other reads\n\npfrest checks the privileges of the API user per endpoint. Grant the user the `api-v2-*` privileges for the endpoints you need (or `page-all` for full access) under **System → User Manager**.\n\n### `ModuleNotFoundError: No module named 'mcp.server.fastmcp'`\n\nThe MCP Python SDK 2.0 removed the module that mcp-pfsense 0.1.1 and earlier import, so fresh installs (`uvx mcp-pfsense`, `pip install`) failed on startup. Upgrade to 0.2.0 or later, which pins `mcp<2`. If you must stay on an older mcp-pfsense: `uvx --with \"mcp<2\" mcp-pfsense`.\n\n### A rule / mapping / override was created but is not in effect\n\nThat is the default: writes are staged (see **Safety**). Check with `get_pending_changes(subsystem)` and activate with `apply_changes(subsystem, confirm=true)`, or in the WebGUI. If a write returns 200 but nothing is stored at all, the pfrest **`read_only`** setting is on (System → REST API → Settings).\n\n## Development\n\n```bash\ngit clone https://github.com/antonio-mello-ai/mcp-pfsense.git\ncd mcp-pfsense\npython -m venv .venv\nsource .venv/bin/activate\npip install -e \".[dev]\"\n\n# Run tests\npytest\n\n# Lint and type check\nruff check .\nmypy src/\n```\n\n## License\n\nMIT\n\n<!-- mcp-name: io.github.antonio-mello-ai/mcp-pfsense -->\n",
  "bytes": 6630,
  "sha": "cd74e73487f0b4c74b53c1fbecaf09577bcd28f22ec008adb05422f18a490bb6",
  "repo_slug": "antonio-mello-ai/mcp-pfsense",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_antonio_mello_ai_mcp_pfsense_6677c1db/readme"
}