# MKTXP turns RouterOS administration into three commands: diag, rsc and export

> A Python command line toolkit for MikroTik RouterOS that bundles terminal diagnostics, deterministic.rsc configuration management and a Prometheus exporter. The three modes are useful on their own, though the two router-facing ones share one config layout and connection model, which is both the design strength and the cost of adoption.

**akpw/mktxp** — CLI Diagnostic, Prometheus Exporter, and GitOps Configuration for Mikrotik RouterOS devices

- Repository: https://github.com/akpw/mktxp
- Stars: 1,100 · Forks: 156
- Language: Python
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/akpw-mktxp

## One package for three jobs that usually live in three tools

MKTXP is an extensible toolkit for MikroTik RouterOS network engineering, and its scope is set by three separate entry points that share a single install. `mktxp diag` runs interactive terminal diagnostics against a live router. `mktxp rsc` performs GitOps style configuration work on local `.rsc` files. `mktxp export` starts a daemon that scrapes routers and serves Prometheus metrics.

That grouping is unusual and worth stating plainly, because most monitoring exporters scrape and stop there. Adding a config formatter and a set of diagnostic queries means an operator can go from a suspicious wireless client to the exported router configuration using one binary and one set of credentials, without switching to a different tool for each task.

The tool is written in Python and targets system administrators, network engineers and IT staff rather than developers building applications on top of RouterOS. The `pyproject.toml` classifies it as a console environment utility with a Beta development status, requires Python 3.9 or newer, and lists Linux, macOS and FreeBSD as supported platforms. A 2.0 series release followed by a 2.1.0 in October 2026 suggests the API surface has been reshaped recently, so anyone upgrading from a 1.x installation should read the changelog rather than assume command compatibility.

## Configuration is split across mktxp.conf and _mktxp.conf

Two files hold every setting, and the split is by audience. `mktxp.conf` holds router connection profiles, credentials, custom labels and metrics switches, and it is edited with `mktxp edit`. `_mktxp.conf` holds daemon listen sockets, timeouts, parallel scraping, GitOps rules and CLI diagnostic thresholds, edited with `mktxp edit -i`.

Files are resolved without configuration, from `~/.config/mktxp/` on a user install or `/etc/mktxp/` for system and Docker installs, and any command can be pointed elsewhere with `--cfg-dir <path>`. The active locations can be checked at any time with `mktxp show -cfg`, which is the command to reach for when the tool appears to be ignoring your edits.

A minimal router entry is a section header with the hostname and credentials. The `ini` block below is the whole required surface for a first connection.

```ini
[My-Router]
    hostname = 192.168.88.1
    username = mktxp_user
    password = secret_password
```

The `[default]` section inheritance, custom labels and parallel fetching are covered in the project's configuration guide, and none of them are needed to get a first metric on a dashboard. That is a reasonable default for a tool whose audience includes on-call engineers.

## The router user group has to allow api and read

Diagnostics and the exporter both speak to the router over the standard RouterOS API, which means the account you configure has to be able to use that API. The README documents a dedicated monitoring user created with a group policy of `api,read`, and a user added to it.

```routeros
/user group add name=mktxp_group policy=api,read
/user add name=mktxp_user group=mktxp_group password=secret_password
```

The read-only design is the point. A group with `api,read` can query configuration and counters without gaining write access to the router, so a monitoring system that is compromised cannot reconfigure your firewall. There is one documented exception: on RouterOS v6, collecting LTE metrics requires the `test` permission policy as well.

Two operational details follow from the file layout. Credentials live in `mktxp.conf` in plaintext, so the config directory needs the same protection as a password file, and the documented Docker pattern is to mount your config directory into the container with the option `-v "$(pwd)/mktxp-config:/etc/mktxp"`.

```bash
docker pull ghcr.io/akpw/mktxp:latest
```

The `XDG_CONFIG_HOME=/etc` environment variable in the image is what makes the container look in `/etc/mktxp` for the same two files.

## Diagnostic one-liners are filter flags, not subcommands

The diagnostics interface is a set of short commands where the domain selects the data set and the flags narrow it. `-en` covers wireless clients, `-kc` covers bandwidth, `-dc` covers DHCP, `-al` covers address lists, and `-im` covers interfaces. The filters stack onto the domain.

