Skip to main content
Glama

mcfortigate

An MCP server that lets a language model read a FortiGate firewall and answer questions about it.

Read-only. Nothing in this server can change a configuration.

Full documentation: mcfortigate.warehack.ing

Why not just wrap the REST API

The obvious way to build this is one tool per FortiOS endpoint returning raw JSON, and that turns out to work badly. A single FortiOS policy object carries more than eighty fields, most of them empty strings, unused IPv6 arrays, and internal UUIDs. Ask a model "which policies allow traffic into the DMZ" against a raw wrapper and it spends most of its attention on "srcaddr6": [] before it finds anything useful.

So the tools here are shaped around the questions operators actually ask rather than around the endpoints FortiOS happens to expose. Three examples.

"Is this address object safe to delete?" is find_references, and it is the tool that shaped the rest of this server.

The obvious implementation scans the tables that obviously hold references: policies, groups, virtual IPs, routes. The appliance disagrees about what "obviously" covers. Asked directly, FortiOS 7.0.14 reports 74 tables that can reference a firewall address and 234 that can reference an interface. An object used only by a web-proxy profile comes back from the obvious implementation as unreferenced, which is a wrong answer in the direction that destroys data.

So the authority here is the appliance's own reference lookup, the one behind the reference counter in its web UI. Two things about it are worth knowing. Every row it returns carries reference_count: 0, genuine references included, so the presence of a row is the signal and the count is a trap. And asked about a key that is absent from the table you named, it answers success with an empty list, so guessing the wrong table reports an in-use object as free. Querying the address table about wan1 finds nothing while the interface table finds two references, which is why this tool works out what kind of object a name refers to before it asks.

It also walks past the direct referrer. The appliance's lookup is not transitive: an address inside a group reports the group and stops, so the policy that actually breaks never appears. On our lab, asking about the switch port internal1 directly returns one row — a virtual switch. Walking two more levels, through the switch and the interface that carries it, reaches the firewall policy that a change to that port would disturb. Reached references are reported separately from direct ones, each carrying the chain that found it, and the walk is depth-capped and says so when it stops early.

The answer is five-valued rather than a boolean, because there are genuinely five things that can be true. Beyond referenced and no_references there is object_not_found for a name that matches nothing, no_references_in_checked_scopes for when the authoritative lookup was unavailable and only the partial scan ran, and indeterminate for when the scan itself was incomplete. safe_to_delete appears only for the first two. A token scoped to firewall objects gets 403 on the routing table, and the client library turns every error status into an empty list, so doing least privilege correctly makes a false clean bill of health more likely, not less.

"What is 198.51.100.47?" is find_device. It searches the wireless client list, the DHCP lease table, and the ARP table, then merges what each one knows about a MAC into a single record.

MAC addresses are normalized before that join, and before matching a query against them. The appliance we test on spells every MAC the same way, so the normalization is insurance rather than an observed fix on that firmware — but the query side is a real defect it closes: a MAC pasted from anywhere else arrives as 20-47-47-7D-DB-7B or 2047.477d.db7b, and a substring match against the colon-separated table form finds nothing and reports the device unknown. The matcher also refuses to read an IPv4 address as a MAC fragment, since an address is nothing but hex digits and dots and a loose matcher would let one match an unrelated device.

"Where does 203.0.113.0/24 appear?" is search_config, which looks through addresses, groups, services, interfaces, routes, and policies at once, for when you do not yet know which kind of object holds the answer.

Related MCP server: Fortigate MCP

Install

uvx mcfortigate

Add it to Claude Code. Read the token rather than typing it on the command line, so it does not land in your shell history:

printf 'FortiGate API token: '; read -rs FORTIGATE_TOKEN; echo

claude mcp add fortigate \
  --env FORTIGATE_HOST=fgt.example.com \
  --env FORTIGATE_TOKEN="$FORTIGATE_TOKEN" \
  -- uvx mcfortigate

History records the literal "$FORTIGATE_TOKEN", because the line is recorded before the shell expands it.

That is worth doing and it is not sufficient. Claude Code stores MCP environment values in ~/.claude.json in plaintext, and nothing on this side changes that. Treat the token as readable at rest and put the real control on the appliance: a read-only profile, and a trusted-host list naming only the machine that runs this. Those hold even if the token leaks; keeping it out of history only means it leaks from one fewer place.

Configuration

Create a read-only REST API admin on the FortiGate under System > Administrators > Create New > REST API Admin, give it a read-only profile, and restrict its trusted hosts to whatever runs this server. Then set two variables:

FORTIGATE_HOST=fgt.example.com
FORTIGATE_TOKEN=your-token

A username and password pair works as a fallback on older firmware, via FORTIGATE_USERNAME and FORTIGATE_PASSWORD, but a token is better because it avoids a login round-trip on every call.

For several appliances, set FORTIGATE_TARGETS to a JSON object. The keys become the target argument on every tool, so short aliases are worth it:

FORTIGATE_TARGETS='{
  "edge":   {"host": "fgt-edge1.example.com", "token": "..."},
  "branch": {"host": "fgt-br2.example.com", "token": "...", "verify_ssl": false}
}'

With one appliance configured the target argument can be omitted everywhere. With several it is required, and omitting it produces an error listing the valid aliases so the model can correct itself.

See .env.example for the optional settings, which are FORTIGATE_NAME, FORTIGATE_VDOM, FORTIGATE_VERIFY_SSL, FORTIGATE_TIMEOUT, and FORTIGATE_PORT.

