Skip to main content

Token-efficient MCP server for Palo Alto Networks PAN-OS firewalls and Panorama

Project description

PAN-OS MCP Server

CI PyPI Python License: MIT

A token-efficient MCP server for Palo Alto Networks PAN-OS firewalls and Panorama, built around three principles:

  1. Lean responses by default. Every list-returning tool exposes only the fields you actually need to answer the question. Verbose responses are opt-in. Typical 40-70% token reduction vs. dump-everything alternatives.
  2. Default-deny RBAC. With no environment configuration, the server exposes only read tools. Writes, commits, and raw API access require explicit opt-in via PANOS_MODE.
  3. TLS verification on by default. Self-signed certs require an explicit opt-out or a custom CA bundle — no silent man-in-the-middle exposure.

137 tools across system, diagnostics/troubleshooting, network, security, objects, NAT, user-ID, admin, VPN, Panorama, logs, threat, certificates, licenses, utility, and aggregation surfaces.

Permission Modes

Mode Tools Description
read (default) 89 Read-only inspection, live troubleshooting (policy-match / NAT-match / FIB-lookup tests, session table, config diff, rule hit counts), and aggregation summaries. No writes.
standard 99 Read + object and tag CRUD (address objects, service objects, tags). No policy rules.
full 130 Standard + policy rule CRUD (security, NAT, PBF, QoS, decryption, static routes; Panorama pre/post rules). All writes go to candidate config — no live impact without commit.
admin 137 Full + commit, push, revert_config, and the raw set_config / delete_config / run_op_command escape hatches. This is the live-impact tier.

Tools above the active mode are not registered with the MCP server — the LLM never sees them, so there is nothing to call. Default mode is read.

Setup

Prerequisites

  • uv (recommended) — manages Python and dependencies for you
    • or Python 3.13+ with pip
  • A PAN-OS firewall or Panorama with the XML API enabled, plus an API key (see below)

Getting a PAN-OS API key

PAN-OS issues API keys via the /api/?type=keygen endpoint. The key inherits the admin account's RBAC — there is no separate "API role," so a read-only admin's key cannot push config even if PANOS_MODE=admin.

Best practice: create a dedicated service account (e.g. apiread) with a Superuser (read-only) dynamic role for PANOS_MODE=read. Issue a separate key from an account with write permissions for higher tiers.

curl:

curl -k -X POST "https://fw.example.com/api/?type=keygen" \
  --data-urlencode "user=apiread" \
  --data-urlencode "password=<password>"

PowerShell:

$body = @{ user = 'apiread'; password = '<password>' }
(Invoke-RestMethod -Method Post -Uri 'https://fw.example.com/api/?type=keygen' -Body $body -SkipCertificateCheck).response.result.key

Copy the returned <key> into PANOS_API_KEY. The same endpoint works against Panorama — point it at the Panorama hostname. Keys do not expire by default but are invalidated if the admin's password changes or the account is deleted.

Environment Variables

Variable Required Description
PANOS_HOST Yes* Single-firewall hostname. *Not required in multi-firewall mode (see Multi-firewall configuration).
PANOS_API_KEY Yes* Single-firewall API key. Stored in the OS keychain in multi-firewall mode.
PANOS_MODE No RBAC mode: read, standard, full, or admin. Default: read.
PANOS_TLS_VERIFY No true / false / 1 / 0 / yes / no. Default: true.
PANOS_TLS_CA No Path to a custom PEM CA bundle. Default: system trust store.
PANOS_FIREWALLS_CONFIG No Override path for firewalls.json. Default: ~/.config/panos-mcp/firewalls.json.
PANOS_AUDIT_LOG No Path to a JSON-lines audit log. Every tool call is logged with sanitized args, success/error state, and timing. Disabled when unset.
PANOS_ENABLE_RAW_CONFIG No Register set_config / delete_config (also requires PANOS_MODE=admin). Default: false.
PANOS_ENABLE_RAW_OPS No Register run_op_command (also requires PANOS_MODE=admin). Default: false.
PANOS_RAW_XPATH_ALLOW No Comma-separated XPath prefixes that set_config / delete_config are restricted to. Default: unset (all non-denied).

The raw escape hatches are off by default and gated twice: they register only when their PANOS_ENABLE_RAW_* flag is truthy and PANOS_MODE=admin, and even then an internal denylist blocks destructive verbs and protected config subtrees. See tools/_guards.py.

Install

Option A — uv (recommended). No install step: uvx fetches the package from PyPI on first run and caches it. Pin the version so upgrades are deliberate:

