Valkyrian Labs logo

Tools

The four tools, their input schemas, results and annotations.

Tools

forti-mcp offers four tools. With --read-only only the first two are listed, and calls to the others are refused with a protocol error (Protocol).

ToolDoesTouches the device
forti_discoverProfiles, a device's identity, version and mode, resource search, a resource's attributesOnly for what: capabilities and live: true (reads)
forti_readConfiguration or monitor dataReads
forti_planValidates a change and stores it as a planReads only
forti_applyExecutes a stored plan, by plan_id onlyWrites, if the profile's mode allows

Every input schema is strict (additionalProperties: false): an unknown argument is an error, and the message lists the allowed ones. The schemas mirror the engine's requests, which forti-cli shares.

Start here

forti_discover

Profiles, device identity and mode, resource search and resource details.

Read

forti_read

Configuration or monitor data, bounded and paginated.

Plan

forti_plan

Validates a change and stores it as a plan, without touching the device.

Apply

forti_apply

Executes a stored plan, by plan_id only, as the profile's mode allows.

Results

Every tool returns the engine's envelope as structuredContent, and the same JSON as the first text content block. isError is true exactly when ok is false.

1{"ok": true, "data": "...", "meta": {"profile": "home", "resource": "firewall/address", "start": 0, "returned": 50, "next_start": 50}}2{"ok": false, "error": {"code": "not_found", "message": "...", "details": {}}}

The outputSchema of every tool describes this envelope: ok (boolean, required), data, meta (object) and error (object with code and message, and optional details).

Anything the model can correct is a tool result with isError: true, not a protocol error: invalid arguments (code usage, with the failing JSON pointer, e.g. /operations/0/op: must be one of "create", "update", "delete", "action"), and every engine and device error.

error.codeMeaning
usageBad arguments or request shape
configMissing or invalid profile, credentials or configuration file
connectionDNS, connect, TLS or timeout
authHTTP 401 or 403
not_foundThe object does not exist
unknown_resourceThe path is not in the catalog
validationUnknown or read-only attribute, or a value that does not decode
apiAny other FortiOS error
stale_planThe device changed since the plan was made
approval_requiredGuarded mode, and the plan has no valid approval
policy_deniedThe profile is read-only, or the plan cannot run (already applied, backup failed, tampered)
partial_failureApply stopped part-way; details has the record
management_connectivity_lostApply stopped after a critical change cut the management path
outcome_unknownA change may have reached the device without a reply
internalA bug or unexpected state

Results are bounded by the byte budget (Large results and paging).

Annotations

ToolreadOnlyHintdestructiveHintidempotentHintopenWorldHint
forti_discovertruenot setnot setfalse
forti_readtruenot setnot setfalse
forti_plantruenot setnot setfalse
forti_applyfalsetruefalsefalse

forti_plan is read-only for the device: it reads the current objects and writes only a local plan file. Every tool also has a title, repeated in its annotations.

Clients may run forti_plan without asking

Some clients run read-only tools without asking. The safety guide covers what that means for planning.

forti_discover

"Start here." Profiles, device identity and mode, resource search and resource details.

FieldTypeDescription
whatdevices, resources, resource, capabilitiesDefault: resource when resource is given, else resources
querystring, at most 256 charactersresources: case-insensitive substring of the path, e.g. addr
kindtable, singleton, monitorresources: restrict to one kind
startinteger, at least 0First item (default 0); continue with meta.next_start
countinteger, 1 to 1000Items per page (default 50)
resourcestring, 1 to 256 charactersresource: e.g. firewall/address, firewall.service/custom, system/interface, monitor/system/status
fieldsarray of up to 200 stringsresource: attributes to describe in full (nested children, and live help and options with live)
livebooleanresource: merge the device's live schema
profilestring matching ^[A-Za-z0-9_-]{1,64}$Device profile; default: --profile, else the configured default
whatdata
devicesThe profiles: name, host, port, mode and where the key comes from (never the key); meta.default_profile
capabilitiesprofile, device (serial, version, build, hostname, model), sdk_schema_version, schema_matches_device, mode, resources (catalog size)
resourcesMatching resources (resource, kind, key); meta.total, start, returned, next_start
resourceresource, kind, key, fields (every attribute, or full detail of the selected ones), operations (read, write) and risk; with live, the device's help text, options and ranges; meta.schema_version, meta.live