Tools

Orientation

Tool

Answers

list_targets

Which appliances can this server reach

get_system_status

Model, serial, firmware, hostname, CPU and memory

search_config

Where does this term appear, anywhere in the config

Firewall

Tool

Answers

list_address_objects

What named addresses exist, with readable values

list_address_groups

What groups exist and what is in them

list_services

What services exist, with protocols and ports

list_policies

What rules exist, in evaluation order, with filters

list_vips

What destination NAT is configured

find_references

What points at this object, and is it safe to delete

Network

Tool

Answers

list_interfaces

What interfaces exist, with addresses and link state

list_vlans

What VLANs exist, with tags and parent interfaces

list_static_routes

What routes were configured

get_routing_table

What routes are actually in use right now

Live state

Tool

Answers

list_wifi_clients

Who is on the wireless right now, with hostnames

list_dhcp_leases

What leases are currently issued

get_arp_table

What IP-to-MAC bindings the appliance sees

find_device

Who is this MAC, IP, or hostname

Configuration tools read what the appliance was told to do. Live tools read what it currently observes, and those answers are true only at the moment of the call. The distinction matters more than it sounds: a DHCP-assigned default route shows up in get_routing_table and never in list_static_routes, because it was never configured.

Why the listing tools page and the others do not

Every listing tool takes limit and offset, defaults to 200 rows, and always reports total_available. A partial page additionally carries truncated and next_offset.

The problem this solves is not memory. A FortiGate with four thousand ARP entries produces a response Python handles without noticing; what breaks is an MCP client with a size limit truncating the payload on the way to the model, which then reads whatever survived as the whole answer. Nothing in the data says otherwise. Bounding the result here makes the same truncation visible instead of silent.

The analysis tools — find_references, search_config, find_device — take no limit on purpose. They scan in order to reach a verdict, and a verdict from a partial scan is not a shorter answer, it is a wrong one.

FortiOS behaviors handled here

These were found against real hardware rather than in documentation, and each one fails silently rather than loudly, which is what makes them worth writing down.

Boolean fields are strings. FortiOS writes "enable" and "disable" where JSON would use true and false. Passing those through bool() reads every disabled thing as enabled, since bool("disable") is True. That single mistake once flipped every non-blackhole route to blackhole.

The same format means two things. A dotted-mask string like 203.0.113.0 255.255.255.0 is a network in firewall.address.subnet but the interface's own address in system.interface.ip. Collapsing the second to its network address invents IPs that do not exist.

Relational fields change shape by version. Fields such as dstaddr arrive as [{"name": "X"}] on FortiOS 7.2 and later, but as a bare string on 7.0.x. Both are handled.

dst is a placeholder when dstaddr is set. When a route points at a named address object, FortiOS writes the all-zeros sentinel into dst. Reading dst first turns every named-destination route into a bogus default route.

Identity lives in the envelope, not the body. The appliance serial, firmware version, and build number are siblings of results on every cmdb response, not inside it. Helpers that unwrap straight to results discard them, which makes the serial look absent from the API entirely.

FortiOS creates its own interfaces. Names prefixed wqtn., vap., ssl., and naf. are bookkeeping, generated alongside VAPs and VPN tunnels. They are hidden by default, since no operator made them and none can act on them. Pass include_internal=true to see them.

Development

uv venv && uv pip install -e ".[dev]"
uv run pytest
uv run ruff check src/ tests/

The reading layer in fortios.py and the configuration layer in config.py are pure functions with no network or framework coupling, so the test suite runs in under a second with no fixtures and no mock appliance.

The FortiOS behaviors above were learned while building nautobot-ssot-fortinet, which syncs FortiGate configuration into Nautobot in both directions. This server reuses that knowledge for a different purpose.

License

Apache-2.0

Available Tools

17 tools
find_deviceIdentify a device by MAC, IP, or hostnameA
Read-onlyIdempotent

Identify a device on the network by MAC, IP, or hostname fragment.

Searches the wireless client list, the DHCP lease table, and the ARP table together, then merges everything known about each matching device into one record. A device seen in several places produces one result rather than three partial ones.

This is the tool for questions like "what is 198.51.100.47", "is that laptop on the network", or "which SSID is this MAC on".

A MAC query matches whatever punctuation the appliance used, so 20-47-47-7d-db-7b, 2047.477d.db7b, and 20:47:47:7d:db:7b all find the same device. An IP query is never treated as a MAC.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to search. Defaults to the one configured for this target. The `vdom` field in the response names the one actually searched, and a device in another vdom will not be found from here.
queryYesA MAC address, an IP address, or part of a hostname. Matching is case-insensitive and substring-based, so a partial MAC or a bare hostname prefix works. Partial MACs must keep their separators to be recognized as MACs.
targetNoWhich FortiGate to query. Optional when only one is configured.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, openWorld, and non-destructive, so the safety profile is covered. The description adds genuinely non-obvious behavior: cross-source merging, one-result-per-device deduplication rather than three partial records, and MAC punctuation normalization. It does not discuss result ordering or ambiguity when many devices match, keeping it below 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short paragraphs, front-loaded with what the tool does, then behavior, then example questions, then query-format edge cases. No filler; each paragraph carries distinct information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described, and annotations carry the safety profile. The description still supplies the merge/dedup behavioral model and query-format rules, leaving no material gap for calling this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description goes further by explaining that MAC matching ignores punctuation (three equivalent forms shown) and that an IP query is never treated as a MAC — semantics that the schema's 'partial MACs must keep their separators' text alone does not make fully clear.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Identify a device on the network by MAC, IP, or hostname fragment') and explains the mechanism: it searches the wireless client list, DHCP lease table, and ARP table together and merges matches. This implicitly and clearly distinguishes it from the sibling raw-table tools list_wifi_clients, list_dhcp_leases, and get_arp_table.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete triggering questions ('what is 198.51.100.47', 'is that laptop on the network', 'which SSID is this MAC on'), which makes the use case unambiguous. It does not explicitly name an alternative tool or state when not to use it (e.g., when raw per-table output is wanted), so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_referencesFind what references an objectA
Read-onlyIdempotent

