Mode: read-only by default; installs require two gates (below)
v2.0.0: this skill previously declared FORTIMANAGER_MCP_CMD pointing at
jmpijll/fortimanager-mcp, which was never vendored, never registered and not
installable — the skill was a claim with no server behind it. It is now backed by
fortinet-mcp, and the command variable changed to FORTINET_MCP_CMD because one
server serves all three Fortinet planes.
The distinction this skill exists to protect
FortiManager holds INTENT. It does not know what a device is actually doing.
Question
Plane
Skill
"What policy is supposed to apply here?"
manager
this skill
"What is the box actually running? Is the tunnel up?"
device
fortigate-ops
"Has anything ever matched this rule?"
analyzer
fortianalyzer-ops
"Run a raw FortiOS CLI command"
CLI
multivendor-raw-cli (spec 076)
A policy package and a FortiGate's running config legitimately diverge between
installs. That gap is where drift, unauthorised change and failed installs live —
use fgt_compare_with_manager to surface it rather than assuming they agree.
Tools (8 read-only + 2 write)
Tool
What it answers
fmg_list_adoms
Which ADOMs exist. The ADOM scopes everything else
fmg_list_devices
Managed FortiGates, connection and sync status
fmg_list_policy_packages
Packages in an ADOM and their install targets
fmg_get_policy_package
Ordered rules: position, action, enabled state
fmg_search_rules
Rules matching a source, destination, service or object
outcome distinguishes results that look alike: ok, empty_result,
plane_unreachable, auth_expired, auth_missing, scope_indeterminate, and the
three separate write refusals. An expired session is auth_expired, never "no
policies exist" — that would be a silent, plausible, wrong answer.
Workflow: policy package audit
fmg_list_adoms → pick the ADOM. A package name is unique only within one.
fmg_list_policy_packages → find the package and its install targets.
fmg_get_policy_package → ordered rules. Note position: shadowing is positional.
fmg_resolve_object on every group a rule references. A rule reported only by
object name is not an audit — "allow GRP_CORP to GRP_DMZ" says nothing about
which addresses that permits.
fmg_get_revisions → rollback context before proposing any change.
Feed the rules to fwrule-analyzer for overlap, shadowing and conflict analysis.
Workflow: is intent matching reality?
fmg_get_policy_package — the intent.
fgt_compare_with_manager (in fortigate-ops) — the divergence.
only_in_device entries are candidate out-of-band changes: someone edited
the firewall directly. This is the single most valuable finding here.
only_in_manager usually means the package has not been installed since those
rules were added — check fmg_list_devices sync status.
Writes: two gates, and neither substitutes for the other
fmg_install_package pushes policy to production firewalls — the highest
blast-radius action available here.
Condition
Outcome
FORTINET_ALLOW_WRITES not set
refused_read_only
No approved_by
refused_no_approval
No approved ServiceNow CR (non-lab)
refused_no_change_record
Both present
proceeds: revision identified → install → verify
Human approval and a ServiceNow change record are different gates. A CR does
not imply a human said yes; a human saying yes does not imply change control
approved it. Lab devices waive the CR gate only — never the approval gate — and
a device that cannot be classified is treated as production.
Always run fmg_preview_install first. It shows what would change and needs no gate.
Integration with other skills
Skill
How they compose
fortigate-ops
Device-plane state; fgt_compare_with_manager for drift
fortianalyzer-ops
Whether a rule has actually matched traffic
fwrule-analyzer
Feed retrieved policy to its FortiOS parser for overlap/shadowing
servicenow-change-workflow
Supplies the CR that satisfies gate 2 of fmg_install_package
multivendor-raw-cli
Raw FortiOS CLI (spec 076) — a different plane, not a substitute
gait-session-tracking
Every operation here is GAIT-audited automatically
Important rules
Treat package install as production change execution — baseline, verify, rollback.
Always name the ADOM. A package without one is ambiguous.
Resolve objects before drawing conclusions.
Never present manager intent as observed device state.
An empty result is not an error, and auth_expired is not "no data".