MikroTik MCP

Manage MikroTik RouterOS routers over SSH: firewall, NAT, DHCP, DNS, routes, VLANs, WireGuard and more

By WireSage Python Local · stdio DevOps and monitoringSecurity

58 popularity score ★ 325 ↓ 11k/mo

Connect your client

Local (PyPI)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

It needs MIKROTIK_HOST, MIKROTIK_USERNAME, MIKROTIK_PASSWORD. Replace each <NAME> with your value.

Claude CodeTerminal
claude mcp add mikrotik -e MIKROTIK_HOST=<MIKROTIK_HOST> -e MIKROTIK_USERNAME=<MIKROTIK_USERNAME> -e MIKROTIK_PASSWORD=<MIKROTIK_PASSWORD> -- uvx mcp-server-mikrotik
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "mikrotik": {
      "command": "uvx",
      "args": [
        "mcp-server-mikrotik"
      ],
      "env": {
        "MIKROTIK_HOST": "<MIKROTIK_HOST>",
        "MIKROTIK_USERNAME": "<MIKROTIK_USERNAME>",
        "MIKROTIK_PASSWORD": "<MIKROTIK_PASSWORD>"
      }
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "mikrotik": {
      "command": "uvx",
      "args": [
        "mcp-server-mikrotik"
      ],
      "env": {
        "MIKROTIK_HOST": "<MIKROTIK_HOST>",
        "MIKROTIK_USERNAME": "<MIKROTIK_USERNAME>",
        "MIKROTIK_PASSWORD": "<MIKROTIK_PASSWORD>"
      }
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "mikrotik": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "mcp-server-mikrotik"
      ],
      "env": {
        "MIKROTIK_HOST": "<MIKROTIK_HOST>",
        "MIKROTIK_USERNAME": "<MIKROTIK_USERNAME>",
        "MIKROTIK_PASSWORD": "<MIKROTIK_PASSWORD>"
      }
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.mikrotik]
command = "uvx"
args = ["mcp-server-mikrotik"]

[mcp_servers.mikrotik.env]
MIKROTIK_HOST = "<MIKROTIK_HOST>"
MIKROTIK_USERNAME = "<MIKROTIK_USERNAME>"
MIKROTIK_PASSWORD = "<MIKROTIK_PASSWORD>"
Gemini CLITerminal
gemini mcp add --scope user -e MIKROTIK_HOST=<MIKROTIK_HOST> -e MIKROTIK_USERNAME=<MIKROTIK_USERNAME> -e MIKROTIK_PASSWORD=<MIKROTIK_PASSWORD> mikrotik uvx -- mcp-server-mikrotik
Local (container)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

It needs MIKROTIK_HOST, MIKROTIK_USERNAME, MIKROTIK_PASSWORD. Replace each <NAME> with your value.

Claude CodeTerminal
claude mcp add mikrotik -e MIKROTIK_HOST=<MIKROTIK_HOST> -e MIKROTIK_USERNAME=<MIKROTIK_USERNAME> -e MIKROTIK_PASSWORD=<MIKROTIK_PASSWORD> -- docker run --rm -i -e MIKROTIK_HOST -e MIKROTIK_USERNAME -e MIKROTIK_PASSWORD ghcr.io/wiresage/mikrotik-mcp:latest
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "mikrotik": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-e",
        "MIKROTIK_HOST",
        "-e",
        "MIKROTIK_USERNAME",
        "-e",
        "MIKROTIK_PASSWORD",
        "ghcr.io/wiresage/mikrotik-mcp:latest"
      ],
      "env": {
        "MIKROTIK_HOST": "<MIKROTIK_HOST>",
        "MIKROTIK_USERNAME": "<MIKROTIK_USERNAME>",
        "MIKROTIK_PASSWORD": "<MIKROTIK_PASSWORD>"
      }
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "mikrotik": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-e",
        "MIKROTIK_HOST",
        "-e",
        "MIKROTIK_USERNAME",
        "-e",
        "MIKROTIK_PASSWORD",
        "ghcr.io/wiresage/mikrotik-mcp:latest"
      ],
      "env": {
        "MIKROTIK_HOST": "<MIKROTIK_HOST>",
        "MIKROTIK_USERNAME": "<MIKROTIK_USERNAME>",
        "MIKROTIK_PASSWORD": "<MIKROTIK_PASSWORD>"
      }
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "mikrotik": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-e",
        "MIKROTIK_HOST",
        "-e",
        "MIKROTIK_USERNAME",
        "-e",
        "MIKROTIK_PASSWORD",
        "ghcr.io/wiresage/mikrotik-mcp:latest"
      ],
      "env": {
        "MIKROTIK_HOST": "<MIKROTIK_HOST>",
        "MIKROTIK_USERNAME": "<MIKROTIK_USERNAME>",
        "MIKROTIK_PASSWORD": "<MIKROTIK_PASSWORD>"
      }
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.mikrotik]
command = "docker"
args = ["run", "--rm", "-i", "-e", "MIKROTIK_HOST", "-e", "MIKROTIK_USERNAME", "-e", "MIKROTIK_PASSWORD", "ghcr.io/wiresage/mikrotik-mcp:latest"]