Find what references an address, service, or interface, before changing it.

This answers the question that precedes every firewall change, which is whether something is safe to touch.

The authority is the appliance itself. FortiOS exposes the same reference lookup its web UI uses, which knows every table that can hold a reference, seventy-four of them for a firewall address on 7.0.14. This tool asks that endpoint and reports what it says in references. It also scans policies, groups, virtual IPs, and static routes directly, because those yield readable detail the endpoint does not, such as a policy's name and action.

Read verdict rather than inferring from a count:

  • referenced, something points at it

  • no_references, the appliance confirmed nothing does

  • no_references_in_checked_scopes, the authoritative lookup was unavailable and a partial scan found nothing, which is a fact about four tables rather than about the appliance

  • object_not_found, no address, group, service, virtual IP, or interface by this name exists, so the question is probably a typo

  • indeterminate, something needed could not be read

safe_to_delete appears only for the first two, because a table this tool could not read cannot support a claim that nothing references the object. A denied read is the likely outcome for a correctly least-privileged token, so an incomplete answer is normal rather than exceptional, and sources_checked names what failed.

The two lists count different things, and will disagree without being in conflict. total_references and references count reference sites: a policy using one address as both its source and its destination is two. The detail lists (policies, groups, vips, routes) count objects, so the same policy appears once there, with referenced_as naming both roles. Neither number is wrong; prefer references when reporting what must be changed before a delete, and the detail lists when naming the objects an operator has to open.

Containers are walked through, and the results are kept separate. references holds what the appliance named directly and every row carries depth: 0. transitive_references holds what was reached through an address group, a service group, a zone, or a switch: each row carries the depth it was found at and a via chain of the container names that led to it. The distinction is the remedy. A direct reference is removed from the object holding it; a transitive one is removed by editing a container or a member list, and the policy that stops matching is not the object you edit.

expansion reports how far the walk got. status is complete when the chain ran out, depth_capped when it hit the ceiling with containers still unopened, which are then named in unexpanded, and incomplete when something along the way could not be read. Only complete means the transitive list is the whole blast radius.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to search. Defaults to the one configured for this target. An object with the same name can exist in several vdoms, and this answer is about one of them.
targetNoWhich FortiGate to query. Optional when only one is configured.
object_nameYesExact name of the address, group, service, virtual IP, or interface. Matching is exact, not a search.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations already declaring read-only, idempotent, and open-world behavior, the description adds rich operational context: the authoritative endpoint, supplementary direct scans, verdict semantics, when safe_to_delete is available, expected denied reads, the distinction between reference sites and objects, transitive reference handling, and expansion completeness. This is substantially more than the annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured with front-loaded purpose and bulleted verdict explanations. Every section appears to serve a distinct need for interpreting this tool's complex output, though some of the prose could be tightened without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of the reference lookup, the need to interpret verdicts and counts, and the existence of an output schema, the description is complete enough for an agent to call and interpret the tool correctly. It covers when to use it, how results are assembled, and how to read the return fields, leaving no critical gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all three parameters (object_name, vdom, target) are already documented in the schema. The description adds no further parameter-level detail such as matching syntax, vdom semantics, or target selection beyond what the schema states, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Find') and resource ('what references an address, service, or interface') and frames the tool's purpose as answering a pre-change safety question. It is clearly distinct from sibling list_* tools and search_config, which enumerate or search configurations rather than resolving references.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says when to use ('before changing it') and what question it answers ('whether something is safe to touch'). However, it does not name alternative tools (e.g., search_config) or state when not to use this tool, leaving some routing inference to the agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_arp_tableShow the ARP tableA
Read-onlyIdempotent

Show the ARP table, which is the IP-to-MAC bindings the appliance sees.

ARP catches devices DHCP does not, meaning anything with a static address, so it is the fallback when a device is present but holds no lease. MAC addresses are reported in one canonical form.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum rows to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.
interfaceNoKeep only entries learned on this interface, matched exactly. A name that matches no interface empties the list, so check `filtered_out` before reading an empty result as an empty ARP table.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds useful behavioral context by noting MAC addresses are reported in one canonical form, which is not in the structured fields. It does not mention pagination or rate limits, but the bar is lower due to annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences, front-loaded with the core purpose and immediately followed by the key usage distinction. Every sentence adds value: definition, comparison to DHCP, and a note on MAC address format.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only table listing tool with a rich output schema, full parameter coverage, and comprehensive annotations, the description covers purpose, usage context, and a behavioral detail (canonical MAC form). Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents all five parameters thoroughly, including defaults, limits, and the interface filter caveat. The description adds no parameter-specific information beyond what the schema provides, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Show) and resource (ARP table), then immediately defines what the ARP table is (IP-to-MAC bindings). It is clearly distinguishable from siblings like list_dhcp_leases because the description explains ARP catches devices DHCP does not.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a clear usage context: 'ARP catches devices DHCP does not... so it is the fallback when a device is present but holds no lease.' This implicitly tells the agent when to prefer this tool over list_dhcp_leases, though it does not explicitly name that sibling or state exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_routing_tableShow the active routing tableA
Read-onlyIdempotent

