MCP Galaxy / Directory / Palo Alto Firewall
Firewall Read / Write Docker / Podman

Palo Alto Firewall

A Model Context Protocol server enabling your AI client (Claude, Gemini, Codex …) to query and modify a Palo Alto Networks PAN-OS firewall via the XML API. Every write stages to the candidate configuration; nothing goes live until commit_config. Ships with a PANOS_ENABLE_WRITE kill-switch for read-only deployments.

Runtime
Docker / Podman
Protocol
PAN-OS XML API
Tools
31 (15 read · 13 write · 3 commit)
01, Overview

What This Server Does

Palo Alto Firewall exposes a curated set of tools that let an MCP-capable assistant inspect and change a Palo Alto Networks PAN-OS firewall over the XML API. Read tools pull system info, configs, policies, objects, and logs. Write tools stage edits, address objects, groups, services, tags, and security rules, to the firewall's candidate configuration. Nothing reaches production until the commit_config tool runs.

Unlike the read-only servers in this directory, this one is intentionally read/write. The commit lifecycle is explicit: stage your changes, run validate_commit to dry-run them, then commit_config to push live, or discard_changes to roll the candidate back. Pair it with a non-committing admin role on the firewall and you can let the assistant propose changes that a human approves before they ship.

If you only want monitoring, set PANOS_ENABLE_WRITE=no and every write/commit tool refuses, the server behaves read-only regardless of the admin role's capabilities.

02, Try Asking

What to Ask, in Plain English

Real questions you can put to your AI client once this server is wired in. The model figures out which tools to call, you describe the outcome. Because this server can also write, the prompts split into two groups: reading (always safe) and writing (stages to the candidate config; you commit explicitly).

Reading (always safe):

  • "Show me all security rules that allow inbound RDP from any zone."
  • "List address objects that aren't referenced by any rule."
  • "What's currently staged in the candidate config but not yet committed?"
  • "Pull the last 50 threat logs and group them by source country."
  • "Run show interface all and tell me which links are down."

Writing & committing (each write stages to the candidate config; nothing reaches production until commit_config):

  • "Create address object web-srv-01 for 10.1.1.10/32 with description 'production web 01'."
  • "Add a security rule allow-web from trust to untrust for that object, action allow."
  • "Validate the candidate config, list any errors or warnings before I commit."
  • "Commit with the description 'add web-srv-01 web rule'."
  • "Actually, discard those staged changes, I want to start over."
03, Requirements

Before You Start

  • Docker Desktop with the MCP Toolkit extension, or Podman 4.x+ on $PATH. Pick one; the step-by-step for each is below.
  • Palo Alto Networks firewall running PAN-OS 10.1 or newer.
  • Pre-generated PAN-OS API key, created via the firewall's type=keygen endpoint (Step 0 below).
  • A scoped admin role bound to the API user, grant only the XML API actions and the objects/rulebases you want the assistant to touch. Strongly consider a role that cannot commit, leaving commit_config as a human-only path. See Write Safety.
  • An MCP-capable client, Claude Desktop, Claude Code, Codex, Gemini CLI, or any client speaking MCP over stdio.
04, Capabilities

31 Tools Across Read, Write, and Commit

A
System & State (read)
System info, PAN-OS version & serial, HA status, async job status, arbitrary <show> operational commands.
B
Config & Policy (read)
Running & candidate config by XPath, security & NAT rules, security profiles (AV, AS, vuln, URL, etc.), uncommitted changes.
C
Objects (read)
Address objects, address groups (static and dynamic), service objects.
D
Logs (read)
Traffic, threat, system, config, URL, and WildFire logs.
E
Objects (write)
Create / delete address objects (ip-netmask, ip-range, fqdn), address groups, service objects, and tags.
F
Security Policy (write)
Create / delete security rules and reorder them with move_security_rule (top / bottom / before / after).
G
Raw XPath (write)
Advanced set_config / edit_config / delete_config for anything not covered by a named tool. Element must parse as well-formed XML.
H
Commit Lifecycle
validate_commit for a dry-run, commit_config to push live, discard_changes to revert the candidate.
05, Installation

Build & Configure

