MCP Galaxy / Directory / Panorama Read-Only
★ Featured Firewall Read-Only v1.0

Panorama Read-Only

A Model Context Protocol server enabling your AI client (Claude, Gemini, Codex …) to query Palo Alto Networks Panorama management servers in read-only mode using the PAN-OS XML API, running inside a Docker or Podman container.

Runtime
Docker / Podman
Protocol
PAN-OS XML API
Tools
23 read-only
01, Overview

What This Server Does

Panorama Read-Only exposes a curated set of read-only tools that let an MCP-capable assistant inspect, but never modify, a Palo Alto Networks Panorama deployment. It talks to Panorama over the PAN-OS XML API and runs inside a Docker or Podman container.

The goal: give network and security teams a safe, audit-friendly way to put natural-language questions to their firewall management plane. Inspect a security policy, ask why a NAT rule exists, pull HA status, or grep through configuration without touching production state.

Every tool in this server is read-only. There are no write paths, no config push, no commit. If a question would require changing Panorama state, the answer is no.

02, Try Asking

What to Ask, in Plain English

A handful of 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.

  • "Show me all security rules that allow inbound RDP from any zone."
  • "Which device groups have rules with threat scanning disabled?"
  • "Pull the top-applications report for the last 7 days."
  • "Are there uncommitted changes anywhere across Panorama right now?"
  • "Which firewalls in the 'branch-offices' device group are out of sync?"
  • "Run show high-availability state on firewall serial ABC123."
03, Requirements

Before You Start

  • Docker Desktop with the MCP Toolkit extension, or Podman 4.4+ (rootless). Pick one; the step-by-step for each is below.
  • Palo Alto Networks Panorama running PAN-OS 11.1 or newer.
  • Pre-generated PAN-OS API key, created via Panorama's API key generation endpoint.
  • Read-only admin role bound to the API user. The server enforces this at the protocol level, but the role provides defense-in-depth.
04, Capabilities

23 Read-Only Tools

A
System Information
Panorama version, serial, uptime, and platform metadata.
B
Device Management
List managed firewalls, device groups, and connection state.
C
Security Policy
Inspect security rules, ordering, profile groups, and tags.
D
Running Configuration
Pull the active configuration as parseable XML.
E
Candidate Configuration
Read the candidate (uncommitted) configuration tree.
F
NAT Rules
Enumerate source and destination NAT policy.
G
Address Objects
List address and address-group definitions.
H
Service Objects
List service and service-group definitions.
I
Security Profiles
Inspect AV, anti-spyware, URL filtering, and file-blocking profiles.
J
Operational Commands
Run a whitelisted set of show commands and return results.
K
Logs
Retrieve traffic, threat, system, and configuration logs.
L
Reports
Pull predefined and custom report output.
M
HA Status
Monitor high-availability peer state and sync.
05, Installation

Build & Configure

Two supported runtimes, pick the one you already run. Both build the same image and keep your Panorama 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://<panorama-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.

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

Clone the repository so the Dockerfile and server files sit in your working directory.

Clone
$ git clone https://github.com/rosarion97/panorama-readonly-mcp-server-public.git
$ cd panorama-readonly-mcp-server-public
Step 2, Build the image
Build
$ docker build -t panorama-readonly-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; Option B writes a plaintext .env for quick local testing.

Option A, Docker secret store (recommended)
$ docker mcp secret set PANORAMA_HOST="panorama.example.com"
$ docker mcp secret set PANORAMA_API_KEY="LUFRPT1xxxxxxxxxxxxxxxxxxxxxxxxxx=="
$ docker mcp secret set PANORAMA_VERIFY_SSL="yes"

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 .env: PANORAMA_HOST / PANORAMA_API_KEY / PANORAMA_VERIFY_SSL
claude_desktop_config.json (Option B)
{
  "mcpServers": {
    "panorama-readonly": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "--env-file", "/absolute/path/to/.env",
        "panorama-readonly-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:
  panorama-readonly:
    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 runs as a container that spawns the Panorama image on demand, reads your catalog and registry, and resolves your PANORAMA_* 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 PANORAMA_* 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   # panorama-readonly → enabled
$ docker mcp tools list
Podman Rootless · Podman 4.4+
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/panorama-readonly-mcp-server-public.git
$ cd panorama-readonly-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 panorama-readonly-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 (also the path for Podman older than 4.4, which lacks --secret type=env).

Option A, Podman secret store (recommended)
$ printf '%s' 'panorama.example.com' | podman secret create PANORAMA_HOST -
$ printf '%s' 'LUFRPT1xxxxxxxxxxxxxxxxxxxxxxxxxx==' | podman secret create PANORAMA_API_KEY -
$ printf '%s' 'yes' | podman secret create PANORAMA_VERIFY_SSL -

printf '%s' (no trailing newline) avoids a stray newline that triggers "Could not connect" 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 / Podman < 4.4)
$ cp .env.example .env
$ chmod 600 .env   # then edit .env with your values
Step 5, Configure your AI client

Add the entry matching your Step 4 choice. Option A references secret names only, the values stay in Podman. Option B reads them from your .env at container start.

claude_desktop_config.json, Option A (secret store)
{
  "mcpServers": {
    "panorama-readonly": {
      "command": "podman",
      "args": [
        "run", "-i", "--rm",
        "--secret", "PANORAMA_HOST,type=env",
        "--secret", "PANORAMA_API_KEY,type=env",
        "--secret", "PANORAMA_VERIFY_SSL,type=env",
        "panorama-readonly-mcp-server:latest"
      ]
    }
  }
}
claude_desktop_config.json, Option B (.env)
{
  "mcpServers": {
    "panorama-readonly": {
      "command": "podman",
      "args": [
        "run", "-i", "--rm",
        "--env-file", "/absolute/path/to/.env",
        "panorama-readonly-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 Panorama 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, Restart the client

Quit fully and reopen. The Panorama server should appear in the MCP tools list.

Step 7, Verify

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

Verify
$ podman run --rm -i \
    --secret PANORAMA_HOST,type=env \
    --secret PANORAMA_API_KEY,type=env \
    --secret PANORAMA_VERIFY_SSL,type=env \
    panorama-readonly-mcp-server:latest
06, License & Disclaimer

Use At Your Own Risk

This project is provided as-is for integrating Palo Alto Networks Panorama with MCP-capable AI assistants via the Model Context Protocol. Use at your own risk. Not affiliated with or endorsed by Palo Alto Networks.