firewalla-mcp-server
Query and monitor your Firewalla firewall through the MSP API: 24 read-only tools by default, plus 11 opt-in write tools that are off unless FIREWALLA_ENABLE_WRITE_TOOLS=true.
Security alarms: list active alarms (
get_active_alarms), get one alarm's details (get_specific_alarm), search alarms by type (1–16), status, device IP or region (search_alarms).Network flows: pull flow data with paging/streaming (
get_flow_data), a 50-flow "right now" snapshot (get_recent_flow_activity), or advanced filtered searches by protocol, status, domain, category, IP, time (search_flows).Devices: check online/offline status (
get_device_status), list offline devices (get_offline_devices), search by name/IP/MAC/vendor/network (search_devices).Firewall rules: list rules (
get_network_rules), summarize counts by action/direction/status/target (get_network_rules_summary), search by action, target, protocol, scope (search_rules).Target lists: list them (
get_target_lists), fetch one with its entries (get_specific_target_list), search by owner, category, target or count (search_target_lists).Analytics: account statistics (
get_simple_statistics), top regions by blocked flows (get_statistics_by_region), top boxes (get_statistics_by_box), category/device insights (get_flow_insights), and flow, alarm and rule trends (get_flow_trends,get_alarm_trends,get_rule_trends).Bandwidth: top devices by upload+download over 1h/24h/7d/30d (
get_bandwidth_usage).Inventory: list the boxes your token can access (
get_boxes).Readable output: every read-only tool takes
response_format— compact JSON (default) or markdown tables.Opt-in writes: create/delete/pause/resume rules, create/update/delete target lists, rename devices, and archive/mute/delete alarms (need a write-capable MSP token).
Transports: stdio for Claude Desktop/Code, or HTTP (with bearer token, Host/Origin allowlists, rate limiting) for Docker and orchestrators.
Supports containerized deployment with Docker, allowing the MCP server to run in isolated containers with appropriate environment variables.
Provides real-time access to Firewalla firewall data through 28 specialized tools for network monitoring, security analysis, bandwidth tracking, rule management, and target list management.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@firewalla-mcp-servershow me recent security alerts from the last hour"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Firewalla MCP Server
A Model Context Protocol (MCP) server that provides real-time access to Firewalla firewall data through 28 read-only tools, plus 11 opt-in write tools, compatible with any MCP client.
This is a community project, not affiliated with Firewalla. It reads your data through the Firewalla MSP API, so it needs an MSP account with API access.
Why Firewalla MCP Server?
Simple Network Security Integration
28 read-only tools for network monitoring and analysis: 23 Direct API Endpoints + 5 Convenience Wrappers
11 write tools, off unless
FIREWALLA_ENABLE_WRITE_TOOLS=true, so by default nothing can change your boxAdvanced Search with query syntax and filters
Clean, Verified Architecture with corrected API schemas
Related MCP server: Firewalla MCP Server
Features
Real-time Firewall Data: Query security alerts, network flows, and device status
Security Analysis: Get insights on threats, blocked attacks, and network anomalies
Bandwidth Monitoring: Track top bandwidth consumers and usage patterns
Rule Management: View firewall rules; with the write tools, create, pause, resume and delete them
Target Lists: View target lists; with the write tools, create, update and delete them
Search Tools: Query syntax with filters and logical operators
Client Setup Guides
Client | Quick Start | Full Guide |
Claude Desktop |
| |
Claude Code |
| |
VS Code | Built-in MCP (1.102+): | |
Cursor |
| |
Roo Code | The extension was shut down on 2026-05-15; the guide covers existing installs | |
Cline | MCP Servers → Configure → | |
Open WebUI | mcpo, or a native MCP connection over HTTP |
How It Works
Claude Desktop/Code ↔ MCP Server ↔ Firewalla APIThe MCP server acts as a bridge between Claude and your Firewalla firewall, translating Claude's requests into Firewalla API calls and returning the results in a format Claude can understand.
Prerequisites
Node.js 18+ and npm. On Node 18-22, npm prints an
EBADENGINEwarning for geoip-lite 2.x, which declares Node 24 for its database update script; the lookups the server uses run on Node 18 and later, and CI tests 18, 20, 22 and 24.Firewalla MSP account with API access
Your Firewalla device online and connected
Upgrading to 2.0.0
2.0.0 changes these defaults from 1.5.0. A setup that relied on an old default needs the setting in the last column.
Up to 1.5.0 | From 2.0.0 | What to set |
| All 11 write tools are off; the server lists 24 read-only tools, and a call to a write tool answers "Unknown tool" and sends nothing |
|
The HTTP transport listened on every interface | It listens on 127.0.0.1. The Docker image sets |
|
Any | 403 unless it is | the name clients connect by (a compose service name, a LAN address) in |
Any | 403 for a request with an | the page's origin in |
No token check ( | On an address other than loopback, the Docker image's |
|
Any path starting with | Only the configured | a client URL that ends in exactly the configured |
| Refused with |
|
| Each server process starts at most | when several server processes or other clients use one token, an |
Other changes a script may notice:
With
FIREWALLA_BOX_IDset,get_alarm_trendscovers that box instead of every box, and makes 31 requests for the default30dinstead of 1. An explicitgroupstill reads the group's series in one request.Tool responses are compact JSON, without the indentation.
AND,ORandNOTare translated to the API's grammar, which has none of them:status:blocked AND region:USmatched 0 flows up to 1.5.0 and now matches whatstatus:blocked region:USdoes. A query with no API form is refused as a validation error that suggests runnable queries: anORbetween different fields,NOTover anAND, a comma list with a space around a comma, and geographic names the API does not have, such ascountry:(useregion:). Up to 1.5.0 these returned wrong results or none.IDs are no longer trimmed: an ID with leading or trailing whitespace,
/,?,#or%is refused before any request.A streamed
get_flow_datachunk gives each flow's time asts, an ISO string, like a plain page, instead oftimestamp.Over HTTP, a request with the session ID of a session the server no longer holds gets 404 instead of 400.
CHANGELOG.md has the full list.
Quick Start
1. Installation
Option A: Install from npm (Recommended)
# Install globally
npm install -g firewalla-mcp-server
# Or install locally in your project
npm install firewalla-mcp-serverOption B: Use Docker
Warning: Not for production use – secrets visible in process list
The examples below pass credentials directly in the command line, which exposes them to process listing and shell history. For production use, consider these secure alternatives:
Use
--env-filewith a.envfile:docker run --env-file .env ...Set environment variables in your shell before running Docker
Use Docker secrets for orchestration environments
Stdio Transport (Default - for Claude Desktop integration):
# Using Docker Hub image (minimal config)
docker run -it --rm \
-e FIREWALLA_MSP_TOKEN=your_token \
-e FIREWALLA_MSP_ID=yourdomain.firewalla.net \
amittell/firewalla-mcp-server
# Or with optional box filter
docker run -it --rm \
-e FIREWALLA_MSP_TOKEN=your_token \
-e FIREWALLA_MSP_ID=yourdomain.firewalla.net \
-e FIREWALLA_BOX_ID=your_box_gid \
amittell/firewalla-mcp-server
# Or build locally
docker build -t firewalla-mcp-server .
docker run -it --rm \
-e FIREWALLA_MSP_TOKEN=your_token \
-e FIREWALLA_MSP_ID=yourdomain.firewalla.net \
firewalla-mcp-server
# Recommended: Using env file (more secure)
docker run -it --rm --env-file .env amittell/firewalla-mcp-serverHTTP Transport (for standalone Docker containers and external access):
# Make a token and keep the value echo prints: every client sends it
export MCP_HTTP_BEARER_TOKEN="$(openssl rand -hex 32)"
echo "$MCP_HTTP_BEARER_TOKEN"
# Run with HTTP transport on port 3000. -e MCP_HTTP_BEARER_TOKEN with no
# value passes the exported one without putting it on the command line
docker run -d --name firewalla-mcp \
-p 3000:3000 \
-e MCP_TRANSPORT=http \
-e MCP_HTTP_PORT=3000 \
-e MCP_HTTP_BEARER_TOKEN \
-e FIREWALLA_MSP_TOKEN=your_token \
-e FIREWALLA_MSP_ID=yourdomain.firewalla.net \
amittell/firewalla-mcp-server
# Add FIREWALLA_BOX_ID if you want to filter to a specific box
# -e FIREWALLA_BOX_ID=your_box_gid \
# The server will be accessible at http://localhost:3000/mcp, and clients
# send the header: Authorization: Bearer <the token echo printed>
# Using env file (recommended): besides the credentials, .env sets
# MCP_TRANSPORT=http and MCP_HTTP_BEARER_TOKEN; to add a new token to it:
# echo "MCP_HTTP_BEARER_TOKEN=$(openssl rand -hex 32)" >> .env
docker run -d --name firewalla-mcp \
-p 3000:3000 \
--env-file .env \
amittell/firewalla-mcp-server
# For docker-compose
cat > docker-compose.yml << EOF
version: '3.8'
services:
firewalla-mcp:
image: amittell/firewalla-mcp-server
ports:
- "3000:3000"
environment:
- MCP_TRANSPORT=http
- MCP_HTTP_PORT=3000
# The image already listens on every interface of the container
- MCP_HTTP_HOST=0.0.0.0
# From the shell or a .env next to this file; openssl rand -hex 32
- MCP_HTTP_BEARER_TOKEN=\${MCP_HTTP_BEARER_TOKEN}
# Other containers reach it as http://firewalla-mcp:3000/mcp
- MCP_HTTP_ALLOWED_HOSTS=firewalla-mcp
- FIREWALLA_MSP_TOKEN=\${FIREWALLA_MSP_TOKEN}
- FIREWALLA_MSP_ID=\${FIREWALLA_MSP_ID}
# Optional: filter to specific box
# - FIREWALLA_BOX_ID=\${FIREWALLA_BOX_ID}
restart: unless-stopped
EOF
docker-compose up -dThe image sets MCP_HTTP_HOST=0.0.0.0 so that a published port reaches the server, and on that address the server does not start without MCP_HTTP_BEARER_TOKEN (at least 16 characters; openssl rand -hex 32 makes one): the container exits with code 1, and docker logs shows a refusing to start line that says why. -p 3000:3000 publishes the port on every interface of the Docker host, where anyone on your network can reach it. Publishing it on this machine only (-p 127.0.0.1:3000:3000) still needs the token: another container on the same Docker network can connect to the container's own address, and one that did, with Host: localhost and no token, got 200 when the check was turned off. MCP_HTTP_ALLOW_NO_TOKEN=true turns the check off, for a network no untrusted machine or container can reach, such as a compose network with no published port; the server then prints a warning when it starts. The server answers only requests whose Host header is localhost, 127.0.0.1 or [::1], so a client that connects by another name, such as the host's LAN address or a compose service name, needs that name in MCP_HTTP_ALLOWED_HOSTS. See HTTP transport security.
Option C: Install from source
git clone https://github.com/amittell/firewalla-mcp-server.git
cd firewalla-mcp-server
npm install
npm run build2. Configuration
Create a .env file with your Firewalla credentials:
# Required
FIREWALLA_MSP_TOKEN=your_msp_access_token_here
FIREWALLA_MSP_ID=yourdomain.firewalla.net
# Optional - filters all queries to a specific box
# FIREWALLA_BOX_ID=your_box_gid_here
# Optional - default box for single-box operations, without filtering queries
# FIREWALLA_DEFAULT_BOX_ID=your_box_gid_here
# Optional - register the 11 write tools (default: off, read-only)
# FIREWALLA_ENABLE_WRITE_TOOLS=trueGetting Your Credentials:
Log into your Firewalla MSP portal at
https://yourdomain.firewalla.netYour MSP ID is the full domain (e.g.,
company123.firewalla.net)Generate an access token in API settings
(Optional) Find your Box GID in device settings to filter queries to a specific box, or retrieve available boxes using the
get_boxestool
Box ID is optional. Without FIREWALLA_BOX_ID, queries cover every box on the account. The few operations that act on one box (get_specific_alarm, archive_alarm, mute_alarm, delete_alarm, create_rule, rename_device) take a gid argument, and without one they use FIREWALLA_BOX_ID, then FIREWALLA_DEFAULT_BOX_ID, then the account's only box. On an account with several boxes and none of those set, get_specific_alarm, archive_alarm, mute_alarm and delete_alarm check each box, and create_rule and rename_device refuse and list the boxes.
Test mode. MCP_TEST_MODE=true starts the server without credentials, to check that it starts: it uses a dummy token, API (https://test.firewalla.net) and box instead of your settings, always runs on stdio, and cannot read your Firewalla data. With NODE_ENV=production the server refuses test mode and exits with code 1. The Docker image sets NODE_ENV=production, so pass -e NODE_ENV=development along with -e MCP_TEST_MODE=true.
Transport Configuration
The MCP server supports two transport modes:
Stdio Transport (Default): Standard input/output communication for Claude Desktop and similar MCP clients
MCP_TRANSPORT=stdioHTTP Transport: HTTP server mode for Docker containers, MCP orchestrators, and external access
MCP_TRANSPORT=http
MCP_HTTP_PORT=3000 # Default: 3000
MCP_HTTP_PATH=/mcp # Default: /mcp. Other paths get 404
MCP_HTTP_HOST=127.0.0.1 # Address to listen on, no port (::1 or [::1] for IPv6). Default: 127.0.0.1 (0.0.0.0 in the Docker image)
MCP_HTTP_BEARER_TOKEN= # Clients must send Authorization: Bearer <token>. Required, 16+ characters, unless MCP_HTTP_HOST is loopback
MCP_HTTP_ALLOW_NO_TOKEN= # "true" starts beyond loopback without a token, for a network no untrusted machine can reach
MCP_HTTP_ALLOWED_HOSTS= # More Host header names to accept, comma-separated
MCP_HTTP_ALLOWED_ORIGINS= # Browser origins to accept, comma-separated, e.g. http://localhost:6274HTTP transport security
Every request can spend your MSP token, so the HTTP server follows the security rules of the MCP transport specification:
It listens on
127.0.0.1, this machine only. SetMCP_HTTP_HOST=0.0.0.0(or one address) to accept other machines, and setMCP_HTTP_BEARER_TOKENwith it: on any address but loopback (127.0.0.0/8,::1,localhost) the server refuses to start without a token, and exits with code 1 after one line on stderr that says why.MCP_HTTP_ALLOW_NO_TOKEN=truestarts it without one, for a network no untrusted machine can reach, such as a compose network with no published port; the server then writes a warning to stderr at startup, whateverLOG_LEVELsays.With
MCP_HTTP_BEARER_TOKENset, a request withoutAuthorization: Bearer <token>gets 401. A token shorter than 16 characters stops startup wherever the server listens;openssl rand -hex 32makes one 64 characters long.A request whose
Hostheader is notlocalhost,127.0.0.1,[::1], theMCP_HTTP_HOSTaddress (unless that is the wildcard0.0.0.0or::, which adds nothing) or a name inMCP_HTTP_ALLOWED_HOSTSgets 403. This stops DNS rebinding, where a web page points its own domain name at your machine.A request with an
Originheader, which browsers send, gets 403 unless the origin is inMCP_HTTP_ALLOWED_ORIGINS, compared as URL origins (letter case and a default port make no difference). Non-browser MCP clients send noOriginand are not affected. An allowed origin gets CORS headers on every answer, refusals such as a 401 for a missing token included, so a web page on it can call the server and read why a request was refused.The MCP endpoint is the configured
MCP_HTTP_PATHexactly (default/mcp), that path with one trailing slash, and either with a query string. Any other path gets 404, CORS preflight requests included: with the default,/mcpxand/mcp/xdo.A request body may be at most 1 MB, and a client has 10 seconds to send the headers and 30 seconds for the whole request. An answer given without reading the body (401, 403, 404, 405, a malformed session ID, a CORS preflight) closes the connection, so a client cannot hold one open by sending the body slowly.
A session ends when the client sends DELETE, after
MCP_SESSION_IDLE_TIMEOUT_MSwithout a request (default 30 minutes), or when the server restarts. A request with the ID of a session the server does not hold gets 404, and the transport specification has the client start a new session with a newinitialize. A request with no session ID, other thaninitialize, gets 400.
When to use HTTP transport:
Running in Docker containers independently
Accessing from MCP orchestrators (e.g., open-webui)
Multiple clients need to connect to the same server instance
Network-based access to the MCP server
When to use stdio transport:
Claude Desktop integration (default)
Claude Code CLI integration
Single-process MCP client setups
Standard MCP client configurations
3. Build and Start
npm run build
npm run mcp:start4. Connect Claude Desktop
Add this configuration to your Claude Desktop claude_desktop_config.json:
If installed via npm
{
"mcpServers": {
"firewalla": {
"command": "npx",
"args": ["firewalla-mcp-server"],
"env": {
"FIREWALLA_MSP_TOKEN": "your_msp_access_token_here",
"FIREWALLA_MSP_ID": "yourdomain.firewalla.net",
"FIREWALLA_BOX_ID": "your_box_gid_here"
}
}
}
}If using Docker
{
"mcpServers": {
"firewalla": {
"command": "docker",
"args": ["run", "-i", "--rm",
"-e", "FIREWALLA_MSP_TOKEN=your_token",
"-e", "FIREWALLA_MSP_ID=yourdomain.firewalla.net",
"-e", "FIREWALLA_BOX_ID=your_box_gid",
"amittell/firewalla-mcp-server"
]
}
}
}If installed from source
{
"mcpServers": {
"firewalla": {
"command": "node",
"args": ["/full/path/to/firewalla-mcp-server/dist/server.js"],
"env": {
"FIREWALLA_MSP_TOKEN": "your_msp_access_token_here",
"FIREWALLA_MSP_ID": "yourdomain.firewalla.net",
"FIREWALLA_BOX_ID": "your_box_gid_here"
}
}
}
}Config file locations:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
5. Next Steps
See USAGE.md for practical examples and common queries
Check TROUBLESHOOTING.md if you encounter issues
Review client-specific setup guides in docs/clients/
Usage Examples
Step-by-Step First Use
1. Verify Connection After completing the setup, verify the MCP server is working:
# Start the server
npm run mcp:start
# stdout carries only the MCP protocol; stderr shows JSON log lines, the
# last one with "message":"Firewalla MCP Server running on stdio transport"2. Test with Claude Open Claude Desktop and try these starter queries:
Basic Health Check:
"Can you check my Firewalla status and show me a summary?"This uses: the firewalla://summary resource and the get_simple_statistics tool
Security Overview:
"What security alerts do I have? Show me the 5 most recent ones."This uses: get_active_alarms tool with limit parameter
Practical Workflows
Daily Security Review:
"Give me today's security report. Include:
1. Any new security alerts
2. Top 3 devices using bandwidth
3. Any devices that went offline
4. Status of critical firewall rules"Investigating Suspicious Activity:
"I noticed unusual traffic. Can you:
1. Show me all security and abnormal upload alarms from the last 4 hours
2. Find any blocked connections to external IPs
3. Check which devices had the most network activity"Network Troubleshooting:
"A device seems to have connectivity issues. Can you:
1. Check if device 192.168.1.100 is online
2. Show its recent network flows
3. See if any rules are blocking its traffic"Bandwidth Investigation:
"Our internet is slow. Help me find the cause:
1. Show top 10 bandwidth users in the last hour
2. Look for any devices with unusual upload/download patterns
3. Check for any streaming or video traffic"Advanced Search Examples
Find Specific Threats:
search for: security activity alarms from IP range 10.0.0.* in the last 24 hoursUses: search_alarms with query: "type:1 AND device.ip:10.0.0. AND ts:>=<unix time 24 hours ago>"*
Analyze Rule Effectiveness:
"Show me firewall rules that blocked the most connections this week"Uses: get_network_rules + search_flows for blocked traffic analysis
Device Behavior Analysis:
"Find all devices that were online yesterday but are offline now"Uses: get_offline_devices, which lists offline devices most recently seen first, with last_seen; search_devices takes no time fields
Troubleshooting Common Issues
Connection Problems: If you get authentication errors:
Verify your
.envfile has correct credentialsCheck your MSP token hasn't expired
Confirm your Box ID is the full GID format
Empty Results: If queries return no data:
Check your Firewalla is online and reporting
Verify the time range isn't too narrow
Try broader search terms first
Performance Issues: If responses are slow:
Reduce the limit parameter in queries
Use more specific time ranges
Check your network connection to the MSP API
Available Tools (28 read-only, 11 opt-in write tools)
Core Tools
Security: Get alarms, analyze threats
Network: Monitor traffic flows, track bandwidth usage
Wi-Fi & Access Points: Discover AP7 access points, query channels/DFS state, Wi-Fi networks, and controller settings
Devices: Check device status, find offline devices
Rules: View firewall rules and their summary
Search: Advanced search across all data types
Analytics: Statistics, trends, and geographic analysis
Target Lists: View security target lists
Quick Reference
Security: get_active_alarms, get_specific_alarm
Network: get_flow_data, get_recent_flow_activity, get_bandwidth_usage
Wi-Fi: get_access_points, get_access_point_channels, get_wifi_networks, get_wifi_settings
Devices: get_device_status, get_offline_devices, get_boxes
Rules: get_network_rules, get_network_rules_summary
Target lists: get_target_lists, get_specific_target_list
Search: search_flows, search_alarms, search_rules, search_devices, search_target_lists
Analytics: get_simple_statistics, get_statistics_by_region, get_statistics_by_box, get_flow_insights, get_flow_trends, get_alarm_trends, get_rule_trends
Write (opt-in): create_rule, delete_rule, pause_rule, resume_rule, create_target_list, update_target_list, delete_target_list, rename_device, archive_alarm, mute_alarm, delete_alarmResponse format
Every read-only tool (readOnlyHint: true) takes an optional response_format. json, the default, returns the compact JSON response. markdown returns the same response as markdown for reading: a heading with the tool name and the number of records in each list, the fields as bullet lists, and each list of records as a table of at most 8 columns and DEFAULT_PAGE_SIZE rows (default 100). Fields with one value in every record are stated once above the table, fields that are not columns are named below it, and a list of one record is shown as a list of its fields. The last line says what the view leaves out (the response's meta block, rows past the cap, cells cut at 120 characters); response_format: json returns all of it. Values and field names are escaped, since device names, domains and alarm messages come from the network: a character that could start markdown or HTML ([, <, *, `, & before an entity, ://, @, ...) gets a backslash, so a renderer shows [a](https://...) or <img ...> as text. Addresses, MACs, gids and timestamps read as they are. Omitting response_format or sending null means json. An error is compact JSON in either format: only a successful read is rendered as markdown. The tools that change state do not take response_format.
get_device_status with {"limit": 2, "response_format": "markdown"}, shortened:
## get_device_status (devices: 2)
- **total_devices:** 2
- **online_devices:** 1
- **devices:** 2 records, under devices below
### devices (2 records)
Same in every record: gid = 00000000-0000-0000-0000-000000000000; ip_reserved = false.
| name | id | last_seen | ip | online |
| --- | --- | --- | --- | --- |
| nas | AA:BB:CC:DD:EE:01 | 2026-09-26T10:00:00.000Z | 192.168.1.10 | true |
| printer | AA:BB:CC:DD:EE:02 | 2026-09-25T18:30:00.000Z | 192.168.1.11 | false |
_This view leaves out the meta block (request_id req_1790000000000_abc123). Call again with `response_format: json` for the full JSON response._Write tools (opt-in)
Every tool that changes something is off by default, so the server is read-only unless you turn them on. Set FIREWALLA_ENABLE_WRITE_TOOLS=true to register the 11 write tools: create_rule, delete_rule, pause_rule and resume_rule (rules), create_target_list, update_target_list and delete_target_list (target lists), rename_device (devices), and archive_alarm, mute_alarm and delete_alarm (alarms). Without it, calling one answers "Unknown tool" and sends nothing. MCP clients that honor tool annotations can ask before calling them; see Tool annotations.
Up to 1.5.0, pause_rule, resume_rule and the three target-list tools were always registered. If you use them, set FIREWALLA_ENABLE_WRITE_TOOLS=true; see Upgrading to 2.0.0.
The write tools need an MSP API token with write access. Firewalla said on 2026-09-08 that MSP 2.12 adds read-only API tokens, which cannot make changes. When a write gets HTTP 403, the error says the token may be read-only and that the write tools need a token with write access. A 403 can also mean the request named a box the token cannot access, and the error says that too; get_boxes lists the boxes the token can access.
IDs that go into a request path (id, rule_id, alarm_id, gid, device_id) are checked before anything is sent. One holding /, a backslash, ?, #, %, whitespace or a control character, or that is . or .., is refused as a validation error naming the argument; leading or trailing whitespace is refused too, not trimmed. Rule IDs such as <box gid>:<n>, MAC device IDs and ovpn: device IDs are accepted.
create_rule and rename_device act on one box: gid, else FIREWALLA_BOX_ID or FIREWALLA_DEFAULT_BOX_ID, else the account's only box. On a multi-box account with none of those, they refuse without writing anything, because the MSP API applies a rule with no gid to every box in the account, including boxes added later. delete_rule needs MSP 2.11.0 or later.
archive_alarm and mute_alarm need MSP 2.11.0 or later. archive_alarm takes an alarm out of the active alarms and does nothing else: future matching traffic can still raise new alarms. mute_alarm archives the alarm and has the box create a lasting silence exception. Its target_type says what is silenced: alarmType every future alarm of that alarm's type, whatever the destination; domain a domain and its subdomains; ip one address. Its scope_type says for which devices: all of them, or the one device, group, user or network named by scope_value. The mute is checked against the documented request model before anything is sent, and this server has no tool to remove the exception afterwards. delete_alarm deletes the alarm for good (measured on 2026-09-26: the alarm was gone afterwards); use archive_alarm to keep it among the archived alarms. Alarm IDs are per box, and the same ID can name different alarms on different boxes: all three tools use the alarm's gid, else FIREWALLA_BOX_ID, else check each box, and they refuse when several boxes have that alarm ID and none of them is FIREWALLA_DEFAULT_BOX_ID. All three read the alarm before writing, so a wrong ID fails without changing anything.
Tool annotations
Every tool carries MCP tool annotations: a title, readOnlyHint, and openWorldHint: true, since each one calls the Firewalla MSP API. All get_* and search_* tools are read-only. The tools that change state have readOnlyHint: false, and all of them need FIREWALLA_ENABLE_WRITE_TOOLS=true:
Tool |
|
|
| false | true |
| false | false |
| true | true |
| true | false |
| true | true |
| false | true |
| false | true |
| true | false |
| true | true |
pause_rule and resume_rule check the rule's status first and change nothing when it is already paused or active. Clients that honor annotations can ask before calling any tool that is not read-only.
Development
Scripts
npm run dev # Start development server with hot reload
npm run build # Build TypeScript to JavaScript
npm run test # Run all tests
npm run test:watch # Run tests in watch mode
npm run lint # Run ESLint
npm run lint:fix # Fix ESLint issuesMCP Execution Methods
Why npx for MCP servers?
Version Management: Always uses the correct/latest version
Dependency Resolution: Handles package dependencies automatically
No global installation required: Works without global installation
MCP Standard: Follows Model Context Protocol conventions
Reliable: Works consistently across different environments
Alternative execution methods:
# Development (from source)
npm run mcp:start
# Production (npm installed)
npx firewalla-mcp-server
# Direct execution (from source after build)
node dist/server.jsLaunch checks in CI
scripts/launch-smoke.mjs starts the server the way a user would and requires an answer to an MCP initialize over stdio. It uses dummy credentials, and initialize is answered locally, so nothing is sent to Firewalla.
The CI workflow's
launchjob packs the package and starts it through the global bin,npxandnode dist/server.js: on Linux for a pull request, and on Linux, macOS and Windows for a push to main or a run by hand (Actions, CI, Run workflow). A change todocs/, top-level Markdown files orLICENSEalone runs no CI; no job reads them (format:checkcoverssrc/only).The Docker Build workflow runs on pull requests that touch the Dockerfile, the package files or the Docker workflows. It builds the image for amd64, arm64 and arm/v7, then runs the amd64 image with
docker run -i --rmand requiresserverInfo.versionto equalpackage.json's version. Run the workflow by hand with theimageinput (for exampleamittell/firewalla-mcp-server:2.1.1) to pull and check a published image instead.The Docker Build and Publish workflow, on a release tag, pushes the image and sets its Docker Hub description from
DOCKERHUB.md, a short page that links here for the rest (Docker Hub keeps only the first 25,000 characters of a description). Run it by hand withdescription_onlyto update just the description.
To run the Docker check locally:
docker build -t firewalla-mcp-server:local .
node scripts/launch-smoke.mjs --docker firewalla-mcp-server:local
# A published image; the expected version comes from the tag
node scripts/launch-smoke.mjs --docker amittell/firewalla-mcp-server:2.1.1 --pullProject Structure
firewalla-mcp-server/
├── src/
│ ├── server.ts # Main MCP server
│ ├── firewalla/ # Firewalla API client
│ ├── tools/ # MCP tool implementations
│ ├── resources/ # MCP resource implementations
│ └── prompts/ # MCP prompt implementations
├── tests/ # Test files
├── docs/
│ └── firewalla-api-reference.md # API documentation
├── CLAUDE.md # Comprehensive development guide
├── SPEC.md # Technical specifications
└── README.md # This fileDocumentation
README.md (this file) - Setup and basic usage
USAGE.md - Simple usage guide with examples
TROUBLESHOOTING.md - Common issues and solutions
SPEC.md - What the server implements: protocol, transports, tools, errors and limits
docs/clients/ - Client-specific setup guides
CLAUDE.md - Development guide and commands
Security
See SECURITY.md to report a vulnerability. For the HTTP transport, see HTTP transport security.
MSP tokens are stored securely in environment variables
No credentials are logged or stored in code
Each server process paces its own requests to
API_RATE_LIMITper rolling 5 minutes (default 100, the limit measured on one MSP token; whether it is per token or per account was not measured). A request that cannot start within 20 s fails at once, saying when capacity returns. Every MCP client that starts the server over stdio starts its own process with its own count, so several of them on one token needAPI_RATE_LIMITvalues that add up to 100 or less. See the rate-limiting guideInput validation prevents injection attacks
Device names, domains and alarm messages are set by the devices and sites on your network, so the server treats them as untrusted: characters that do not display are shown as markers such as
<U+E0041>, the prompts quote API data only inside a marked data block, and theinitializeinstructions tell the client to treat results as data. See Untrusted dataAll API communications use HTTPS
Known Behaviors and Limitations
Category Classification
Flow Categories: Many network flows may show as empty category ("") in the Firewalla API response. This is expected behavior - Firewalla categorizes traffic when it recognizes the domain/service (e.g., "av" for audio/video, "social" for social media).
Target List Categories: Some target lists may show category as "unknown". This is normal for user-created or certain system lists.
Timeline: Category classification happens at the Firewalla device level and may take time to build up meaningful categorization data.
Data Characteristics
Response Sizes: The
get_recent_flow_activitytool reads the 50 most recent flows in one request, so it covers minutes on a busy network. For larger datasets or historical analysis, usesearch_flowswith time filters for more targeted queries.Geographic Data: IP geolocation is enriched by the MCP server and includes country, city, and risk scores when available.
API Limitations
MSP only: The server sends every request to the MSP API at
https://<FIREWALLA_MSP_ID>and never connects to the box on your LAN. It has no local mode, so it needs an MSP account with API access even for one box at home, and it sees only what the MSP API returns.Alarm Deletion: In July 2025 the MSP API answered
DELETE /v2/alarms/{gid}/{aid}with{"message": "success", "success": true}and kept the alarm, sodelete_alarmwas withdrawn. Measured again on 2026-09-26, the same request deleted the alarm (a GET of it then answered 404, and the archived alarm count fell by one), anddelete_alarmis back as an opt-in write tool.
Troubleshooting
Quick Fixes
Server won't start:
# Clean and rebuild
npm run clean
npm run build
# If build fails, try:
npm install
npm run buildAuthentication errors:
Check your MSP token is valid
Verify Box ID format (long UUID)
Confirm MSP domain is correct
No data returned:
Try broader queries: "last week" vs "last hour"
Check if Firewalla is online
Test with: "show me basic statistics"
Slow responses:
Add limits: "top 10 devices"
Use shorter time ranges
Restart the server
Debug Mode
Enable detailed logging:
DEBUG=firewalla:* npm run mcp:startFor more detailed troubleshooting, see TROUBLESHOOTING.md
Contributing
Fork the repository
Create a feature branch
Make your changes
Add tests for new functionality
Run the test suite
Submit a pull request
What's New
Release notes for every version, newest first, are in CHANGELOG.md. Changes that are merged but not yet released are listed there under Unreleased.
License
Support
For issues and questions:
Check the troubleshooting guide
Review the technical specifications
Open an issue on GitHub
GitHub Repository
Repository: https://github.com/amittell/firewalla-mcp-server
Quick Links
Repository Stats
Available Tools
24 toolsget_active_alarmsARead-only
Retrieve active security alarms from the Firewalla MSP API (GET /v2/alarms): status:1 is added unless the query names a status (status:2 for archived alarms). Without a ts: qualifier the API covers the last 30 days. Returns up to limit alarms and a cursor for the next page, or groups with groupBy. Scoped to FIREWALLA_BOX_ID when set, otherwise every box.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Results per page (optional, default: 200, API maximum: 500) | |
| query | No | Search query for filtering alarms. Active alarms only (status:1) unless the query names a status. Use type:N where N is: 1=Security Activity, 2=Abnormal Upload, 3=Large Bandwidth Usage, 4=Monthly Data Plan, 5=New Device, 6=Device Back Online, 7=Device Offline, 8=Video Activity, 9=Gaming Activity, 10=Porn Activity, 11=VPN Activity, 12=VPN Connection Restored, 13=VPN Connection Error, 14=Open Port, 15=Internet Connectivity Update, 16=Large Upload. Examples: type:8 (video), type:10 (porn), region:US, device.ip:192.168.*. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes. | |
| cursor | No | Pagination cursor from previous response | |
| sortBy | No | Sort alarms (default: ts:desc) | |
| groupBy | No | Fields to group by, comma-separated, e.g. "type", "status", "device" or "type,box". The API then returns groups instead of alarms: groups of { key, count }, where key holds the group fields (gid for box, device.id for device) and count the alarms in the group. | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint and openWorldHint already covering the safety profile, the description still adds real behavioral context: the implicit status:1 filter, the 30-day default window when no ts: qualifier is given, cursor-based pagination, and the FIREWALLA_BOX_ID-based scoping. It stops short of noting auth requirements or rate limits, so a 4 rather than 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four compact sentences, each carrying a distinct fact (scope, default filter, time window, pagination/grouping, box scoping) with no filler. The default-filter behavior is front-loaded, which is the most important thing to know before calling.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does the work of explaining returns: up to limit alarms plus a cursor, or { key, count } groups when groupBy is used. Combined with the default-window and scoping notes, an agent has nearly everything needed; only sibling disambiguation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 meaning the schema does not: the default 30-day time window for the query, the implicit status:1 injection, and how groupBy changes the return shape. These clarify parameter effects beyond the field-level documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (retrieve active security alarms) and even names the underlying endpoint GET /v2/alarms, so the operation is unambiguous. It does not explicitly differentiate itself from the close sibling search_alarms, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied through defaults: it explains that status:1 is injected unless the query names a status, and that status:2 yields archived alarms, which tells the agent how to reach both active and archived data. However, it never states when to pick this tool over search_alarms, get_specific_alarm, or get_alarm_trends, leaving the routing decision to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_alarm_trendsARead-only
Alarms generated per day for the last 30 days, one point per day, the last being today so far; period (default 30d) returns the days that overlap it. Without a box it is one GET /v2/trends/alarms covering every box, or the box group. That endpoint takes no box, so with box (else FIREWALLA_BOX_ID, unless group is given) each day is counted with one GET /v2/alarms groupBy=box scoped to the box: 1 request plus 1 per day, ~31 for 30d, of the 100 requests the API allows per 5 minutes. box and group cannot be combined.
| Name | Required | Description | Default |
|---|---|---|---|
| box | No | Only alarms of this box (box gid), counted per day: 1 request plus 1 per day (~31 for 30d). Defaults to FIREWALLA_BOX_ID unless group is given; without either, every box. Not with group | |
| group | No | Get trends for a specific box group. Takes precedence over FIREWALLA_BOX_ID; not with box | |
| period | No | Return the days that overlap this period (default: 30d). The API has no finer resolution than a day, so 1h returns today so far and 24h returns yesterday and today | 30d |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations covering only readOnlyHint and openWorldHint, the description adds substantive operational context: the exact request cost (1 + 1 per day, ~31 for 30d), the 100-requests-per-5-minutes budget it consumes, and the fact that the no-box endpoint differs in behavior. This is exactly the kind of cost/rate-limit disclosure an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core output shape, but it devolves into a dense run-on sentence that mixes request accounting and parameter rules, and duplicates the schema's per-parameter wording. Reasonably sized for the complexity, but the structure makes it hard to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description conveys the return shape (one point per day) and the markdown/response_format view, plus cost and rate-limit context. Sufficient for correct invocation, though a note on what trend values represent would round it out.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 body text largely restates what the parameter descriptions already say (box/group precedence, no combination, period overlap), adding little semantic value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening states a specific verb and resource with granularity: alarms counted per day over the last 30 days, one point per day. This clearly separates it from search_alarms/get_active_alarms (filtering) and aligns it with the *trends family. It never names a sibling, so differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit conditional logic for box vs group vs neither, including precedence (FIREWALLA_BOX_ID unless group is given) and the constraint that box and group cannot be combined. It does not, however, say when to prefer this tool over search_alarms or get_statistics_by_box, so no exclusion/alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_bandwidth_usageARead-only
Top devices by upload plus download over the period, summed client-side from up to 10 times limit (1,000 at most) of the period's most recent flows (GET /v2/flows, 500 per request), so on a busy network the totals cover a sample. Scoped to box, else FIREWALLA_BOX_ID, else every box.
| Name | Required | Description | Default |
|---|---|---|---|
| box | No | Only flows of this box (box gid). Defaults to FIREWALLA_BOX_ID; without either, every box. | |
| limit | No | Number of top devices to return | |
| period | Yes | Time period for bandwidth calculation | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=true, openWorldHint=true), and the description adds meaningful behavior beyond that: the totals are summed client-side from a bounded, sampled set of recent flows, so on a busy network the result is approximate. Disclosing this accuracy caveat is real value. It doesn't cover auth or rate limits, but the sampling disclosure is the key trait.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is a single dense sentence, front-loading the purpose and then the derivation. It is appropriately sized and every clause carries information, though the run-on structure makes it harder to parse quickly than a couple of short sentences would.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only analytics tool with annotations covering safety and no output schema, the description supplies the essential behavioral context (sampling, scoping). It does not describe the shape of the returned device list, but the annotations and stated metric cover most of what an agent needs to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so baseline is 3, but the description adds genuine meaning: it explains that `limit` drives a fetch of up to 10×limit flows (1,000 max), revealing the cost/accuracy tradeoff behind that parameter. The `box` scoping logic is restated, which duplicates the schema slightly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific output (top devices by upload+download over a period), giving an agent a clear picture of the resource and metric. It does not explicitly differentiate itself from analytics siblings like get_simple_statistics or get_statistics_by_box, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains the scoping logic (box, else FIREWALLA_BOX_ID, else every box), which is useful context for choosing inputs. However, it never states when to reach for this tool versus alternatives like search_flows or get_statistics_by_box, leaving usage selection implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_boxesARead-only
List the Firewalla boxes this MSP token can see (GET /v2/boxes, optionally one box group), with online status, model and version. Not limited by FIREWALLA_BOX_ID.
| Name | Required | Description | Default |
|---|---|---|---|
| group | No | Get boxes within a specific group (requires group ID) | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds the HTTP endpoint, the token-level scope, and the fields returned, but says nothing about pagination, result caps, or rate limits against a live MSP API.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence containing the verb, the scope, the endpoint, the optional filter, the returned fields, and the env-var carve-out. No filler, no repetition of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully names the payload fields (online status, model, version) and both parameters are fully documented in the schema. It is nearly complete, though pagination behavior and any error/empty-result semantics remain unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the group parameter's own description already states it needs a group ID, so the schema does the heavy lifting. The description's "optionally one box group" merely restates the group parameter rather than adding format, ID syntax, or interaction detail beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("List the Firewalla boxes"), names the backing endpoint (GET /v2/boxes), scopes it to the MSP token, and enumerates the returned fields (online status, model, version). No sibling tool in the list also enumerates boxes, so the agent can identify it immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clarifies the scoping rule that matters most here: "Not limited by FIREWALLA_BOX_ID" tells the agent this call spans all boxes the token sees, and "optionally one box group" describes the narrowing case. It offers no explicit when-not-to-use or named alternative, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_device_statusARead-only
Check online/offline status of devices on the Firewalla network. Reads the device list from GET /v2/devices (box, else FIREWALLA_BOX_ID, else every box; group limits it to a box group) and returns up to limit devices, sorted by name.
| Name | Required | Description | Default |
|---|---|---|---|
| box | No | Get devices under a specific Firewalla box (requires box ID) | |
| group | No | Get devices under a specific box group (requires group ID) | |
| limit | Yes | Maximum number of devices to return (required) | |
| cursor | No | The next_cursor of a previous page, for the page after it; a cursor this tool did not issue is refused | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, setting a low bar, and the description adds real context: the resolution order (box, else FIREWALLA_BOX_ID, else every box), group scoping, the cap of 'up to limit' devices, and name-based sorting. This is genuinely useful behavioral detail beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with purpose, followed by the resolution and return behavior. Dense but no wasted clauses. The parenthetical resolution logic is compact rather than bloated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and strong annotation coverage, the description carries the load adequately: it states what is returned (online/offline status, up to limit devices, sorted by name) and how scope is resolved. It could say more about the status fields returned, but it's sufficient to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all five parameters are self-documented in the schema. The description reinforces box/group resolution semantics, but adds little syntax or format detail the schema doesn't already carry, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb+resource: 'Check online/offline status of devices on the Firewalla network.' It is clear what the tool returns, but it doesn't differentiate itself from close siblings like search_devices or get_offline_devices, which an agent must choose between.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use or when-not-to-use guidance. The description explains how box/group resolution works, but nothing tells the agent when this tool is preferable to search_devices or get_offline_devices, leaving selection to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_flow_dataARead-only
Query network traffic flows from the Firewalla MSP API (GET /v2/flows). Without a ts: qualifier the API covers the last 24 hours. Returns up to limit flows and a cursor for the next page, or groups with groupBy; coverage gives the oldest and newest ts returned and why paging stopped. A limit over 50 is streamed: pass nextContinuationToken back as cursor, or sessionId as streaming_session_id. Scoped to FIREWALLA_BOX_ID when set, otherwise every box.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum results (optional, default: 200, at most 1000; read 500 per request, following the cursor) | |
| query | No | Search query for flows. Supports region:US for geographic filtering, protocol:tcp, status:blocked, domain:*, category:social, etc. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes. | |
| cursor | No | Pagination cursor from a previous response: pagination.cursor, or the nextContinuationToken of a streamed one. Returns the page at that cursor, not streamed. | |
| sortBy | No | Sort flows (default: "ts:desc") | |
| stream | No | true streams any limit, false returns a plain page with pagination.cursor (default: a limit over 50 is streamed) | |
| groupBy | No | Fields to group by, comma-separated, e.g. "category", "domain", "device", "box" or "device,category". The API then returns groups instead of flows: groups of { key, count, download, upload, total }, where key holds the group fields (gid for box; for device the device with its name, but only its id for "device,category") and the rest are the group's summed connection count and bytes. | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
| streaming_session_id | No | The sessionId of a streamed response: returns its next chunk, of the same size. A session expires 10 minutes after its latest chunk. Refused with stream: false; with a cursor, the cursor is read instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds real behavioral context beyond that: the implicit 24-hour coverage window, the automatic switch to streaming above limit 50, the cursor/session continuation contract, and the FIREWALLA_BOX_ID scoping rule that changes the result set.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five sentences, no filler, and the most decision-relevant facts (what it queries, default time window, streaming threshold) are front-loaded before result-shape and scoping details. Dense but readable; only slightly over-packed with paging mechanics.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully describes the return shape itself: up to limit flows plus a cursor, groups when groupBy is set, and a coverage block reporting oldest/newest ts and why paging stopped. An agent can call it and interpret the response correctly; only sibling-level routing guidance is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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. The description does add one genuinely external fact not in the schema — that omitting a ts: qualifier yields a 24-hour window — plus the cursor/stream interplay and box scoping, but most parameter meaning is already carried by the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with the backing endpoint: 'Query network traffic flows from the Firewalla MSP API (GET /v2/flows)'. An agent immediately knows it retrieves flow records. It does not, however, distinguish itself from close siblings like search_flows or get_recent_flow_activity, so the differentiation half of the criterion is unmet.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives operational guidance (default 24-hour window without a ts: qualifier, stream once limit exceeds 50, pass nextContinuationToken as cursor or sessionId as streaming_session_id) but this is mechanism rather than tool selection. There is no statement of when to prefer this tool over sibling flow tools such as search_flows or get_recent_flow_activity, and no explicit when-not condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_flow_insightsARead-only
Get category-based flow analysis for a period: top content categories and their domains, top devices by bandwidth, and optionally blocked traffic. Ideal for answering questions like "what porn sites were accessed" or "what social media was used". Computed client-side from the period's largest flows (GET /v2/flows by total bytes: up to 500 for categories, 200 for devices) and, with include_blocked, the 50 most frequent blocked flows, so on a busy network it covers the largest flows, not all of them. Scoped to FIREWALLA_BOX_ID when set, otherwise every box.
| Name | Required | Description | Default |
|---|---|---|---|
| period | No | Time period for analysis (default: 24h) | 24h |
| categories | No | Filter to specific content categories (optional) | |
| include_blocked | No | Include blocked traffic analysis (default: false) | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/openWorld annotations by disclosing the sampling basis (GET /v2/flows by total bytes: up to 500 for categories, 200 for devices; 50 most frequent blocked flows with include_blocked), an explicit coverage caveat ('covers the largest flows, not all of them'), and the scope rule (FIREWALLA_BOX_ID when set, otherwise every box). These are exactly the behavioral traits an agent needs and cannot infer from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and use cases are front-loaded, and every sentence carries information. However, it is a single dense paragraph with deep nesting like '(GET /v2/flows by total bytes: up to 500 for categories, 200 for devices)', which slightly taxes readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations covering the safety profile and no output schema required, the description supplies the remaining essentials: use cases, computation method, sampling limits, and scoping. An agent has everything needed to call it correctly and to know when not to rely on it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3. The description still adds meaning beyond the schema by explaining what include_blocked actually pulls in (the 50 most frequent blocked flows) and how period-scoped aggregation is computed, exceeding the flat schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It gives a specific verb and resource ('Get category-based flow analysis for a period') and enumerates the concrete payload: top categories/domains, top devices by bandwidth, and optional blocked traffic. The aggregate-analysis framing implicitly separates it from raw-flow siblings like search_flows and get_flow_data, but no sibling is named, so it stops short of explicit differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Strong when-to-use signal via the concrete example questions ('what porn sites were accessed', 'what social media was used'). The mention that it covers only the largest flows hints at when a raw-flow alternative is needed, but no alternative tool or explicit exclusion is named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_flow_trendsARead-only
Blocked flows per day for the last 30 days, one point per day, the last being today so far; period (default 30d) returns the days that overlap it. Without a box it is one GET /v2/trends/flows covering every box, or the box group. That endpoint takes no box, so with box (else FIREWALLA_BOX_ID, unless group is given) each day is counted with one GET /v2/flows status:blocked groupBy=box scoped to the box: 1 request plus 1 per day, ~31 for 30d, of the 100 requests the API allows per 5 minutes. box and group cannot be combined.
| Name | Required | Description | Default |
|---|---|---|---|
| box | No | Only blocked flows of this box (box gid), counted per day: 1 request plus 1 per day (~31 for 30d). Defaults to FIREWALLA_BOX_ID unless group is given; without either, every box. Not with group | |
| group | No | Get trends for a specific box group. Takes precedence over FIREWALLA_BOX_ID; not with box | |
| period | No | Return the days that overlap this period (default: 30d). The API has no finer resolution than a day, so 1h returns today so far and 24h returns yesterday and today | 30d |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial operational context beyond the annotations: request counts (about 31 for 30d), the 100 requests per 5 minutes rate limit, endpoint-specific behavior, day-level granularity, and the box/group incompatibility. Annotations only provide readOnlyHint and openWorldHint, so this is valuable added disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded, and nearly every clause contributes useful detail about behavior and request cost. The single dense paragraph with semicolon-separated clauses is information-rich but somewhat harder to parse than a more structured layout.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only trends tool with no output schema, the description covers aggregation granularity, period semantics, and request cost well. It does not specify the exact fields returned per daily point, but the essential behavior and invocation constraints are complete enough for correct use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the parameter descriptions in the schema already explain box, group, period, and response_format in detail. The top-level description largely restates these semantics rather than adding new parameter-level meaning, 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.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific resource and aggregation: blocked flows per day for the last 30 days, one point per day. It clearly distinguishes this aggregated trend view from raw flow search, though it does not name a sibling alternative explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains how to call the tool with and without box/group, and the precedence of group over FIREWALLA_BOX_ID. However, it does not explicitly state when to use this tool versus alternatives like search_flows or get_flow_insights, leaving that comparison to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_network_rulesARead-only
Retrieve firewall rules and conditions (GET /v2/rules). The API returns every matching rule; the tool returns the first limit. Scoped to FIREWALLA_BOX_ID when set, otherwise every box.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | Yes | Maximum number of rules to return (required) | |
| query | No | Search conditions for filtering rules, e.g. action:block status:active. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes. A word or quoted phrase with no field is free text, matched case-insensitively in the name, notes, action, target type or value, or scope of each rule (GET /v2/rules matches no free text, so the words are not sent and every rule the other terms match is read; free_text_coverage says how many were checked and whether that was all). | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds genuinely useful behavior beyond that: the API returns all matching rules while the tool truncates to "the first limit", and it discloses the box scoping default. This truncation warning is exactly the kind of context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences with the core action front-loaded and the truncation/scoping caveats immediately after. Nothing is wasted, though it is terse enough that a routing hint toward siblings could have been added without bloat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
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 schema coverage and no output schema, the description covers the essential call-time behavior: truncation semantics and scope resolution. The remaining gap is disambiguation from the sibling search/ summary tools, which the agent must resolve on its own.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds real meaning: it clarifies that limit truncates the full API result set to the first N, and explains the FIREWALLA_BOX_ID scoping that governs what the query filters over. These details go beyond the schema's bare "Maximum number of rules to return".
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Retrieve firewall rules and conditions") and names the underlying endpoint (GET /v2/rules). The purpose is unambiguous, but it never distinguishes this tool from the sibling search_rules or get_network_rules_summary, leaving the agent to infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains scoping (FIREWALLA_BOX_ID when set) and the effective limit, but gives no guidance on when to choose this over the closely related search_rules or get_network_rules_summary. There is no when-to-use or when-not-to-use statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_network_rules_summaryARead-only
Get overview counts of network rules by action, direction, status and target type (convenience wrapper): reads the rules from GET /v2/rules and counts them locally. Scoped to FIREWALLA_BOX_ID when set, otherwise every box.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many rules to read for the summary (default: 200) | |
| rule_type | No | Summarize only rules with this action (default: 'all') | all |
| active_only | No | Leave paused rules out of the summary (default: true) | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safe-read profile (readOnlyHint=true, openWorldHint=true), and the description adds genuinely useful context beyond them: the counts are computed client-side from a rules read, which implies the summary is bounded by the limit parameter rather than a server-side aggregate. The scope rule for FIREWALLA_BOX_ID is also disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, output shape front-loaded, with the wrapper/implementation detail and scope following. No filler and nothing repeated from the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description's enumeration of the counting dimensions is what tells the agent what comes back, and it does that adequately. It could say more about what the counts omit (e.g. rules beyond the limit) for a summary tool, but nothing essential is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including enum and default documentation for rule_type, active_only, limit, and response_format, so the schema carries the parameter burden. The description only adds the non-parameter FIREWALLA_BOX_ID scope note, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get overview counts of network rules') plus the grouping dimensions (action, direction, status, target type). The 'convenience wrapper' framing and the note that it reads GET /v2/rules and counts locally implicitly separates it from raw-rule siblings like get_network_rules and search_rules, though no sibling is named outright.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'convenience wrapper' phrasing and scope note ('Scoped to FIREWALLA_BOX_ID when set, otherwise every box') imply when the tool is appropriate, but it never says explicitly to prefer this over get_network_rules/search_rules when only counts are needed, nor when it is insufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_offline_devicesARead-only
List offline devices from the full device list (GET /v2/devices), most recently seen first by default, up to limit; total_offline_devices counts all of them. Scoped to box, else FIREWALLA_BOX_ID, else every box.
| Name | Required | Description | Default |
|---|---|---|---|
| box | No | Filter devices under a specific Firewalla box | |
| limit | No | Maximum number of offline devices to return | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
| sort_by_last_seen | No | Sort devices by last seen time (default: true) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the bar is lower; the description still adds real context beyond them: default ordering ('most recently seen first by default'), the underlying endpoint, the scope fallback chain, and the meaning of the total_offline_devices counter. It stops short of describing pagination or error behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences, front-loaded with the primary action and scope fallback, with no filler. The semicolon-packed second clause is slightly dense but every element carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only list tool with no output schema, the description covers scope resolution, default ordering, the limit bound, and the total-count semantics. Only return-shape and pagination details are left unstated, which is minor given the readOnly annotation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema itself documents box, limit, sort_by_last_seen and response_format, establishing a baseline of 3. The description reinforces the default sort direction and the scope precedence for 'box', but adds no format or syntax 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.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('List offline devices') and grounds it in the source endpoint 'GET /v2/devices', which is enough for an agent to grasp what it returns. It does not distinguish itself from the closely related sibling search_devices, so the agent has no in-description cue for why it would pick this over a general device search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the name and the scope-resolution note ('Scoped to box, else FIREWALLA_BOX_ID, else every box'), which is genuinely useful routing context. However there is no explicit when-to-use or when-not-to-use guidance versus search_devices or get_device_status.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_recent_flow_activityARead-only
Get a snapshot of the 50 most recent network flows (one GET /v2/flows request) with protocol, region and blocked/allowed counts; the minutes they span depend on how busy the network is. Use this for: "what's happening right now?", current security threats, immediate network issues. DO NOT use for: historical analysis, more than 50 flows, or daily/weekly patterns; use search_flows with time queries like "ts:>24h" for those. Scoped to FIREWALLA_BOX_ID when set, otherwise every box.
| Name | Required | Description | Default |
|---|---|---|---|
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, lowering the bar. The description adds real behavioral context beyond that: the 50-flow ceiling, that it maps to a single API request, that the covered time window is variable depending on network load, and that results are scoped to FIREWALLA_BOX_ID when set and otherwise span every box. It stops short of rate-limit or auth detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the snapshot definition, then use-for, then do-not-use, then scoping. Every sentence carries distinct information with no padding despite the density.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a snapshot tool with no output schema and annotations covering the safety profile, the definition covers purpose, scope, routing, and the returned fields (protocol, region, blocked/allowed counts) plus the variable time window. Return shape beyond those fields is left implicit, but nothing needed 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.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter (response_format) with 100% schema description coverage, so the schema fully documents the enum and default behavior. The description adds nothing about the parameter, which is acceptable but not additive; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (get recent flow activity), the exact scope (50 most recent flows, one GET /v2/flows request), and the fields returned (protocol, region, blocked/allowed counts). An agent can distinguish it from get_flow_data, get_flow_insights, and search_flows 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names when to use it ("what's happening right now?", current threats, immediate issues) and when not to (historical analysis, more than 50 flows, daily/weekly patterns), routing the agent to the correct alternative with a concrete query example ("ts:>24h" on search_flows). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_rule_trendsARead-only
Rules created per day for the last 30 days, one point per day, the last being today so far; period (default 30d) returns the days that overlap it. Without a box it is GET /v2/trends/rules covering every box, or the box group. When that endpoint answers 400 (it did when measured), each day counts the rules in GET /v2/rules created on it, on the days of GET /v2/trends/alarms (UTC days if that read fails): 3 requests, 4 with group. That endpoint takes no box, so with box (else FIREWALLA_BOX_ID, unless group is given) the rules of the box are counted that way: 2 requests. Rules deleted since are not counted, and the response says how the days were counted. box and group cannot be combined.
| Name | Required | Description | Default |
|---|---|---|---|
| box | No | Only rules of this box (box gid), counted from GET /v2/rules: 2 requests. Defaults to FIREWALLA_BOX_ID unless group is given; without either, every box. Not with group | |
| group | No | Get trends for a specific box group. Takes precedence over FIREWALLA_BOX_ID; not with box | |
| period | No | Return the days that overlap this period (default: 30d). The API has no finer resolution than a day | 30d |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, and the description goes beyond them by disclosing that rules deleted since are not counted and that the response declares how the days were counted. It also notes the 400 fallback and per-call request cost, which helps an agent anticipate behavior, though it never describes the response shape directly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is front-loaded with the purpose, but the body is a dense run-on chain of clauses about endpoints, status codes, and request counts that is hard to parse. Much of the mid-section reads as implementation notes rather than agent-facing guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only trends tool with no output schema, the description covers the counting semantics, fallback path, and the box/group mutual exclusion an agent needs to call it correctly. Remaining gaps are minor given the rich schema descriptions and annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each parameter (box, group, period, response_format) is already fully documented in the schema, including the 'Not with group' constraint the description repeats. The description adds little parameter meaning beyond what the schema carries.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states a specific verb+resource and the exact output granularity: 'Rules created per day for the last 30 days, one point per day, the last being today so far.' The resource (rules) clearly distinguishes it from siblings get_alarm_trends and get_flow_trends 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description details internal routing (box vs no box, endpoint fallback on 400, request counts) rather than when an agent should prefer this tool over get_alarm_trends or get_flow_trends. The constraint 'box and group cannot be combined' is genuinely useful, but usage is implied rather than framed as guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_simple_statisticsARead-only
Get account-wide counts from GET /v2/stats/simple: online boxes, offline boxes, alarms and rules, optionally for one box group. Not limited by FIREWALLA_BOX_ID.
| Name | Required | Description | Default |
|---|---|---|---|
| group | No | Get statistics for specific box group | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds meaningful non-annotation context: this call is account-wide and explicitly not constrained by FIREWALLA_BOX_ID, which is a scoping behavior the agent could not infer from the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the API endpoint and returned metrics front-loaded, followed by the optional scoping and the exclusion note. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description appropriately names the counts returned (online/offline boxes, alarms, rules), and annotations cover the read-only nature. A brief note on pagination or result size would close the remaining gap, but the essentials for correct invocation are present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both 'group' and 'response_format' are already documented in the schema. The description only echoes the optional group filtering ('optionally for one box group') without adding format or syntax 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.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get account-wide counts from GET /v2/stats/simple') and enumerates exactly what is returned: online boxes, offline boxes, alarms and rules. The closing note 'Not limited by FIREWALLA_BOX_ID' distinguishes it from the box-scoped sibling get_statistics_by_box without needing to open either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description tells the agent when to use it (account-wide roll-up, optionally narrowed to one box group) and signals the contrast with box-ID-scoped statistics. It stops short of naming get_statistics_by_box explicitly as the alternative, so the routing is clear but not fully spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_specific_alarmARead-only
Get detailed information for one Firewalla alarm (GET /v2/alarms/{gid}/{aid}). Alarm IDs are per box: pass gid on a multi-box account, or each box is checked, one request per box, until one has the alarm.
| Name | Required | Description | Default |
|---|---|---|---|
| gid | No | Box the alarm belongs to (the gid field of get_active_alarms or search_alarms results). Defaults to FIREWALLA_BOX_ID; without either, each box on the account is checked. | |
| alarm_id | Yes | Alarm ID (required for API call): the aid from get_active_alarms or search_alarms, as a number or a string | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so safety is covered; the description adds real value beyond that by disclosing the fan-out behavior (one request per box until a match is found) on multi-box accounts. It omits rate-limit or auth details, which keeps it short of 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, front-loaded with the purpose and endpoint before the multi-box caveat. No filler and nothing repeated from the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema the description should ideally say what the alarm payload contains, but for a single-record fetch whose annotations already flag it read-only and open-world, the multi-box retrieval mechanics and ID sourcing cover what an agent needs to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 meaning the schema alone does not convey: that alarm IDs are scoped per box and that gid should come from get_active_alarms or search_alarms results. That is genuine added semantic context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Get detailed information for one Firewalla alarm') and pins it to the exact endpoint GET /v2/alarms/{gid}/{aid}, making it clearly distinct from the list-oriented siblings get_active_alarms and search_alarms.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the operational context: pass gid on multi-box accounts, and that alarm IDs are per box so each box may be checked until one has the alarm. It does not explicitly name search_alarms as the alternative for finding an aid, but the required-parameter flow implies it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_specific_target_listARead-only
Retrieve one target list by ID, including its targets (GET /v2/target-lists/{id}).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Target list ID (required) | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so safety is covered. The description adds useful context beyond the annotations by noting the response embeds the list's targets, but it says nothing about pagination, target-volume limits, or error behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence, front-loaded with the verb and resource, with the endpoint appended as compact reference. Nothing is wasted and nothing needs reordering.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter read tool with full schema coverage and readOnly annotations, the description covers purpose and return scope. Without an output schema it could have sketched the returned shape slightly more, but the essential invocation information is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters (id, response_format) are fully documented in the schema, including the markdown/json enum semantics. The description adds no parameter detail beyond the required id, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Retrieve one target list by ID") and adds that the response includes the list's targets, which distinguishes it from the sibling get_target_lists. It never names a sibling explicitly, so an agent must infer the single-vs-collection split from the description alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase "by ID" implies the precondition (you already have a target list ID), which is adequate context, but there is no explicit when-to-use guidance and no mention of get_target_lists or search_target_lists as alternatives for discovering lists.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_statistics_by_boxARead-only
Top boxes by blocked flows (the default) or by Security Activity alarms, from GET /v2/stats/{type}, with each box's details from GET /v2/boxes; each box's value is the statistic, over about the last 30 days when measured. Not limited by FIREWALLA_BOX_ID.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | Statistics type to retrieve | topBoxesByBlockedFlows |
| group | No | Get statistics for specific box group | |
| limit | No | Maximum number of results (optional, default: 5) | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, and the description adds meaningful context beyond them: the backing endpoints, that values are measured over roughly the last 30 days, and that scope is not constrained by FIREWALLA_BOX_ID. It stops short of describing ordering or output shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that leads with the core purpose before the endpoint/scope details. It is slightly dense with semicolons and endpoint strings, but every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations covering the safety profile and a fully described schema, the remaining need is scope and data-window context, which the description supplies. No output schema exists, so return-value explanation is not required; the only minor gap is ordering/pagination.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 real meaning by translating the enum values into plain language (blocked flows vs Security Activity alarms) and confirming the default. It says nothing extra about 'group' or 'limit' beyond what the schema already documents.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource and dimension: top boxes ranked by blocked flows (default) or Security Activity alarms, distinguishing it from region-based stats. Sibling differentiation is implicit via the 'by_box' framing rather than explicitly naming alternatives, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Implies applicability by stating the default type and that results are 'not limited by FIREWALLA_BOX_ID', which hints this is an aggregate view. However, it names no alternative tools (e.g., get_statistics_by_region, get_simple_statistics) and gives no when-to-use/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_statistics_by_regionARead-only
Top regions by blocked flows, from GET /v2/stats/topRegionsByBlockedFlows, optionally for one box group; the API returned no more than 5 regions. Not limited by FIREWALLA_BOX_ID.
| Name | Required | Description | Default |
|---|---|---|---|
| group | No | Get statistics for specific box group | |
| limit | No | Maximum number of regions (optional, default: 5; the API returned no more than 5 when a larger limit was tried) | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only/open-world profile, and the description adds genuine behavioral facts beyond them: the source endpoint, the hard cap of no more than 5 regions, and the FIREWALLA_BOX_ID scope exemption. It omits auth or rate-limit details, so it stops short of 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: the purpose leads, then the endpoint, the optional-group note, and the cap. Every clause carries information, though the phrasing is slightly clipped and packed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only stats tool with no output schema, the description covers purpose, scope, and the retrieval cap, which is enough for an agent to call it correctly. Return-value shape is unspecified but not required given the read-only nature.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all three parameters are already documented with constraints and defaults. The description only lightly reinforces the group and limit semantics, adding little beyond the schema – the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Top regions by blocked flows') and names the exact endpoint, so the purpose is unambiguous. It implicitly separates itself from the region-of-a-box sibling but never names an alternative tool, keeping it just short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Signals that the group parameter is optional ('optionally for one box group') and clarifies scope with 'Not limited by FIREWALLA_BOX_ID'. However, it never states when to reach for this versus get_statistics_by_box or the other statistics siblings, leaving usage to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_target_listsARead-only
Retrieve target lists (GET /v2/target-lists). Without owner the API returns the MSP's global lists and the Firewalla-managed lists; owner selects global lists, a box's lists, or several. entry_count is the number of entries in each list; the API does not return the entries of Firewalla-managed lists, so their targets is null. Returns up to limit lists.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | Yes | Maximum number of target lists to return (required) | |
| owner | No | Only lists with this owner: "global" (MSP lists), a box gid (that box's lists), or several comma-separated, e.g. "global,<box_gid>". Default: global and Firewalla-managed lists. | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only and open-world profile, and the description goes further by disclosing that Firewalla-managed lists omit entries so their targets is null, and that entry_count reflects list size. The limit-based truncation behavior is also mentioned. It stops short of describing pagination beyond limit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, front-loaded with the endpoint and the core default-versus-owner behavior, with no filler. Slightly dense in the middle but every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description usefully explains what a returned list contains (entry_count, and why targets can be null) and the result cap. For a 3-parameter read tool with full schema coverage and safety annotations, this is close to complete; only deeper pagination/response details are missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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. The description reinforces owner's selection semantics and adds the return-shape consequence (null targets for Firewalla-managed lists), but adds little syntax beyond what the schema already documents.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource plus the underlying endpoint (GET /v2/target-lists), and 'Returns up to limit lists' signals this is a collection-listing tool. It does not explicitly distinguish itself from the sibling list-related tools (get_specific_target_list, search_target_lists), so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description spends its words on what happens without owner versus with owner, which is usage-relevant context, but it never states when to pick this tool over get_specific_target_list or search_target_lists. Usage is implied rather than directed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_alarmsARead-only
Search alarms using full-text or field filters. Alarm types: 1=Security Activity, 2=Abnormal Upload, 3=Large Bandwidth Usage, 4=Monthly Data Plan, 5=New Device, 6=Device Back Online, 7=Device Offline, 8=Video Activity, 9=Gaming Activity, 10=Porn Activity, 11=VPN Activity, 12=VPN Connection Restored, 13=VPN Connection Error, 14=Open Port, 15=Internet Connectivity Update, 16=Large Upload. Reads GET /v2/alarms, 500 per request, following the cursor up to limit. Scoped to FIREWALLA_BOX_ID when set, otherwise every box.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum results (optional, default: 200, at most 1000; read 500 per request, following the cursor) | |
| query | Yes | Search query using Firewalla syntax. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes. Supported fields: type:1-16 (see alarm types above), status:1/2 (active/archived), device.ip:192.168.*, region:US (country code), box.id:box_gid, device.name:*. Examples: "type:8 AND region:US" (video from US), "type:10 AND status:1" (active porn alerts), "device.ip:192.168.* AND status:1" (active alarms from the LAN), "porn" (free text: a term without a qualifier searches alarm text) | |
| cursor | No | Pagination cursor from previous response | |
| sortBy | No | Sort alarms (default: ts:desc) | |
| groupBy | No | Fields to group by, comma-separated, e.g. "type", "status", "device" or "type,box". The API then returns groups instead of alarms: groups of { key, count }, where key holds the group fields (gid for box, device.id for device) and count the alarms in the group. | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
| geographic_filters | No | Countries of the remote end to limit the alarms to, sent as one remote.region: comma list ANDed with the query ({"countries": ["US", "CN"]} is sent as remote.region:US,CN, either country). remote.region, an ISO 3166 country code, is the one geographic alarm qualifier the MSP API documents; other geographic filters and names not listed here are refused as a validation error before any request. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. Beyond that, the description adds real behavior: it reads GET /v2/alarms, fetches 500 per request while following the cursor up to limit, and scopes to FIREWALLA_BOX_ID when set otherwise all boxes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose, then the required alarm-type legend that the schema explicitly points back to ('see alarm types above'), then the transport/behavior notes. The type list is long but load-bearing, so little is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully covers the API endpoint, pagination cadence, and box scoping, which is most of what an agent needs. It is thin on return-shape expectations beyond what groupBy/response_format already state in the schema, and silent on rate limits/auth.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all seven parameters are already documented in the schema (including the query syntax and geographic_filters). The description largely restates the alarm-type enumeration already referenced in the schema's query description, adding little syntax or format meaning beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (search alarms) plus the mode (full-text or field filters), which is clear enough for an agent to grasp intent. However, it never distinguishes itself from close siblings like get_active_alarms or get_specific_alarm, leaving the agent to infer which alarm-retrieval tool to pick.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when this tool is appropriate (searching with free-text/field filters) and gives some scoping context (FIREWALLA_BOX_ID set vs every box), but names no alternatives and states no when-not conditions against get_active_alarms, get_specific_alarm, or the trend tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_devicesARead-only
Search devices by name, IP, MAC or status (convenience wrapper with client-side filtering): reads the device list from GET /v2/devices (box, else FIREWALLA_BOX_ID, else every box) and filters it locally.
| Name | Required | Description | Default |
|---|---|---|---|
| box | No | Filter devices under a specific Firewalla box | |
| limit | No | Maximum number of devices to return | |
| query | Yes | Search query using Firewalla syntax. A word or quoted phrase with no field is free text, found case-insensitively in the name, IP, MAC or id, vendor, or network or group name. ip: also takes an IPv4 CIDR block, and a comma list matches any of its values (name:tv,nas). Supported fields: mac:AA:BB:CC:DD:EE:FF, ip:192.168.1.*, name:*iPhone*, online:true/false, mac_vendor:Apple, gid:box_gid, network.name:*, group.name:*. Examples: "online:false AND mac_vendor:Apple", "ip:192.168.1.* AND name:*laptop*", "mac:AA:* OR name:*phone*", "ip:192.168.1.0/24", "nas", "kids AND online:true" | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so safety is covered. The description adds genuinely useful behavior beyond that: filtering happens client-side after reading the full device list, and the box scope resolves as box param -> FIREWALLA_BOX_ID -> every box. It does not disclose result shape or how 'limit' interacts with local filtering.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence names the resource and searchable fields first, with implementation detail confined to a trailing parenthetical. Dense but no wasted sentences; only the nested 'else ... else ...' clause requires a second read.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still covers the data source, the filtering model, and box scoping, which is enough for correct invocation. Return format and limit semantics are left unaddressed, but these are secondary for a read-only search tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 real meaning for the 'box' parameter by documenting the three-step resolution fallback (explicit box, environment variable, all boxes). The query syntax is fully specified in the schema, so no further description value is needed there.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Search devices') and enumerates the searchable dimensions (name, IP, MAC, status), plus discloses the implementation (client-side wrapper over GET /v2/devices). It does not name sibling alternatives such as get_offline_devices or get_device_status, so an agent must infer differentiation itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The mechanism note ('convenience wrapper with client-side filtering') implies this is the right tool for ad-hoc filtering of the device list, and the box fallback chain tells the agent what happens when 'box' is omitted. There is no explicit when-not-to-use guidance or named alternative for the device domain.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_flowsARead-only
Search network flows with advanced query filters. Use this for: historical analysis, specific time ranges, complex filtering, or when you need more than 50 flows. Supports pagination, time-based queries (e.g., "ts:>1h" for the last hour, or Unix seconds such as "ts:1735689600-1735693200"), and all flow fields including geographic filtering. For quick "what's happening now" snapshots, use get_recent_flow_activity instead. Reads GET /v2/flows, 500 per request, following the cursor up to limit; coverage gives the oldest and newest ts returned and why paging stopped. Scoped to FIREWALLA_BOX_ID when set, otherwise every box.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum results (optional, default: 200, at most 1000; read 500 per request, following the cursor) | |
| query | Yes | Search query using Firewalla syntax. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes. Supported fields: protocol:tcp/udp, direction:inbound/outbound/local, status:blocked/ok, total:>1MB (download + upload in B/KB/MB/GB/TB), download:>10MB, upload:>10MB, domain:example.com (the root domain: *.example.com matches nothing and *word* matches any domain containing word), region:US (country code), category:social/games/porn/etc, box.id:box_gid, device.ip:192.168.*, source.ip:*, destination.ip:*, ts:>1h. Examples: "region:US AND protocol:tcp", "status:blocked AND region:CN", "category:social OR category:games" | |
| cursor | No | Pagination cursor from previous response | |
| sortBy | No | Sort flows (default: "ts:desc") | |
| groupBy | No | Fields to group by, comma-separated, e.g. "category", "domain", "device", "box" or "device,category". The API then returns groups instead of flows: groups of { key, count, download, upload, total }, where key holds the group fields (gid for box; for device the device with its name, but only its id for "device,category") and the rest are the group's summed connection count and bytes. | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
| geographic_filters | No | Countries to limit the flows to, sent as one region: comma list ANDed with the query ({"countries": ["US", "CN"]} is sent as region:US,CN, either country). region, an ISO 3166 country code, is the one geographic flow qualifier the MSP API documents; other geographic filters (continents, cities, ASNs, hosting providers, risk scores) and names not listed here are refused as a validation error before any request. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover safety (readOnlyHint, openWorldHint), and the description adds real behavioral context beyond them: it discloses the backing endpoint (GET /v2/flows), the 500-per-request page size and cursor-following up to limit, the contents of the 'coverage' field (oldest/newest ts and why paging stopped), and the FIREWALLA_BOX_ID scoping rule.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose sentence, then usage, then mechanics. Every sentence carries information, though the description is dense and the query-example list makes it longer than strictly necessary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description explains what comes back (flows vs. grouped {key,count,download,upload,total}, the coverage field, markdown table limits), which is exactly the burden the description must carry for a 7-parameter, open-world search tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 meaning beyond the schema by tying the query, pagination and coverage semantics together and showing time syntax ('ts:>1h', Unix-seconds ranges). It slightly restates limit/query details that already live in the schema, keeping it just short of 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Search network flows') plus the scope (advanced query filters) and names the sibling it differs from (get_recent_flow_activity for 'what's happening now' snapshots). An agent can distinguish it from get_flow_data/get_flow_trends by the stated 'historical analysis, complex filtering, >50 flows' framing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly enumerates when to use it (historical analysis, specific time ranges, complex filtering, more than 50 flows) and names the alternative with the condition that selects it: get_recent_flow_activity for quick current snapshots. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_rulesARead-only
Search firewall rules by target, action or status; the MSP API applies the query (GET /v2/rules). Supports all rule fields. Scoped to FIREWALLA_BOX_ID when set, otherwise every box.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of rules to return | |
| query | Yes | Search query using Firewalla syntax. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes. A word or quoted phrase with no field is free text, matched case-insensitively in the name, notes, action, target type or value, or scope of each rule (GET /v2/rules matches no free text, so the words are not sent and every rule the other terms match is read; free_text_coverage says how many were checked and whether that was all). Supported fields: action:allow/block/timelimit, target.type:domain/ip/device, target.value:*.facebook.com, status:active/paused, direction:bidirection/inbound/outbound, protocol:tcp/udp, box.id:box_gid, scope.type:device/network, notes:"description text". Examples: "action:block AND target.value:*.social.com", "status:paused", "target.type:domain AND action:block" | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint=true) and open-world scope, so little is owed here, yet the description still adds real behavioral context: that filtering is applied server-side by the MSP API via GET /v2/rules, and that results are confined to one box when FIREWALLA_BOX_ID is set and across all boxes otherwise. It stops short of describing pagination/limit interaction or result shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short clauses with zero filler; the core verb+resource and the endpoint are front-loaded, and the scope caveat follows. It is efficiently sized for a three-parameter tool, with only minor denseness from packing endpoint and scope into a semicolon clause.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still gives the agent enough to call correctly: the operation is a read (annotations), the backend call and scope are named, and the full query grammar and response_format behavior live in the schema. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already carries full parameter meaning (including the detailed Firewalla query syntax and response_format semantics). The description's only added claim, 'Supports all rule fields', is too vague to add meaning beyond the enum of fields already enumerated in 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.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('Search firewall rules') plus the searchable facets (target, action, status) and the backing endpoint (GET /v2/rules), so the purpose is unambiguous. It does not, however, distinguish itself from sibling list/read tools such as get_network_rules or get_network_rules_summary, which is why it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no statement of when to use this tool versus the sibling rules tools (get_network_rules, get_network_rules_summary, get_rule_trends). The only conditional is a scoping rule ('Scoped to FIREWALLA_BOX_ID when set, otherwise every box'), which describes result scope rather than tool selection, so an agent gets essentially no routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_target_listsARead-only
Search target lists (convenience wrapper with client-side filtering): reads GET /v2/target-lists, sending owner if given (without it, the global and Firewalla-managed lists), and applies the query locally.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of target lists to return | |
| owner | No | Only lists with this owner, sent to the API: "global" (MSP lists), a box gid (that box's lists), or several comma-separated, e.g. "global,<box_gid>". Default: global and Firewalla-managed lists. | |
| query | Yes | Search query for target lists. A word or quoted phrase with no field is free text, found case-insensitively in the name, the notes or an entry; a comma list matches any of its values (category:social,games). Supported fields: name:*Social*, owner:global/box_gid, category:social/games/ad/porn/etc, targets:*.facebook.com, notes:"description text", target_count:>100 (entries: n, >n, >=n, <n, <=n or a range 10-50), last_updated:>2026-09-01 (a date or Unix seconds, with the same comparisons). Examples: "category:social", "category:social,games", "owner:global AND name:*Block*", "targets:*.gaming.com", "target_count:>1000", "last_updated:<2026-01-01", "facebook" | |
| response_format | No | Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way. | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds genuine behavioral context beyond that: it names the underlying call (GET /v2/target-lists), discloses that owner is sent upstream while the query is applied locally, and states the default scope when owner is omitted. It does not explain how client-side filtering interacts with limit or what the response looks like, so it falls short of 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence that front-loads the purpose and then the mechanism, with no filler. It is compact, though the parenthetical mechanics could have been split for readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the mechanism, the owner scope, and the filtering model, which is adequate for invoking the tool. However, with no output schema, it says nothing about the shape of returned target lists or how limit behaves relative to client-side filtering, leaving a real gap for a search tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 all four parameters in detail, including query syntax and owner values. The description's only added parameter meaning is the owner default ('without it, the global and Firewalla-managed lists'), which largely restates the schema. Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Search target lists') and immediately characterizes the tool as a 'convenience wrapper with client-side filtering', which distinguishes it from a plain list fetch. It does not explicitly name the sibling it contrasts with (get_target_lists / get_specific_target_list), so an agent must infer the boundary from the 'convenience wrapper' phrasing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: the client-side filtering note suggests this is the tool for query-driven lookups, and the owner behavior is described. But there is no explicit when-to-use/when-not statement, no routing to get_target_lists or get_specific_target_list, and no mention of when the wrapper's local filtering is preferable to a direct API call.
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.
29 tool updates
v2.0.1- Removed
create_target_list - Removed
delete_target_list - Changed
get_active_alarms2 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"Search query for filtering alarms. Active alarms only (status:1) unless the query names a status. Use type:N where N is: 1=Security Activity, 2=Abnormal Upload, 3=Large Bandwidth Usage, 4=Monthly Data Plan, 5=New Device, 6=Device Back Online, 7=Device Offline, 8=Video Activity, 9=Gaming Activity, 10=Porn Activity, 11=VPN Activity, 12=VPN Connection Restored, 13=VPN Connection Error, 14=Open Port, 15=Internet Connectivity Update, 16=Large Upload. Examples: type:8 (video), type:10 (porn), region:US, device.ip:192.168.*"New value: +"Search query for filtering alarms. Active alarms only (status:1) unless the query names a status. Use type:N where N is: 1=Security Activity, 2=Abnormal Upload, 3=Large Bandwidth Usage, 4=Monthly Data Plan, 5=New Device, 6=Device Back Online, 7=Device Offline, 8=Video Activity, 9=Gaming Activity, 10=Porn Activity, 11=VPN Activity, 12=VPN Connection Restored, 13=VPN Connection Error, 14=Open Port, 15=Internet Connectivity Update, 16=Large Upload. Examples: type:8 (video), type:10 (porn), region:US, device.ip:192.168.*. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes." - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_alarm_trends3 fields changed- added
Input schema / properties / boxAdded value: +{ + "description": "Only alarms of this box (box gid), counted per day: 1 request plus 1 per day (~31 for 30d). Defaults to FIREWALLA_BOX_ID unless group is given; without either, every box. Not with group", + "type": "string" +} - changed
Input schema / properties / group / descriptionPrevious value: -"Get trends for a specific box group"New value: +"Get trends for a specific box group. Takes precedence over FIREWALLA_BOX_ID; not with box" - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_bandwidth_usage1 field changed- added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_boxes1 field changed- added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_device_status2 fields changed- added
Input schema / properties / cursorAdded value: +{ + "description": "The next_cursor of a previous page, for the page after it; a cursor this tool did not issue is refused", + "type": "string" +} - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_flow_data7 fields changed- changed
Input schema / properties / cursor / descriptionPrevious value: -"Pagination cursor from previous response"New value: +"Pagination cursor from a previous response: pagination.cursor, or the nextContinuationToken of a streamed one. Returns the page at that cursor, not streamed." - changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum results (optional, default: 200, API maximum: 500)"New value: +"Maximum results (optional, default: 200, at most 1000; read 500 per request, following the cursor)" - changed
Input schema / properties / limit / maximumPrevious value: -500New value: +1000 - changed
Input schema / properties / query / descriptionPrevious value: -"Search query for flows. Supports region:US for geographic filtering, protocol:tcp, status:blocked, domain:*, category:social, etc."New value: +"Search query for flows. Supports region:US for geographic filtering, protocol:tcp, status:blocked, domain:*, category:social, etc. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes." - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +} - added
Input schema / properties / streamAdded value: +{ + "description": "true streams any limit, false returns a plain page with pagination.cursor (default: a limit over 50 is streamed)", + "type": "boolean" +} - added
Input schema / properties / streaming_session_idAdded value: +{ + "description": "The sessionId of a streamed response: returns its next chunk, of the same size. A session expires 10 minutes after its latest chunk. Refused with stream: false; with a cursor, the cursor is read instead.", + "type": "string" +}
- Changed
get_flow_insights1 field changed- added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Added
get_flow_trends - Changed
get_network_rules2 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"Search conditions for filtering rules"New value: +"Search conditions for filtering rules, e.g. action:block status:active. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes. A word or quoted phrase with no field is free text, matched case-insensitively in the name, notes, action, target type or value, or scope of each rule (GET /v2/rules matches no free text, so the words are not sent and every rule the other terms match is read; free_text_coverage says how many were checked and whether that was all)." - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_network_rules_summary6 fields changed- changed
Input schema / properties / active_only / descriptionPrevious value: -"Only include active rules in summary (default: true)"New value: +"Leave paused rules out of the summary (default: true)" - added
Input schema / properties / limitAdded value: +{ + "default": 200, + "description": "How many rules to read for the summary (default: 200)", + "maximum": 2000, + "minimum": 1, + "type": "number" +} - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +} - added
Input schema / properties / rule_type / defaultAdded value: +"all" - changed
Input schema / properties / rule_type / descriptionPrevious value: -"Filter by rule type"New value: +"Summarize only rules with this action (default: 'all')" - added
Input schema / properties / rule_type / enumAdded value: +[ + "block", + "allow", + "timelimit", + "all" +]
- Changed
get_offline_devices2 fields changed- changed
Input schema / properties / limit / maximumPrevious value: -500New value: +1000 - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_recent_flow_activity1 field changed- added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_rule_trends3 fields changed- added
Input schema / properties / boxAdded value: +{ + "description": "Only rules of this box (box gid), counted from GET /v2/rules: 2 requests. Defaults to FIREWALLA_BOX_ID unless group is given; without either, every box. Not with group", + "type": "string" +} - changed
Input schema / properties / group / descriptionPrevious value: -"Get trends for a specific box group"New value: +"Get trends for a specific box group. Takes precedence over FIREWALLA_BOX_ID; not with box" - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_simple_statistics1 field changed- added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_specific_alarm1 field changed- added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_specific_target_list1 field changed- added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_statistics_by_box1 field changed- added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_statistics_by_region1 field changed- added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
get_target_lists1 field changed- added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Removed
pause_rule - Removed
resume_rule - Changed
search_alarms5 fields changed- added
Input schema / properties / geographic_filtersAdded value: +{ + "description": "Countries of the remote end to limit the alarms to, sent as one remote.region: comma list ANDed with the query ({\"countries\": [\"US\", \"CN\"]} is sent as remote.region:US,CN, either country). remote.region, an ISO 3166 country code, is the one geographic alarm qualifier the MSP API documents; other geographic filters and names not listed here are refused as a validation error before any request.", + "properties": { + "countries": { + "description": "ISO 3166-1 alpha-2 country codes, any of which may match, e.g. [\"US\", \"CN\"]; a code that is not assigned is refused (put remote.region:<code> in the query to send one anyway). An empty list asks for nothing.", + "items": { + "pattern": "^[A-Za-z]{2}$", + "type": "string" + }, + "type": "array" + }, + "regions": { + "description": "Country codes too, merged with countries: the API's remote.region is a country code", + "items": { + "pattern": "^[A-Za-z]{2}$", + "type": "string" + }, + "type": "array" + } + }, + "type": "object" +} - changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum results (optional, default: 200, API maximum: 500)"New value: +"Maximum results (optional, default: 200, at most 1000; read 500 per request, following the cursor)" - changed
Input schema / properties / limit / maximumPrevious value: -500New value: +1000 - changed
Input schema / properties / query / descriptionPrevious value: -"Search query using Firewalla syntax. Supported fields: type:1-16 (see alarm types above), status:1/2 (active/archived), device.ip:192.168.*, region:US (country code), box.id:box_gid, device.name:*. Examples: \"type:8 AND region:US\" (video from US), \"type:10 AND status:1\" (active porn alerts), \"device.ip:192.168.* AND status:1\" (active alarms from the LAN), \"porn\" (free text: a term without a qualifier searches alarm text)"New value: +"Search query using Firewalla syntax. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes. Supported fields: type:1-16 (see alarm types above), status:1/2 (active/archived), device.ip:192.168.*, region:US (country code), box.id:box_gid, device.name:*. Examples: \"type:8 AND region:US\" (video from US), \"type:10 AND status:1\" (active porn alerts), \"device.ip:192.168.* AND status:1\" (active alarms from the LAN), \"porn\" (free text: a term without a qualifier searches alarm text)" - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
search_devices3 fields changed- changed
Input schema / properties / limit / maximumPrevious value: -500New value: +1000 - changed
Input schema / properties / query / descriptionPrevious value: -"Search query using Firewalla syntax. Supported fields: mac:AA:BB:CC:DD:EE:FF, ip:192.168.1.*, name:*iPhone*, online:true/false, mac_vendor:Apple, gid:box_gid, network.name:*, group.name:*. Examples: \"online:false AND mac_vendor:Apple\", \"ip:192.168.1.* AND name:*laptop*\", \"mac:AA:* OR name:*phone*\""New value: +"Search query using Firewalla syntax. A word or quoted phrase with no field is free text, found case-insensitively in the name, IP, MAC or id, vendor, or network or group name. ip: also takes an IPv4 CIDR block, and a comma list matches any of its values (name:tv,nas). Supported fields: mac:AA:BB:CC:DD:EE:FF, ip:192.168.1.*, name:*iPhone*, online:true/false, mac_vendor:Apple, gid:box_gid, network.name:*, group.name:*. Examples: \"online:false AND mac_vendor:Apple\", \"ip:192.168.1.* AND name:*laptop*\", \"mac:AA:* OR name:*phone*\", \"ip:192.168.1.0/24\", \"nas\", \"kids AND online:true\"" - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
search_flows5 fields changed- added
Input schema / properties / geographic_filtersAdded value: +{ + "description": "Countries to limit the flows to, sent as one region: comma list ANDed with the query ({\"countries\": [\"US\", \"CN\"]} is sent as region:US,CN, either country). region, an ISO 3166 country code, is the one geographic flow qualifier the MSP API documents; other geographic filters (continents, cities, ASNs, hosting providers, risk scores) and names not listed here are refused as a validation error before any request.", + "properties": { + "countries": { + "description": "ISO 3166-1 alpha-2 country codes, any of which may match, e.g. [\"US\", \"CN\"]; a code that is not assigned is refused (put region:<code> in the query to send one anyway). An empty list asks for nothing.", + "items": { + "pattern": "^[A-Za-z]{2}$", + "type": "string" + }, + "type": "array" + }, + "exclude_cloud": { + "description": "Only false, which asks for nothing: the MSP API has no qualifier for cloud providers, so true is refused", + "enum": [ + false + ], + "type": "boolean" + }, + "exclude_known_providers": { + "description": "Only false, which asks for nothing: the MSP API has no qualifier for hosting providers, so true is refused", + "enum": [ + false + ], + "type": "boolean" + }, + "exclude_vpn": { + "description": "Only false, which asks for nothing: the MSP API has no qualifier for VPN traffic, so true is refused", + "enum": [ + false + ], + "type": "boolean" + }, + "high_risk_countries": { + "description": "Only false, which asks for nothing: the MSP API has no qualifier for country risk, so true is refused", + "enum": [ + false + ], + "type": "boolean" + }, + "regions": { + "description": "Country codes too, merged with countries: the API's region is a country code", + "items": { + "pattern": "^[A-Za-z]{2}$", + "type": "string" + }, + "type": "array" + }, + "threat_analysis": { + "description": "Only false, which asks for nothing: the flow search has no threat analysis, so true is refused", + "enum": [ + false + ], + "type": "boolean" + } + }, + "type": "object" +} - changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum results (optional, default: 200, API maximum: 500)"New value: +"Maximum results (optional, default: 200, at most 1000; read 500 per request, following the cursor)" - changed
Input schema / properties / limit / maximumPrevious value: -500New value: +1000 - changed
Input schema / properties / query / descriptionPrevious value: -"Search query using Firewalla syntax. Supported fields: protocol:tcp/udp, direction:inbound/outbound/local, status:blocked/ok, total:>1MB (download + upload in B/KB/MB/GB/TB), download:>10MB, upload:>10MB, domain:*.example.com, region:US (country code), category:social/games/porn/etc, box.id:box_gid, device.ip:192.168.*, source.ip:*, destination.ip:*, ts:>1h. Examples: \"region:US AND protocol:tcp\", \"status:blocked AND region:CN\", \"category:social OR category:games\""New value: +"Search query using Firewalla syntax. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes. Supported fields: protocol:tcp/udp, direction:inbound/outbound/local, status:blocked/ok, total:>1MB (download + upload in B/KB/MB/GB/TB), download:>10MB, upload:>10MB, domain:example.com (the root domain: *.example.com matches nothing and *word* matches any domain containing word), region:US (country code), category:social/games/porn/etc, box.id:box_gid, device.ip:192.168.*, source.ip:*, destination.ip:*, ts:>1h. Examples: \"region:US AND protocol:tcp\", \"status:blocked AND region:CN\", \"category:social OR category:games\"" - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
search_rules5 fields changed- added
Input schema / properties / limit / defaultAdded value: +200 - added
Input schema / properties / limit / maximumAdded value: +1000 - added
Input schema / properties / limit / minimumAdded value: +1 - changed
Input schema / properties / query / descriptionPrevious value: -"Search query using Firewalla syntax. Supported fields: action:allow/block/timelimit, target.type:domain/ip/device, target.value:*.facebook.com, status:active/paused, direction:bidirection/inbound/outbound, protocol:tcp/udp, box.id:box_gid, scope.type:device/network, notes:\"description text\". Examples: \"action:block AND target.value:*.social.com\", \"status:paused\", \"target.type:domain AND action:block\""New value: +"Search query using Firewalla syntax. Terms joined by spaces or AND must all match; OR works between values of one field (sent as a comma list, e.g. region:US,CN) and is refused across fields; NOT or a leading - excludes. A word or quoted phrase with no field is free text, matched case-insensitively in the name, notes, action, target type or value, or scope of each rule (GET /v2/rules matches no free text, so the words are not sent and every rule the other terms match is read; free_text_coverage says how many were checked and whether that was all). Supported fields: action:allow/block/timelimit, target.type:domain/ip/device, target.value:*.facebook.com, status:active/paused, direction:bidirection/inbound/outbound, protocol:tcp/udp, box.id:box_gid, scope.type:device/network, notes:\"description text\". Examples: \"action:block AND target.value:*.social.com\", \"status:paused\", \"target.type:domain AND action:block\"" - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Changed
search_target_lists3 fields changed- changed
Input schema / properties / limit / maximumPrevious value: -500New value: +1000 - changed
Input schema / properties / query / descriptionPrevious value: -"Search query for target lists. Supported fields: name:*Social*, owner:global/box_gid, category:social/games/ad/porn/etc, targets:*.facebook.com, notes:\"description text\", target_count:>100 (entries: n, >n, >=n, <n, <=n or a range 10-50), last_updated:>2026-09-01 (a date or Unix seconds, with the same comparisons). Examples: \"category:social\", \"owner:global AND name:*Block*\", \"targets:*.gaming.com\", \"target_count:>1000\", \"last_updated:<2026-01-01\""New value: +"Search query for target lists. A word or quoted phrase with no field is free text, found case-insensitively in the name, the notes or an entry; a comma list matches any of its values (category:social,games). Supported fields: name:*Social*, owner:global/box_gid, category:social/games/ad/porn/etc, targets:*.facebook.com, notes:\"description text\", target_count:>100 (entries: n, >n, >=n, <n, <=n or a range 10-50), last_updated:>2026-09-01 (a date or Unix seconds, with the same comparisons). Examples: \"category:social\", \"category:social,games\", \"owner:global AND name:*Block*\", \"targets:*.gaming.com\", \"target_count:>1000\", \"last_updated:<2026-01-01\", \"facebook\"" - added
Input schema / properties / response_formatAdded value: +{ + "default": "json", + "description": "Response format. 'json' (default): the compact JSON response. 'markdown': the same response as readable markdown, its fields as bullet lists and each list of records as a table of up to 8 columns and DEFAULT_PAGE_SIZE rows (default 100), ending with a line that says what the view leaves out. Omitted or null: 'json'. Errors are JSON either way.", + "enum": [ + "json", + "markdown", + null + ], + "type": [ + "string", + "null" + ] +}
- Removed
update_target_list
15 tool updates
v1.5.0- Changed
get_active_alarms2 fields changed- changed
Input schema / properties / groupBy / descriptionPrevious value: -"Group alarms by field (e.g., type, box)"New value: +"Fields to group by, comma-separated, e.g. \"type\", \"status\", \"device\" or \"type,box\". The API then returns groups instead of alarms: groups of { key, count }, where key holds the group fields (gid for box, device.id for device) and count the alarms in the group." - changed
Input schema / properties / query / descriptionPrevious value: -"Search query for filtering alarms (default: status:1 for active). Use type:N where N is: 1=Security Activity, 2=Abnormal Upload, 3=Large Bandwidth Usage, 4=Monthly Data Plan, 5=New Device, 6=Device Back Online, 7=Device Offline, 8=Video Activity, 9=Gaming Activity, 10=Porn Activity, 11=VPN Activity, 12=VPN Connection Restored, 13=VPN Connection Error, 14=Open Port, 15=Internet Connectivity Update, 16=Large Upload. Examples: type:8 (video), type:10 (porn), region:US, source_ip:*"New value: +"Search query for filtering alarms. Active alarms only (status:1) unless the query names a status. Use type:N where N is: 1=Security Activity, 2=Abnormal Upload, 3=Large Bandwidth Usage, 4=Monthly Data Plan, 5=New Device, 6=Device Back Online, 7=Device Offline, 8=Video Activity, 9=Gaming Activity, 10=Porn Activity, 11=VPN Activity, 12=VPN Connection Restored, 13=VPN Connection Error, 14=Open Port, 15=Internet Connectivity Update, 16=Large Upload. Examples: type:8 (video), type:10 (porn), region:US, device.ip:192.168.*"
- Changed
get_alarm_trends1 field changed- added
Input schema / properties / periodAdded value: +{ + "default": "30d", + "description": "Return the days that overlap this period (default: 30d). The API has no finer resolution than a day, so 1h returns today so far and 24h returns yesterday and today", + "enum": [ + "1h", + "24h", + "7d", + "30d" + ], + "type": "string" +}
- Changed
get_bandwidth_usage1 field changed- changed
Input schema / properties / box / descriptionPrevious value: -"Filter devices under a specific Firewalla box"New value: +"Only flows of this box (box gid). Defaults to FIREWALLA_BOX_ID; without either, every box."
- Changed
get_flow_data2 fields changed- changed
Input schema / properties / groupBy / descriptionPrevious value: -"Group flows by specified values (e.g., \"domain,box\")"New value: +"Fields to group by, comma-separated, e.g. \"category\", \"domain\", \"device\", \"box\" or \"device,category\". The API then returns groups instead of flows: groups of { key, count, download, upload, total }, where key holds the group fields (gid for box; for device the device with its name, but only its id for \"device,category\") and the rest are the group's summed connection count and bytes." - changed
Input schema / properties / query / descriptionPrevious value: -"Search query for flows. Supports region:US for geographic filtering, protocol:tcp, blocked:true, domain:*, category:social, etc."New value: +"Search query for flows. Supports region:US for geographic filtering, protocol:tcp, status:blocked, domain:*, category:social, etc."
- Changed
get_rule_trends1 field changed- added
Input schema / properties / periodAdded value: +{ + "default": "30d", + "description": "Return the days that overlap this period (default: 30d). The API has no finer resolution than a day", + "enum": [ + "1h", + "24h", + "7d", + "30d" + ], + "type": "string" +}
- Changed
get_specific_alarm3 fields changed- changed
Input schema / properties / alarm_id / descriptionPrevious value: -"Alarm ID (required for API call)"New value: +"Alarm ID (required for API call): the aid from get_active_alarms or search_alarms, as a number or a string" - changed
Input schema / properties / alarm_id / typePrevious value: -"string"New value: +[ + "string", + "number" +] - added
Input schema / properties / gidAdded value: +{ + "description": "Box the alarm belongs to (the gid field of get_active_alarms or search_alarms results). Defaults to FIREWALLA_BOX_ID; without either, each box on the account is checked.", + "type": "string" +}
- Changed
get_statistics_by_region1 field changed- changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum number of results (optional, default: 5)"New value: +"Maximum number of regions (optional, default: 5; the API returned no more than 5 when a larger limit was tried)"
- Changed
get_target_lists1 field changed- added
Input schema / properties / ownerAdded value: +{ + "description": "Only lists with this owner: \"global\" (MSP lists), a box gid (that box's lists), or several comma-separated, e.g. \"global,<box_gid>\". Default: global and Firewalla-managed lists.", + "type": "string" +}
- Changed
pause_rule3 fields changed- removed
Input schema / properties / boxRemoved value: -{ - "description": "Box GID for context (required by API)", - "type": "string" -} - removed
Input schema / properties / durationRemoved value: -{ - "default": 60, - "description": "Duration in minutes to pause the rule (optional, default: 60, range: 1-1440)", - "maximum": 1440, - "minimum": 1, - "type": "number" -} - changed
Input schema / requiredPrevious value: -[ - "rule_id", - "box" -]New value: +[ + "rule_id" +]
- Changed
resume_rule2 fields changed- removed
Input schema / properties / boxRemoved value: -{ - "description": "Box GID for context (required by API)", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "rule_id", - "box" -]New value: +[ + "rule_id" +]
- Changed
search_alarms2 fields changed- changed
Input schema / properties / groupBy / descriptionPrevious value: -"Group alarms by specified fields (comma-separated)"New value: +"Fields to group by, comma-separated, e.g. \"type\", \"status\", \"device\" or \"type,box\". The API then returns groups instead of alarms: groups of { key, count }, where key holds the group fields (gid for box, device.id for device) and count the alarms in the group." - changed
Input schema / properties / query / descriptionPrevious value: -"Search query using Firewalla syntax. Supported fields: type:1-16 (see alarm types above), resolved:true/false, status:1/2 (active/archived), source_ip:192.168.*, region:US (country code), gid:box_id, device.name:*, message:\"text search\". Examples: \"type:8 AND region:US\" (video from US), \"type:10 AND status:1\" (active porn alerts), \"source_ip:192.168.* AND NOT resolved:true\""New value: +"Search query using Firewalla syntax. Supported fields: type:1-16 (see alarm types above), status:1/2 (active/archived), device.ip:192.168.*, region:US (country code), box.id:box_gid, device.name:*. Examples: \"type:8 AND region:US\" (video from US), \"type:10 AND status:1\" (active porn alerts), \"device.ip:192.168.* AND status:1\" (active alarms from the LAN), \"porn\" (free text: a term without a qualifier searches alarm text)"
- Changed
search_devices2 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"Search query using Firewalla syntax. Supported fields: mac:AA:BB:CC:DD:EE:FF, ip:192.168.1.*, name:*iPhone*, online:true/false, vendor:Apple, gid:box_id, network.name:*, group.name:*. Examples: \"online:false AND vendor:Apple\", \"ip:192.168.1.* AND name:*laptop*\", \"mac:AA:* OR name:*phone*\""New value: +"Search query using Firewalla syntax. Supported fields: mac:AA:BB:CC:DD:EE:FF, ip:192.168.1.*, name:*iPhone*, online:true/false, mac_vendor:Apple, gid:box_gid, network.name:*, group.name:*. Examples: \"online:false AND mac_vendor:Apple\", \"ip:192.168.1.* AND name:*laptop*\", \"mac:AA:* OR name:*phone*\"" - removed
Input schema / properties / statusRemoved value: -{ - "default": "any", - "description": "Filter by online status", - "enum": [ - "online", - "offline", - "any" - ], - "type": "string" -}
- Changed
search_flows2 fields changed- changed
Input schema / properties / groupBy / descriptionPrevious value: -"Group flows by specified values (e.g., \"domain,box\")"New value: +"Fields to group by, comma-separated, e.g. \"category\", \"domain\", \"device\", \"box\" or \"device,category\". The API then returns groups instead of flows: groups of { key, count, download, upload, total }, where key holds the group fields (gid for box; for device the device with its name, but only its id for \"device,category\") and the rest are the group's summed connection count and bytes." - changed
Input schema / properties / query / descriptionPrevious value: -"Search query using Firewalla syntax. Supported fields: protocol:tcp/udp, direction:inbound/outbound/local, blocked:true/false, bytes:>1MB, domain:*.example.com, region:US (country code), category:social/games/porn/etc, gid:box_id, device.ip:192.168.*, source_ip:*, destination_ip:*. Examples: \"region:US AND protocol:tcp\", \"blocked:true AND bytes:>1MB\", \"category:social OR category:games\""New value: +"Search query using Firewalla syntax. Supported fields: protocol:tcp/udp, direction:inbound/outbound/local, status:blocked/ok, total:>1MB (download + upload in B/KB/MB/GB/TB), download:>10MB, upload:>10MB, domain:*.example.com, region:US (country code), category:social/games/porn/etc, box.id:box_gid, device.ip:192.168.*, source.ip:*, destination.ip:*, ts:>1h. Examples: \"region:US AND protocol:tcp\", \"status:blocked AND region:CN\", \"category:social OR category:games\""
- Changed
search_rules1 field changed- changed
Input schema / properties / query / descriptionPrevious value: -"Search query using Firewalla syntax. Supported fields: action:allow/block/timelimit, target.type:domain/ip/device, target.value:*.facebook.com, status:active/paused, direction:bidirection/inbound/outbound, protocol:tcp/udp, gid:box_id, scope.type:device/network, notes:\"description text\". Examples: \"action:block AND target.value:*.social.com\", \"status:paused\", \"target.type:domain AND action:block\""New value: +"Search query using Firewalla syntax. Supported fields: action:allow/block/timelimit, target.type:domain/ip/device, target.value:*.facebook.com, status:active/paused, direction:bidirection/inbound/outbound, protocol:tcp/udp, box.id:box_gid, scope.type:device/network, notes:\"description text\". Examples: \"action:block AND target.value:*.social.com\", \"status:paused\", \"target.type:domain AND action:block\""
- Changed
search_target_lists3 fields changed- removed
Input schema / properties / categoryRemoved value: -{ - "description": "Filter by category", - "type": "string" -} - changed
Input schema / properties / owner / descriptionPrevious value: -"Filter by owner (global or box gid)"New value: +"Only lists with this owner, sent to the API: \"global\" (MSP lists), a box gid (that box's lists), or several comma-separated, e.g. \"global,<box_gid>\". Default: global and Firewalla-managed lists." - changed
Input schema / properties / query / descriptionPrevious value: -"Search query for target lists. Supported fields: name:*Social*, owner:global/box_gid, category:social/games/ad/porn/etc, targets:*.facebook.com, notes:\"description text\". Examples: \"category:social\", \"owner:global AND name:*Block*\", \"targets:*.gaming.com\""New value: +"Search query for target lists. Supported fields: name:*Social*, owner:global/box_gid, category:social/games/ad/porn/etc, targets:*.facebook.com, notes:\"description text\", target_count:>100 (entries: n, >n, >=n, <n, <=n or a range 10-50), last_updated:>2026-09-01 (a date or Unix seconds, with the same comparisons). Examples: \"category:social\", \"owner:global AND name:*Block*\", \"targets:*.gaming.com\", \"target_count:>1000\", \"last_updated:<2026-01-01\""
5 tool updates
v1.3.0- Changed
search_alarms1 field changed- changed
Input schema / requiredPrevious value: -[]New value: +[ + "query" +]
- Changed
search_devices1 field changed- changed
Input schema / requiredPrevious value: -[]New value: +[ + "query" +]
- Changed
search_flows1 field changed- changed
Input schema / requiredPrevious value: -[]New value: +[ + "query" +]
- Changed
search_rules2 fields changed- added
Input schema / properties / limitAdded value: +{ + "description": "Maximum number of rules to return", + "type": "number" +} - changed
Input schema / requiredPrevious value: -[]New value: +[ + "query" +]
- Changed
search_target_lists1 field changed- changed
Input schema / requiredPrevious value: -[]New value: +[ + "query" +]
28 tool updates
- First observed
create_target_list - First observed
delete_target_list - First observed
get_active_alarms - First observed
get_alarm_trends - First observed
get_bandwidth_usage - First observed
get_boxes - First observed
get_device_status - First observed
get_flow_data - First observed
get_flow_insights - First observed
get_network_rules - First observed
get_network_rules_summary - First observed
get_offline_devices - First observed
get_recent_flow_activity - First observed
get_rule_trends - First observed
get_simple_statistics - First observed
get_specific_alarm - First observed
get_specific_target_list - First observed
get_statistics_by_box - First observed
get_statistics_by_region - First observed
get_target_lists - First observed
pause_rule - First observed
resume_rule - First observed
search_alarms - First observed
search_devices - First observed
search_flows - First observed
search_rules - First observed
search_target_lists - First observed
update_target_list
TDQS
Scored across 24 tools
Several tools overlap in purpose: search_flows vs get_flow_data both query /v2/flows with similar filtering/pagination, search_rules vs get_network_rules both retrieve rules, and get_offline_devices/get_device_status/search_devices all cover device status. The descriptions provide some guidance (e.g., get_recent_flow_activity explicitly warns against historical use), but an agent could still misselect among the search/get pairs.
All 24 tool names use snake_case with a consistent verb_noun pattern (get_*, search_*), and resource nouns are predictable (alarms, flows, rules, devices, target_lists). The only minor variation is get_specific_* and get_network_rules_summary, but these still fit the pattern.
24 tools is borderline heavy per the rubric, and the set includes redundant wrappers (search_target_lists vs get_target_lists, search_devices vs get_device_status, search_flows vs get_flow_data). While the Firewalla MSP API is broad, consolidation of overlapping query tools would improve focus.
Assuming a read-only monitoring/analytics domain, the surface covers alarms, flows, rules, devices, boxes, target lists, statistics, and trends thoroughly, with multiple analytical angles. Gaps remain: no direct get-specific-device or get-specific-rule lookups (only search/list), no alarm acknowledgment/archival write, and no mutation tools for rules or target lists, which agents can work around for query tasks.
Maintenance
Related MCP Connectors
Hosted MCP servers for MSP tools: ConnectWise, NinjaOne, Microsoft 365, SentinelOne, Pax8 and more.
MCP Server for agents to onboard, pay, and provision services autonomously with InFlow
Crypto transaction firewall and risk tools for MCP agents.
Unified MCP Server is a remote MCP connector for AI agents and vertical AI products that provides access to 22,000+ authorized SaaS tools across 400+ integrations and 24 categories directly inside LLMs (Claude, GPT, Gemini, Cohere). Tools operate only on explicitly authorized customer connections, enabling agents to safely read and write against live third-party systems.
Related MCP Servers
- AlicenseNot gradedqualityNot gradedmaintenanceProvides 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.495 npm1-
- AlicenseNot gradedqualityNot gradedmaintenanceEnables interaction with Firewalla network security devices for network monitoring, device management, traffic analysis, and security rule configuration through MCP tools.-
- AlicenseAqualityCmaintenanceA secure MCP server for managing OPNsense firewalls through AI assistants. Provides 81 tools across system, firewall, network, DNS, DHCP, VPN, HAProxy, services, diagnostics, and security domains.8111,779 PyPI21MIT
- AlicenseNot gradedqualityDmaintenanceProvides AI assistants and MCP clients with API access to manage Firewalla MSP resources including boxes, devices, alarms, rules, flows, and target lists.15 npmGPL 3.0