Two supported runtimes, pick the one you already run. Both build the same image and keep your firewall credentials out of the AI client's config: in the runtime's secret store (recommended) or a local .env file you control. Generate the API key first (it's identical for either path), then expand your runtime below.

New to the Docker MCP Gateway? The Docker pane below uses a catalog → registry → gateway flow with three bind-mounts. If any of that terminology is unfamiliar, skim Docker MCP Gateway under Good to Know first, it walks through the architecture these steps build on. The Podman pane runs the container directly and doesn't depend on the gateway.
Step 0, Generate a PAN-OS API key (out of band)
$ curl -X POST 'https://<firewall-host>/api/?type=keygen' \
    --data-urlencode 'user=<admin-username>' \
    --data-urlencode 'password=<admin-password>'

Copy the <key> value from the response. Don't paste it into a chat, it goes into a runtime secret (or your local .env) in the steps below. If your firewall uses a self-signed cert, pin it once with openssl s_client and use --cacert rather than -k.

Docker Docker Desktop · MCP Gateway
Step 1, Get the project files

Clone the repository. The Docker backend lives at the repo root and ships a custom-catalog.yaml alongside the Dockerfile.

Clone
$ git clone https://github.com/rosarion97/palo_alto-mcp-server-public.git
$ cd palo_alto-mcp-server-public
Step 2, Build the image

The image tag must match the image: field in custom-catalog.yaml (paloalto-mcp-server:latest).

Build
$ docker build -t paloalto-mcp-server .
Step 3, Provide secrets

Two ways to hand the container its credentials. Option A keeps your key in Docker's secret store and is recommended. The PANOS_ENABLE_WRITE flag controls whether write/commit tools are active, set it to "no" to deploy this server as read-only.

Option A, Docker secret store (recommended)
$ docker mcp secret set PANOS_HOST="firewall.example.com"
$ docker mcp secret set PANOS_API_KEY="LUFRPT1xxxxxxxxxxxxxxxxxxxxxxxxxx=="
$ docker mcp secret set PANOS_VERIFY_SSL="yes"
$ docker mcp secret set PANOS_VSYS="vsys1"
$ docker mcp secret set PANOS_ENABLE_WRITE="yes"   # "no" for read-only

With Option A, continue through Steps 4–7 below.

Option B writes your API key to disk in clear text. Use it only for local testing, chmod 600 .env, never commit it. This path skips the gateway: skip Steps 4–6, point your client at docker run --env-file (below), then jump to Step 7.
Option B, plaintext .env (testing only)
$ cp .env.example .env
$ chmod 600 .env   # then edit: PANOS_HOST / PANOS_API_KEY / PANOS_VERIFY_SSL / PANOS_VSYS / PANOS_ENABLE_WRITE
claude_desktop_config.json (Option B)
{
  "mcpServers": {
    "paloalto-firewall": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "--env-file", "/absolute/path/to/.env",
        "paloalto-mcp-server:latest"
      ]
    }
  }
}
Step 4, Install the custom catalog

Steps 4–6 are the Option A (secret store) path. Used Option B? Skip to Step 7.

Catalog
$ mkdir -p ~/.docker/mcp/catalogs
$ cp custom-catalog.yaml ~/.docker/mcp/catalogs/custom.yaml
Step 5, Enable the server in the registry

Add the entry under the single top-level registry: key in ~/.docker/mcp/registry.yaml. Don't overwrite the file if it already exists.

~/.docker/mcp/registry.yaml
registry:
  paloalto-firewall:
    catalog: custom
    enabled: true
Step 6, Point Claude Desktop at the gateway

Add the gateway block to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json). The gateway spawns the firewall image on demand, reads your catalog and registry, and resolves your PANOS_* secrets at request time. Replace <your-username> with your macOS username (run whoami to check):

claude_desktop_config.json, gateway block
{
  "mcpServers": {
    "mcp-toolkit-gateway": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-v", "/var/run/docker.sock:/var/run/docker.sock",
        "-v", "/Users/<your-username>/.docker/mcp:/mcp",
        "-v", "/Users/<your-username>/Library/Caches/docker-secrets-engine/engine.sock:/root/.cache/docker-secrets-engine/engine.sock",
        "docker/mcp-gateway:latest",
        "--catalog=/mcp/catalogs/custom.yaml",
        "--registry=/mcp/registry.yaml",
        "--transport=stdio"
      ]
    }
  }
}

All three bind-mounts are required: the Docker socket lets the gateway spawn the server container; ~/.docker/mcp is where it reads your catalog and registry; the docker-secrets-engine socket is the resolver Docker Desktop exposes for the secret store, without it your PANOS_* URLs resolve to empty strings and the server never starts. On Linux Docker Desktop the path is ~/.docker/desktop/secrets-engine/engine.sock; find it with find ~ -name engine.sock.

Works the same for other clients. Claude Code takes the same args via claude mcp add -s user mcp-toolkit-gateway -- docker run …; Codex reads the same shape from ~/.codex/config.toml as [mcp_servers.mcp-toolkit-gateway]. Any MCP-capable client, Google's Gemini included, reads an mcpServers block from its own settings file; only the location changes, the entry is identical.

Then quit and reopen the client. claude_desktop_config.json never contains the API key, the gateway resolves it from Docker's secret store at request time. As a shortcut, docker mcp client connect claude-desktop (or MCP Toolkit → Clients in Docker Desktop) writes a similar block automatically; the explicit JSON above survives Docker Desktop updates that may rewrite the auto-managed entry.

Step 7, Verify
Verify
$ docker mcp server list   # paloalto-firewall → enabled
$ docker mcp tools list
Podman Rootless · stdio
Step 1, Get the project files

Clone the repo and change into the podman/ directory, which holds the Containerfile and server files.

Clone
$ git clone https://github.com/rosarion97/palo_alto-mcp-server-public.git
$ cd palo_alto-mcp-server-public/podman
Step 2, Start a Podman machine (macOS / Windows)

The machine is a small VM that runs your containers. Linux users skip this step.