```bash
mktxp diag -en My-Router -cc --low-signal --low-rate 1M
mktxp diag -en My-Router -kc --top 5
mktxp diag -en My-Router -dc --unidentified
mktxp diag -en My-Router -al blacklist --dynamic-only
mktxp diag -en My-Router -im --degraded
```

Read in order, those lines ask for wireless clients that have a low signal or a low rate, the top five bandwidth consumers, DHCP clients with no hostname, dynamic firewall bans, and interfaces that have negotiated down below 100 Mbps or are half duplex. Each one is a question a network engineer asks often enough to be worth a single keystroke rather than a RouterOS path typed by hand.

Output is a text table with a footer line reporting matching CAPsMAN clients against total connected clients, and the documented sample shows signal values as negative numbers, rates in Mbps and an uptime column. Appending `-h` to a command scopes the help output to that command's filters only, which keeps a long flag list from getting in the way.

The drawback is that the flags are terse enough to be misremembered, and the memory cost of an operator's first hour is real. The command scoped help exists precisely because of that.

## RSC formatting and splitting make exports diffable

The `mktxp rsc` mode is the part with the least hardware dependency and the clearest long term value. It works on local `.rsc` files with no router and no configuration file, which makes it safe to try and easy to put in CI.

```bash
mktxp rsc format -i backup.rsc -o clean_backup.rsc
mktxp rsc split -i backup.rsc -o ./config-repo/ --extract-scripts
```

The first command normalises an export so that commands are on single lines and headers are standardised, which is what turns a RouterOS export into something a Git diff can read. The second breaks a monolithic export into numbered component files and pulls scripts out separately, giving you a directory layout instead of one enormous file.

The project describes this as deterministic formatting, and the AST architecture, custom domain handlers, live backups over SSH and CI/CD automation are pointed at in a separate GitOps RSC guide. The distinction matters for a reviewer: `format` and `split` operate on a local file, so they can be validated on a copy before anyone connects to a production router.

What the documentation does not spell out is how the formatter decides which commands belong to which domain file during a split, or what it does with commands it cannot classify. Anyone planning to make a split the source of truth for a production router should test the round trip on a real export first, which is also the check to run before trusting it in version control.

## The exporter serves plaintext metrics on port 49090

The Prometheus mode starts a daemon that scrapes the routers listed in the config and serves the results.

```bash
mktxp export
# Serving Prometheus metrics at http://localhost:49090/metrics
```

Prometheus reaches it through a normal scrape job, and the port is the one the Docker image exposes.

```yaml
scrape_configs:
  - job_name: 'mktxp'
    static_configs:
      - targets: ['localhost:49090']
```

A Grafana dashboard is published under ID 13679 and covers traffic and interface data, wireless clients and device health, so a first deployment starts with imported panels rather than hand built queries.

Two details are worth reading carefully. The endpoint is plain HTTP with no authentication described in the documentation, so the metric port belongs on a management network or behind whatever your Prometheus already uses for that. The other is the `speedtest-cli` dependency in `pyproject.toml`, which suggests the exporter can pull bandwidth measurements, a step that consumes router resources in a way that a plain counter scrape does not.

For a full monitoring environment rather than a single binary, the project points to a separate MKTXP Stack repository that packages this exporter with Prometheus, Grafana, Loki and Promtail for centralized MikroTik syslog processing. That is the deployment route to choose when you want syslog correlation instead of a lone metrics endpoint.

## Two files, one credential store, and no documented rollback

The design has consequences that the marketing summary does not spell out, and they are worth weighing before you depend on it.

Because diagnostics and the exporter both read the same `mktxp.conf`, a typo in that file breaks both at once, while `mktxp rsc` on local files needs no configuration at all. A wrong filter is harmless; a wrong hostname or password in the shared profile is a shared failure. The counter is that one credential set is also the reason the tool is small enough to learn in an afternoon.

There is also no documented rollback for the daemon. The README does not describe how to undo a configuration change made through the tool, and the GitOps guide is where live backups and CI/CD automation are described, so if your rollback plan depends on a previous known good export, the `mktxp rsc format` and `mktxp rsc split` commands are the tools that produce the artifact you would restore from.

