node804-panos-mcp 0.1.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- node804_panos_mcp-0.1.6/.gitignore +18 -0
- node804_panos_mcp-0.1.6/.jscpd.json +12 -0
- node804_panos_mcp-0.1.6/CHANGELOG.md +206 -0
- node804_panos_mcp-0.1.6/LICENSE +21 -0
- node804_panos_mcp-0.1.6/PKG-INFO +376 -0
- node804_panos_mcp-0.1.6/README.md +336 -0
- node804_panos_mcp-0.1.6/pyproject.toml +126 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/__init__.py +34 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/__main__.py +20 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/_redact.py +69 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/client.py +155 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/config/__init__.py +0 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/config/firewalls.py +336 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/py.typed +0 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/responses/__init__.py +0 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/responses/schemas.py +493 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/responses/shapers.py +165 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/server.py +119 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/__init__.py +0 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/_common.py +506 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/_guards.py +271 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/_schemas.py +96 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/_xml_writers.py +93 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/admin.py +98 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/admin_ops.py +316 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/aggregations.py +720 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/certificates.py +249 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/diagnostics.py +362 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/firewalls.py +43 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/licenses.py +73 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/logs.py +210 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/nat.py +173 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/network.py +365 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/objects.py +454 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/panorama.py +1323 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/security.py +679 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/status.py +52 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/system.py +181 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/threat.py +122 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/userid.py +114 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/utility.py +352 -0
- node804_panos_mcp-0.1.6/src/panos_mcp/tools/vpn.py +127 -0
- node804_panos_mcp-0.1.6/tests/__init__.py +0 -0
- node804_panos_mcp-0.1.6/tests/benchmark/__init__.py +0 -0
- node804_panos_mcp-0.1.6/tests/benchmark/conftest.py +238 -0
- node804_panos_mcp-0.1.6/tests/benchmark/test_find_workflows.py +112 -0
- node804_panos_mcp-0.1.6/tests/benchmark/test_inventory_summary.py +65 -0
- node804_panos_mcp-0.1.6/tests/benchmark/test_policy_audit.py +101 -0
- node804_panos_mcp-0.1.6/tests/unit/__init__.py +0 -0
- node804_panos_mcp-0.1.6/tests/unit/test_admin_ops.py +779 -0
- node804_panos_mcp-0.1.6/tests/unit/test_aggregations.py +858 -0
- node804_panos_mcp-0.1.6/tests/unit/test_client.py +204 -0
- node804_panos_mcp-0.1.6/tests/unit/test_crud_tools.py +374 -0
- node804_panos_mcp-0.1.6/tests/unit/test_dg_hierarchy.py +145 -0
- node804_panos_mcp-0.1.6/tests/unit/test_diagnostics.py +464 -0
- node804_panos_mcp-0.1.6/tests/unit/test_firewalls.py +294 -0
- node804_panos_mcp-0.1.6/tests/unit/test_panorama_walkers.py +511 -0
- node804_panos_mcp-0.1.6/tests/unit/test_read_tools.py +797 -0
- node804_panos_mcp-0.1.6/tests/unit/test_redact.py +99 -0
- node804_panos_mcp-0.1.6/tests/unit/test_rule_crud.py +503 -0
- node804_panos_mcp-0.1.6/tests/unit/test_security_profiles.py +120 -0
- node804_panos_mcp-0.1.6/tests/unit/test_shapers.py +184 -0
- node804_panos_mcp-0.1.6/tests/unit/test_smoke.py +36 -0
- node804_panos_mcp-0.1.6/tests/unit/test_tools.py +160 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.mypy_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
.venv/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.log
|
|
11
|
+
.coverage
|
|
12
|
+
htmlcov/
|
|
13
|
+
.env
|
|
14
|
+
firewalls.json
|
|
15
|
+
audit*.log
|
|
16
|
+
|
|
17
|
+
# Generated duplication/analysis reports (jscpd, etc.)
|
|
18
|
+
report/
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
|
|
6
|
+
versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.6] — 2026-06-11
|
|
9
|
+
|
|
10
|
+
### Added — live troubleshooting
|
|
11
|
+
|
|
12
|
+
Nine tools that close the gap between auditing policy and actually
|
|
13
|
+
troubleshooting it. The read-only ``<test>`` operational commands are now
|
|
14
|
+
first-class ``Mode.READ`` tools instead of being reachable only through the
|
|
15
|
+
ADMIN-gated raw-op escape hatch.
|
|
16
|
+
|
|
17
|
+
- **`test_security_policy_match`** — which security rule a flow matches, the
|
|
18
|
+
live ``test security-policy-match``. Answers "is traffic from X to Y
|
|
19
|
+
allowed, and by which rule?" without changing state.
|
|
20
|
+
- **`test_nat_policy_match`** — matching NAT rule and the resulting
|
|
21
|
+
translation.
|
|
22
|
+
- **`test_routing_fib_lookup`** — egress interface / next-hop for a
|
|
23
|
+
destination (``test routing fib-lookup``).
|
|
24
|
+
- **`get_sessions`** — filtered live session table (``show session all filter
|
|
25
|
+
...``) by source / destination / port / protocol / application, with the
|
|
26
|
+
NAT-translation fields (``xsource``, ``xdst``, ``xdport``, ``nat``) in the
|
|
27
|
+
lean view.
|
|
28
|
+
- **`get_session_detail`** — full per-session record (``show session id N``).
|
|
29
|
+
- **`get_pending_changes`** — uncommitted candidate changes
|
|
30
|
+
(``show config list changes``); the "is anything staged?" check to run
|
|
31
|
+
before ``commit``.
|
|
32
|
+
- **`get_config_diff`** — entry-level candidate-vs-running diff at an XPath
|
|
33
|
+
(added / removed / modified), so the staged-write workflow is reviewable
|
|
34
|
+
before commit. Subject to the same read-side denylist as
|
|
35
|
+
``get_config_xpath``.
|
|
36
|
+
- **`get_rule_hit_counts`** — per-rule hit counts and last-hit timestamps
|
|
37
|
+
(``show rule-hit-count``).
|
|
38
|
+
- **`unused_rules`** — security rules with zero hits, joined with the
|
|
39
|
+
rulebase for disabled status — a ready cleanup worklist.
|
|
40
|
+
- **`revert_config`** (ADMIN) — discard all uncommitted candidate changes,
|
|
41
|
+
reverting to the running config; audited, with a loud warning that it
|
|
42
|
+
discards every admin's staged work.
|
|
43
|
+
|
|
44
|
+
Source/destination IP inputs to the diagnostics tools are validated as bare
|
|
45
|
+
IP addresses; all interpolated values are XML-escaped. The per-firewall ops
|
|
46
|
+
return a clear error when pointed at a Panorama target.
|
|
47
|
+
|
|
48
|
+
## [0.1.5] — 2026-06-11
|
|
49
|
+
|
|
50
|
+
First public release, published to PyPI as **`node804-panos-mcp`**.
|
|
51
|
+
|
|
52
|
+
### Security
|
|
53
|
+
|
|
54
|
+
- **XPath injection hardening (`get_config_xpath`).** LLM-supplied xpaths are
|
|
55
|
+
now XML-escaped and the schema rejects angle brackets, so a value can no
|
|
56
|
+
longer break out of the `<xpath>` element to inject sibling op-command XML.
|
|
57
|
+
All `<show><config><running>` command construction is centralized in
|
|
58
|
+
`build_running_config_xpath_cmd`, so the escaping can't be dropped by a
|
|
59
|
+
refactor.
|
|
60
|
+
- **Read-side denylist.** `get_config_xpath` and `run_show_command` now refuse
|
|
61
|
+
reads of secret-bearing config subtrees (certificates, `mgt-config` admin
|
|
62
|
+
accounts/password hashes, authentication profiles), mirroring the existing
|
|
63
|
+
write-side denylist.
|
|
64
|
+
- **License authcodes** are no longer returned in the default `get_licenses`
|
|
65
|
+
response — pass `verbose=true` or `fields=["authcode"]` to include them.
|
|
66
|
+
|
|
67
|
+
### Packaging
|
|
68
|
+
|
|
69
|
+
- Renamed the distribution to `node804-panos-mcp` and declared its dependency
|
|
70
|
+
on `node804-mcp-toolkit` (previously installed out-of-band). The version is
|
|
71
|
+
now single-sourced from `panos_mcp.__version__`. Added a `py.typed` marker,
|
|
72
|
+
trove classifiers, keywords, and an sdist exclude list. CI installs the
|
|
73
|
+
declared dependency instead of an unclaimed PyPI name.
|
|
74
|
+
|
|
75
|
+
### Fixed
|
|
76
|
+
|
|
77
|
+
- `panorama_summarize_security_policy` no longer pre-rejects legitimate
|
|
78
|
+
Panorama targets with a redundant `isinstance` gate that misfired when
|
|
79
|
+
the resolved client's class didn't identity-match the locally-imported
|
|
80
|
+
`Panorama` symbol. Sibling tools (`panorama_count_rules_per_device_group`,
|
|
81
|
+
`panorama_walk_all_rules`) trust resolution; this one now does too, and
|
|
82
|
+
surfaces a clean error if `DeviceGroup.refreshall` actually fails.
|
|
83
|
+
|
|
84
|
+
### Changed (breaking)
|
|
85
|
+
|
|
86
|
+
- Renamed the derived security-rule audit boolean **`has_profile` →
|
|
87
|
+
`has_inspection`** on every rule listing (lean default field) and the
|
|
88
|
+
matching aggregate **`rules_without_profiles` → `rules_without_inspection`**
|
|
89
|
+
in `summarize_security_policy` / `panorama_summarize_security_policy`. The
|
|
90
|
+
old flag computed `bool(group) or bool(profile_setting)`, but
|
|
91
|
+
`profile_setting` is never a top-level key on a `SecurityRule.about()`
|
|
92
|
+
dict — so the flag effectively meant "is there a profile *group*?" and
|
|
93
|
+
reported every individual-profile-attachment rule (a common Panorama
|
|
94
|
+
pattern: `virus`, `spyware`, `vulnerability`, `url_filtering`,
|
|
95
|
+
`file_blocking`, `data_filtering`, `wildfire_analysis` set directly)
|
|
96
|
+
as "no inspection". The new flag is true when any of those individual
|
|
97
|
+
fields is set OR a profile group is bound. Anyone who filtered with
|
|
98
|
+
`attrs={"has_profile": "false"}` to find rules missing inspection was
|
|
99
|
+
getting confidently wrong results in environments that don't use
|
|
100
|
+
profile groups; update such filters to `attrs={"has_inspection": "false"}`.
|
|
101
|
+
|
|
102
|
+
## [0.1.0] — 2026-05-13
|
|
103
|
+
|
|
104
|
+
Initial release. 123 tools across 14 categories, built on
|
|
105
|
+
[`pan-os-python`](https://github.com/PaloAltoNetworks/pan-os-python) and the
|
|
106
|
+
[`node804-mcp-toolkit`](https://github.com/Node804/node804-mcp-toolkit) shared utilities
|
|
107
|
+
package.
|
|
108
|
+
|
|
109
|
+
### Added — RBAC and security posture
|
|
110
|
+
|
|
111
|
+
- **Default-deny RBAC** via `PANOS_MODE` with four tiers: `read` (default, 76
|
|
112
|
+
tools), `standard` (+10 object/tag CRUD), `full` (+31 rule CRUD), `admin`
|
|
113
|
+
(+6 commit/push/raw-API tools).
|
|
114
|
+
- **TLS verification on by default**. Opt out via `PANOS_TLS_VERIFY=false` or
|
|
115
|
+
trust a custom CA via `PANOS_TLS_CA=/path/to/ca.pem`.
|
|
116
|
+
- **Audit logging** to a JSON-lines file via `PANOS_AUDIT_LOG=`. Captures one
|
|
117
|
+
event per tool call with sanitized arguments (api_key/password/secret/token
|
|
118
|
+
redacted at any depth), timing, and error state.
|
|
119
|
+
- **Multi-firewall registry** in `~/.config/panos-mcp/firewalls.json` (override
|
|
120
|
+
with `PANOS_FIREWALLS_CONFIG`). API keys live in the OS keychain via the
|
|
121
|
+
`keyring` package; the JSON file holds only names and hosts.
|
|
122
|
+
- **Plaintext-to-keychain auto-migration** on first load — older configs with
|
|
123
|
+
inline `api_key` fields are migrated to the keychain and the JSON is
|
|
124
|
+
rewritten without them. Headless Linux servers without a keychain backend
|
|
125
|
+
fall back to plaintext storage with `0o600` file permissions.
|
|
126
|
+
- **Input validation**: rule, object, tag, device-group, and virtual-router
|
|
127
|
+
names restricted to PAN-OS-safe charset (letters, digits, dot, underscore,
|
|
128
|
+
hyphen, space) at the schema layer — defends against XPath injection before
|
|
129
|
+
reaching pan-os-python.
|
|
130
|
+
- **XML escaping** of user-supplied values in the QoS xapi fallback path
|
|
131
|
+
(`tools/_xml_writers.py`), via `xml.sax.saxutils.escape`.
|
|
132
|
+
|
|
133
|
+
### Added — Token efficiency
|
|
134
|
+
|
|
135
|
+
- **Lean responses by default.** Every list-returning tool exposes only the
|
|
136
|
+
fields most relevant to its purpose; verbose responses are opt-in via
|
|
137
|
+
`verbose=True`.
|
|
138
|
+
- **Shared parameters from mcp-toolkit**: `verbose`, `fields` (projection),
|
|
139
|
+
`pagination.limit` / `pagination.offset`, `pattern` (server-side substring
|
|
140
|
+
filter). Same names across every tool.
|
|
141
|
+
- **Aggregation tools** that replace dump-and-grep with focused queries:
|
|
142
|
+
`count_rules_by_action`, `find_rule_by_name`, `find_address_object`,
|
|
143
|
+
`summarize_security_policy`, `count_objects_by_type`.
|
|
144
|
+
- **Regression-guarded benchmark suite** in `tests/benchmark/` asserting
|
|
145
|
+
measured savings (e.g. `summarize_security_policy` is 338× smaller than
|
|
146
|
+
verbose `get_security_rules`, `find_address_object` is 241× smaller than
|
|
147
|
+
dumping address objects). Run with `pytest -m benchmark`.
|
|
148
|
+
|
|
149
|
+
### Added — Tool surface (123 tools)
|
|
150
|
+
|
|
151
|
+
- **System (4)**: `get_firewall_info`, `get_ha_status`, `get_active_sessions`,
|
|
152
|
+
`get_system_resources`.
|
|
153
|
+
- **Network (10)**: 8 reads (interfaces, zones, routing, ARP, VLANs, DHCP,
|
|
154
|
+
DNS proxy, static routes) + 2 CRUD (`add_static_route`,
|
|
155
|
+
`delete_static_route`).
|
|
156
|
+
- **Security (18)**: 6 reads (rules, profiles, profile groups, PBF, DoS, QoS)
|
|
157
|
+
+ 12 CRUD covering security/PBF/QoS rule add/delete/move/set_disabled.
|
|
158
|
+
- **Objects & tags (16)**: 6 reads (address/service objects + groups,
|
|
159
|
+
application filters, tags) + 10 CRUD for the same.
|
|
160
|
+
- **NAT (5)**: 1 read + add/delete/move/set_disabled.
|
|
161
|
+
- **User-ID (3)**: mappings, groups, agent config.
|
|
162
|
+
- **Administrators (3)**: admin accounts, role definitions, auth profiles.
|
|
163
|
+
- **VPN (3)**: IPSec tunnels, GlobalProtect users, GlobalProtect config.
|
|
164
|
+
- **Panorama (29)**: 20 reads (managed devices, device groups, templates,
|
|
165
|
+
shared objects, pre/post rules, log collectors, push/commit status, HA,
|
|
166
|
+
device-group hierarchy) + 9 rule CRUD (pre/post/DG-NAT).
|
|
167
|
+
- **Logs (5)**: traffic, threat, system, config, URL filter.
|
|
168
|
+
- **Threat & content (4)**: WildFire status, AV signatures, content versions,
|
|
169
|
+
URL categories.
|
|
170
|
+
- **Certificates (7)**: 3 reads + 4 decryption rule CRUD.
|
|
171
|
+
- **Licenses (2)**: license info, usage details.
|
|
172
|
+
- **Utility (2)**: `get_config_xpath` (read), `run_op_command` (admin).
|
|
173
|
+
- **Server diagnostic (2)**: `server_status`, `list_firewalls`. Always
|
|
174
|
+
available, even in `read` mode.
|
|
175
|
+
- **Aggregations (5)**: see Token efficiency above.
|
|
176
|
+
- **Commit & raw API (5, admin-only)**: `commit`, `panorama_commit`,
|
|
177
|
+
`panorama_push_to_devices`, `set_config`, `delete_config`.
|
|
178
|
+
|
|
179
|
+
### Notes
|
|
180
|
+
|
|
181
|
+
- pan-os-python 1.12.x still imports the removed-in-Python-3.12 `distutils`
|
|
182
|
+
module. The package shims it from `setuptools._distutils` in
|
|
183
|
+
`panos_mcp/__init__.py` before any pan-os-python import. When
|
|
184
|
+
pan-os-python ships a 2.0 that drops the legacy import, the shim becomes
|
|
185
|
+
a no-op and can be removed.
|
|
186
|
+
- pan-os-python 1.12.5 doesn't model QoS rules. QoS CRUD tools fall back to
|
|
187
|
+
`client.xapi.set/delete/move/edit` with hand-built XML
|
|
188
|
+
(`tools/_xml_writers.py`), using `xml.sax.saxutils.escape` on every
|
|
189
|
+
interpolated value. Deletable when pan-os-python adds first-class QoS.
|
|
190
|
+
- A handful of read tools (`get_dos_profiles`, `get_certificates`,
|
|
191
|
+
`get_decryption_profiles`, `get_userid_config`) include guarded
|
|
192
|
+
`ImportError` stubs for pan-os-python classes that may not exist on all
|
|
193
|
+
versions. These auto-upgrade to native modeling when present.
|
|
194
|
+
|
|
195
|
+
### Verification
|
|
196
|
+
|
|
197
|
+
- 227 unit tests + benchmark suite passing on Python 3.13/3.14
|
|
198
|
+
- Ruff (`E F I B UP SIM RUF`), `ruff format`, and mypy (`--strict`) clean
|
|
199
|
+
across all source files
|
|
200
|
+
- POSIX file-permission tests skipped on Windows; everything else runs on
|
|
201
|
+
every platform
|
|
202
|
+
|
|
203
|
+
[Unreleased]: https://github.com/Node804/node804-panos-mcp/compare/v0.1.6...HEAD
|
|
204
|
+
[0.1.6]: https://github.com/Node804/node804-panos-mcp/releases/tag/v0.1.6
|
|
205
|
+
[0.1.5]: https://github.com/Node804/node804-panos-mcp/releases/tag/v0.1.5
|
|
206
|
+
[0.1.0]: https://github.com/Node804/node804-panos-mcp/releases/tag/v0.1.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael Pope
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: node804-panos-mcp
|
|
3
|
+
Version: 0.1.6
|
|
4
|
+
Summary: Token-efficient MCP server for Palo Alto Networks PAN-OS firewalls and Panorama
|
|
5
|
+
Project-URL: Homepage, https://github.com/Node804/node804-panos-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/Node804/node804-panos-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/Node804/node804-panos-mcp/issues
|
|
8
|
+
Author-email: Michael Pope <me@michaelpope.cv>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: firewall,mcp,model-context-protocol,network-security,palo-alto,pan-os,panorama,panos
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Information Technology
|
|
14
|
+
Classifier: Intended Audience :: System Administrators
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: System :: Networking :: Firewalls
|
|
21
|
+
Classifier: Topic :: System :: Systems Administration
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.13
|
|
24
|
+
Requires-Dist: httpx<1.0,>=0.28.1
|
|
25
|
+
Requires-Dist: keyring<30,>=25.0
|
|
26
|
+
Requires-Dist: mcp[cli]<2.0,>=1.3.0
|
|
27
|
+
Requires-Dist: node804-mcp-toolkit<1.0,>=0.1.0
|
|
28
|
+
Requires-Dist: pan-os-python<2.0,>=1.12.0
|
|
29
|
+
Requires-Dist: pydantic<3.0,>=2.10.6
|
|
30
|
+
Requires-Dist: python-dotenv<2.0,>=1.0.0
|
|
31
|
+
Requires-Dist: setuptools>=68
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: mypy<2.0,>=1.10; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-asyncio<2.0,>=0.23; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-cov<9.0,>=5.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest<11.0,>=8.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
38
|
+
Requires-Dist: tiktoken<1.0,>=0.7; extra == 'dev'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# PAN-OS MCP Server
|
|
42
|
+
|
|
43
|
+
[](https://github.com/Node804/node804-panos-mcp/actions/workflows/ci.yml)
|
|
44
|
+
[](https://pypi.org/project/node804-panos-mcp/)
|
|
45
|
+
[](https://pypi.org/project/node804-panos-mcp/)
|
|
46
|
+
[](LICENSE)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
A token-efficient [MCP](https://modelcontextprotocol.io/) server for **Palo Alto Networks PAN-OS firewalls and Panorama**, built around three principles:
|
|
50
|
+
|
|
51
|
+
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.
|
|
52
|
+
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`.
|
|
53
|
+
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.
|
|
54
|
+
|
|
55
|
+
**137 tools** across system, diagnostics/troubleshooting, network, security, objects, NAT, user-ID, admin, VPN, Panorama, logs, threat, certificates, licenses, utility, and aggregation surfaces.
|
|
56
|
+
|
|
57
|
+
## Permission Modes
|
|
58
|
+
|
|
59
|
+
| Mode | Tools | Description |
|
|
60
|
+
|------|-------|-------------|
|
|
61
|
+
| `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. |
|
|
62
|
+
| `standard` | 99 | Read + object and tag CRUD (address objects, service objects, tags). No policy rules. |
|
|
63
|
+
| `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.** |
|
|
64
|
+
| `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.** |
|
|
65
|
+
|
|
66
|
+
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`.
|
|
67
|
+
|
|
68
|
+
## Setup
|
|
69
|
+
|
|
70
|
+
### Prerequisites
|
|
71
|
+
|
|
72
|
+
- **[uv](https://docs.astral.sh/uv/)** (recommended) — manages Python and dependencies for you
|
|
73
|
+
- or **Python 3.13+** with pip
|
|
74
|
+
- A **PAN-OS firewall or Panorama** with the XML API enabled, plus an API key (see below)
|
|
75
|
+
|
|
76
|
+
### Getting a PAN-OS API key
|
|
77
|
+
|
|
78
|
+
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`.
|
|
79
|
+
|
|
80
|
+
> **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.
|
|
81
|
+
|
|
82
|
+
**curl:**
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
curl -k -X POST "https://fw.example.com/api/?type=keygen" \
|
|
86
|
+
--data-urlencode "user=apiread" \
|
|
87
|
+
--data-urlencode "password=<password>"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**PowerShell:**
|
|
91
|
+
|
|
92
|
+
```powershell
|
|
93
|
+
$body = @{ user = 'apiread'; password = '<password>' }
|
|
94
|
+
(Invoke-RestMethod -Method Post -Uri 'https://fw.example.com/api/?type=keygen' -Body $body -SkipCertificateCheck).response.result.key
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
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.
|
|
98
|
+
|
|
99
|
+
### Environment Variables
|
|
100
|
+
|
|
101
|
+
| Variable | Required | Description |
|
|
102
|
+
|----------|----------|-------------|
|
|
103
|
+
| `PANOS_HOST` | Yes\* | Single-firewall hostname. \*Not required in multi-firewall mode (see [Multi-firewall configuration](#multi-firewall-configuration)). |
|
|
104
|
+
| `PANOS_API_KEY` | Yes\* | Single-firewall API key. Stored in the OS keychain in multi-firewall mode. |
|
|
105
|
+
| `PANOS_MODE` | No | RBAC mode: `read`, `standard`, `full`, or `admin`. Default: `read`. |
|
|
106
|
+
| `PANOS_TLS_VERIFY` | No | `true` / `false` / `1` / `0` / `yes` / `no`. Default: `true`. |
|
|
107
|
+
| `PANOS_TLS_CA` | No | Path to a custom PEM CA bundle. Default: system trust store. |
|
|
108
|
+
| `PANOS_FIREWALLS_CONFIG` | No | Override path for `firewalls.json`. Default: `~/.config/panos-mcp/firewalls.json`. |
|
|
109
|
+
| `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. |
|
|
110
|
+
| `PANOS_ENABLE_RAW_CONFIG` | No | Register `set_config` / `delete_config` (also requires `PANOS_MODE=admin`). Default: `false`. |
|
|
111
|
+
| `PANOS_ENABLE_RAW_OPS` | No | Register `run_op_command` (also requires `PANOS_MODE=admin`). Default: `false`. |
|
|
112
|
+
| `PANOS_RAW_XPATH_ALLOW` | No | Comma-separated XPath prefixes that `set_config` / `delete_config` are restricted to. Default: unset (all non-denied). |
|
|
113
|
+
|
|
114
|
+
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`](src/panos_mcp/tools/_guards.py).
|
|
115
|
+
|
|
116
|
+
### Install
|
|
117
|
+
|
|
118
|
+
**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:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uvx node804-panos-mcp==0.1.6
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Option B — pip:**
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
pip install node804-panos-mcp
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Option C — from source (development):**
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
git clone https://github.com/Node804/node804-panos-mcp.git
|
|
134
|
+
cd node804-panos-mcp
|
|
135
|
+
uv sync # or: pip install -e ".[dev]"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
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.
|
|
139
|
+
|
|
140
|
+
> Until `node804-mcp-toolkit` is published to PyPI, install it from source first: `pip install git+https://github.com/Node804/node804-mcp-toolkit.git`
|
|
141
|
+
|
|
142
|
+
### Claude Desktop
|
|
143
|
+
|
|
144
|
+
1. Open your Claude Desktop config file:
|
|
145
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
146
|
+
- **Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
147
|
+
|
|
148
|
+
2. Add the server under `mcpServers` (create the file if it doesn't exist):
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"mcpServers": {
|
|
153
|
+
"PAN-OS": {
|
|
154
|
+
"command": "uvx",
|
|
155
|
+
"args": ["node804-panos-mcp==0.1.6"],
|
|
156
|
+
"env": {
|
|
157
|
+
"PANOS_HOST": "fw.example.com",
|
|
158
|
+
"PANOS_API_KEY": "LUFRPT1xxx...",
|
|
159
|
+
"PANOS_MODE": "read"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
If you installed with pip instead of uv, use `"command": "python"` with `"args": ["-m", "panos_mcp"]`.
|
|
167
|
+
|
|
168
|
+
3. 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.
|
|
169
|
+
|
|
170
|
+
### Claude Code (CLI)
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
claude mcp add node804-panos-mcp \
|
|
174
|
+
-e PANOS_HOST=fw.example.com \
|
|
175
|
+
-e PANOS_API_KEY=LUFRPT1xxx... \
|
|
176
|
+
-e PANOS_MODE=read \
|
|
177
|
+
-- uvx node804-panos-mcp==0.1.6
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Verify with `claude mcp list`.
|
|
181
|
+
|
|
182
|
+
### Verifying It Works
|
|
183
|
+
|
|
184
|
+
Once connected, ask your LLM:
|
|
185
|
+
|
|
186
|
+
- **"What's my access level?"** → calls `server_status`, showing the active mode, live tool counts, TLS posture, and configured firewalls
|
|
187
|
+
- **"What firewalls are configured?"** → calls `list_firewalls`, confirming the registry and which targets require an explicit `firewall` argument
|
|
188
|
+
|
|
189
|
+
If either fails, see [Troubleshooting](#troubleshooting).
|
|
190
|
+
|
|
191
|
+
## Token efficiency
|
|
192
|
+
|
|
193
|
+
Every list-returning tool accepts these parameters (from `node804-mcp-toolkit`):
|
|
194
|
+
|
|
195
|
+
| Parameter | Default | Effect |
|
|
196
|
+
|---|---|---|
|
|
197
|
+
| `verbose` | `false` | When `true`, returns every field the underlying API exposes. Default returns only the fields most relevant to the tool's purpose. |
|
|
198
|
+
| `fields` | `null` | Explicit projection. `["name", "action", "disabled"]` returns exactly those fields. Overrides both `verbose` and the default whitelist. |
|
|
199
|
+
| `pagination.limit` | `100` | Max items per response. Hard ceiling: 1000. |
|
|
200
|
+
| `pagination.offset` | `0` | Skip count. Use with `limit` to page through inventories. |
|
|
201
|
+
| `pattern` | `null` | Server-side substring filter on the item's name field. Far cheaper than fetching the inventory and filtering client-side. |
|
|
202
|
+
|
|
203
|
+
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`.
|
|
204
|
+
|
|
205
|
+
### Measured savings
|
|
206
|
+
|
|
207
|
+
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.
|
|
208
|
+
|
|
209
|
+
| Scenario | Naive approach | Tokens | Better approach | Tokens | Saving |
|
|
210
|
+
| --- | --- | ---: | --- | ---: | ---: |
|
|
211
|
+
| Find an address object by IP | `get_address_objects` (dump 500) | 21,207 | `find_address_object("10.0.0.5")` | 88 | **241× smaller** |
|
|
212
|
+
| Inventory snapshot | `get_address_objects` (dump 500) | 21,207 | `count_objects_by_type` | 27 | **785× smaller** |
|
|
213
|
+
| Audit security policy | `get_security_rules` (verbose, 100 rules) | 19,627 | `summarize_security_policy` | 58 | **338× smaller** |
|
|
214
|
+
| Audit security policy | `get_security_rules` (lean, 100 rules) | 5,095 | `summarize_security_policy` | 58 | **88× smaller** |
|
|
215
|
+
| Find rules matching a pattern | `get_security_rules` (lean dump) | 5,095 | `find_rule_by_name("rule-001")` | 249 | **20× smaller** |
|
|
216
|
+
| Filter rules by pattern | `get_security_rules` (no filter) | 5,095 | `get_security_rules(pattern="rule-00")` | 523 | **10× smaller** |
|
|
217
|
+
| Lean default vs verbose | `get_security_rules(verbose=true)` | 19,627 | `get_security_rules` (default) | 5,095 | **74% reduction** |
|
|
218
|
+
|
|
219
|
+
Run the benchmark suite yourself:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
pytest -v -s -m benchmark
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The headline number: **a policy audit that would cost ~20K tokens via the naive "dump everything" approach costs ~60 tokens via `summarize_security_policy`.**
|
|
226
|
+
|
|
227
|
+
## Audit logging
|
|
228
|
+
|
|
229
|
+
Every tool invocation can be captured to a JSON-lines file:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
export PANOS_AUDIT_LOG=/var/log/panos-mcp/audit.jsonl
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Each line is one event:
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
{"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}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
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.
|
|
242
|
+
|
|
243
|
+
The audit log is the only after-the-fact record for admin-mode operations (`commit`, `set_config`, `run_op_command`). Treat it accordingly.
|
|
244
|
+
|
|
245
|
+
## TLS verification
|
|
246
|
+
|
|
247
|
+
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:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
# Option A: trust a custom CA bundle
|
|
251
|
+
export PANOS_TLS_CA=/etc/pki/internal-ca.pem
|
|
252
|
+
|
|
253
|
+
# Option B: disable verification (emits a startup warning)
|
|
254
|
+
export PANOS_TLS_VERIFY=false
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The startup log reports the active posture:
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
PanOS TLS: verify=ON (system trust store)
|
|
261
|
+
PanOS TLS: verify=ON (custom CA via PANOS_TLS_CA)
|
|
262
|
+
PanOS TLS: verify=OFF (PANOS_TLS_VERIFY=false)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Multi-firewall configuration
|
|
266
|
+
|
|
267
|
+
For environments managing multiple firewalls or Panorama instances, define them in `~/.config/panos-mcp/firewalls.json` (override with `PANOS_FIREWALLS_CONFIG=/path`):
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"firewalls": [
|
|
272
|
+
{ "name": "hq", "host": "hq.example.com" },
|
|
273
|
+
{ "name": "branch", "host": "branch.example.com" },
|
|
274
|
+
{ "name": "panorama", "host": "panorama.example.com" }
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
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.
|
|
280
|
+
|
|
281
|
+
**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.
|
|
282
|
+
|
|
283
|
+
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.
|
|
284
|
+
|
|
285
|
+
## Tools by category
|
|
286
|
+
|
|
287
|
+
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`.
|
|
288
|
+
|
|
289
|
+
| Category | Read | Standard | Full | Admin | Total |
|
|
290
|
+
| :---------------- | ---: | -------: | ---: | ----: | ----: |
|
|
291
|
+
| System | 4 | — | — | — | 4 |
|
|
292
|
+
| Diagnostics | 5 | — | — | — | 5 |
|
|
293
|
+
| Network | 8 | — | 2 | — | 10 |
|
|
294
|
+
| Security | 6 | — | 12 | — | 18 |
|
|
295
|
+
| Objects & tags | 6 | 10 | — | — | 16 |
|
|
296
|
+
| NAT | 1 | — | 4 | — | 5 |
|
|
297
|
+
| User-ID | 3 | — | — | — | 3 |
|
|
298
|
+
| Administrators | 3 | — | — | — | 3 |
|
|
299
|
+
| VPN | 3 | — | — | — | 3 |
|
|
300
|
+
| Panorama | 22 | — | 9 | — | 31 |
|
|
301
|
+
| Logs | 5 | — | — | — | 5 |
|
|
302
|
+
| Threat & content | 4 | — | — | — | 4 |
|
|
303
|
+
| Certificates | 3 | — | 4 | — | 7 |
|
|
304
|
+
| Licenses | 2 | — | — | — | 2 |
|
|
305
|
+
| Utility | 4 | — | — | 1 | 5 |
|
|
306
|
+
| Server diagnostic | 2 | — | — | — | 2 |
|
|
307
|
+
| Aggregations | 8 | — | — | — | 8 |
|
|
308
|
+
| Commit & raw API | — | — | — | 6 | 6 |
|
|
309
|
+
| **Total** | **89** | **+10** | **+31** | **+7** | **137** |
|
|
310
|
+
|
|
311
|
+
A few entries worth calling out by name:
|
|
312
|
+
|
|
313
|
+
- **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.
|
|
314
|
+
- **Utility** — `get_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.
|
|
315
|
+
- **Aggregations** (read) — includes `get_rule_hit_counts` and `unused_rules` for usage-based rule cleanup.
|
|
316
|
+
- **Commit & raw API** (admin) — `commit`, `panorama_commit`, `panorama_push_to_devices`, `revert_config`, `set_config`, `delete_config`.
|
|
317
|
+
- **Server diagnostic** — `server_status` and `list_firewalls`. Always available, even in `read` mode.
|
|
318
|
+
|
|
319
|
+
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.
|
|
320
|
+
|
|
321
|
+
## Aggregation tools
|
|
322
|
+
|
|
323
|
+
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.
|
|
324
|
+
|
|
325
|
+
| Tool | What it answers |
|
|
326
|
+
|---|---|
|
|
327
|
+
| `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. |
|
|
328
|
+
| `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. |
|
|
329
|
+
| `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. |
|
|
330
|
+
| `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. |
|
|
331
|
+
| `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. |
|
|
332
|
+
| `get_rule_hit_counts(rule_base, vsys)` | Per-rule hit counts and last-hit timestamps (`show rule-hit-count`) — which rules actually carry traffic. |
|
|
333
|
+
| `unused_rules(vsys, include_disabled=False)` | Security rules with zero hits, joined with the rulebase for disabled status — a ready cleanup worklist. |
|
|
334
|
+
|
|
335
|
+
All are gated at `Mode.READ` — same tier as the underlying inventory reads.
|
|
336
|
+
|
|
337
|
+
## Troubleshooting
|
|
338
|
+
|
|
339
|
+
| Symptom | Cause | Fix |
|
|
340
|
+
|---------|-------|-----|
|
|
341
|
+
| `No module named panos_mcp` | Package not installed | Use the `uvx` config (installs automatically), or run `pip install node804-panos-mcp`. |
|
|
342
|
+
| Server starts but tools return an auth error | Invalid or expired API key | Regenerate the key (see [Getting a PAN-OS API key](#getting-a-pan-os-api-key)) and update your config. The key is invalidated if the admin's password changes. |
|
|
343
|
+
| 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). |
|
|
344
|
+
| Tools you expect are missing | Mode is too restrictive | Check `server_status` for the active mode, then raise `PANOS_MODE` (`read` → `standard` → `full` → `admin`). |
|
|
345
|
+
| 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. |
|
|
346
|
+
| "firewall is required" errors | Multi-firewall mode with no target | Pass `firewall: <name>`; run `list_firewalls` to see configured targets. |
|
|
347
|
+
| `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`. |
|
|
348
|
+
| 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. |
|
|
349
|
+
|
|
350
|
+
## Development
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
git clone https://github.com/Node804/node804-panos-mcp.git
|
|
354
|
+
cd node804-panos-mcp
|
|
355
|
+
pip install -e ".[dev]" # or: uv sync --extra dev
|
|
356
|
+
|
|
357
|
+
pytest -v # full test suite
|
|
358
|
+
pytest -v -m "not integration and not benchmark" # CI-equivalent
|
|
359
|
+
ruff check . && ruff format --check . # lint + format
|
|
360
|
+
mypy src # type check
|
|
361
|
+
node804-panos-mcp # boot the server
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
`node804-mcp-toolkit` installs automatically as a dependency. Until it's on PyPI, install it from source first (see [Install](#install)).
|
|
365
|
+
|
|
366
|
+
## Acknowledgments
|
|
367
|
+
|
|
368
|
+
Built on [`pan-os-python`](https://github.com/PaloAltoNetworks/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.
|
|
369
|
+
|
|
370
|
+
## AI-Assisted Development
|
|
371
|
+
|
|
372
|
+
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.
|
|
373
|
+
|
|
374
|
+
## License
|
|
375
|
+
|
|
376
|
+
MIT
|