[mcp_servers.mikrotik.env]
MIKROTIK_HOST = "<MIKROTIK_HOST>"
MIKROTIK_USERNAME = "<MIKROTIK_USERNAME>"
MIKROTIK_PASSWORD = "<MIKROTIK_PASSWORD>"
Gemini CLITerminal
gemini mcp add --scope user -e MIKROTIK_HOST=<MIKROTIK_HOST> -e MIKROTIK_USERNAME=<MIKROTIK_USERNAME> -e MIKROTIK_PASSWORD=<MIKROTIK_PASSWORD> mikrotik docker -- run --rm -i -e MIKROTIK_HOST -e MIKROTIK_USERNAME -e MIKROTIK_PASSWORD ghcr.io/wiresage/mikrotik-mcp:latest

Settings 10

Set together: single device
MIKROTIK_HOST Required: IP or hostname of the router in single-device mode (the Docker image uses 192.168.88.1). Default 127.0.0.1.
MIKROTIK_USERNAME Required: SSH username. Default admin.
MIKROTIK_PASSWORD secret Required: SSH password; or log in with MIKROTIK_KEY_FILENAME or MIKROTIK_ALLOW_SSH_AGENT instead.
MIKROTIK_PORT Optional: SSH port. Default 22.
MIKROTIK_KEY_FILENAME Optional: Path to an SSH private key for key-based login.
MIKROTIK_ALLOW_SSH_AGENT Optional: true logs in with keys offered by the SSH agent through SSH_AUTH_SOCK. Default false.
MIKROTIK_READ_ONLY Optional: true exposes only tools marked read-only. Default false.
MIKROTIK_SENSITIVE_HIDING Optional: true redacts credentials and keys from output and logs and drops two tools that return secrets. Default false.
Set together: inventory
MIKROTIK_INVENTORY_FILE Optional: Path to a YAML file listing several devices; replaces the single-device settings.
MIKROTIK_INVENTORY secret Optional: Inline YAML or JSON device list; wins over MIKROTIK_INVENTORY_FILE.

In a container, a setting goes in with -e NAME=value after docker run.

What it does

MikroTik MCP is a Python server that connects to MikroTik RouterOS devices over SSH and exposes router administration as tools. You can work on interfaces, VLANs, IPv4 and IPv6 addresses, DHCP, IP pools, firewall filter rules for both IP versions, NAT, address lists, routes, DNS, users, queues, PoE, WireGuard and wireless. Backups and exports are covered too, as are RouterOS Safe Mode sessions. Newer releases add read-only views of IPsec, ARP and IPv6 neighbors, netwatch, schedulers, management services and system health.

In version 0.26.2 the source registers 212 tools. Of those, 96 are annotated read-only. Removals are flagged as destructive, and four tools carry a separate dangerous flag: create_basic_firewall_setup, restore_backup, import_configuration and remove_file. The README never gives that count. The tool reference index also has no entry for the wireless, IPsec, system, netwatch, scheduler or services groups.