A narrower limitation: the diagnostics tables and thresholds are shaped around RouterOS data, and the LTE permission note shows the project is tested against both RouterOS v6 and later versions. A router in an older or unusual configuration may expose fields the queries do not expect, and the documentation does not promise graceful handling of missing properties.

## GPLv2 in pyproject, a licence GitHub could not classify

The project metadata reports a custom licence that GitHub could not classify, pointing at the LICENSE file for the authoritative text. The `pyproject.toml` in the repository declares the licence as the GNU General Public License v2, with a classifier for GPLv2 or later, and the container image label reads `org.opencontainers.image.licenses=GPLv2+`.

For most teams this distinction is a formality rather than a blocker. The practical consequence of a GPL family licence is that distributing a modified version of the code, including inside a container image, means offering the corresponding source. Using the tool unmodified on your own infrastructure raises no such question, and embedding its modules inside a closed source product is the case that would need a lawyer rather than a README.

The base image is `python:3-alpine` with a non root user created at UID 1000, a config directory prepared at `/etc/mktxp` and owned by that user, and the container entrypoint running `mktxp export`. The comment in the Dockerfile explains that the user, the editor and the config directory are provisioned in a single layer to keep the image small, and the run explicitly avoids caching pip packages during install. The exposed port and the non root user are the two choices worth reviewing for a container that holds router credentials.

Release pace is the other upgrade consideration. The last push to the repository was on 2026-10-10, and the tags sit close together: v2.1.0 on 2026-10-08, v2.0.3 on 2026-09-08 and v1.2.20 on 2026-08-16. Three releases in under two months, including a major version bump, is fast for a tool that touches production network equipment, and the README documents no migration path or compatibility matrix for a 1.x to 2.x move. Treat a version bump as a change that needs a test router, a saved `mktxp.conf` and a copy of the current metrics output for comparison. The dependency floor is modest, Python 3.9 or newer, and the libraries in `pyproject.toml` including `RouterOS-api`, `prometheus-client`, `configobj`, `texttable`, `waitress` and `pyyaml` carry lower bound versions rather than exact pins, so an unattended install can pull newer releases over time. The test setup lives in `tests/` with a `tox.ini`, and the repository also carries a `deploy/` directory and GitHub workflows.

## Conclusion

Adopt MKTXP if you run more than one MikroTik router, want repeatable .rsc formatting in version control, and already have Prometheus in place. Do not adopt it as a replacement for the RouterOS terminal, since the tool depends on the RouterOS API and a dedicated api,read user, and the exporter exposes a plaintext metric port. Verify first that your router accepts the api,read group you create, that the 49090 endpoint is not exposed beyond your monitoring network, and that your existing .rsc exports survive a round trip through mktxp rsc format unchanged in meaning.

## FAQ

### How do I install MKTXP for MikroTik RouterOS?

The README recommends pipx install mktxp for local CLI usage, with pip install mktxp, brew install mktxp and the ghcr.io/akpw/mktxp:latest image as alternatives. Python 3.9 or newer is required.

### What permissions does the MKTXP router user need?

Create a group with the api and read policies and add a user to it, so the account can query the router through the RouterOS API without write access. On RouterOS v6 the test policy is also needed for LTE metrics.

### Where does MKTXP keep its configuration?

Connection profiles and credentials live in mktxp.conf, and daemon and diagnostic settings live in _mktxp.conf. Files are read from ~/.config/mktxp/ or /etc/mktxp/, and mktxp show -cfg prints the active paths.

### How do I point Prometheus at the MKTXP exporter?

Start the daemon with mktxp export, which serves metrics at http://localhost:49090/metrics, then add a scrape job whose target is localhost:49090 in prometheus.yml. A ready made Grafana dashboard is published under ID 13679.

### Can MKTXP format and split RouterOS configuration without a router?

Yes. The rsc mode works on local .rsc files with no router setup and no configuration file, so mktxp rsc format and mktxp rsc split can run before anything is connected to the network.

## Sources

- [akpw/mktxp on GitHub](https://github.com/akpw/mktxp)
- [Issues](https://github.com/akpw/mktxp/issues)
- [README](https://github.com/akpw/mktxp/blob/main/README.md)
- [Releases](https://github.com/akpw/mktxp/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/akpw-mktxp