Show the active IPv4 routing table as the appliance is forwarding it.

This is live state rather than configuration, so it includes connected routes, dynamically learned routes, and routes handed over by DHCP, none of which appear in the static route configuration.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum rows to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.
protocolNoFilter by route type, such as static, connect, or dhcp. Matched exactly; `filtered_out` reports how many rows it removed.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, and openWorld, so the safety profile is covered. The description adds real behavioral content beyond that: it discloses that the result is live state including connected, dynamically learned, and DHCP-delivered routes that never appear in static config, which tells the agent what to expect in the payload.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no waste, with the core scope ('live state, not configuration') front-loaded immediately after the purpose statement. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and annotations covering safety and idempotency, the description only needs to frame what the tool returns and when it differs from config-oriented siblings, which it does. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with vdom, limit, offset, target, and protocol all documented in-schema, so the baseline is 3. The description adds no syntax or format detail beyond what the schema already supplies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Show the active IPv4 routing table') and pins down the scope as live forwarding state rather than config. It never names the obvious sibling list_static_routes, so the differentiation from that tool is left implicit rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The contrast between 'live state' and 'configuration' implies when this tool applies versus the static-route siblings, but no alternative tool is named and no when-not guidance is given. Usage is inferable rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_system_statusShow appliance identity and healthA
Read-onlyIdempotent

Report appliance identity and health: model, serial, firmware, load.

The serial and firmware version come from the response envelope rather than the body. FortiOS puts them as siblings of the results object on every cmdb call, and helpers that unwrap straight to results discard them, which is why they appear missing from the API until you read the raw response.

Fields that a given firmware does not report are omitted rather than returned as null, so an absent key means the appliance did not offer the value. FortiOS 7.0.14, for instance, reports no uptime anywhere in the monitor tree.

ParametersJSON Schema
NameRequiredDescriptionDefault
targetNoWhich FortiGate to query. Optional when only one is configured.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, open world), yet the description adds substantial non-obvious behavior: serial/firmware live in the response envelope not the body, and unreported fields are omitted rather than null so an absent key is meaningful. This is exactly the kind of quirk disclosure that prevents an agent from misreading the result.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and field list are front-loaded in the first sentence, which is the part that drives selection. The remaining sentences on envelope placement and omitted keys are long and drift into FortiOS API internals, which is informative for interpretation but heavier than strictly needed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so the description rightly avoids explaining return structure, and annotations carry the safety profile. It is nearly complete, only missing any guidance on the optional 'target' parameter's default behavior or when a multi-appliance scenario applies.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single 'target' parameter is fully documented in the schema, so the description carries no additional parameter burden. Baseline 3 applies since the description adds nothing beyond the schema here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Report') and resource ('appliance identity and health') and then enumerates the concrete fields returned: model, serial, firmware, load. Combined with the title, an agent can immediately distinguish this single-status tool from the surrounding list_* siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the field list (identity, health) makes the intended situation clear, but there is no explicit when-to-use statement, no prerequisites, and no alternatives named versus siblings like find_device or search_config. Adequate but with a clear gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_address_groupsList address groupsA
Read-onlyIdempotent

List firewall address groups and their members.

Compare count against total_available before concluding anything about the whole table. When truncated is present this is one page.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum groups to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.
name_containsNoCase-insensitive substring filter on the group name.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false. The description adds useful behavioral context beyond annotations by explaining that count should be compared to total_available and that truncated indicates a single page, which helps the agent interpret completeness.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core purpose and followed by a high-value pagination caveat. No repetition or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has an output schema, so return values need not be explained. Annotations cover safety, the schema covers parameters, and the description supplies the key pagination caveat, making the definition complete for an agent to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the schema already documents all five input parameters. The description adds no input-parameter semantics; the fields it mentions (count, total_available, truncated) are output fields, not inputs.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'List firewall address groups and their members.' It distinguishes itself from generic listing by including group members, but it does not name or compare against closely related siblings like list_address_objects.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no explicit guidance on when to use this tool versus alternatives such as list_address_objects. The only practical guidance concerns interpreting pagination output, not tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_address_objectsList address objectsA
Read-onlyIdempotent

List firewall address objects, optionally filtered.

Address objects are the named source and destination values that policies reference. Each is reported with its type and a single readable value, so a subnet object shows CIDR, an FQDN object shows the hostname, and a MAC object shows the MAC addresses.