A single router is set with MIKROTIK_HOST and its login. Since 0.14.0 you can instead hand it a YAML inventory of many devices (MIKROTIK_INVENTORY_FILE, or MIKROTIK_INVENTORY inline), and each tool then takes a device argument naming the target. Two switches cut down what the assistant gets. MIKROTIK_READ_ONLY drops every tool that is not marked read-only, while MIKROTIK_SENSITIVE_HIDING redacts passwords and keys from output and removes download_file and generate_wireguard_client_config. Transport is stdio by default. It can also run as an SSE or streamable HTTP service with a /health endpoint.

What it needs

RuntimePython 3.10+Docker
Runs onmacOS, Windows, Linux
MikroTik RouterOSYour own instanceA device with SSH reachable from the server and an account with a password, SSH key or agent key. RouterOS 7 is the tested version.
Also
  • uv, for the uvx command

Run it with uvx (needs uv) or pip on Python 3.10+, or use the Docker image ghcr.io/wiresage/mikrotik-mcp (amd64 and arm64), which needs neither. The RouterOS account's permissions set the real limit on what the tools can change, so create a restricted account for audits.

Limits

  • Limit With no settings the host defaults to 127.0.0.1 in config.py, and the Docker entrypoint uses 192.168.88.1 instead, so give a host or an inventory.
  • Limit The MCP registry entry (server.json) still describes version 0.14.1.0, well behind 0.26.2 on PyPI.
  • Read only MIKROTIK_READ_ONLY only hides tools. Its registry entry advises a read-only RouterOS account as well, since that is what blocks writes on the device.
  • Limit Sensitive hiding redacts recognised credential fields and key material, so a secret written into a comment or a free-text log line can still show.
  • Limit A command fails after 180 seconds with no output from the device by default (MIKROTIK_COMMAND_TIMEOUT).
  • Not covered RouterOS 7 is the version its install guide says is tested.
  • Limit The HTTP transports listen on 0.0.0.0:8000 by default and accept any client IP unless MIKROTIK_MCP__ALLOWED_IPS is set.

Its install guide lists RouterOS API access and the routeros-api package as prerequisites, but the code connects over SSH with paramiko only. With no settings the host defaults to 127.0.0.1 in config.py (the Docker entrypoint uses 192.168.88.1 instead), so a host must be given. The MCP registry entry still describes version 0.14.1.0, older than the 0.24.2 on PyPI. MIKROTIK_READ_ONLY only trims the tool list; its docs say a restricted RouterOS account is the real write protection. Sensitive hiding cannot spot unlabelled secrets in free-text log lines or comments. The HTTP transports listen on 0.0.0.0:8000 by default with no client IP limit unless MIKROTIK_MCP__ALLOWED_IPS is set.

Who it suits

Suits network admins who run MikroTik routers and want an assistant to inspect or change their configuration, on one device or a fleet, with read-only mode for audits and Safe Mode for risky edits. It is a community project, not from MikroTik, and it acts with whatever rights the SSH account has, so it is a poor fit where no restricted RouterOS account can be made. People who prefer the RouterOS REST API to SSH can look at mikrotik-rest-mcp, which we also list: it works through the RouterOS 7 REST API and asks for confirmation before disruptive changes.

Tools 60 of 212

25 only read, 27 change things, 8 can delete or overwrite. A ? marks an optional parameter.

