OPERATIONS GUIDE

v6.11.0

Configuration

Practical setup, operations and limits for Configuration.

Use a JSON config for the complete settings surface. Common settings also have environment variables and CLI flags. See the complete schema and CLI reference.

Resolution order

Settings are resolved with the following precedence (later wins):

built-in defaults → config-file settings → explicit environment variables → command-line flags

So a --host flag overrides MIKROTIK_HOST, which overrides the 127.0.0.1 default.

Connection settings

These control the SSH connection to the RouterOS device. On their own they define a single device named default.

SettingCLI flagEnvironment variableDefault
Host / IP--hostMIKROTIK_HOST127.0.0.1
SSH username--usernameMIKROTIK_USERNAMEadmin
SSH password--passwordMIKROTIK_PASSWORD(empty)
SSH port--portMIKROTIK_PORT22
Private key file path--key-filenameMIKROTIK_KEY_FILENAME(unset)
Inline private key (PEM)--private-keyMIKROTIK_PRIVATE_KEY(unset)
Private key passphrase--key-passphraseMIKROTIK_KEY_PASSPHRASE(unset)
SSH connect timeout (ms)--timeout-msMIKROTIK_TIMEOUT_MS10000

REST API (RouterOS 7.9+)

Opt a device into the RouterOS REST API. Commands that map cleanly run over HTTPS and come back as structured JSON with real status codes; everything REST cannot express — /export, Safe Mode, the interactive /tool commands, [find] selectors — are routed through SSH before execution. Failed or ambiguous writes are not blindly retried over another transport. Requires the www-ssl service enabled on the router.

SettingCLI flagEnvironment variableDefault
Use the REST API--apiMIKROTIK_APIfalse
REST HTTPS port--api-portMIKROTIK_API_PORT443
Accept self-signed TLS--api-insecure-tlsMIKROTIK_API_INSECURE_TLSfalse

Configure a trusted certificate for www-ssl. --api-insecure-tls disables certificate verification and is an explicit troubleshooting opt-in; it is not required for a correctly trusted certificate.

Two behaviours worth knowing before enabling it:

  • List output changes shape. REST replies render in the print detail form (0 key=value …) rather than the columnar print layout, because column selection is per-menu console knowledge that cannot be reconstructed from JSON.
  • A device reached by mac ignores api. MAC-Telnet has no routable IP for HTTPS to reach, so the two together can only mean MAC-Telnet.

SSH jump host (bastion / ProxyJump)

Reach a router with no exposed SSH port by tunnelling through another over SSH — only the bastion is reachable, no new port is opened on the target. For a single device, point it at an inline bastion:

SettingCLI flagEnvironment variableDefault
Jump host / IP--jump-hostMIKROTIK_JUMP_HOST(unset)
Jump SSH port--jump-portMIKROTIK_JUMP_PORT22
Jump username--jump-usernameMIKROTIK_JUMP_USERNAMEadmin
Jump password--jump-passwordMIKROTIK_JUMP_PASSWORD(unset)
Jump key file path--jump-key-filenameMIKROTIK_JUMP_KEY_FILENAME(unset)
Jump key passphrase--jump-key-passphraseMIKROTIK_JUMP_KEY_PASSPHRASE(unset)

In a multi-device config, prefer a device's jumpVia: "<device-name>" to reuse an existing entry as the bastion (chains and the RouterOS forwarding-enabled prerequisite are covered in Multiple devices → SSH jump hosts).

Multiple devices

To manage more than one router from a single server (e.g. to build a tunnel between two), define a named devices map. The AI then targets a device per call via an injected device argument.

SettingCLI flagEnvironment variable
Named-devices JSON file--configMIKROTIK_CONFIG_FILE
Named-devices inline JSON--devicesMIKROTIK_DEVICES

Full guide, file format, and the per-device Safe Mode behaviour: Multiple devices.

Transport settings

These control how MCP clients reach the server. See Transports for the full behavior.