Compare count against total_available before concluding anything about the whole table. When truncated is present this is one page and next_offset says where the following one begins.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum objects to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.
address_typeNoExact FortiOS type filter, such as ipmask, fqdn, iprange, geography, or mac.
name_containsNoCase-insensitive substring filter on the object NAME only, never the value. Searching for a subnet or an IP finds nothing here; search_config is the tool that looks at values.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety profile is covered. The description adds genuine behavioral context beyond that: how each object type is rendered into a single readable value, and how pagination flags (truncated, next_offset, count vs total_available) behave. Some of this overlaps with the output schema, which keeps it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose in the first clause, then spends its remaining sentences on information an agent actually needs (value rendering, pagination interpretation). Three short blocks with no filler, though the pagination paragraph is slightly verbose for what it conveys.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list tool with full annotation coverage, 100% schema description coverage, and an output schema, the description fills the remaining gaps: what an address object is, how values are surfaced, and how to read pagination metadata. Nothing an agent needs to call or interpret this tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all six parameters (including the vdom/target/limit/offset semantics and the name_contains-vs-values distinction) are already documented in the schema. The description itself only alludes to filtering generically. Baseline 3 is appropriate when the schema carries parameter detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('List firewall address objects, optionally filtered') and then defines the resource domain by explaining that address objects are the named source/destination values policies reference, which separates it from list_address_groups and list_services. The type-to-value mapping ('a subnet object shows CIDR, an FQDN object shows the hostname') further pins down what this tool returns versus other list_* siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete interpretive guidance for this tool's output ('Compare count against total_available before concluding anything about the whole table'), which tells the agent how to use the results correctly. It does not, however, state when to reach for a sibling such as search_config or list_address_groups in the description body itself. Clear context, but no explicit exclusions or alternatives at the description level.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_dhcp_leasesList DHCP leasesA
Read-onlyIdempotent

List current DHCP leases issued by the appliance.

Read filtered_out before concluding anything from a short list. Both filters here drop rows without saying so otherwise, and an interface name with a typo produces an empty list that looks exactly like an appliance handing out no leases.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum rows to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.
interfaceNoKeep only leases issued on this interface, matched exactly.
hostname_containsNoCase-insensitive substring filter on the hostname, falling back to the vendor class identifier when the client sent no name. A lease with neither is dropped by this filter.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety (readOnly, idempotent, non-destructive), yet the description adds genuinely new behavioral facts: both filters silently drop rows, and a mistyped interface yields an empty result indistinguishable from an appliance issuing no leases. That is exactly the kind of hidden-behavior disclosure annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, purpose front-loaded, then the single most consequential caveat. No filler and no repetition of schema content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a low-complexity, all-optional list tool with an output schema and full annotation coverage, the description supplies everything an agent needs: what it returns, how filters can mislead, and which response field to check before drawing conclusions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description goes beyond the schema by cross-referencing filtered_out and warning that both filter parameters drop rows without signalling it. It adds interpretive meaning the parameter descriptions alone do not convey, though it does not touch limit/offset/target semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb and resource ('List current DHCP leases issued by the appliance'), which is enough for an agent to distinguish it from siblings like list_wifi_clients or get_arp_table. It stops short of explicitly contrasting with any alternative, but the resource is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear operational guidance for interpreting results ('Read filtered_out before concluding anything from a short list') and explains the trap of a typo'd interface name producing an empty list. It does not, however, name a sibling tool or say when a different listing tool would be the better choice.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_interfacesList interfacesA
Read-onlyIdempotent

List interfaces with their addresses, VLAN tags, and link state.

FortiOS creates bookkeeping interfaces alongside real ones, such as the quarantine interface that accompanies every wireless VAP. Those are hidden by default and named in hidden_internal so the omission is visible.

Which ones count as bookkeeping is decided by the appliance rather than by the name. FortiOS reports whether each interface is offered as a policy endpoint, and anything it offers is shown regardless of what it is called, so this tool cannot hide an interface a policy could name. hidden_internal_basis says whether that lookup succeeded; when it did not, the fallback is the name and the omission is less trustworthy.

Filters narrow the list silently unless you read filtered_out, which names each active filter and how many rows it removed. with_ip_only keeps interfaces carrying an IPv4 address in the configuration, which includes a DHCP interface that has taken a lease, because FortiOS writes the leased address back into the config.

An interface that holds no address reports addressing instead of ip. Use get_routing_table for the runtime view.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum interfaces to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.
with_ip_onlyNoKeep only interfaces carrying an IPv4 address in the configuration.
interface_typeNoExact FortiOS type filter, such as physical, vlan, aggregate, hard-switch, switch, or tunnel. Not a substring match.
include_internalNoInclude FortiOS-generated interfaces, meaning those the appliance does not offer as policy endpoints and whose names carry a generated prefix such as wqtn., vap., ssl., or naf.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover only the safety profile (readOnly/idempotent/destructive/openWorld); the description adds substantial behavioral context: bookkeeping interfaces hidden by default, the appliance-driven rather than name-driven hiding rule, the hidden_internal_basis fallback and when the omission is less trustworthy, and silent filtering disclosed via filtered_out. This is far beyond what the structured fields convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first sentence and every paragraph carries distinct information. It is dense and longer than typical, with several sentences devoted to output-field semantics rather than the call itself, but little is truly redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a seven-parameter listing tool with an output schema and rich annotations, this is complete: it covers identity, scoping, hidden-by-default behavior, filter transparency, the address-field quirk, and the sibling alternative. An agent could call this correctly without reading anything else.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning the schema lacks: it clarifies that with_ip_only counts a DHCP interface holding a leased address, and explains why interfaces without an address report `addressing` instead of `ip`. It does not touch limit/offset/interface_type, which the schema already covers well.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource ('List interfaces') and immediately names what is returned: addresses, VLAN tags, link state. It also distinguishes itself from get_routing_table by scoping itself to configuration rather than the runtime view.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent to get_routing_table for the runtime view and explains when include_internal and with_ip_only are relevant. It stops short of a full 'use this vs. list_vlans' disambiguation, but the runtime/configuration split is a clear contextual guide.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_policiesList firewall policiesA
Read-onlyIdempotent

