@usex/mikrotik-mcp
v4.16.0
Published
MCP server for MikroTik RouterOS — 780+ tools over SSH for firewall, NAT, routing, DHCP, DNS, WireGuard, wireless, QoS and more.
Maintainers
Readme
@usex/mikrotik-mcp exposes MikroTik RouterOS as 819 Model Context Protocol
tools across 111 modules, so an AI client (Claude Desktop, Claude Code, any MCP
client) can read and configure your router in plain language. It speaks to the
device over SSH — no agent, no API package to install on RouterOS — runs on
Bun, and validates every tool call against a Zod schema.
Every tool is risk-annotated (read / write / destructive) so clients can gate what runs, and risky changes can be wrapped in Safe Mode — RouterOS holds them in memory and auto-reverts if your session drops, so you can't lock yourself out.
// claude_desktop_config.json
{
"mcpServers": {
"mikrotik": {
"command": "mikrotik-mcp",
"env": {
"MIKROTIK_HOST": "192.168.88.1",
"MIKROTIK_USERNAME": "admin",
"MIKROTIK_PASSWORD": "your-password",
},
},
},
}"Show me the firewall input chain, then block SSH from the WAN under safe mode." "Build an IKEv2 site-to-site tunnel to 203.0.113.5 for 192.168.20.0/24." "Why can't VLAN 50 reach the internet?"
Why it's different
- 🧰 Breadth — 819 tools covering the whole device: L2 (bridge, VLAN, wireless, PoE), L3 (addressing, routing, DHCP, DNS), security (firewall, NAT, address-lists, certificates), QoS (queues), and system ops (users, logs, backups, scheduler).
- 🔐 A complete VPN suite — WireGuard, IPsec (IKEv1/IKEv2), L2TP, PPTP, SSTP,
OpenVPN, plus GRE/IPIP/EoIP/VXLAN tunnels. With a
choose-vpn-solutionprompt that picks the right one for you. See the VPN guide. - 🛟 Safe Mode — a real transactional window (
enable_safe_mode→ changes →commit_safe_mode/rollback_safe_mode) backed by a persistent SSH session. Auto-reverts on disconnect. - 🚦 Risk-annotated tools —
readOnlyHint/destructiveHintlet clients auto-approve reads and prompt on writes. - 🧱 Injection-safe by construction — a command builder quotes/escapes every
value, so a hostname like
LAN; /system resetcan never split into a second command. - 🖧 Multiple devices — define named routers and the AI targets one per call
(a validated
deviceargument). Configure both ends of a tunnel from one conversation. See docs/multi-device.md. - 🪜 SSH jump hosts — reach a router with no exposed port by tunnelling
through another via
jumpVia(ProxyJump/bastion) — commands, Safe Mode and file upload all ride the hop. No new WAN port. - ⚡ Connection pooling — one persistent SSH session per device, reused across tool calls. Saves ~200-500 ms handshake per command (double through jump hosts). Idle connections auto-close after 30 s.
- 🤖 Guided prompts — 9 built-in workflows (harden, diagnose, guest Wi-Fi, VPNs, cross-device tunnels, backup & document) that turn an intent into tool calls.
Quickstart
# 1. Install (requires Bun ≥ 1.3 — https://bun.sh)
bun add -g @usex/mikrotik-mcp
# 2. Point it at your router and verify SSH connectivity
MIKROTIK_HOST=192.168.88.1 MIKROTIK_USERNAME=admin MIKROTIK_PASSWORD=•••• \
mikrotik-mcp auth-check
# 3. List the catalog (name · risk · title)
mikrotik-mcp tools
# 4. Run it (stdio by default — wire it into your MCP client)
mikrotik-mcp serveTry it without an AI client — open the official MCP Inspector against the server (from source):
bun run inspect # opens the Inspector UI to browse/run all 819 toolsPrefer SSH keys over a password? Point the server at a key file instead — and add a passphrase if the key is encrypted:
MIKROTIK_HOST=192.168.88.1 MIKROTIK_USERNAME=admin \
MIKROTIK_KEY_FILENAME=~/.ssh/id_ed25519 \
MIKROTIK_KEY_PASSPHRASE=•••• \
mikrotik-mcp auth-check # prints "Auth mode: SSH key"The key (file via --key-filename or inline PEM via --private-key) takes
precedence over a password. Full configuration reference:
docs/configuration.md.
From source
git clone https://github.com/mikrotik-mcp/mikrotik-mcp && cd mikrotik-mcp
bun install
bun run start # serve from source
bun run build # bundle to dist/As an MCP Bundle (.mcpb)
A one-click install for Claude Desktop and other MCPB hosts — no Bun, Node or npm needed on the machine, and the router credentials are entered in the host's UI rather than a shell.
bun run build:mcp # bundle for this machine
bun run build:mcp --target linux-x64 # or one specific target
bun run build:mcp:all # every targetBundles land in dist-mcpb/ as mikrotik-mcp-<version>-<platform>-<arch>.mcpb.
Open one with your MCPB host (on Claude Desktop, drag it onto Settings →
Extensions) and fill in the router address and credentials it prompts for.
Because the server is Bun-native — bun:sqlite, Bun.serve, Bun.S3Client, and
@tikoci/centrs, which ships raw TypeScript — it cannot run on the Node runtime an
MCPB host provides. Each bundle therefore vendors the Bun binary it was built
against and runs runtime/bun dist/cli.js serve, so every subsystem (MAC-Telnet,
the dashboard, S3 backups) behaves exactly as it does from source. That costs about
60 MB per bundle and makes each one platform-specific — hence one artifact per
platform/arch rather than a single universal file.
The build stages the bundle, validates the manifest, and drives the staged server
over stdio (initialize + tools/list, asserting the tool count matches the
manifest) before packing. Pass --no-smoke to skip that last check.
The tool catalog
819 tools across 111 modules. Full, always-current reference (parameters + risk per tool) is generated from source: docs/tools-reference.md.
| Group | Tools | Modules | | ------------------------ | ----: | ---------------------------------------------------------------------------------------------------------- | | Interfaces | 41 | interfaces, VLAN, bridge, wireless, PoE | | Addressing & Routing | 46 | IP addresses, IP pools, routing, DHCP, DNS | | Dynamic Routing | 99 | router-id, settings, tables, rules, next-hops, filters, BFD, BGP, OSPF, RIP, PIM-SM, IGMP proxy, GMP, RPKI | | Security | 34 | firewall filter, NAT, address-lists, certificates, IP services | | VPN & Tunneling | 96 | WireGuard, IPsec, PPP, L2TP, PPTP, SSTP, OpenVPN, GRE/IPIP/EoIP/VXLAN | | QoS | 19 | queue types, queue trees, simple queues | | System & Ops | 102 | system, network tools, scheduler/scripts, users, logs, backup, Safe Mode |
VPN & tunneling — expert coverage
Every MikroTik VPN technology, modeled the way RouterOS actually layers them (the
PPP-based VPNs share one /ppp backend for users and addressing):
| Need | Use | Build it with |
| ----------------------------------- | ----------------------- | -------------------------------------------------------------------------------------- |
| MikroTik ↔ MikroTik, modern clients | WireGuard | create_wireguard_interface, add_wireguard_peer, generate_wireguard_client_config |
| Interop site-to-site / native IKEv2 | IPsec | create_ipsec_{profile,peer,identity,proposal,policy}, get_ipsec_active_peers |
| Built-in OS VPN clients | L2TP/IPsec | set_l2tp_server, create_ppp_secret, create_ppp_profile |
| Through restrictive firewalls | SSTP (TLS) | set_sstp_server, create_sstp_client |
| Cross-platform OpenVPN | OpenVPN | set_ovpn_server, create_ovpn_client |
| Route / L2-bridge between sites | GRE/IPIP/EoIP/VXLAN | create_gre_tunnel, create_eoip_tunnel, create_vxlan_tunnel |
Not sure which? Invoke the choose-vpn-solution prompt and the server
recommends one and outlines the build. Details: docs/vpn-guide.md.
Manage multiple devices
Give each router a name and the AI can drive them all from one conversation —
exactly what you need to set up a tunnel between two MikroTiks and test it from
both ends. Point the server at a JSON file (or MIKROTIK_DEVICES):
// devices.json
{
"defaultDevice": "site-a",
"devices": {
"site-a": { "host": "203.0.113.10", "username": "admin", "keyFilename": "/keys/site-a" },
"site-b": { "host": "198.51.100.20", "username": "admin", "password": "••••" },
},
}mikrotik-mcp serve --config ./devices.json
mikrotik-mcp devices # site-a (default) · site-b
mikrotik-mcp auth-check # probes every deviceWhen more than one device is configured, every tool gains an optional device
argument (a validated enum of your names); omit it to use the default. The AI
discovers names with list_mikrotik_devices, and Safe Mode is per-device so
each router commits independently. The setup-tunnel-between-sites prompt
drives the whole both-ends flow. Full guide: docs/multi-device.md.
// the AI calls a tool against a specific router:
// create_wireguard_interface { "device": "site-a", "name": "wg-to-b", "listen_port": 13231 }Behind a bastion? Reach a router with no exposed SSH port by jumping through
another (OpenSSH-style ProxyJump) — jumpVia names a configured device to tunnel
through; commands, Safe Mode and SFTP upload all ride the hop:
"home-ax3": { "host": "10.10.30.100", "username": "admin", "jumpVia": "hex" }The bastion router needs SSH TCP forwarding enabled (/ip ssh set
forwarding-enabled=local). See docs/multi-device.md.
Built-in prompts
MCP prompts are one-click guided workflows. This server ships 9 — authored as
Markdown in prompts/, so you can edit or add your own without
touching code:
harden-router · diagnose-connectivity · setup-guest-wifi ·
choose-vpn-solution · setup-wireguard-vpn · setup-ipsec-site-to-site ·
setup-l2tp-ipsec-roadwarrior · setup-tunnel-between-sites · backup-and-document
See docs/prompts.md.
Transports
| Transport | When | Run |
| ------------------- | --------------------------------- | ---------------------------------------------------------------- |
| stdio (default) | Claude Desktop, local MCP clients | mikrotik-mcp serve |
| streamable-http | Remote / shared, behind a proxy | mikrotik-mcp serve --transport streamable-http --mcp-port 8000 |
| sse | Legacy HTTP clients | mikrotik-mcp serve --transport sse |
HTTP transports expose POST /mcp and a GET /health check, with DNS-rebinding
protection that reconciles with your bind host automatically. See
docs/transports.md.
SSH connection pooling
By default the server keeps one persistent SSH connection per device and opens a fresh exec channel for each tool call — eliminating the ~200-500 ms handshake overhead that a one-shot connection incurs on every command. Through a jump host the savings double (two handshakes avoided). Idle connections are closed automatically after 30 s.
# Disable pooling (revert to one-shot per tool call)
MIKROTIK_SSH__KEEP_ALIVE=false mikrotik-mcp serve
# Tune the idle timeout (ms)
mikrotik-mcp serve --ssh-idle-timeout 60000In a JSON config file:
{
"ssh": {
"keepAlive": true, // default — set false to disable
"keepAliveInterval": 10000, // SSH keepalive packet interval (ms)
"idleTimeout": 30000, // close idle connections after (ms)
},
}Connection pooling is SSH-only; MAC-Telnet devices always use one-shot connections. Safe Mode still uses its own dedicated persistent session.
Safe Mode
enable_safe_mode → (make changes) → commit_safe_mode # persist
→ rollback_safe_mode # discardWhile active, every change is held in memory; if the SSH session drops (e.g. a firewall rule that locks you out), RouterOS reverts everything automatically. Commands issued during the window are routed through the same persistent session. See docs/safe-mode.md.
Configuration
Connection and transport settings come from MIKROTIK_* env vars or matching CLI
flags (highest precedence last: defaults → env → flags).
| Variable | Flag | Default | Purpose |
| ----------------------------- | -------------------- | ----------- | ---------------------------------------------------------------------------------------------------- |
| MIKROTIK_HOST | --host | 127.0.0.1 | RouterOS host |
| MIKROTIK_USERNAME | --username | admin | SSH user |
| MIKROTIK_PORT | --port | 22 | SSH port |
| MIKROTIK_PASSWORD | --password | — | SSH password (or use a key →) |
| MIKROTIK_KEY_FILENAME | --key-filename | — | SSH private-key file path |
| MIKROTIK_PRIVATE_KEY | --private-key | — | Inline private key (PEM) |
| MIKROTIK_KEY_PASSPHRASE | --key-passphrase | — | Passphrase for an encrypted key |
| MIKROTIK_JUMP_HOST | --jump-host | — | SSH bastion to tunnel through (jump hosts) |
| MIKROTIK_CONFIG_FILE | --config | — | JSON file of named devices (multi-device) |
| MIKROTIK_DEVICES | --devices | — | Inline JSON of named devices |
| MIKROTIK_MCP__TRANSPORT | --transport | stdio | stdio / streamable-http / sse |
| MIKROTIK_MCP__PORT | --mcp-port | 8000 | HTTP bind port |
| MIKROTIK_SSH__KEEP_ALIVE | --ssh-keep-alive | true | SSH connection pooling (reuse connections across tool calls) |
| MIKROTIK_SSH__IDLE_TIMEOUT | --ssh-idle-timeout | 30000 | Close idle pooled connections after (ms) |
| MIKROTIK_DASHBOARD__ENABLED | --dashboard | false | Real-time observability dashboard (docs) |
Full table (incl. HTTP host, allow-lists, timeouts, MIKROTIK_LOG_LEVEL):
docs/configuration.md.
Observability dashboard (optional)
A localhost-only web dashboard that intercepts every tool call the LLM makes — live feed of inputs/outputs (secrets redacted), latency percentiles, error rate and per-tool/risk/device analytics — persisted to a Bun-native SQLite store and served on its own port alongside any transport:
mikrotik-mcp serve --dashboard # → http://127.0.0.1:9090Beyond the catalog
On top of the per-scope tools, the server ships higher-level workflows:
- Change Plan & Dry-Run — preview intended commands as
a terraform-style plan (risk-scored, lock-out-aware, safely reordered), then
apply_planruns them under Safe Mode, shows the exact/exportdiff, and commits only if the device is still reachable (auto-reverts a lock-out). - Config Snapshots — store
/exportsnapshots on the host and time-travel diff any two, or one against the live device. - Firewall Audit —
firewall_auditfinds shadowed, overly-broad, missing-default-drop, duplicate and dead rules, risk-scored, with one-click fixes in MCP App hosts. - Security Hardening — granular audit+remediate
pairs per risk category (firewall default-deny, address-list enforcement, kernel
IP, IPv6 baseline, SSH, service exposure, helpers, management plane, accounts,
CRL, segmentation, DNS) plus an orchestrator. Every audit is read-only; every
fix defaults to dry-run and snapshots + Safe-Modes before writing, remediating
by explicit
finding_id. - Port-Scan Detection — detect (never block) six
port-scan signatures (psd, Nmap FIN/NULL/Xmas, SYN/FIN, SYN/RST) by tagging the
source, inside a trust-excluding
detect-portscanjump-gate; explicit signature selection, trust-list pre-flight, snapshot + Safe-Mode apply. - Packet Capture Studio — stream mirrored packets to
the host as TZSP, decode them live in the dashboard, and export
.pcap. - Discovery —
bun run discoverlists MikroTik devices on the LAN by MAC (MNDP); the dashboard draws a live topology map. - Config Studio — edit the config JSON in the dashboard with autocomplete, validation, and safe-apply auto-rollback.
Schemas
schemas/ ships machine-readable JSON Schemas, generated from the TypeScript
source (bun run gen:schemas) so they can never drift:
schemas/tool-catalog.json— every tool with risk, description, and input schemaschemas/tools/<name>.json— per-tool input schemaschemas/config.schema.json— the runtime configuration
Documentation
| Doc | |
| ------------------------------------------------------------- | --------------------------------------------------------------------- |
| Getting started | Install, verify, first run |
| Configuration | Every env var & flag |
| Multiple devices | Manage several routers; per-call targeting |
| Connecting clients | Claude Desktop, stdio, HTTP |
| Transports | stdio / HTTP / SSE, DNS-rebinding |
| Observability | Real-time dashboard: live feed + analytics, SQLite |
| Safe Mode | Transactional changes |
| Change Plan & Dry-Run | Preview commands, apply with the exact diff + auto-rollback |
| Config Snapshots | /export snapshots + time-travel diff |
| Firewall Audit | Shadowed/broad/dead rules, risk-scored |
| Security Hardening | Per-category audit+remediate, fix by finding_id, snapshot + Safe-Mode |
| Port-Scan Detection | Detect+tag six scan signatures behind a trust-excluding jump-gate |
| Packet Capture Studio | Live TZSP capture + pcap export |
| Discovery | bun run discover, MNDP neighbours, topology map |
| Config Studio | Edit config in the dashboard with autocomplete |
| VPN guide | Every tunnel type + how to build it |
| Prompts | The 9 guided workflows |
| Architecture | How it's built |
| Security | Credentials, risk gating |
| Tool reference | The full generated catalog |
| MCP Inspector | Test tools/prompts in the UI or CLI |
| Development · Docker | Build, test, deploy |
Development
bun run test:types # tsc --noEmit
bun test # unit tests
bun run gen # regenerate schemas/ + docs/tools-reference.md from source
bun run build # bundle to dist/See docs/development.md and CONTRIBUTING.md.
Security
Talks to RouterOS over SSH using credentials you supply; nothing is sent anywhere else. Tool values are quoted/escaped to prevent console-command injection. Destructive and dangerous tools are annotated so clients can require confirmation, and a plaintext-password-in-a-container warning nudges you toward key files or secrets. Details: docs/security.md. Only point this at devices you're authorized to manage.
License
MIT. Reuse freely. No warranty.