uvx node804-panos-mcp==0.1.6

Option B — pip:

pip install node804-panos-mcp

Option C — from source (development):

git clone https://github.com/Node804/node804-panos-mcp.git
cd node804-panos-mcp
uv sync          # or: pip install -e ".[dev]"

Each option provides the node804-panos-mcp command and the panos_mcp Python module (runnable as python -m panos_mcp). The package pulls in its dependency node804-mcp-toolkit — shared RBAC, audit-logging, TLS, and lean-response utilities — automatically.

Until node804-mcp-toolkit is published to PyPI, install it from source first: pip install git+https://github.com/Node804/node804-mcp-toolkit.git

Claude Desktop

  1. Open your Claude Desktop config file:

    • Windows: %APPDATA%\Claude\claude_desktop_config.json
    • Mac: ~/Library/Application Support/Claude/claude_desktop_config.json
  2. Add the server under mcpServers (create the file if it doesn't exist):

{
  "mcpServers": {
    "PAN-OS": {
      "command": "uvx",
      "args": ["node804-panos-mcp==0.1.6"],
      "env": {
        "PANOS_HOST": "fw.example.com",
        "PANOS_API_KEY": "LUFRPT1xxx...",
        "PANOS_MODE": "read"
      }
    }
  }
}

If you installed with pip instead of uv, use "command": "python" with "args": ["-m", "panos_mcp"].

  1. Restart Claude Desktop — the server starts automatically when Claude needs it. It starts in read-only mode by default; raise PANOS_MODE to enable writes.

Claude Code (CLI)

claude mcp add node804-panos-mcp \
  -e PANOS_HOST=fw.example.com \
  -e PANOS_API_KEY=LUFRPT1xxx... \
  -e PANOS_MODE=read \
  -- uvx node804-panos-mcp==0.1.6

Verify with claude mcp list.

Verifying It Works

Once connected, ask your LLM:

  • "What's my access level?" → calls server_status, showing the active mode, live tool counts, TLS posture, and configured firewalls
  • "What firewalls are configured?" → calls list_firewalls, confirming the registry and which targets require an explicit firewall argument

If either fails, see Troubleshooting.

Token efficiency

Every list-returning tool accepts these parameters (from node804-mcp-toolkit):

Parameter Default Effect
verbose false When true, returns every field the underlying API exposes. Default returns only the fields most relevant to the tool's purpose.
fields null Explicit projection. ["name", "action", "disabled"] returns exactly those fields. Overrides both verbose and the default whitelist.
pagination.limit 100 Max items per response. Hard ceiling: 1000.
pagination.offset 0 Skip count. Use with limit to page through inventories.
pattern null Server-side substring filter on the item's name field. Far cheaper than fetching the inventory and filtering client-side.

Responses are wrapped as {total, count, items} so the LLM knows when pagination truncated the result and whether to fetch more. Single-record tools (get_firewall_info, get_ha_status, etc.) accept verbose and fields.

Measured savings

Token counts below were measured against synthetic fixtures sized to mid-range deployments (100 security rules, 500 address objects). Encoding: cl100k_base (GPT-4 / Claude approximation). Every scenario is a regression-guarded test in tests/benchmark/ — the build fails if a future change widens a response shape past the budget.

Scenario Naive approach Tokens Better approach Tokens Saving
Find an address object by IP get_address_objects (dump 500) 21,207 find_address_object("10.0.0.5") 88 241× smaller
Inventory snapshot get_address_objects (dump 500) 21,207 count_objects_by_type 27 785× smaller
Audit security policy get_security_rules (verbose, 100 rules) 19,627 summarize_security_policy 58 338× smaller
Audit security policy get_security_rules (lean, 100 rules) 5,095 summarize_security_policy 58 88× smaller
Find rules matching a pattern get_security_rules (lean dump) 5,095 find_rule_by_name("rule-001") 249 20× smaller
Filter rules by pattern get_security_rules (no filter) 5,095 get_security_rules(pattern="rule-00") 523 10× smaller
Lean default vs verbose get_security_rules(verbose=true) 19,627 get_security_rules (default) 5,095 74% reduction

Run the benchmark suite yourself:

pytest -v -s -m benchmark

The headline number: a policy audit that would cost ~20K tokens via the naive "dump everything" approach costs ~60 tokens via summarize_security_policy.

Audit logging

Every tool invocation can be captured to a JSON-lines file:

export PANOS_AUDIT_LOG=/var/log/panos-mcp/audit.jsonl

Each line is one event:

{"ts":"2026-05-07T14:32:11.483Z","tool":"add_security_rule","mode":"full","firewall":"hq-fw","args":{"name":"block-tor","action":"deny"},"success":true,"duration_ms":412}

Sensitive keys (api_key, password, secret, token, auth) are redacted at any depth before logging. Strings over 2 KB are elided. Write failures warn once and never block tool execution.

The audit log is the only after-the-fact record for admin-mode operations (commit, set_config, run_op_command). Treat it accordingly.

TLS verification

Connections to PAN-OS are TLS-verified by default. For environments where the firewall presents a self-signed certificate or one signed by an internal CA:

# Option A: trust a custom CA bundle
export PANOS_TLS_CA=/etc/pki/internal-ca.pem

# Option B: disable verification (emits a startup warning)
export PANOS_TLS_VERIFY=false

The startup log reports the active posture:

PanOS TLS:   verify=ON (system trust store)
PanOS TLS:   verify=ON (custom CA via PANOS_TLS_CA)
PanOS TLS:   verify=OFF (PANOS_TLS_VERIFY=false)

Multi-firewall configuration

For environments managing multiple firewalls or Panorama instances, define them in ~/.config/panos-mcp/firewalls.json (override with PANOS_FIREWALLS_CONFIG=/path):

{
  "firewalls": [
    { "name": "hq",       "host": "hq.example.com" },
    { "name": "branch",   "host": "branch.example.com" },
    { "name": "panorama", "host": "panorama.example.com" }
  ]
}

API keys live in the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service via keyring). On first run, plaintext api_key fields in older configs auto-migrate to the keychain and the JSON is rewritten without them.