list_devices
List the devices in the configured inventory by title
safe_mode_status
Report whether RouterOS Safe Mode is ondevice?: string
enable_safe_mode changes
Start Safe Mode so later changes revert if the session dropsdevice?: string
commit_safe_mode changes
Keep the pending Safe Mode changes and leave Safe Modedevice?: string
rollback_safe_mode changes
Throw away pending Safe Mode changes by closing the sessiondevice?: string
create_filter_rule changes
Add an IPv4 firewall filter rulechain: enumaction: enumsrc_address?: stringdst_address?: stringsrc_port?: stringdst_port?: stringprotocol?: stringin_interface?: stringout_interface?: stringin_interface_list?: stringout_interface_list?: stringconnection_state?: stringconnection_nat_state?: stringsrc_address_list?: stringdst_address_list?: stringlimit?: stringtcp_flags?: stringcomment?: stringdisabled?: booleandevice?: string
list_filter_rules
List IPv4 firewall filter rules, with filterschain_filter?: stringaction_filter?: stringsrc_address_filter?: stringdst_address_filter?: stringprotocol_filter?: stringinterface_filter?: stringdisabled_only?: booleaninvalid_only?: booleandynamic_only?: booleandevice?: string
get_filter_rule
Show one firewall filter rulerule_id: stringdevice?: string
update_filter_rule changes
Change fields of an existing filter rulerule_id: stringchain?: stringaction?: stringsrc_address?: stringdst_address?: stringsrc_port?: stringdst_port?: stringprotocol?: stringin_interface?: stringout_interface?: stringin_interface_list?: stringout_interface_list?: stringconnection_state?: stringconnection_nat_state?: stringsrc_address_list?: stringdst_address_list?: stringlimit?: stringtcp_flags?: stringcomment?: stringdevice?: string
remove_filter_rule deletes
Delete a firewall filter rulerule_id: stringdevice?: string
move_filter_rule changes
Change a filter rule's position in the chainrule_id: stringdestination: integerdevice?: string
enable_filter_rule changes
Turn a disabled filter rule back onrule_id: stringdevice?: string
disable_filter_rule changes
Turn a filter rule off without deleting itrule_id: stringdevice?: string
create_basic_firewall_setup changes
Apply a starter set of input and forward filter rulesdevice?: string
set_dns_servers changes
Set upstream DNS servers and remote-request handlingservers: arrayallow_remote_requests?: booleanmax_udp_packet_size?: integermax_concurrent_queries?: integercache_size?: integercache_max_ttl?: stringuse_doh?: booleandoh_server?: stringverify_doh_cert?: booleandevice?: string
get_dns_settings
Show the router's DNS configurationdevice?: string
add_dns_static changes
Add a static DNS recordname: stringaddress?: stringcname?: stringmx_preference?: integermx_exchange?: stringtext?: stringsrv_priority?: integersrv_weight?: integersrv_port?: integersrv_target?: stringttl?: stringcomment?: stringdisabled?: booleanregexp?: stringdevice?: string
list_dns_static
List static DNS recordsname_filter?: stringaddress_filter?: stringtype_filter?: stringdisabled_only?: booleanregexp_only?: booleandevice?: string
get_dns_static
Show one static DNS recordentry_id: stringdevice?: string
update_dns_static changes
Change a static DNS recordentry_id: stringname?: stringaddress?: stringcname?: stringmx_preference?: integermx_exchange?: stringtext?: stringsrv_priority?: integersrv_weight?: integersrv_port?: integersrv_target?: stringttl?: stringcomment?: stringdisabled?: booleanregexp?: stringdevice?: string
remove_dns_static deletes
Delete a static DNS recordentry_id: stringdevice?: string
enable_dns_static changes
Enable a static DNS recordentry_id: stringdevice?: string
disable_dns_static changes
Disable a static DNS recordentry_id: stringdevice?: string
get_dns_cache
Show cached DNS entriesdevice?: string
flush_dns_cache deletes
Empty the DNS cachedevice?: string
get_dns_cache_statistics
Show DNS cache size and usagedevice?: string
add_dns_regexp changes
Add a static DNS entry matched by regular expressionregexp: stringaddress: stringttl?: stringcomment?: stringdisabled?: booleandevice?: string
test_dns_query
Resolve a name through the routername: stringserver?: stringtype?: stringdevice?: string
export_dns_config changes
Write the DNS configuration to an export file on the routerfilename?: stringdevice?: string
create_backup changes
Save a binary backup file on the routername?: stringdont_encrypt?: booleaninclude_password?: booleancomment?: stringdevice?: string
list_backups
List backup and export files on the routername_filter?: stringinclude_exports?: booleandevice?: string
create_export changes
Write the configuration as a script file on the routername?: stringfile_format?: enumexport_type?: enumhide_sensitive?: booleanverbose?: booleancompact?: booleancomment?: stringdevice?: string
export_section
Return the exported configuration of one sectionsection: stringhide_sensitive?: booleancompact?: booleandevice?: string
download_file
Return a backup or export file's contents as base64filename: stringfile_type?: enumdevice?: string
upload_file changes
Put a base64-encoded file onto the routerfilename: stringcontent_base64: stringdevice?: string
restore_backup deletes
Load a backup file, replacing the running configurationfilename: stringpassword?: stringdevice?: string
import_configuration deletes
Run an exported script file on the routerfilename: stringrun_after_reset?: booleanverbose?: booleandevice?: string
remove_file deletes
Delete a file from the router's storagefilename: stringdevice?: string
backup_info
Show details of one backup filefilename: stringdevice?: string
create_wireguard_interface changes
Create a WireGuard interfacename: stringlisten_port?: integerprivate_key?: stringmtu?: integercomment?: stringdisabled?: booleandevice?: string
list_wireguard_interfaces
List WireGuard interfacesname_filter?: stringdisabled_only?: booleanrunning_only?: booleandevice?: string
get_wireguard_interface
Show one WireGuard interfacename: stringdevice?: string
update_wireguard_interface changes
Change a WireGuard interface's settingsname: stringnew_name?: stringlisten_port?: integerprivate_key?: stringmtu?: integercomment?: stringdisabled?: booleandevice?: string
remove_wireguard_interface deletes
Delete a WireGuard interfacename: stringdevice?: string
enable_wireguard_interface changes
Enable a WireGuard interfacename: stringdevice?: string
disable_wireguard_interface changes
Disable a WireGuard interfacename: stringdevice?: string
add_wireguard_peer changes
Add a peer to a WireGuard interfaceinterface: stringpublic_key: stringallowed_address: stringendpoint_address?: stringendpoint_port?: integerpreshared_key?: stringpersistent_keepalive?: stringcomment?: stringdisabled?: booleandevice?: string
list_wireguard_peers
List WireGuard peersinterface_filter?: stringdisabled_only?: booleandevice?: string
get_wireguard_peer
Show one WireGuard peerpeer_id: stringdevice?: string
update_wireguard_peer changes
Change a WireGuard peerpeer_id: stringallowed_address?: stringendpoint_address?: stringendpoint_port?: integerpreshared_key?: stringpersistent_keepalive?: stringcomment?: stringdisabled?: booleandevice?: string
remove_wireguard_peer deletes
Delete a WireGuard peerpeer_id: stringdevice?: string
enable_wireguard_peer changes
Enable a WireGuard peerpeer_id: stringdevice?: string
disable_wireguard_peer changes
Disable a WireGuard peerpeer_id: stringdevice?: string
generate_wireguard_client_config
Build a client config file for a WireGuard peerclient_private_key: stringclient_address: stringserver_public_key: stringserver_endpoint: stringserver_port?: integerallowed_ips?: stringdns?: stringpersistent_keepalive?: integerdevice?: string
get_system_resource
Show uptime, RouterOS version, board, CPU and memorydevice?: string
list_ip_services
List management services with their ports and allowed addressesname_filter?: stringenabled_only?: booleandevice?: string
list_arp_entries
List IPv4 ARP entriesaddress_filter?: stringmac_filter?: stringinterface_filter?: stringstatus_filter?: stringdevice?: string
list_netwatch
List netwatch probes and their current statushost_filter?: stringcomment_filter?: stringstatus_filter?: stringtype_filter?: stringinclude_source?: booleandevice?: string
list_schedulers
List scheduled tasks with interval and next runname_filter?: stringinclude_source?: booleandevice?: string
list_ipsec_peers
List configured IPsec peersname_filter?: stringaddress_filter?: stringdevice?: string

Similar servers