List firewall policies in evaluation order, optionally filtered.

Policies come back in the order FortiOS evaluates them, and each carries an explicit order index so that ordering survives filtering and re-serialization. Order is the entire meaning of a ruleset, and a list position is not something downstream is obliged to preserve.

Three counts appear and they mean different things. count is rows in this page, total_available is rows matching your filters, and total_policies is the size of the whole ruleset. A truncated flag means this is one page of the matches, not all of them, which matters more here than elsewhere: reasoning about a ruleset from an arbitrary prefix of it produces confident wrong answers about what traffic is allowed.

The filters match names exactly and do not expand indirection. A policy referencing a group that contains your address will not match address, and a policy referencing a zone that contains your interface will not match interface. If filtered_out shows a filter removed everything, that is the cue: the object is probably reached through a group or a zone, and find_references answers "what touches this object" properly, walking those containers.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum policies to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large ruleset.
targetNoWhich FortiGate to query. Optional when only one is configured.
addressNoKeep only policies naming this address object or group directly, on either side.
serviceNoKeep only policies naming this service object directly.
interfaceNoKeep only policies naming this interface directly as a source or destination interface.
enabled_onlyNoDrop policies whose status is disabled.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile (readOnly, idempotent, non-destructive), so the bar is lower, yet the description still discloses non-obvious behavior: the meaning of the three distinct counts, the `truncated` paging flag and why prefix-based reasoning about a ruleset is dangerous, and the fact that filters match names exactly and do not expand indirection.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short paragraphs, each front-loaded with its point (ordering, counts, filter semantics, fallback to find_references), and no filler sentences. It is longer than average but every paragraph carries distinct, actionable information, so it stops just short of maximal conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, yet the description explains the counts and truncation flag that an agent must interpret to avoid confident wrong answers. Combined with filtering caveats and the find_references fallback, nothing needed to call this tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3, but the description adds real semantic content the schema lacks: that `address`/`interface`/`service` filters match only direct references and will not match objects reached through a group or zone. That changes how an agent interprets a null result.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List firewall policies') and immediately adds the decisive scope detail: results come back in FortiOS evaluation order with an explicit `order` index. It is clearly separable from siblings like list_address_objects or find_references.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use context and names the alternative: when `filtered_out` shows the filter removed everything, the object is likely reached through a group or zone and 'find_references answers "what touches this object" properly'. That is a concrete condition plus a named sibling, not inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_servicesList servicesA
Read-onlyIdempotent

List firewall service objects with their protocols and ports.

Compare count against total_available before concluding anything about the whole table. When truncated is present this is one page.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum services to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.
name_containsNoCase-insensitive substring filter on the service name.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so safety is covered. The description adds genuine behavioral context beyond that: it warns that the response may be paginated and tells the agent to compare count against total_available and to treat a truncated field as a single-page signal, which prevents premature conclusions about the whole table.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences: the purpose is front-loaded and the pagination caveat follows immediately, with zero filler. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value explanation is not required, and the description appropriately focuses on the pagination fields (count, total_available, truncated) that matter for correct use. It is nearly complete, though it never explains that the tool requires no required parameters or how offset interacts with limit for paging.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter (vdom, limit, offset, target, name_contains) is already documented, including the 200 default and 1000 cap. The description adds no additional parameter syntax or format detail, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'List firewall service objects with their protocols and ports,' which also hints at what the returned objects contain. It distinguishes itself implicitly from siblings like list_vips or list_policies by resource name, but never explicitly names an alternative or scoping boundary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit when-to-use guidance or routing to an alternative sibling tool (e.g., search_config or find_references) for drilling into services. The sentences about count/total_available and truncated are about interpreting results, not about when this tool is the right choice over another.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_static_routesList configured static routesA
Read-onlyIdempotent

List configured static routes.

These are the routes an operator configured, which is not the same as the routes in use. A DHCP-assigned default route never appears here because it was never configured. Use get_routing_table for what the appliance is actually forwarding on.

A route whose destination is a named address object is resolved to the underlying CIDR where possible, with the object name kept alongside it.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. Routes are per-vdom, so this changes the answer on a multi-VDOM appliance. The `vdom` field names the one actually read.
limitNoMaximum rows to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint=true, idempotentHint=true, openWorldHint=true, and destructiveHint=false, covering the safety profile. The description adds useful behavioral context beyond that: configured routes are not necessarily routes in use, DHCP default routes never appear, and named address objects are resolved to CIDRs with the object name preserved. It does not discuss authentication or rate limits, but for a read-only list operation the added data-scoping behavior is substantial.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, then adds the distinction from get_routing_table and the object-resolution behavior in a logical order. Every sentence carries useful information without redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema, full schema descriptions for all four optional parameters, and annotations covering safety and idempotency, the description only needs to add context that the structured fields cannot convey. It does so by clarifying the configured-vs-in-use distinction, the DHCP exclusion, and the address-object resolution behavior, leaving no essential gap for an agent to call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents vdom, limit, offset, and target thoroughly. The description adds no parameter-level meaning beyond what the schema provides, which makes the baseline score of 3 appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource ('List configured static routes') and immediately distinguishes it from the sibling get_routing_table by explaining the configured-vs-in-use difference. It also excludes DHCP-assigned default routes, so an agent can tell exactly what this tool returns versus what it does not.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly names the alternative tool and the condition that selects it: 'Use get_routing_table for what the appliance is actually forwarding on.' It further clarifies when a route will not appear here (DHCP-assigned default routes), which is a clear when-not-to-use signal.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_targetsList configured FortiGatesA
Read-onlyIdempotent