Everything except capabilities and live: true is answered from the compiled-in catalog. Monitor paths that are not in the catalog can still be read untyped with forti_read.

forti_read

Read configuration (cmdb tables and singletons) or monitor data over the FortiOS REST API.

FieldTypeDescription
resourcestring, 1 to 256 characters, requiredResource path from forti_discover: firewall/address, firewall/policy, system/global, monitor/system/status, ...
keystring or integerTable object key (its name, or the number for policyid-style keys)
filterarray of up to 32 stringsFortiOS filter clauses, ANDed: ["type==ipmask", "name=@lan"]
fieldsarray of up to 200 stringsReturn only these attributes, e.g. ["name", "subnet"]
startinteger, at least 0First item (default 0); continue with meta.next_start
countinteger, 1 to 1000Items per page (default 50)
vdomstring matching ^[A-Za-z0-9._-]{1,31}$VDOM (default: the profile's)
profilestring matching ^[A-Za-z0-9_-]{1,64}$Device profile
paramsobject of string, number or boolean valuesExtra query parameters, mainly for monitor endpoints

Each string in filter and fields is 1 to 256 characters. Filter operators are ==, !=, =@, !@, <, <=, > and >=; a comma inside one clause ORs. Attribute names in filter and fields are checked against the catalog.

data is the device's JSON as FortiOS sent it (an object for key and singletons, an array for listings), with secrets replaced by "<redacted>". meta has resource, profile, device (serial, version, build), vdom, and for listings start, returned, next_start, total and truncated as described in Large results and paging, plus redacted (JSON pointers of redacted values, e.g. ["/*/psksecret"]).

forti_plan

Validate a configuration change and store it as a plan, without touching the device.

FieldTypeDescription
operationsarray, at least 1 item, requiredThe operations, run in order at apply time
profilestring matching ^[A-Za-z0-9_-]{1,64}$Device profile
vdomstring matching ^[A-Za-z0-9._-]{1,31}$VDOM (default: the profile's)

Each operation:

FieldTypeDescription
opcreate, update, delete, action, required
resourcestring, 1 to 256 characters, requiredA cmdb resource; for action a monitor path (monitor/...)
keystring or integerupdate, delete: the object's key
objectobjectcreate: the new object's attributes
setobjectupdate: attributes to change
cleararray of up to 200 stringsupdate: attributes to reset to their defaults
bodyobjectaction: the request body

data has the plan id (pass it to forti_apply as plan_id), digest, kind, created_at, device (profile, host, port, vdom, serial, version), risk, summary, operations (each with its diff and the exact request, wire, secrets redacted), mode, notes, apply (the equivalent forti apply <id> command) and, in guarded mode, approve (forti plan approve <id>).

Redacted values cannot be written

A value of "<redacted>" is refused (validation): a model cannot write back a secret it was never shown.

forti_apply

Execute a stored plan on the live firewall.

Writes to the device

forti_apply is annotated destructive and not idempotent. Whether it runs depends on the profile's mode, not on the client (Safety and modes).

FieldTypeDescription
plan_idstring matching ^[a-z0-9][a-z0-9-]{11,31}$, requiredThe plan id forti_plan returned

Nothing else is accepted: the operations come from the stored plan. The outcome follows the profile's mode (Workflow):

ModeOutcome
read-onlypolicy_denied
guardedapproval_required until a person runs forti plan approve <plan_id>. forti-mcp adds details.approve_command and a second text block asking the model to relay the command
autonomousExecutes now

On success, data has status: "applied", plan_id, digest, operations (per-operation status: verified, applied_unverified, failed, outcome_unknown or not_attempted), the numbers verified and applied_unverified, rollback (the generated rollback plan, with its plan_id), backup for critical plans, and audit_error if the audit record could not be written. partial_failure, outcome_unknown and management_connectivity_lost carry the same record in error.details.