Podman machine
$ podman machine init
$ podman machine start
Step 3, Build the image
Build
$ podman build -t paloalto-mcp-server:latest .
Step 4, Provide secrets

Two ways to hand the container its credentials. Option A keeps your key in Podman's encrypted secret store and is recommended; Option B writes a plaintext .env. Five values to set: PANOS_HOST, PANOS_API_KEY, PANOS_VERIFY_SSL, PANOS_VSYS, and PANOS_ENABLE_WRITE.

Option A, Podman secret store (recommended)
$ printf '%s' 'firewall.example.com' | podman secret create PANOS_HOST -
$ printf '%s' 'LUFRPT1xxxxxxxxxxxxxxxxxxxxxxxxxx==' | podman secret create PANOS_API_KEY -
$ printf '%s' 'yes' | podman secret create PANOS_VERIFY_SSL -
$ printf '%s' 'vsys1' | podman secret create PANOS_VSYS -
$ printf '%s' 'yes' | podman secret create PANOS_ENABLE_WRITE -   # "no" for read-only

printf '%s' (no trailing newline) avoids a stray newline that can trigger "Could not connect" or "Write operations are disabled" errors.

Option B writes your API key to disk in clear text. Use it only for local testing or Podman < 4.4, chmod 600 .env, never commit it.
Option B, plaintext .env (testing only)
$ cp .env.example .env
$ chmod 600 .env   # then edit with your values
Step 5, Configure your AI client

Add the entry matching your Step 4 choice.

claude_desktop_config.json, Option A (secret store)
{
  "mcpServers": {
    "paloalto-firewall": {
      "command": "podman",
      "args": [
        "run", "-i", "--rm",
        "--secret", "PANOS_HOST,type=env",
        "--secret", "PANOS_API_KEY,type=env",
        "--secret", "PANOS_VERIFY_SSL,type=env",
        "--secret", "PANOS_VSYS,type=env",
        "--secret", "PANOS_ENABLE_WRITE,type=env",
        "paloalto-mcp-server:latest"
      ]
    }
  }
}
claude_desktop_config.json, Option B (.env)
{
  "mcpServers": {
    "paloalto-firewall": {
      "command": "podman",
      "args": [
        "run", "-i", "--rm",
        "--env-file", "/absolute/path/to/.env",
        "paloalto-mcp-server:latest"
      ]
    }
  }
}
Works the same for other assistants. Any MCP-capable client reads an mcpServers block from its own settings.json , Google's Gemini included. Drop this same entry into that client's settings.json and the firewall tools appear there too. Only the file's name and location change; the server entry is identical.

If podman isn't on the client's PATH (common for macOS GUI apps), replace "podman" with its absolute path, run which podman to find it.

Step 6, Verify

Run the same command your client will run, it should start and wait on stdin for JSON-RPC. Press Ctrl+C to exit.

Verify
$ podman run --rm -i \
    --secret PANOS_HOST,type=env \
    --secret PANOS_API_KEY,type=env \
    --secret PANOS_VERIFY_SSL,type=env \
    --secret PANOS_VSYS,type=env \
    --secret PANOS_ENABLE_WRITE,type=env \
    paloalto-mcp-server:latest
06, Write Safety

Six Safeguards Between the LLM and Production

This server can change live firewall configuration. The model is honest about what's at stake; the server has six layers of defense built in:

  • Staging by default. Every write tool targets the candidate config (action=set/edit/delete/move). Changes are not live until commit_config runs. discard_changes rolls back the candidate to the running config.
  • Dry-run validation. validate_commit runs a full commit validation and surfaces errors / warnings before you commit.
  • Write kill-switch. Set PANOS_ENABLE_WRITE=no and every write / commit tool refuses; the server behaves read-only. Flip it to yes only when you intend to make changes.
  • Input validation. Object names are restricted to [A-Za-z0-9_.\- ]; ports, tag colors, and address types are validated against patterns / enums; free-text fields (descriptions, comments, DAG filters) are XML-escaped before being embedded, blocking attribute-quote breakouts and XML injection.
  • Well-formed-only raw edits. set_config / edit_config require the XPath to start with /config and the element to parse as valid XML before anything is sent.
  • RBAC is the backstop. Scope the API key's admin role to exactly what the model should touch. Consider a role that can stage and validate but cannot commit, leaving commit_config as a human-only path. The firewall rejects anything the role forbids.
Read-only is not harmless, and write is not reversible. A broad admin role can leak password hashes, certificate private keys, and shared secrets; a committed change takes effect immediately. Scope the role tightly, keep validate_commit in your workflow, and prefer a non-committing role plus PANOS_ENABLE_WRITE=no until you're confident.
07, License & Disclaimer

Use At Your Own Risk

This project is provided as-is for integrating Palo Alto Networks PAN-OS firewalls with MCP-capable AI assistants via the Model Context Protocol. This server can modify live firewall configuration. Read the Write Safety section above before pointing it at production, scope the API key's admin role narrowly, and keep PANOS_ENABLE_WRITE=no on any deployment that should stay observational. Use at your own risk. Not affiliated with or endorsed by Palo Alto Networks.