List the FortiGate appliances this server can reach.

Call this first when several appliances may be configured, since every other tool takes an optional target argument naming one of these. When exactly one is configured, that argument can be omitted entirely.

Credentials are never included in the response.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already establish read-only, idempotent, non-destructive behavior, but the description adds useful context beyond them: credentials are never included in the response, and this tool orients later calls by discovering valid target names. It does not discuss rate limits or auth requirements, but for a parameterless list operation with output schema present, the disclosure is strong.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the core purpose, then the operational guidance. Every sentence earns its place without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless discovery tool with annotations and an output schema, the description covers the essential context: what it lists, when to call it, how its results relate to other tools, and a key privacy guarantee. Nothing needed for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With zero parameters, the baseline is 4. The description does not need to explain parameters for this tool, though it helpfully explains that other tools take an optional target argument derived from this tool's results.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'List the FortiGate appliances this server can reach.' It clearly distinguishes this discovery/orientation tool from the many sibling list_* tools, which list configuration objects rather than reachable appliances.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says to call this first when several appliances may be configured, explains why (every other tool takes an optional target argument), and clarifies that the target argument can be omitted when exactly one appliance is configured. This gives direct when-to-use guidance and the condition for the alternative behavior.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_vipsList virtual IPsA
Read-onlyIdempotent

List virtual IPs, which are the destination NAT rules.

A VIP maps an external address, and optionally an external port, to an internal one. FortiOS stores those addresses inline on the VIP rather than as references to address objects.

Compare count against total_available before concluding anything about the whole table. When truncated is present this is one page.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum VIPs to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive/openWorld, so the safety profile is covered. The description earns credit by adding real behavioral context the annotations lack: how to read `count` vs `total_available` and what `truncated` means for paging.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads what a VIP is, then the storage detail, then the pagination caveat; no filler. Slightly more sprawling than a single tight sentence, but each clause carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and annotations covering safety, the description supplies the only missing piece — pagination semantics — so an agent can call it correctly. It stops short of explicit routing advice against the many sibling list_* tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so vdom, limit, offset and target are already fully documented in the schema. The description adds no parameter-level syntax or constraint beyond that, which is the correct baseline of 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource ("List virtual IPs") plus domain grounding: "destination NAT rules" that map an external address/port to an internal one. This is enough to separate it from siblings like list_address_objects and list_policies without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the resource described, and the pagination note tells the agent when the result is partial, but no sibling tool is named as an alternative and no when-not-to-use condition is given. Adequate but with a clear gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_vlansList VLANsA
Read-onlyIdempotent

List VLAN sub-interfaces with their tags and parent interfaces.

A focused view of the VLAN subset of the interface table, since what VLANs exist and what they attach to is asked far more often than the full interface list. FortiOS quarantine VLANs are excluded, and filtered_out says how many that was.

ParametersJSON Schema
NameRequiredDescriptionDefault
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum rows to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds valuable behavioral context beyond annotations: FortiOS quarantine VLANs are excluded, and a filtered_out count reports how many were omitted. It does not mention pagination behavior, but the schema already documents limit and offset.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences and front-loads the core purpose before explaining the rationale and exclusion behavior. It is efficient and avoids repetition, though the second sentence carries some explanation that could be trimmed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a full output schema, four fully documented parameters, and complete annotations, the description does not need to explain return values or parameter formats. It adds the key domain-specific caveat about quarantine VLAN exclusion and filtered_out. The only minor gap is explicit guidance on sibling selection, which would make usage unambiguous.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all four parameters are fully documented in the input schema including defaults and caps. The description does not add parameter syntax, format, or semantics beyond the schema, which is the expected baseline when the schema does the work.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: list VLAN sub-interfaces with their tags and parent interfaces. It also distinguishes itself from the closest sibling, list_interfaces, by framing itself as a focused subset. However, it does not explicitly name list_interfaces or list_vlans alternatives, leaving a small gap.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives implied usage: it explains that this is a focused view because VLANs are asked about more often than the full interface list. But it never states when an agent should choose list_vlans instead of list_interfaces or any other sibling, nor any prerequisites such as required target or vdom context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_wifi_clientsList connected wireless clientsA
Read-onlyIdempotent

List wireless clients currently associated, enriched with DHCP and ARP.

Each client is joined against the DHCP lease and ARP tables by MAC, which is what turns an anonymous MAC into a recognizable device. The hostname comes from the DHCP lease, falling back to the vendor class identifier when the client sent no name. MAC addresses are reported in one canonical lowercase colon-separated form whatever spelling the source used, since that is what makes the join work at all.

authenticated is true or false only when the appliance said so, and absent when it did not, because inferring "not authenticated" from a missing field would fabricate a security-relevant claim.