SettingCLI flagEnvironment variableDefault
Transport--transportMIKROTIK_MCP__TRANSPORT (alias MCP_TRANSPORT)stdio
HTTP bind host--mcp-hostMIKROTIK_MCP__HOST0.0.0.0
HTTP bind port--mcp-portMIKROTIK_MCP__PORT8000
Allowed Host headers--mcp-allowed-hostsMIKROTIK_MCP__ALLOWED_HOSTS(empty)
Allowed Origin headers--mcp-allowed-originsMIKROTIK_MCP__ALLOWED_ORIGINS(empty)
CORS allow-list for /mcp--mcp-cors-originsMIKROTIK_MCP__CORS_ORIGINS(MCP-host defaults)
Read-only mode--read-onlyMIKROTIK_READ_ONLYfalse
App Views--app-viewsMIKROTIK_MCP__APP_VIEWSfalse
Capability gating--capability-gatingMIKROTIK_MCP__CAPABILITY_GATINGannotate

Transport values are stdio, streamable-http, or sse. The HTTP bind host, port, and allow-lists only apply to the HTTP transports; they're ignored for stdio.

Capability gating is off, annotate (default) or filter — how to treat tools the target device cannot run. filter is honoured only in single-device mode. See docs/capabilities.md.

--mcp-cors-origins controls CORS on the /mcp endpoint, needed by the ChatGPT Apps connector. Empty allows the built-in MCP-host origins (ChatGPT, Claude); pass a comma-separated list to add your own, or * for any.

Read-only mode registers only readOnlyHint tools — inspection only, every write/destructive tool is withheld. Turn it on whenever the server is exposed publicly (e.g. a ChatGPT Apps connector) before authentication is in place. See Deploying to ChatGPT Apps.

App Views controls whether read tools (list_*/get_*/show_*/print_*) emit MCP App view metadata (_meta.ui). When enabled, these tools render interactive table/detail widgets in supporting MCP hosts — but they also add (renders an MCP App view) to every tool description, which can bloat the LLM context. Disabled by default for a lean tool surface. Enable via the config file (mcp.appViews: true), environment, CLI flag, or the dashboard's Modules view.

The __ (double underscore) in the env var names is the nested-key delimiter.

Tool surface (curation)

The server exposes several hundred tools across ~110 modules. MCP clients discover tools by relevance search and only feed a capped candidate set to the model, so on a surface this large a query can crowd out simple read tools (e.g. list_wireguard_* losing to build_wireguard_mesh). If the model claims a tool "doesn't exist" or can't be found, that's almost always retrieval bloat, not a missing tool. Narrowing the surface to the scopes a deployment actually uses makes every matching tool surface reliably.

Filter by module slug or group (see the module list in Tools reference):

SettingCLI flagEnvironment variableDefault
Enable modules--tools-enabled-modulesMIKROTIK_TOOLS__ENABLED_MODULES(all)
Disable modules--tools-disabled-modulesMIKROTIK_TOOLS__DISABLED_MODULES(none)
Enable groups--tools-enabled-groupsMIKROTIK_TOOLS__ENABLED_GROUPS(all)
Disable groups--tools-disabled-groupsMIKROTIK_TOOLS__DISABLED_GROUPS(none)

Env/flag values are comma-separated lists; a JSON config file's tools block (arrays) overrides them. Matching is case-insensitive. Semantics: when any allow-list (enabledModules/enabledGroups) is non-empty, only matching modules register and everything else drops. The deny-lists are then subtracted and win over the allow-lists. Empty everywhere = the full surface (the default — zero behaviour change).

Groups are: Interfaces, Switch, Addressing & Routing, Dynamic Routing, IPv6, Security, QoS, VPN & Tunneling, AAA, Tools, System & Ops, MCP Apps.

# Only expose addressing/routing + VPN scopes (smallest surface)
mikrotik-mcp serve --tools-enabled-groups "Addressing & Routing,VPN & Tunneling"

# Full surface minus the noisy diagnostic tools
MIKROTIK_TOOLS__DISABLED_GROUPS="Tools" mikrotik-mcp serve

Or in a JSON config file:

{
  "tools": {
    "enabledGroups": ["VPN & Tunneling", "Security"],
    "disabledModules": ["wireguard-mesh"]
  }
}

Read-only mode and tool curation compose: curation picks the modules, then read-only drops every write/destructive tool from what remains.

Logging

SettingEnvironment variableDefaultValues
Log verbosityMIKROTIK_LOG_LEVELinfodebug, info, warn, error

All log output is written to stderr (never stdout, which carries the JSON-RPC protocol stream on the stdio transport). Each line is prefixed with [mikrotik-mcp] and the level; color is added automatically when stderr is a TTY. Set MIKROTIK_LOG_LEVEL=debug to see every command the server issues.

