mikromcp 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -132
- package/dist/main.js +43 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
[](https://github.com/AliKarami/MikroMCP/actions/workflows/ci.yml)
|
|
14
14
|
[](https://github.com/AliKarami/MikroMCP/actions/workflows/release.yml)
|
|
15
|
-
[](package.json)
|
|
16
16
|
[](LICENSE)
|
|
17
17
|
[](package.json)
|
|
18
18
|
[](https://help.mikrotik.com/docs/display/ROS/REST+API)
|
|
@@ -37,8 +37,6 @@ MikroMCP exists because raw router CLI access is the wrong abstraction for AI ag
|
|
|
37
37
|
| Raw network access for every assistant | RBAC identities, bearer tokens for HTTP mode, tool allowlists, and audit trails |
|
|
38
38
|
| Fragile troubleshooting workflows | Router-originated ping, traceroute, torch, logs, interfaces, DHCP, firewall, routes, WiFi, WireGuard, and more |
|
|
39
39
|
|
|
40
|
-
MikroMCP is especially useful when you want AI agents to help with network operations without giving them unchecked terminal access.
|
|
41
|
-
|
|
42
40
|
---
|
|
43
41
|
|
|
44
42
|
## Feature Showcase
|
|
@@ -56,8 +54,6 @@ MikroMCP is especially useful when you want AI agents to help with network opera
|
|
|
56
54
|
| 🤖 **AI-agent fit** | Human-readable responses plus structured JSON content for reasoning, chaining, and automation |
|
|
57
55
|
| 🧩 **MCP compatibility** | stdio for desktop clients, Streamable HTTP and legacy SSE for remote or service-style clients |
|
|
58
56
|
|
|
59
|
-
**Best-in-class strengths:** MikroMCP is not just a thin REST wrapper. It models operational safety around RouterOS: typed tool contracts, safe write patterns, router-aware credentials, destructive-action gates, and rollback-oriented workflows.
|
|
60
|
-
|
|
61
57
|
---
|
|
62
58
|
|
|
63
59
|
## Demo
|
|
@@ -78,10 +74,9 @@ MikroMCP is especially useful when you want AI agents to help with network opera
|
|
|
78
74
|
|
|
79
75
|
### Prerequisites
|
|
80
76
|
|
|
81
|
-
- Node.js 22 or newer
|
|
77
|
+
- Node.js 22 or newer (for npm install) — or use a standalone binary below
|
|
82
78
|
- MikroTik RouterOS 7.x with the REST API enabled
|
|
83
|
-
- A RouterOS user with the policies
|
|
84
|
-
- Git and npm
|
|
79
|
+
- A RouterOS user with the policies your tools require
|
|
85
80
|
|
|
86
81
|
Recommended RouterOS policies for full tool coverage:
|
|
87
82
|
|
|
@@ -89,29 +84,65 @@ Recommended RouterOS policies for full tool coverage:
|
|
|
89
84
|
read, write, api, rest-api, test, ssh, sniff, ftp
|
|
90
85
|
```
|
|
91
86
|
|
|
92
|
-
|
|
87
|
+
> `ssh` is required for `ping`, `traceroute`, `torch`, and `run_command`. `sniff` is required by `torch`. `ftp` is required only for `upload_file`.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### Install
|
|
92
|
+
|
|
93
|
+
**npm (recommended)**
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install -g mikromcp
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Standalone binaries**
|
|
93
100
|
|
|
94
|
-
|
|
95
|
-
- `sniff` is required by `torch`.
|
|
96
|
-
- `ftp` is required only for `upload_file`.
|
|
101
|
+
Download the binary for your platform from the [latest GitHub release](https://github.com/AliKarami/MikroMCP/releases/latest) — no Node.js required.
|
|
97
102
|
|
|
98
|
-
|
|
103
|
+
**Docker**
|
|
99
104
|
|
|
100
105
|
```bash
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
docker pull ghcr.io/alikarami/mikromcp:latest
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
### Set Up With the Init Wizard
|
|
112
|
+
|
|
113
|
+
Run the interactive setup wizard:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
mikromcp init
|
|
107
117
|
```
|
|
108
118
|
|
|
109
|
-
|
|
119
|
+
The wizard will ask for your router details and write everything to `~/.mikromcp/`:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
~/.mikromcp/
|
|
123
|
+
├── routers.yaml # router registry
|
|
124
|
+
├── identities.yaml # RBAC identities (HTTP mode)
|
|
125
|
+
└── .env # credentials and runtime settings
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`~/.mikromcp/.env` is loaded automatically every time MikroMCP starts — no shell exports or Claude Desktop `env` blocks needed. Fill in the credentials it generates:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# ~/.mikromcp/.env (generated by mikromcp init)
|
|
132
|
+
ROUTER_CORE01_USER=
|
|
133
|
+
ROUTER_CORE01_PASS=
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
To edit your router registry directly:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
nano ~/.mikromcp/routers.yaml
|
|
140
|
+
```
|
|
110
141
|
|
|
111
142
|
```yaml
|
|
112
143
|
routers:
|
|
113
144
|
core-01:
|
|
114
|
-
host: "
|
|
145
|
+
host: "192.168.88.1"
|
|
115
146
|
port: 443
|
|
116
147
|
tls:
|
|
117
148
|
enabled: true
|
|
@@ -119,59 +150,34 @@ routers:
|
|
|
119
150
|
credentials:
|
|
120
151
|
source: "env"
|
|
121
152
|
envPrefix: "ROUTER_CORE01"
|
|
122
|
-
tags: ["core"
|
|
123
|
-
rosVersion: "7
|
|
153
|
+
tags: ["core"]
|
|
154
|
+
rosVersion: "7"
|
|
124
155
|
```
|
|
125
156
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
export ROUTER_CORE01_USER="mcp-api"
|
|
130
|
-
export ROUTER_CORE01_PASS="your-router-password"
|
|
131
|
-
npm start
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Docker
|
|
157
|
+
---
|
|
135
158
|
|
|
136
|
-
|
|
159
|
+
### Verify With Doctor
|
|
137
160
|
|
|
138
161
|
```bash
|
|
139
|
-
|
|
162
|
+
mikromcp doctor
|
|
140
163
|
```
|
|
141
164
|
|
|
142
|
-
|
|
165
|
+
Doctor checks Node version, config files, router reachability, Claude Desktop registration, and whether a newer version is available.
|
|
143
166
|
|
|
144
|
-
|
|
145
|
-
docker run --rm \
|
|
146
|
-
-e MIKROMCP_TRANSPORT=http \
|
|
147
|
-
-e MIKROMCP_PORT=3000 \
|
|
148
|
-
-e MIKROMCP_CONFIRMATION_SECRET="$(openssl rand -hex 32)" \
|
|
149
|
-
-e ROUTER_CORE01_USER=mcp-api \
|
|
150
|
-
-e ROUTER_CORE01_PASS=your-router-password \
|
|
151
|
-
-v "$(pwd)/config:/app/config:ro" \
|
|
152
|
-
-p 3000:3000 \
|
|
153
|
-
ghcr.io/alikarami/mikromcp:latest
|
|
154
|
-
```
|
|
167
|
+
---
|
|
155
168
|
|
|
156
|
-
|
|
169
|
+
### Run
|
|
157
170
|
|
|
158
|
-
|
|
171
|
+
**stdio (for Claude Desktop and other desktop MCP clients)**
|
|
159
172
|
|
|
160
173
|
```bash
|
|
161
|
-
|
|
162
|
-
cp config/routers.example.yaml config/routers.yaml
|
|
163
|
-
cp config/identities.example.yaml config/identities.yaml
|
|
164
|
-
# edit config/routers.yaml and set MIKROMCP_CONFIRMATION_SECRET + router credentials in .env
|
|
165
|
-
docker compose up -d
|
|
174
|
+
mikromcp serve
|
|
166
175
|
```
|
|
167
176
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
#### Build from source
|
|
177
|
+
**HTTP mode (for service deployments)**
|
|
171
178
|
|
|
172
179
|
```bash
|
|
173
|
-
|
|
174
|
-
docker run --rm -e MIKROMCP_TRANSPORT=http -p 3000:3000 mikromcp
|
|
180
|
+
MIKROMCP_TRANSPORT=http mikromcp serve
|
|
175
181
|
```
|
|
176
182
|
|
|
177
183
|
---
|
|
@@ -180,25 +186,22 @@ docker run --rm -e MIKROMCP_TRANSPORT=http -p 3000:3000 mikromcp
|
|
|
180
186
|
|
|
181
187
|
### Claude Desktop
|
|
182
188
|
|
|
183
|
-
|
|
189
|
+
Run `mikromcp init` and choose **Register with Claude Desktop** — it patches `claude_desktop_config.json` automatically.
|
|
190
|
+
|
|
191
|
+
Or add it manually to `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS:
|
|
184
192
|
|
|
185
193
|
```json
|
|
186
194
|
{
|
|
187
195
|
"mcpServers": {
|
|
188
|
-
"
|
|
189
|
-
"command": "
|
|
190
|
-
"args": ["
|
|
191
|
-
"env": {
|
|
192
|
-
"MIKROMCP_CONFIG_PATH": "/absolute/path/to/MikroMCP/config/routers.yaml",
|
|
193
|
-
"ROUTER_CORE01_USER": "mcp-api",
|
|
194
|
-
"ROUTER_CORE01_PASS": "your-router-password"
|
|
195
|
-
}
|
|
196
|
+
"mikromcp": {
|
|
197
|
+
"command": "mikromcp",
|
|
198
|
+
"args": ["serve"]
|
|
196
199
|
}
|
|
197
200
|
}
|
|
198
201
|
}
|
|
199
202
|
```
|
|
200
203
|
|
|
201
|
-
Restart Claude Desktop, then ask:
|
|
204
|
+
No `env` block needed — credentials are loaded from `~/.mikromcp/.env` at startup. Restart Claude Desktop, then ask:
|
|
202
205
|
|
|
203
206
|
```text
|
|
204
207
|
Use MikroMCP to show CPU, memory, uptime, active interfaces, and warning logs for core-01.
|
|
@@ -206,48 +209,72 @@ Use MikroMCP to show CPU, memory, uptime, active interfaces, and warning logs fo
|
|
|
206
209
|
|
|
207
210
|
### HTTP / SSE Mode
|
|
208
211
|
|
|
209
|
-
HTTP mode is useful for service deployments and MCP clients that connect over a
|
|
212
|
+
HTTP mode is useful for service deployments and MCP clients that connect over a network endpoint.
|
|
213
|
+
|
|
214
|
+
Set in `~/.mikromcp/.env`:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
MIKROMCP_TRANSPORT=http
|
|
218
|
+
MIKROMCP_PORT=3000
|
|
219
|
+
MIKROMCP_CONFIRMATION_SECRET=<openssl rand -hex 32>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Then run:
|
|
210
223
|
|
|
211
224
|
```bash
|
|
212
|
-
|
|
213
|
-
export MIKROMCP_PORT=3000
|
|
214
|
-
export MIKROMCP_BIND_HOST=127.0.0.1
|
|
215
|
-
export MIKROMCP_CONFIRMATION_SECRET="$(openssl rand -hex 32)"
|
|
216
|
-
export ROUTER_CORE01_USER="mcp-api"
|
|
217
|
-
export ROUTER_CORE01_PASS="your-router-password"
|
|
218
|
-
npm start
|
|
225
|
+
mikromcp serve
|
|
219
226
|
```
|
|
220
227
|
|
|
221
|
-
Every HTTP
|
|
228
|
+
Every HTTP request must include:
|
|
222
229
|
|
|
223
230
|
```text
|
|
224
231
|
Authorization: Bearer <token>
|
|
225
232
|
```
|
|
226
233
|
|
|
227
|
-
Tokens are configured as bcrypt hashes in
|
|
234
|
+
Tokens are configured as bcrypt hashes in `~/.mikromcp/identities.yaml`. Use `mikromcp init` to generate them.
|
|
235
|
+
|
|
236
|
+
### Docker
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
docker run --rm \
|
|
240
|
+
-e MIKROMCP_TRANSPORT=http \
|
|
241
|
+
-e MIKROMCP_PORT=3000 \
|
|
242
|
+
-e MIKROMCP_CONFIRMATION_SECRET="$(openssl rand -hex 32)" \
|
|
243
|
+
-e ROUTER_CORE01_USER=mcp-api \
|
|
244
|
+
-e ROUTER_CORE01_PASS=your-router-password \
|
|
245
|
+
-e MIKROMCP_CONFIG_PATH=/config/routers.yaml \
|
|
246
|
+
-v "$HOME/.mikromcp:/config:ro" \
|
|
247
|
+
-p 3000:3000 \
|
|
248
|
+
ghcr.io/alikarami/mikromcp:latest
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Pass `MIKROMCP_CONFIG_PATH` and `MIKROMCP_IDENTITIES_PATH` explicitly when running in Docker since `~/.mikromcp/` inside the container refers to the container's home directory.
|
|
228
252
|
|
|
229
253
|
---
|
|
230
254
|
|
|
231
255
|
## Configuration Reference
|
|
232
256
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
|
236
|
-
|
|
|
237
|
-
| `
|
|
238
|
-
| `
|
|
239
|
-
| `
|
|
240
|
-
| `
|
|
241
|
-
| `
|
|
242
|
-
| `
|
|
243
|
-
| `
|
|
244
|
-
| `
|
|
245
|
-
| `
|
|
246
|
-
| `
|
|
247
|
-
| `
|
|
248
|
-
| `
|
|
249
|
-
| `
|
|
250
|
-
| `
|
|
257
|
+
All settings can be placed in `~/.mikromcp/.env` or passed as environment variables. Values in `~/.mikromcp/.env` are loaded at startup; explicit environment variables always take precedence.
|
|
258
|
+
|
|
259
|
+
| Variable | Default | Purpose |
|
|
260
|
+
| --------------------------------- | -------------------------------- | ------------------------------------------------------ |
|
|
261
|
+
| `MIKROMCP_TRANSPORT` | `stdio` | `stdio` or `http` |
|
|
262
|
+
| `MIKROMCP_CONFIG_PATH` | `~/.mikromcp/routers.yaml` | Router registry path |
|
|
263
|
+
| `MIKROMCP_IDENTITIES_PATH` | `~/.mikromcp/identities.yaml` | Identity and bearer-token registry |
|
|
264
|
+
| `MIKROMCP_STDIO_IDENTITY` | built-in superadmin | Named identity for stdio mode |
|
|
265
|
+
| `MIKROMCP_PORT` | `3000` | HTTP transport port |
|
|
266
|
+
| `MIKROMCP_BIND_HOST` | `127.0.0.1` | HTTP bind address |
|
|
267
|
+
| `MIKROMCP_CONFIRMATION_SECRET` | unset | HMAC secret for destructive-action confirmation tokens |
|
|
268
|
+
| `MIKROMCP_AUDIT_LOG_PATH` | unset | Optional NDJSON audit log file path |
|
|
269
|
+
| `MIKROMCP_DATA_DIR` | `~/.mikromcp/data` | Snapshots and write-journal directory |
|
|
270
|
+
| `MIKROMCP_HTTP_MAX_BODY_BYTES` | `1048576` | HTTP request body cap |
|
|
271
|
+
| `MIKROMCP_HTTP_RATE_LIMIT_RPM` | `60` | Requests per minute per IP; `0` disables rate limiting |
|
|
272
|
+
| `MIKROMCP_SSH_COMMAND_TIMEOUT_MS` | `30000` | SSH command timeout |
|
|
273
|
+
| `MIKROMCP_SSH_MAX_OUTPUT_BYTES` | `524288` | SSH output cap |
|
|
274
|
+
| `MIKROMCP_CMD_ALLOW` | unset | Global allowlist patterns for `run_command` |
|
|
275
|
+
| `MIKROMCP_CMD_DENY` | unset | Global denylist patterns for `run_command` |
|
|
276
|
+
| `ROUTER_<PREFIX>_USER` | unset | Router username from `envPrefix` |
|
|
277
|
+
| `ROUTER_<PREFIX>_PASS` | unset | Router password from `envPrefix` |
|
|
251
278
|
|
|
252
279
|
---
|
|
253
280
|
|
|
@@ -353,14 +380,6 @@ to 1.1.1.1. If packet loss is present, use torch on the WAN interface for a
|
|
|
353
380
|
short traffic snapshot.
|
|
354
381
|
```
|
|
355
382
|
|
|
356
|
-
### Configuration Backup And Audit
|
|
357
|
-
|
|
358
|
-
```text
|
|
359
|
-
List files, scripts, scheduled jobs, firewall rules, DNS static records, and
|
|
360
|
-
routes on core-01. Produce an audit summary with change-risk notes and suggested
|
|
361
|
-
cleanup tasks.
|
|
362
|
-
```
|
|
363
|
-
|
|
364
383
|
### Plan / Apply / Rollback Workflow
|
|
365
384
|
|
|
366
385
|
```text
|
|
@@ -383,15 +402,13 @@ AI assistants can use MikroMCP to:
|
|
|
383
402
|
- Preview changes before mutation and explain exactly what would happen.
|
|
384
403
|
- Respect tool-level authorization, router scoping, maintenance windows, and confirmation gates.
|
|
385
404
|
|
|
386
|
-
This makes MikroMCP a practical bridge between MikroTik networks and the emerging AI infrastructure ecosystem: Claude MCP, LLM tooling, infrastructure automation, DevOps workflows, and network operations copilots.
|
|
387
|
-
|
|
388
405
|
---
|
|
389
406
|
|
|
390
407
|
## Documentation
|
|
391
408
|
|
|
392
409
|
| Resource | Use it for |
|
|
393
410
|
| ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
394
|
-
| [ROADMAP.md](ROADMAP.md) | Shipped milestones and planned
|
|
411
|
+
| [ROADMAP.md](ROADMAP.md) | Shipped milestones and planned work |
|
|
395
412
|
| [Architecture](https://github.com/AliKarami/MikroMCP/wiki/Architecture) | System layers and request pipeline |
|
|
396
413
|
| [Setup Guide](https://github.com/AliKarami/MikroMCP/wiki/Setup-Guide) | RouterOS REST setup and end-to-end onboarding |
|
|
397
414
|
| [Configuration](https://github.com/AliKarami/MikroMCP/wiki/Configuration) | Router registry, TLS, SSH, credentials, HTTP mode |
|
|
@@ -401,7 +418,6 @@ This makes MikroMCP a practical bridge between MikroTik networks and the emergin
|
|
|
401
418
|
| [Error Handling](https://github.com/AliKarami/MikroMCP/wiki/Error-Handling) | Typed errors, retry behavior, circuit breaker behavior |
|
|
402
419
|
| [Development](https://github.com/AliKarami/MikroMCP/wiki/Development) | Project structure, tests, MCP Inspector workflow |
|
|
403
420
|
| [Contributing](https://github.com/AliKarami/MikroMCP/wiki/Contributing) | Adding tools, coding conventions, PR checklist |
|
|
404
|
-
| [Roadmap](https://github.com/AliKarami/MikroMCP/wiki/Roadmap) | Wiki mirror of the milestone roadmap |
|
|
405
421
|
|
|
406
422
|
---
|
|
407
423
|
|
|
@@ -411,30 +427,23 @@ This makes MikroMCP a practical bridge between MikroTik networks and the emergin
|
|
|
411
427
|
npm run dev # tsx watch hot-reload
|
|
412
428
|
npm run build # build ESM output to dist/main.js
|
|
413
429
|
npm start # run built server
|
|
414
|
-
npm test #
|
|
415
|
-
npm run typecheck # TypeScript type checking
|
|
416
|
-
npm run lint # ESLint
|
|
430
|
+
npm test # vitest + tsc + eslint
|
|
417
431
|
npm run format # Prettier
|
|
418
432
|
```
|
|
419
433
|
|
|
420
|
-
Run this before committing:
|
|
421
|
-
|
|
422
|
-
```bash
|
|
423
|
-
npm test
|
|
424
|
-
npm run typecheck
|
|
425
|
-
```
|
|
426
|
-
|
|
427
434
|
Key project paths:
|
|
428
435
|
|
|
429
436
|
| Path | Purpose |
|
|
430
437
|
| -------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
431
|
-
| `src/main.ts` | Loads
|
|
438
|
+
| `src/main.ts` | Loads `~/.mikromcp/.env` and starts stdio or HTTP transport |
|
|
432
439
|
| `src/mcp/tool-registry.ts` | Registers tools and applies auth, retry, circuit breaker, audit, snapshots, and credentials |
|
|
433
440
|
| `src/domain/tools/` | Tool definitions and handlers |
|
|
434
441
|
| `src/domain/snapshot/` | Snapshot, diff, and write-journal support |
|
|
435
442
|
| `src/adapter/rest-client.ts` | RouterOS REST API client |
|
|
436
443
|
| `src/adapter/ssh-client.ts` | SSH execution adapter for diagnostics and guarded commands |
|
|
437
444
|
| `src/config/router-registry.ts` | Router inventory loader |
|
|
445
|
+
| `src/cli/init.ts` | Interactive setup wizard (`mikromcp init`) |
|
|
446
|
+
| `src/cli/doctor.ts` | Health check command (`mikromcp doctor`) |
|
|
438
447
|
| `config/routers.example.yaml` | Example multi-router registry |
|
|
439
448
|
| `config/identities.example.yaml` | Example RBAC identity registry |
|
|
440
449
|
|
|
@@ -448,7 +457,7 @@ Key project paths:
|
|
|
448
457
|
| v0.7 | ✅ Shipped | Identity, bearer auth, RBAC, audit log, confirmation gate |
|
|
449
458
|
| v0.8 | ✅ Shipped | Snapshots, write journal, plan/apply, rollback, maintenance windows |
|
|
450
459
|
| v0.9 | ✅ Shipped | Fleet operations, IPSec, certificates, users, DHCP servers/pools, queues/QoS, VRRP, SNMP/NTP, Netwatch, discovery, ARP, health checks |
|
|
451
|
-
| v1.0 |
|
|
460
|
+
| v1.0 | ✅ Shipped | npm package, standalone binaries, Docker images, `mikromcp init` wizard, `mikromcp doctor`, `~/.mikromcp/` convention |
|
|
452
461
|
|
|
453
462
|
See [ROADMAP.md](ROADMAP.md) for the complete milestone plan.
|
|
454
463
|
|
|
@@ -468,12 +477,9 @@ Good first contributions:
|
|
|
468
477
|
|
|
469
478
|
Development standards:
|
|
470
479
|
|
|
471
|
-
- TypeScript strict mode
|
|
472
|
-
-
|
|
473
|
-
-
|
|
474
|
-
- Idempotency and `dryRun` for write tools
|
|
475
|
-
- `MikroMCPError` for domain errors
|
|
476
|
-
- Focused Vitest coverage for every tool
|
|
480
|
+
- TypeScript strict mode, ESM imports with `.js` extensions
|
|
481
|
+
- Zod schemas with `.strict()`, idempotency and `dryRun` for write tools
|
|
482
|
+
- `MikroMCPError` for domain errors, focused Vitest coverage for every tool
|
|
477
483
|
|
|
478
484
|
Please open an issue before large changes so maintainers can align on scope.
|
|
479
485
|
|
|
@@ -481,18 +487,17 @@ Please open an issue before large changes so maintainers can align on scope.
|
|
|
481
487
|
|
|
482
488
|
## Security
|
|
483
489
|
|
|
484
|
-
MikroMCP
|
|
490
|
+
MikroMCP controls real network devices. Treat it like an operations system.
|
|
485
491
|
|
|
486
492
|
- Use least-privilege RouterOS users.
|
|
487
493
|
- Prefer TLS verification and certificate fingerprint pinning.
|
|
488
|
-
-
|
|
489
|
-
- Keep router credentials in environment variables or a secrets system, not YAML.
|
|
494
|
+
- Keep router credentials in `~/.mikromcp/.env`, not in YAML or shell history.
|
|
490
495
|
- Use HTTP mode behind a trusted network boundary.
|
|
491
496
|
- Configure identities with the smallest practical `allowedRouters` and `allowedToolPatterns`.
|
|
492
|
-
- Enable audit logging for shared or production use.
|
|
497
|
+
- Enable audit logging (`MIKROMCP_AUDIT_LOG_PATH`) for shared or production use.
|
|
493
498
|
- Test write tools with `dryRun: true` before applying changes.
|
|
494
499
|
|
|
495
|
-
For vulnerabilities or unsafe behavior, open a private security advisory
|
|
500
|
+
For vulnerabilities or unsafe behavior, open a private security advisory or contact the maintainer before publishing details.
|
|
496
501
|
|
|
497
502
|
---
|
|
498
503
|
|
|
@@ -501,7 +506,6 @@ For vulnerabilities or unsafe behavior, open a private security advisory if avai
|
|
|
501
506
|
- ⭐ Star the repository if MikroMCP helps your MikroTik or MCP workflow.
|
|
502
507
|
- 🍴 Fork it to add RouterOS surfaces your network depends on.
|
|
503
508
|
- 🧵 Open an issue for bugs, feature requests, compatibility notes, or documentation gaps.
|
|
504
|
-
- 🛣️ Follow the [roadmap](ROADMAP.md) for upcoming fleet, distribution, and production-readiness work.
|
|
505
509
|
|
|
506
510
|
---
|
|
507
511
|
|
package/dist/main.js
CHANGED
|
@@ -7,6 +7,7 @@ import { homedir as homedir5 } from "os";
|
|
|
7
7
|
|
|
8
8
|
// src/cli/index.ts
|
|
9
9
|
import { Command } from "commander";
|
|
10
|
+
import { spawnSync } from "child_process";
|
|
10
11
|
|
|
11
12
|
// src/config/app-config.ts
|
|
12
13
|
import { join } from "path";
|
|
@@ -8613,7 +8614,7 @@ function createServerFactory(config, identityRegistry) {
|
|
|
8613
8614
|
const makeServer = () => {
|
|
8614
8615
|
const server = new McpServer({
|
|
8615
8616
|
name: "mikromcp",
|
|
8616
|
-
version: "1.0.
|
|
8617
|
+
version: "1.0.5"
|
|
8617
8618
|
});
|
|
8618
8619
|
registerAllTools(server, registry, pool, circuitBreakers, config, identityRegistry);
|
|
8619
8620
|
return server;
|
|
@@ -8936,7 +8937,7 @@ import { existsSync as existsSync3, readFileSync as readFileSync6 } from "fs";
|
|
|
8936
8937
|
import { homedir as homedir3 } from "os";
|
|
8937
8938
|
import * as net from "net";
|
|
8938
8939
|
import chalk from "chalk";
|
|
8939
|
-
var localVersion = "1.0.
|
|
8940
|
+
var localVersion = "1.0.5";
|
|
8940
8941
|
var results = [];
|
|
8941
8942
|
function ok(msg) {
|
|
8942
8943
|
console.log(chalk.green("\u2705 ") + msg);
|
|
@@ -9262,8 +9263,7 @@ async function collectRouterInfo() {
|
|
|
9262
9263
|
}
|
|
9263
9264
|
});
|
|
9264
9265
|
const port = Number(portStr);
|
|
9265
|
-
const
|
|
9266
|
-
const tlsEnabled = await confirm({ message: "Enable TLS?", default: tlsDefault });
|
|
9266
|
+
const tlsEnabled = await confirm({ message: "Enable TLS?", default: false });
|
|
9267
9267
|
let rejectUnauthorized = true;
|
|
9268
9268
|
if (tlsEnabled) {
|
|
9269
9269
|
rejectUnauthorized = await confirm({
|
|
@@ -9284,6 +9284,14 @@ async function collectRouterInfo() {
|
|
|
9284
9284
|
default: suggestedPrefix,
|
|
9285
9285
|
validate: (v) => v.trim().length > 0 ? true : "Env prefix is required"
|
|
9286
9286
|
});
|
|
9287
|
+
const routerUser = await input({
|
|
9288
|
+
message: `Router username (${envPrefix}_USER):`,
|
|
9289
|
+
validate: (v) => v.trim().length > 0 ? true : "Username is required"
|
|
9290
|
+
});
|
|
9291
|
+
const routerPass = await input({
|
|
9292
|
+
message: `Router password (${envPrefix}_PASS):`,
|
|
9293
|
+
validate: (v) => v.trim().length > 0 ? true : "Password is required"
|
|
9294
|
+
});
|
|
9287
9295
|
const tagsRaw = await input({
|
|
9288
9296
|
message: "Tags (comma-separated, optional):",
|
|
9289
9297
|
default: ""
|
|
@@ -9294,7 +9302,7 @@ async function collectRouterInfo() {
|
|
|
9294
9302
|
default: "7",
|
|
9295
9303
|
validate: (v) => v.trim().length > 0 ? true : "Version is required"
|
|
9296
9304
|
});
|
|
9297
|
-
return { routerId, host, port, tlsEnabled, rejectUnauthorized, envPrefix, tags, rosVersion };
|
|
9305
|
+
return { routerId, host, port, tlsEnabled, rejectUnauthorized, envPrefix, routerUser, routerPass, tags, rosVersion };
|
|
9298
9306
|
}
|
|
9299
9307
|
async function collectIdentityInfo() {
|
|
9300
9308
|
console.log(chalk2.bold("\n\u2500\u2500 Identity / HTTP transport \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
@@ -9350,6 +9358,25 @@ async function collectIdentityInfo() {
|
|
|
9350
9358
|
tokenHash
|
|
9351
9359
|
};
|
|
9352
9360
|
}
|
|
9361
|
+
async function collectTransport() {
|
|
9362
|
+
console.log(chalk2.bold("\n\u2500\u2500 Transport \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
9363
|
+
const transport2 = await select({
|
|
9364
|
+
message: "Transport mode:",
|
|
9365
|
+
choices: [
|
|
9366
|
+
{ value: "stdio", name: "stdio \u2014 launched by Claude Desktop or an MCP client (recommended)" },
|
|
9367
|
+
{ value: "http", name: "http \u2014 standalone HTTP server with bearer-token auth" }
|
|
9368
|
+
],
|
|
9369
|
+
default: "stdio"
|
|
9370
|
+
});
|
|
9371
|
+
if (transport2 === "http") {
|
|
9372
|
+
console.log(
|
|
9373
|
+
chalk2.yellow(
|
|
9374
|
+
"\n \u26A0 HTTP mode requires every request to include:\n Authorization: Bearer <token>\n Set MIKROMCP_CONFIRMATION_SECRET in ~/.mikromcp/.env and create an identity above."
|
|
9375
|
+
)
|
|
9376
|
+
);
|
|
9377
|
+
}
|
|
9378
|
+
return transport2;
|
|
9379
|
+
}
|
|
9353
9380
|
async function collectEnvPreference() {
|
|
9354
9381
|
return confirm({
|
|
9355
9382
|
message: "Write credentials to ~/.mikromcp/.env? (No = inject env vars at runtime)",
|
|
@@ -9410,17 +9437,16 @@ function writeDotEnv(data) {
|
|
|
9410
9437
|
const userKey = `${data.envPrefix}_USER`;
|
|
9411
9438
|
const passKey = `${data.envPrefix}_PASS`;
|
|
9412
9439
|
const auditLogPath = defaultAuditLogPath();
|
|
9413
|
-
const
|
|
9414
|
-
const confirmationSecret = data.createIdentity ? randomBytes(32).toString("hex") : "";
|
|
9440
|
+
const confirmationSecret = data.transport === "http" ? randomBytes(32).toString("hex") : "";
|
|
9415
9441
|
const lines = [
|
|
9416
9442
|
"# \u2500\u2500 Router credentials \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
9417
|
-
`${userKey}
|
|
9418
|
-
`${passKey}
|
|
9443
|
+
`${userKey}=${data.routerUser}`,
|
|
9444
|
+
`${passKey}=${data.routerPass}`,
|
|
9419
9445
|
"",
|
|
9420
9446
|
"# \u2500\u2500 Transport \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
9421
9447
|
`# stdio \u2192 launched directly by Claude Desktop or another MCP client`,
|
|
9422
9448
|
`# http \u2192 standalone server mode with bearer-token auth`,
|
|
9423
|
-
`MIKROMCP_TRANSPORT=${
|
|
9449
|
+
`MIKROMCP_TRANSPORT=${data.transport}`,
|
|
9424
9450
|
"",
|
|
9425
9451
|
"# \u2500\u2500 Config paths \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
9426
9452
|
`MIKROMCP_CONFIG_PATH=${join4(data.configDir, "routers.yaml")}`,
|
|
@@ -9446,9 +9472,6 @@ function writeDotEnv(data) {
|
|
|
9446
9472
|
} else {
|
|
9447
9473
|
writeFileSync2(data.envPath, content);
|
|
9448
9474
|
}
|
|
9449
|
-
console.log(
|
|
9450
|
-
chalk2.dim(` Fill in ${userKey} and ${passKey} in ${data.envPath}`)
|
|
9451
|
-
);
|
|
9452
9475
|
}
|
|
9453
9476
|
function registerClaudeDesktop() {
|
|
9454
9477
|
const configPath = findClaudeDesktopConfig();
|
|
@@ -9486,6 +9509,7 @@ async function runInit() {
|
|
|
9486
9509
|
const identityInfo = await collectIdentityInfo();
|
|
9487
9510
|
const configDir = mikromcpDir2();
|
|
9488
9511
|
const envPath = join4(configDir, ".env");
|
|
9512
|
+
const transport2 = await collectTransport();
|
|
9489
9513
|
const writeEnv = await collectEnvPreference();
|
|
9490
9514
|
let writeRouters = true;
|
|
9491
9515
|
const routersYamlPath = join4(configDir, "routers.yaml");
|
|
@@ -9500,6 +9524,7 @@ async function runInit() {
|
|
|
9500
9524
|
const data = {
|
|
9501
9525
|
...routerInfo,
|
|
9502
9526
|
...identityInfo,
|
|
9527
|
+
transport: transport2,
|
|
9503
9528
|
envPath,
|
|
9504
9529
|
configDir,
|
|
9505
9530
|
writeEnv,
|
|
@@ -9550,10 +9575,14 @@ async function runInit() {
|
|
|
9550
9575
|
}
|
|
9551
9576
|
|
|
9552
9577
|
// src/cli/index.ts
|
|
9553
|
-
var program = new Command().name("mikromcp").description("MikroTik RouterOS MCP server").version("1.0.
|
|
9578
|
+
var program = new Command().name("mikromcp").description("MikroTik RouterOS MCP server").version("1.0.5");
|
|
9554
9579
|
program.command("serve", { isDefault: true }).description("Start the MCP server (default)").action(runServe);
|
|
9555
9580
|
program.command("doctor").description("Check config, connectivity, and permissions").action(runDoctor);
|
|
9556
9581
|
program.command("init").description("Interactive setup wizard").action(runInit);
|
|
9582
|
+
program.command("update").description("Update mikromcp to the latest version via npm").action(() => {
|
|
9583
|
+
const result = spawnSync("npm", ["update", "-g", "mikromcp"], { stdio: "inherit" });
|
|
9584
|
+
if (result.status !== 0) process.exit(result.status ?? 1);
|
|
9585
|
+
});
|
|
9557
9586
|
|
|
9558
9587
|
// src/main.ts
|
|
9559
9588
|
loadDotenv({ path: join5(homedir5(), ".mikromcp", ".env"), override: false });
|