ParametersJSON Schema
NameRequiredDescriptionDefault
ssidNoKeep only clients associated to this SSID, matched exactly. `filtered_out` reports how many clients it removed.
vdomNoVirtual domain to read. Defaults to the one configured for this target. The `vdom` field in the response names the one actually read.
limitNoMaximum rows to return. Defaults to 200, capped at 1000.
offsetNoIndex to start from, for paging through a large table.
targetNoWhich FortiGate to query. Optional when only one is configured.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover the safety profile (readOnly, idempotent, openWorld), so the description carries the behavioral load and does so well: it explains the MAC-based join, the hostname fallback to vendor class identifier, MAC canonicalization, and the tri-state `authenticated` field where absence is deliberately not treated as false to avoid fabricating a security claim.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the verb and resource, and the multi-paragraph structure separates data-provenance semantics from the field-level caveat. Slightly verbose on MAC canonicalization, but every sentence carries substantive information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and full annotations, the description need not explain return values, and it complements them with the provenance and null-semantics an agent needs. The only real gap is guidance on when to prefer this over the DHCP-lease or ARP siblings.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so ssid, vdom, limit, offset and target are already fully documented in the schema. The description adds no parameter-level format or syntax detail, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List wireless clients currently associated') and immediately qualifies the scope with the DHCP/ARP enrichment, which cleanly distinguishes it from siblings like list_dhcp_leases and get_arp_table. An agent can route to it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The enrichment explanation implies when this is preferable to a raw MAC listing, but there is no explicit when-to-use or when-not-to-use statement naming alternatives among the many list_* siblings. Usage is inferable rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_configSearch the whole configurationA
Read-onlyIdempotent

Search the whole configuration for a term, across every object type.

Looks through address objects and groups, services, interfaces, static routes, and optionally policies, matching names, values, comments, and member lists. This is the tool for an open question such as "where does 203.0.113.0/24 appear" or "what mentions guest", when you do not yet know which kind of object holds the answer.

Check sources_checked before concluding from a zero result. A source that could not be read contributes no matches, so no matches is not the same as nothing found.

ParametersJSON Schema
NameRequiredDescriptionDefault
termYesCase-insensitive substring to look for.
targetNoWhich FortiGate to query. Optional when only one is configured.
include_policiesNoSearch policy names, comments, and member lists. Policies are the largest table, so this can be turned off when only object definitions matter.

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint=false, openWorldHint), so the bar is lower, yet the description adds a genuinely non-obvious caveat: a source that could not be read contributes no matches, so an empty result is not proof of absence and sources_checked must be inspected. It also discloses what fields are matched (names, values, comments, member lists) and the case-insensitive substring semantics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and scope, then the object coverage, then the critical zero-result caveat. The coverage sentence and the open-question sentence overlap slightly in function, so it is efficient but not maximally tight.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With three well-documented parameters, an output schema, and rich annotations, the description supplies exactly the missing piece: how to interpret a zero result via sources_checked. Nothing an agent needs to invoke it or read its output correctly is absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already explains term, target, and the include_policies tradeoff in full detail. The description only echoes the optional-policies behavior and adds no new syntax, format, or defaulting meaning beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (search) and scope (the whole configuration, across every object type), then enumerates the covered domains: address objects and groups, services, interfaces, static routes, and optionally policies. An agent can distinguish this cross-cutting search from the enumerating siblings (list_address_objects, list_policies, list_static_routes) without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames the use case as the open-ended question ('where does 203.0.113.0/24 appear', 'what mentions guest') when the object type is unknown, which implicitly excludes the list_* siblings that require knowing the type. It also gives a concrete tuning rule: drop include_policies when only object definitions matter.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 17 tool updatesv0.1.0
    • First observedfind_device
    • First observedfind_references
    • First observedget_arp_table
    • First observedget_routing_table
    • First observedget_system_status
    • First observedlist_address_groups
    • First observedlist_address_objects
    • First observedlist_dhcp_leases
    • First observedlist_interfaces
    • First observedlist_policies
    • First observedlist_services
    • First observedlist_static_routes
    • First observedlist_targets
    • First observedlist_vips
    • First observedlist_vlans
    • First observedlist_wifi_clients
    • First observedsearch_config

TDQS

A4.1/5.0

Scored across 17 tools

Disambiguation5/5

Each tool targets a clearly distinct FortiGate resource or action. Overlaps such as list_interfaces vs list_vlans, find_device vs the individual client/lease/ARP lists, and find_references vs search_config are explicitly distinguished in the descriptions.

Naming Consistency5/5

All tools follow a consistent snake_case verb_noun pattern: list_*, get_*, find_*, search_*. The verb choice accurately reflects the operation, with no mixing of conventions.

Tool Count4/5

17 tools is slightly above the typical 3-15 range, but each covers a distinct inspection surface for FortiGate appliances. A few could be consolidated (e.g. list_vlans as a filtered list_interfaces), but the count is reasonable for the domain breadth.

Completeness4/5

The set provides broad read-only coverage of firewall policies, addresses, services, interfaces, routes, references, and client/lease/ARP data. Some useful read surfaces are missing (logs, security profiles, zones/schedules, single-object detail beyond list filters), and mutation operations appear intentionally out of scope.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    Provides real-time access to Firewalla firewall data through 28 specialized tools for network monitoring, security analysis, bandwidth tracking, and firewall rule management. Enables users to query security alerts, analyze network flows, monitor device status, and manage firewall configurations through natural language.
    45
    1
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables read-only querying and diagnostics of Fortigate firewalls via SSH, providing security analysis, traffic monitoring, and configuration inspection through natural language.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Provides read-only SSH access to network devices (routers, switches, firewalls) with command allow/deny policies, nt-templates output parsing, and an audit trail, enabling an AI agent to query device state securely.
    10
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI assistants to manage FortiGate firewalls from bootstrap to production, with safe preview/apply changes and secure credential handling. Covers inventory, VDOMs, interfaces, routing, firewall policies, VPN, security analysis, and documentation generation.
    MIT