Linux headless servers without a keychain backend fall back to plaintext storage. The file is written with mode 0o600 (owner read/write only). The startup log emits a warning.

In multi-firewall mode, every tool that talks to a firewall requires an explicit firewall: <name> argument — no default is picked. Call list_firewalls to see configured targets and whether firewall is required.

Tools by category

Each cell shows how many tools that category contributes at that RBAC tier. A means none. The Total column sums across tiers; the bottom row matches the tool counts reported by server_status.

Category Read Standard Full Admin Total
System 4 4
Diagnostics 5 5
Network 8 2 10
Security 6 12 18
Objects & tags 6 10 16
NAT 1 4 5
User-ID 3 3
Administrators 3 3
VPN 3 3
Panorama 22 9 31
Logs 5 5
Threat & content 4 4
Certificates 3 4 7
Licenses 2 2
Utility 4 1 5
Server diagnostic 2 2
Aggregations 8 8
Commit & raw API 6 6
Total 89 +10 +31 +7 137

A few entries worth calling out by name:

  • Diagnostics (read) — test_security_policy_match, test_nat_policy_match, test_routing_fib_lookup, get_sessions, get_session_detail. Live troubleshooting via read-only <test> and session ops.
  • Utilityget_config_xpath, run_show_command, get_pending_changes, get_config_diff (read) for ad-hoc inspection and reviewing staged changes; run_op_command (admin) for the operational-command escape hatch.
  • Aggregations (read) — includes get_rule_hit_counts and unused_rules for usage-based rule cleanup.
  • Commit & raw API (admin) — commit, panorama_commit, panorama_push_to_devices, revert_config, set_config, delete_config.
  • Server diagnosticserver_status and list_firewalls. Always available, even in read mode.

Call server_status from your MCP client at runtime to see the active mode, live tool counts, TLS posture, audit destination, and the configured firewall registry.

Aggregation tools

Purpose-built summarization tools that replace "dump everything and grep" patterns with focused queries. Returning a structured answer is 10-20x cheaper in tokens than returning the full inventory and letting the LLM compute the same thing — the largest single source of token savings in the project.

Tool What it answers
find_rule_by_name(pattern, rule_types=None) Search rule names across security, NAT, PBF, and decryption rulebases. Case-insensitive substring match; each result is tagged with its rule type.
find_address_object(query) Find address objects by name substring or by IP membership. If the query parses as an IP/CIDR, returns objects whose ip-netmask, ip-range, or ip-wildcard value overlaps the query. Otherwise matches names.
count_rules_by_action() {"allow": 142, "deny": 38, "drop": 12} plus enabled/disabled counts. Replaces a 10K-token rule dump with a ~200-token snapshot.
summarize_security_policy() One-call policy audit: rule counts, action breakdown, any-any-any rules (worth reviewing), rules with logging disabled, rules without a profile group, and the set of zones referenced.
count_objects_by_type() Inventory snapshot: address objects by type (ip-netmask vs fqdn vs range), address groups (static vs dynamic), service objects by protocol, plus tag and application-filter totals.
get_rule_hit_counts(rule_base, vsys) Per-rule hit counts and last-hit timestamps (show rule-hit-count) — which rules actually carry traffic.
unused_rules(vsys, include_disabled=False) Security rules with zero hits, joined with the rulebase for disabled status — a ready cleanup worklist.

All are gated at Mode.READ — same tier as the underlying inventory reads.

Troubleshooting

Symptom Cause Fix
No module named panos_mcp Package not installed Use the uvx config (installs automatically), or run pip install node804-panos-mcp.
Server starts but tools return an auth error Invalid or expired API key Regenerate the key (see Getting a PAN-OS API key) and update your config. The key is invalidated if the admin's password changes.
TLS / certificate verification errors on connect Firewall presents a self-signed or internal-CA cert Set PANOS_TLS_CA to your CA bundle, or PANOS_TLS_VERIFY=false to disable verification (emits a startup warning).
Tools you expect are missing Mode is too restrictive Check server_status for the active mode, then raise PANOS_MODE (readstandardfulladmin).
Writes succeed but nothing changes on the firewall Changes are staged in candidate config Call commit (admin mode). Use get_pending_changes / get_config_diff to review what's staged first.
"firewall is required" errors Multi-firewall mode with no target Pass firewall: <name>; run list_firewalls to see configured targets.
set_config / run_op_command not available in admin mode Raw escape hatches are off by default Set PANOS_ENABLE_RAW_CONFIG=true / PANOS_ENABLE_RAW_OPS=true and PANOS_MODE=admin.
A vsys-scoped query returns the wrong vsys's data Tools default to vsys1 This release targets vsys1; for other virtual systems use get_config_xpath with an explicit vsys path until a vsys parameter lands.

Development

git clone https://github.com/Node804/node804-panos-mcp.git
cd node804-panos-mcp
pip install -e ".[dev]"          # or: uv sync --extra dev

pytest -v                                        # full test suite
pytest -v -m "not integration and not benchmark" # CI-equivalent
ruff check . && ruff format --check .            # lint + format
mypy src                                         # type check
node804-panos-mcp                                # boot the server

node804-mcp-toolkit installs automatically as a dependency. Until it's on PyPI, install it from source first (see Install).

Acknowledgments

Built on pan-os-python — Palo Alto Networks' official Python SDK. The PAN-OS object model and API client behavior come from there; this project provides the MCP wrapper, response shaping, RBAC, and audit infrastructure on top.

AI-Assisted Development

Portions of this project — including code, tests, and documentation — were developed with the assistance of generative AI (Anthropic's Claude, ChatGPT). All changes are human-reviewed before merge and exercised by the automated test suite, but as with any software, review the code and test against a non-production firewall or Panorama before trusting it with write access (standard mode or above) to a live device.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

node804_panos_mcp-0.1.6.tar.gz (125.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

node804_panos_mcp-0.1.6-py3-none-any.whl (98.5 kB view details)

Uploaded Python 3

File details

Details for the file node804_panos_mcp-0.1.6.tar.gz.

File metadata

  • Download URL: node804_panos_mcp-0.1.6.tar.gz
  • Upload date:
  • Size: 125.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for node804_panos_mcp-0.1.6.tar.gz
Algorithm Hash digest
SHA256 5d57713468eda87a75da3f36fac71090e143fcbfeaec11f9d8b11c8453525dae
MD5 e38437a697c8299472734d81ee12176d
BLAKE2b-256 e65835d2f258feb67b2b8fa9c66d18c630e0c0fb7ae76f2dd3c295abfee8d30a

See more details on using hashes here.

Provenance

The following attestation bundles were made for node804_panos_mcp-0.1.6.tar.gz:

Publisher: publish.yml on Node804/node804-panos-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file node804_panos_mcp-0.1.6-py3-none-any.whl.

File metadata

File hashes

Hashes for node804_panos_mcp-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 78dba036096ec9ece8e7baabeb607db32f423fa5456d37131c357197e2b29c12
MD5 10c74f02c1699462d49c4701d04fe2ba
BLAKE2b-256 be3ce6f60359f742589fa08db47dc02afc25a20e9a33c681f817f4f3799f5534

See more details on using hashes here.

Provenance

The following attestation bundles were made for node804_panos_mcp-0.1.6-py3-none-any.whl:

Publisher: publish.yml on Node804/node804-panos-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page