Wiring it into Claude Code
The one-liner from getting started is enough to work. This covers the decisions it makes for you.
Which scope
Section titled “Which scope”claude mcp add writes the server into one of three places, and the choice
determines who else gets it and whether your token ends up in git.
# local (default) — this project, this machine, not committedclaude mcp add fortigate \ --env FORTIGATE_HOST=fgt.example.com \ --env FORTIGATE_TOKEN=your-token \ -- uvx mcfortigate
# user — every project on this machineclaude mcp add fortigate --scope user \ --env FORTIGATE_HOST=fgt.example.com \ --env FORTIGATE_TOKEN=your-token \ -- uvx mcfortigate
# project — written to .mcp.json, which is committedclaude mcp add fortigate --scope project -- uvx mcfortigate--scope user is right for an appliance you ask about from anywhere, which is
most of them. A firewall is rarely a property of one repository.
Verifying
Section titled “Verifying”claude mcp list # every configured server and its statusclaude mcp get fortigate # this one, including the command and scopeInside a session, /mcp shows connection status and the tools each server
exposes. A server that connected reports seventeen tools; one that failed
reports the error.
The server also writes a line to stderr at startup, which Claude Code surfaces in the MCP logs:
mcfortigate v2026.9.11 | targets: fgt.example.comThat line is the fastest way to tell a credential problem from a configuration
problem. If it names your appliance, the environment reached the process and
anything still failing is between the server and the firewall. If it says
targets: none configured, the environment did not reach the process at all.
Pinning a version
Section titled “Pinning a version”uvx mcfortigate fetches the latest release each time the server starts, which
is usually what you want. When it is not — a change-freeze window, or
reproducing a result from last month — pin it:
claude mcp add fortigate \ --env FORTIGATE_HOST=fgt.example.com \ --env FORTIGATE_TOKEN=your-token \ -- uvx mcfortigate@2026.9.11Versions are dates. 2026.9.11 is the release built on 11 September 2026,
which tells you when it was last tested against a real appliance — a more
useful fact about a server that talks to vendor firmware than a semantic
version number would be.
Asking questions from a script
Section titled “Asking questions from a script”Claude Code’s headless mode turns any of this into something you can run from
cron or CI. Two flags matter: -p auto-denies tools by default, so
--allowedTools is what grants permission.
claude -p "List every enabled policy that allows traffic to the internet, \ with its source objects and services. Answer as a markdown table." \ --allowedTools "mcp__fortigate__*"The tool naming convention is mcp__<server-name>__<tool-name>, so the
wildcard grants the whole server. To grant a narrower set — a scheduled job
that should only ever read live state, say:
claude -p "How many wireless clients are connected, by SSID?" \ --allowedTools "mcp__fortigate__list_wifi_clients"Without --allowedTools, every tool call is auto-denied and the model answers
that it has no access, which looks exactly like a broken server.
Several appliances
Section titled “Several appliances”Set FORTIGATE_TARGETS instead of FORTIGATE_HOST and the aliases become the
target argument on every tool. The multi-appliance
guide covers the whole pattern, including what to
do about the JSON quoting, which is the part that bites.