Skip to main content
Glama
mikrotik-swos-mcp

mikrotik-swos-mcp

by saniyo

mikrotik-swos-mcp

An MCP server that lets an AI assistant (Claude Code, Claude Desktop or any MCP client) read and change MikroTik SwOS / SwOS Lite switches live through their web API. You no longer have to download, edit and upload .swb backups by hand.

Українською

  • No hard-coded field tables. The server downloads each switch's own engine.js and learns field ids, names, types, option lists and UI forms from it. The minified names change with every SwOS build, and the parser copes with that.

  • Writes work exactly like the web UI. The server POSTs one UI form to /<section>.b, and the change applies live without a reboot.

  • Safe by default. Every write first returns a dry-run diff and a token. Nothing changes until the tool is called again with confirm=<token>, and the token is refused if the live configuration changed in between. After a write the server reads the values back, appends a changelog entry and saves a fresh backup.

  • Backups with real field names. It decodes .swb files and diffs live against file or file against file. A prepared .swb can be restored live by applying only the forms that differ, without a reboot.

  • Gentle on production switches. One request at a time, at least 0.2 s between requests, a 3 s cache and no background polling.

  • Verifiable. verify/ renders the switch's own web UI offline on captured data and compares every value it shows with the decoder (see Verification).

Supported devices

Device / firmware

Status

CSS610-8G-2S+, SwOS Lite 2.21

Verified against the web UI on 3 production switches: 3,251 displayed values, 0 mismatches. Live write tested (identity round trip, read back, no reboot)

CSS610-8G-2S+, SwOS Lite 2.18

Used in production before an upgrade: reads, backups and dry runs; .swb decoding byte-checked. Parser OK

CSS610-8G-2S+, SwOS Lite 2.20

Parser OK on the reference engine.js from lanrat/python-mikrotik-swos (no device test)

CSS610-8P-2S+ (PoE), SwOS Lite 2.20

Parser OK on the reference engine.js, PoE tab included (no device test)

Full SwOS (CRS305/309/310/326, CSS326)

Not supported yet. Same UI framework, but descriptive keys, variable port count and >32-bit masks. Parser fails on the reference files

Other SwOS Lite devices probably work because everything is read from the device. Please run verify/ on yours and open an issue with the result line.

Related MCP server: RouterOS MCP Server

Install

git clone https://github.com/saniyo/mikrotik-swos-mcp
cd mikrotik-swos-mcp
pip install -r requirements.txt          # mcp (1.x or 2.x) + requests
cp switches.example.json switches.json   # then edit it

switches.json:

{
  "user": "admin",
  "configs_dir": "configs",
  "changelog": "configs/CHANGELOG.md",
  "switches": [
    {"ip": "192.168.88.1", "name": "core", "password": "", "note": "CSS610 in rack A"}
  ]
}
  • configs_dir holds current/ (the latest backup of each switch), archive/<date>/ (superseded backups) and manual-changes/ (prepared .swb files for restore_backup). Relative paths are relative to the config file.

  • Passwords: use the password field, or the environment variables SWOS_PASSWORD_192_168_88_1 (one switch) or SWOS_PASSWORD (all switches). Environment variables win. Passwords are never printed or written anywhere. An empty admin password only triggers a warning; nothing is blocked.

  • SWOS_CONFIG=/path/to/switches.json keeps the config outside the repository.

Register with your MCP client

Claude Code:

claude mcp add swos --scope user -- /path/to/python /path/to/mikrotik-swos-mcp/server.py

Claude Desktop (claude_desktop_config.json):

{"mcpServers": {"swos": {"command": "/path/to/python", "args": ["/path/to/mikrotik-swos-mcp/server.py"]}}}

Use a stable interpreter, not a virtual environment that another tool may rebuild. The server runs over stdio.

Tools

Tool

What it does

list_switches

Configured switches with live identity, version, uptime and a warning for an empty password

read_config

Config with the web-UI field names. section filters by tab (VLAN, VLANs, Link, System, SNMP...). source is live or a .swb path

read_status

Per port: link, speed, duplex, flow control. Plus uptime, CPU temperature, serial and MAC. detail adds RSTP, traffic rates, SFP and cable diagnostics

diff_configs

Diff of any two of: a live switch, a .swb file

set_identity

System > Identity

set_port

Port name, enabled, VLAN mode / receive / default VLAN ID / force VLAN ID

set_vlan

Add, change or remove one VLAN table entry (members, IGMP snooping)

set_field

Any web-UI field by tab and field name, e.g. SNMP / Location, System / Allow From Ports

save_backup

Saves current/<identity>-<IP>.swb. The previous file moves to archive/<date>/; no duplicates are created

restore_backup

Applies a .swb from manual-changes/: live (only the differing forms, no reboot) or upload (Restore Backup, which reboots)

A write session looks like this:

> set_identity switch=core identity=CSS610-RACK-A
DRY RUN - 192.168.88.1: identity -> CSS610-RACK-A
[System / General] POST /sys.b (whole UI form, other fields re-sent unchanged, applies live):
  System / General: Identity: MikroTik -> CSS610-RACK-A
To apply, call again with confirm="b39d5ed576".
> set_identity switch=core identity=CSS610-RACK-A confirm=b39d5ed576
APPLIED - 192.168.88.1
[System / General] POST /sys.b: HTTP 200, read-back OK