Authentication: key file vs. password

The SSH client accepts a private key, a password, or both. Resolution:

  1. Inline private key (MIKROTIK_PRIVATE_KEY / --private-key) — a PEM string. Takes precedence over a key file.
  2. Key file (MIKROTIK_KEY_FILENAME / --key-filename) — a path read from disk at connect time. If the file can't be read, the connection fails with a logged error.
  3. Key passphrase (MIKROTIK_KEY_PASSPHRASE / --key-passphrase) — supply this when the private key (file or inline) is encrypted. It is ignored when no key is configured.
  4. Password (MIKROTIK_PASSWORD / --password) — added to the SSH config when present. The key is tried first; a password can be supplied as a fallback.

auth-check prints which mode it used (Auth mode: SSH key or password) so you can confirm at a glance.

Recommendation: prefer key-based auth, especially in containers, where a plaintext password in the environment is visible via docker inspect. The server emits a security warning when it detects a plaintext password while running inside a container. See Security.

S3 backup storage (optional)

The S3 backup tools ship device backups and config exports to any S3-compatible bucket (AWS S3, Cloudflare R2, MinIO, DigitalOcean Spaces, …) using Bun's native S3 client. The feature is opt-in: with no S3 settings the tools simply report that storage is disabled and do nothing.

Credentials follow Bun's native lookup order — S3_* first, then AWS_* as a fallback — and can be overridden by flags or a JSON config s3 block.

SettingCLI flagEnvironment variableDefault
Access key ID--s3-access-key-idS3_ACCESS_KEY_ID / AWS_ACCESS_KEY_ID(unset)
Secret access key--s3-secret-access-keyS3_SECRET_ACCESS_KEY / AWS_SECRET_ACCESS_KEY(unset)
Session token--s3-session-tokenS3_SESSION_TOKEN / AWS_SESSION_TOKEN(unset)
Region--s3-regionS3_REGION / AWS_REGION(unset)
Endpoint (R2/MinIO/…)--s3-endpointS3_ENDPOINT / AWS_ENDPOINT(AWS S3)
Bucket--s3-bucketS3_BUCKET / AWS_BUCKET(unset)
Key prefix--s3-prefixMIKROTIK_S3_PREFIX(empty)
Presigned-URL TTL (s)--s3-presign-expires-inMIKROTIK_S3_PRESIGN_EXPIRES_IN3600

S3 is considered configured once a bucket, endpoint, or access key is present.

Per-device layout

Backups are organised per device so each router's files live under their own "folder": object keys default to <prefix>/<device>/<filename> (e.g. mikrotik/site-a/daily.backup). list_s3_backups defaults to the current device's prefix; pass an explicit prefix (including "" for the whole bucket) to look elsewhere.

How transfers work

Uploads and downloads are performed by the device itself via /tool fetch against a short-lived presigned URL generated by the Bun S3 client, so large or binary backups stream straight between the router and S3 without passing through the MCP server. Object listing, stat and deletion are done server-side with the native Bun S3 client.

JSON config block

When using a config file (--config / MIKROTIK_CONFIG_FILE), add an s3 block alongside devices:

{
  "defaultDevice": "site-a",
  "devices": { "site-a": { "host": "203.0.113.10", "keyFilename": "/keys/a" } },
  "s3": {
    "bucket": "my-mikrotik-backups",
    "region": "us-east-1",
    "prefix": "mikrotik/",
    "endpoint": "https://<account-id>.r2.cloudflarestorage.com"
  }
}

Example

A fully explicit invocation over the streamable-HTTP transport, bound to localhost with key auth:

mikrotik-mcp serve \
  --host 192.168.88.1 \
  --username automation \
  --key-filename ~/.ssh/mikrotik_ed25519 \
  --transport streamable-http \
  --mcp-host 127.0.0.1 \
  --mcp-port 8000

The same thing via environment variables:

export MIKROTIK_HOST=192.168.88.1
export MIKROTIK_USERNAME=automation
export MIKROTIK_KEY_FILENAME=~/.ssh/mikrotik_ed25519
export MIKROTIK_MCP__TRANSPORT=streamable-http
export MIKROTIK_MCP__HOST=127.0.0.1
export MIKROTIK_MCP__PORT=8000
mikrotik-mcp serve

On this page