Sophos Xgs Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Sophos Xgs Mcp (Agent Skill) and scored it 92/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 2 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 2 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A Model Context Protocol (MCP) server for the Sophos XGS Firewall XML API. Gives AI assistants like Claude visibility into your firewall configuration, and — only when you explicitly enable it — the ability to change it.
Read-only by default. The write tools are not registered unless SOPHOS_ENABLE_WRITE=1 is set. Without it this server cannot modify the appliance.
routing, DHCP, DNS, IPS, SSL/TLS inspection, and admin settings
accepts raw XML
| Category | Tools |
|---|---|
| Profiles | get_active_profile, list_profiles, switch_profile — target multiple firewalls from one server |
| Firewall | list_firewall_rules, list_firewall_rule_groups, get_firewall_rule, search_firewall_rules |
| Network Objects | list_ip_hosts, list_ip_host_groups, list_fqdn_hosts, list_fqdn_host_groups, list_mac_hosts, get_ip_host, search_ip_hosts |
| Services | list_services, list_service_groups, get_service |
| Zones & Interfaces | list_zones, list_interfaces, list_vlans, list_interface_aliases, list_lag_interfaces, get_zone, get_interface |
| NAT | list_nat_rules |
| VPN | list_sslvpn_policies, list_vpn_ipsec_connections |
| Web Filtering | list_web_filter_policies, list_url_groups, list_web_filter_exceptions |
| SSL/TLS Inspection | list_ssl_tls_inspection_rules, get_ssl_tls_inspection_settings, list_decryption_profiles |
| IPS | list_ips_policies |
| Routing & SD-WAN | list_static_routes, list_sdwan_policy_routes, list_sdwan_profiles, list_gateway_hosts, list_gateway_configurations |
| DHCP & DNS | list_dhcp_servers, list_dns_forwarders, list_dns_request_routes, list_dns_host_entries |
| Users & Admin | list_users, list_admin_profiles, get_admin_settings, get_admin_authen, get_user_activity |
| System | get_backup_restore_settings, get_time_settings, get_reports_retention, list_syslog_servers, list_notifications, list_snmpv3_users, get_pim_settings, get_captive_portal |
list_smtp_policies | |
| Access Control | list_local_service_acl, list_schedules, list_access_time_policies, list_surfing_quota_policies, list_data_transfer_policies |
| IPv6 | list_router_advertisements |
| Advanced | raw_api_query — query any entity with optional filters |
| Write (opt-in) | create_entity, update_entity, delete_entity, preview_write |
All The Time is missingfrom the result and from an exact-name filter, yet it is the most-used schedule in a typical ruleset. Absence from this list is not evidence that a schedule does not exist — check the rules that reference it.
live under Services; a Get on Service fails with 529 Input request module is Invalid. That code means unknown entity, not no such object — if raw_api_query returns it, try the other spelling before concluding the object is gone.
recommended; see Write access.
git clone https://github.com/Leon69924/sophos-xgs-mcp.git
cd sophos-xgs-mcp
pnpm install
pnpm buildmkdir -p ~/.config/sophos-xgs
chmod 700 ~/.config/sophos-xgsCreate ~/.config/sophos-xgs/config.json with one profile per firewall. activeProfile selects which firewall the tools target; switch at runtime with the switch_profile tool (the switch is persisted to this file):
{
"activeProfile": "main",
"profiles": {
"main": {
"host": "your-sophos-hostname-or-ip",
"port": "4444",
"username": "your-api-user",
"description": "optional free-text note"
}
}
}Create ~/.config/sophos-xgs/credentials-<profile> with just the password, one file per profile:
echo -n "your-password" > ~/.config/sophos-xgs/credentials-main
chmod 600 ~/.config/sophos-xgs/config.json ~/.config/sophos-xgs/credentials-mainAlternatively, use environment variables — they override the config file entirely (profile switching is disabled while they are set):
export SOPHOS_HOST=your-sophos-hostname-or-ip
export SOPHOS_PORT=4444
export SOPHOS_USERNAME=your-api-user
export SOPHOS_PASSWORD=your-passwordFor Claude Code, add to ~/.mcp.json:
{
"mcpServers": {
"sophos-xgs": {
"type": "stdio",
"command": "node",
"args": ["/path/to/sophos-xgs-mcp/dist/index.js"]
}
}
}Write tools are registered only when SOPHOS_ENABLE_WRITE=1 is present in the server's environment:
{
"mcpServers": {
"sophos-xgs": {
"type": "stdio",
"command": "node",
"args": ["/path/to/sophos-xgs-mcp/dist/index.js"],
"env": { "SOPHOS_ENABLE_WRITE": "1" }
}
}
}Back this with a restricted API user. The env flag governs what this server offers; it does not limit what the credentials may do. Sophos authenticates the API with ordinary administrator accounts, and their rights come from the assigned administration profile, where every module can be set to None, Read-Only or Read-Write. Use a read-only profile for read-only deployments, and give a write deployment only the modules it actually needs. That boundary holds regardless of bugs in this server.
Set operation="update" replaces the entity definition on the appliance. Fields omitted from the request fall back to defaults — they do not stay unchanged. An update meant to flip one flag can silently empty a firewall rule's source and destination networks.
update_entity therefore always fetches the current object, merges your fields onto it, and sends the complete definition. It aborts rather than continuing if:
That third condition exists because a filtered Get does not always answer "no such object" by returning nothing. Four entities on an XGS 2100 — SSLVPNPolicy, VPNIPSecConnection, AdminSettings, GatewayConfiguration — answer a Name filter with the element and nothing inside it, because they hold their contents in one record with no top-level Name to filter on. SSLVPNPolicy filtered by name returns literally [{}].
An empty result is not null, so the "does not exist" check passes; merging onto it yields little more than your delta; and the field-loss check has nothing to compare, because the fields were never there. What would reach the appliance is a partial update — against an API that replaces what it updates. For SSLVPNPolicy that is every tunnel policy on the box reduced to a name.
create_entity aborts if the name already exists, delete_entity fetches the object first so you can see what disappears, and preview_write shows the exact XML and field-level diff without sending anything.
To clear a field on purpose, pass null. Omitting it means "leave unchanged".
This server does not prompt — MCP gives it no mechanism to. In Claude Code you can get a confirmation per write with a PreToolUse hook matching mcp__sophos-xgs__.* that returns permissionDecision: "ask" for the write tools. ask outranks the permission allowlist, so it keeps asking even after "don't ask again".
Two things such a guard should do, both learned the hard way:
switch_profile persists acrosssessions, so without the hostname a change gets confirmed for one firewall and applied to another.
to a later version then lands on the safe side by default.
The design, including the guard's decision matrix, is written up in docs/superpowers/specs/2026-08-04-write-support-design.md.
SOPHOS_ENABLE_WRITE=1Password, PasswordHash, PreSharedKey and similarfields are masked before results leave the server, and writing a redaction placeholder back to the appliance is refused
^[A-Za-z][A-Za-z0-9_]*$ and every value is escaped
~/.config/sophos-xgs/ or env varsSophos connection only
pnpm build # tsc
pnpm test # node --test
pnpm dev # run from sourceAGPL-3.0-only — see LICENSE
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.