How SwOS Lite talks (read from engine.js, not guessed)

  • GET /<section>.b (sys.b, link.b, fwd.b, vlan.b, snmp.b, rstp.b, lacp.b, host.b, acl.b; read-only ones start with !, like !stats.b) returns a JavaScript literal with iNN keys, e.g. {i01:0x03ff,i0a:['506f727431',...]}. Strings are hex, IPv4 is a little-endian 32-bit number, per-port checkboxes are bit masks.

  • The web UI writes one form at a time (one tab block with its own Apply button): POST /<section>.b, Content-Type: text/plain, and the body holds every writable field of that form in the same literal format. Several tabs share fwd.b / sys.b, and each posts only its own fields. The change applies immediately. This server posts the same form and re-sends the untouched fields with the values it has just read.

  • Restore Backup = multipart POST /backup.swb (field file), then POST /reboot.

  • A .swb backup holds the same data with one-letter keys: index NN becomes 'A'+NN, continuing with 'a'.. after 'Z'.

  • HTTP digest auth, HTTP/1.0, one connection at a time.

  • Field definitions look like {n:"VLAN Mode",id:"i15",t:G,m:["disabled","optional","strict"]}. The type function names (G) and property names (m) differ between builds, so the parser identifies them by code signatures (for example, the checkbox type is the one whose parser contains >>1&2147483647).

Verification

The decoder is checked against the switch's own web UI, not against a hand-written expectation:

python verify/make_harness.py core          # captures each section once (read-only), builds verify/out/<ip>/
python -m http.server 8765 --bind 127.0.0.1 --directory verify/out
# open http://127.0.0.1:8765/<ip>/index.html and wait a few seconds

The page is the switch's real index.html + engine.js, fed with the captured data through a fake XMLHttpRequest, so it never talks to the switch (POSTs are dropped). It renders every tab and compares each input, select, checkbox and read-only value with the decoder. The result line reads like ok 870, blank=default 117, mismatch 0, missing 3, extra 0:

  • blank=default: the UI leaves a field empty when it holds its default value (for example 0.0.0.0).

  • missing 3: Root Bridge and Allow From are composite fields that the UI shows as one combined input (8000.aa:bb:cc:dd:ee:ff). They are expected; check them by eye.

  • extra: a UI element the decoder does not know. It should be 0. Anything else is a bug, so please report it.

Keys that the switch sends but no UI field shows (SwOS Lite 2.21): sys.b i02 current IP, i06 version, i0b build time, i0c upgrade flag, i0d watchdog (shown on 2.18, hidden on 2.21); link.b i09 per-port counter (lanrat names it port uptime; the unit is unverified); rstp.b i04 matches the STP path cost (4 / 19 / 100 for 1G / 100M / 10M links). The rest are zero and not referenced by engine.js: sys.b i15 i16 i1c-i1f i20 i21 i23-i26 i2b, link.b i0b i0c, sfp.b i07, stats.b i03.

this project

MikroMCP

python-mikrotik-swos

Type

MCP server (Python)

MCP server (TypeScript, RouterOS + SwOS)

Library, CLI, Ansible (Python)

Field map

read from each switch's engine.js at runtime

static tables

static tables per platform

SwOS Lite / full SwOS

Lite only (for now)

both (SwOS marked experimental)

both, more devices

Coverage

every web-UI field (generic set_field)

sys, link, fwd, VLAN, LACP, SNMP, PoE, upgrade

sys, ports, PoE, LAG, VLAN, SNMP, password

Write safety

dry run + token, read-back, changelog, backup

dry run, lockout guard, snapshot/rollback

Ansible check mode

Restore

live (only differing forms) or upload + reboot

upload + reboot

upload

.swb decode / diff

yes

no

no

Verified against the UI

yes (verify/)

no

no

Not here yet, worth adopting: full SwOS, a hard lockout guard (MikroMCP), PoE convenience tools, firmware upgrade.

Safety notes

  • Fields that affect management access (IP, Allow From, VLAN changes) produce warnings in the dry run. Unlike some related projects, there is no automatic lockout guard yet, so review VLAN changes on the uplink port yourself.

  • The admin password is never changed. A live restore never touches the password either.

  • Static hosts and ACL entries are read and diffed but have no dedicated write tool; use restore_backup instead.

  • verify/ and all read tools never write. The verify page drops every POST.

License

MIT. Use at your own risk: these switches often carry production traffic, so always read the dry run.

Tool Schema Changelog

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

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      A bridge between AI assistants and MikroTik RouterOS devices, allowing natural language interaction to manage network configurations including VLANs, firewalls, DNS settings, and more.
      1
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI assistants to interact with MikroTik RouterOS devices through API and SSH connections, supporting network monitoring, configuration management, and diagnostics across multiple routers with automatic connection fallback.
      3
      MIT
    • A
      license
      C
      quality
      A
      maintenance
      Provides a bridge between AI assistants and MikroTik RouterOS devices, enabling natural language management of VLANs, firewall rules, DNS settings, and more.
      234
      1,052 PyPI
      334
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Bridges AI assistants with MikroTik RouterOS devices, enabling natural language management of network configurations, firewall, VLANs, VPNs, and diagnostics via ~300 tools.
      1
      MIT