mikrotik-mcp
mcp-name: io.github.StefanKnol/mikrotik-mcp
An MCP server for MikroTik RouterOS, over the binary API rather than by driving the CLI over SSH.
That distinction is the whole point. The CLI prints positional numbers, which
are not a rule's identity. A server that lists rules by position and then writes
by position either fails outright — where .id=3 matches nothing, so every
write reports "not found" for rules that plainly exist — or, worse, succeeds
against a different rule once the order has shifted. On a firewall that means
deleting the wrong rule.
The binary API returns the real .id (*7, *1f) on every read. So:
- every read returns
id, and every write takes one back; - list results also carry
position, which is display-only and refused for writes, with an error that explains why; - writes read back what they wrote, so a change can be verified rather than assumed;
remove_firewall_ruletakes an optionalconfirm_commentand returns the rule it deleted.
Use it
uvx mikrotik-mcp
Configure through the environment — ps would show a password passed as a flag:
| Variable | Default | Meaning |
|---|---|---|
MIKROTIK_HOST |
— | Router address. Required. |
MIKROTIK_USERNAME |
— | Required. |
MIKROTIK_PASSWORD |
— | |
MIKROTIK_PORT |
8729 |
8729 for api-ssl, 8728 for plaintext. |
MIKROTIK_TLS |
true |
|
MIKROTIK_TLS_FINGERPRINT |
— | SHA-256 of the router certificate, to pin it. |
MIKROTIK_TIMEOUT |
10 |
In an MCP client's config:
{
"mcpServers": {
"mikrotik": {
"command": "uvx",
"args": ["mikrotik-mcp"],
"env": {
"MIKROTIK_HOST": "192.168.88.1",
"MIKROTIK_USERNAME": "mcp-agent",
"MIKROTIK_PASSWORD": "..."
}
}
}
}
On the router
/ip service enable api-ssl
/user group add name=mcp policy=api,read,write,test
/user add name=mcp-agent group=mcp password=<strong-password>
The api policy is not optional, and its absence produces a login error
identical to a wrong password — so if credentials look right and login still
fails, check the group first.
Set MIKROTIK_TLS_FINGERPRINT if you can. MikroTik's API-SSL certificate is
self-signed, so ordinary CA validation cannot succeed against a stock device;
pinning is what makes the connection authenticated rather than merely encrypted.
Tools
24 of them, covering system info, interfaces, IP addressing, firewall filter
and NAT, DHCP leases, static DNS, routes and logs — plus ros_list, which
reads any RouterOS path and so covers everything without a dedicated tool.
There is deliberately no generic write escape hatch.
With mcphub
Two ways, and the first is the better default:
Launched as a subprocess by mcphub,
configured as a command — uvx mikrotik-mcp — with credentials as encrypted
environment variables. It runs in its own process and cannot read credentials
held for other backends.
Loaded in-process via the mcphub.plugins entry point this package also
ships, which gives typed host/username/password fields in mcphub's settings UI.
Nicer to configure, but an in-process plugin can read everything the hub holds.
Install it into the hub's environment to use this route.
Publishing to the MCP registry
server.json is the manifest for the official MCP registry,
validated against the published schema. It declares the uvx mikrotik-mcp
command and every MIKROTIK_* variable, marking which are required and which
are secret — so a client that browses the registry can generate a correct
settings form without knowing anything about this server.
Publishing has an order to it, because the registry verifies that whoever publishes an entry actually owns the package it points at.
1. The package must already be on PyPI. The registry fetches
pypi.org/pypi/mikrotik-mcp/<version>/json and refuses an entry whose package
does not exist. Tag a release and let CI publish it:
git tag v0.1.0 && git push --tags
(That needs a PyPI Trusted Publisher configured for this project first —
PyPI → your project → Publishing → add a GitHub publisher for
StefanKnol/mikrotik-mcp, workflow ci.yml, environment pypi.)
2. The README must carry the ownership token. The registry looks for
mcp-name: io.github.StefanKnol/mikrotik-mcp in the PyPI description, which is
this file — it is at the top, on its own line. That is what proves the person
publishing the registry entry controls the PyPI package.
3. Then publish the entry.
curl -sL https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz | tar xz mcp-publisher
./mcp-publisher login github
./mcp-publisher publish
login github opens a device flow and proves you are StefanKnol, which is
what authorises the io.github.StefanKnol/* namespace. In CI, login github-oidc does the same from a workflow with id-token: write.
Bump version in server.json and pyproject.toml together; the registry
treats each version as its own row.
Development
uv sync --extra dev
uv run pytest
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mikrotik_mcp-0.1.0.tar.gz.
File metadata
- Download URL: mikrotik_mcp-0.1.0.tar.gz
- Upload date:
- Size: 83.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d4add197f648bb959d7b88c2652af8927edff9b6e1bd2d8151a7656cf3462d80
|
|
| MD5 |
9aaf655c70367b1ad0f62536a775288d
|
|
| BLAKE2b-256 |
9d0a3ea42123377e2c31123509e82f29ae886b40d8263b39325c28e0044c88cc
|
Provenance
The following attestation bundles were made for mikrotik_mcp-0.1.0.tar.gz:
Publisher:
ci.yml on StefanKnol/mikrotik-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mikrotik_mcp-0.1.0.tar.gz -
Subject digest:
d4add197f648bb959d7b88c2652af8927edff9b6e1bd2d8151a7656cf3462d80 - Sigstore transparency entry: 2850516205
- Sigstore integration time:
-
Permalink:
StefanKnol/mikrotik-mcp@7a4388cac715e3dfbd1674bda6b81ce2ad70f48a -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/StefanKnol
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@7a4388cac715e3dfbd1674bda6b81ce2ad70f48a -
Trigger Event:
push
-
Statement type:
File details
Details for the file mikrotik_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mikrotik_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36b28b78973cf9e25479e114262405f9f827f480b79f18b1e5e6e11cabaac954
|
|
| MD5 |
043600748a0f3eb8beb77a53adc7e569
|
|
| BLAKE2b-256 |
853c50e098a87eb6ca08fc437feb54cd6ac0056cfb2a652dcbc3c949014c9c4f
|
Provenance
The following attestation bundles were made for mikrotik_mcp-0.1.0-py3-none-any.whl:
Publisher:
ci.yml on StefanKnol/mikrotik-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mikrotik_mcp-0.1.0-py3-none-any.whl -
Subject digest:
36b28b78973cf9e25479e114262405f9f827f480b79f18b1e5e6e11cabaac954 - Sigstore transparency entry: 2850516233
- Sigstore integration time:
-
Permalink:
StefanKnol/mikrotik-mcp@7a4388cac715e3dfbd1674bda6b81ce2ad70f48a -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/StefanKnol
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@7a4388cac715e3dfbd1674bda6b81ce2ad70f48a -
Trigger Event:
push
-
Statement type: