@usex/mikrotik-mcp 2.3.0 → 2.5.0

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.
@@ -10,7 +10,7 @@ import{i as e}from"./app-DU6NBjf_.js";import{a as t,i as n,n as r,o as i,r as a,
10
10
  <link rel="modulepreload" crossorigin href="../assets/app-DU6NBjf_.js">
11
11
  <link rel="modulepreload" crossorigin href="../assets/kit-DAVkZl3Q.js">
12
12
  <style>
13
- @media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}.card__value small{color:var(--mt-text-dim);font-size:12px;font-weight:400}.gauge{align-items:center;gap:14px;display:flex}.gauge svg{flex:none}.gauge__track{stroke:var(--mt-surface-2)}.gauge__bar{stroke:var(--mt-accent);stroke-linecap:round;transform-origin:50%;transition:stroke-dashoffset .6s cubic-bezier(.2,.8,.2,1);transform:rotate(-90deg)}.gauge__pct{font-family:var(--mt-mono);fill:var(--mt-text);font-size:16px;font-weight:650}.gauge__meta{min-width:0}.gauge__meta .card__label{margin-bottom:4px}.gauge__meta small{color:var(--mt-text-faint);font-family:var(--mt-mono);font-size:11px}.is-good{stroke:var(--mt-good)}.is-warn{stroke:var(--mt-warn)}.is-bad{stroke:var(--mt-bad)}details.kv{background:var(--mt-surface);border:1px solid var(--mt-border);border-radius:var(--mt-radius);overflow:hidden}details.kv>summary{cursor:pointer;color:var(--mt-text-dim);-webkit-user-select:none;user-select:none;padding:12px 14px;font-weight:600;list-style:none}details.kv>summary::-webkit-details-marker{display:none}details.kv>summary:after{content:"▸";float:right;color:var(--mt-text-faint);transition:transform .2s}details.kv[open]>summary:after{transform:rotate(90deg)}.kv__body{border-top:1px solid var(--mt-border);grid-template-columns:minmax(120px,.4fr) 1fr;display:grid}.kv__body>div{border-bottom:1px solid color-mix(in srgb, var(--mt-border) 55%, transparent);overflow-wrap:anywhere;min-width:0;padding:7px 14px;font-size:12px}.kv__k{color:var(--mt-text-dim);font-family:var(--mt-mono)}.kv__v{font-family:var(--mt-mono);color:var(--mt-text)}.foot{color:var(--mt-text-faint);font-size:11px;font-family:var(--mt-mono);align-items:center;gap:10px;display:flex}.btn{appearance:none;border:1px solid var(--mt-border);background:var(--mt-surface);color:var(--mt-text);font:inherit;border-radius:var(--mt-radius-sm);cursor:pointer;padding:5px 11px;font-size:12px;transition:border-color .15s,background .15s}.skeleton{color:var(--mt-text-faint);text-align:center;padding:40px 0}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}table.tbl tbody tr.is-disabled td,table.tbl td.col-num{color:var(--mt-text-faint)}.act{font-family:var(--mt-mono);border:1px solid var(--mt-border);color:var(--mt-text-dim);border-radius:999px;padding:1px 8px;font-size:11px;display:inline-block}.act.is-accept{color:var(--mt-good);border-color:color-mix(in srgb, var(--mt-good) 45%, var(--mt-border))}.act.is-drop{color:var(--mt-bad);border-color:color-mix(in srgb, var(--mt-bad) 45%, var(--mt-border))}.act.is-jump{color:var(--mt-accent);border-color:color-mix(in srgb, var(--mt-accent) 45%, var(--mt-border))}.matchers{color:var(--mt-text-dim);max-width:340px;white-space:normal!important}.matchers b{color:var(--mt-text);font-weight:500}td.num{text-align:right;color:var(--mt-text-dim)}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}table.tbl tbody tr.is-disabled td,table.tbl td.col-num{color:var(--mt-text-faint)}.if-grid{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;display:grid}.if-card{gap:8px;display:grid}.if-card__top{align-items:center;gap:8px;display:flex}.if-card__name{font-family:var(--mt-mono);overflow-wrap:anywhere;font-size:14px;font-weight:650}.if-card.is-disabled{opacity:.6}.dot{background:var(--mt-text-faint);border-radius:50%;flex:none;width:9px;height:9px}.dot.is-up{background:var(--mt-good);box-shadow:0 0 0 4px color-mix(in srgb, var(--mt-good) 22%, transparent)}.dot.is-down{background:var(--mt-bad);box-shadow:0 0 0 4px color-mix(in srgb, var(--mt-bad) 18%, transparent)}.if-card__meta{font-family:var(--mt-mono);color:var(--mt-text-dim);grid-template-columns:auto 1fr;gap:2px 10px;font-size:11px;display:grid}.if-card__meta b{color:var(--mt-text);overflow-wrap:anywhere;font-weight:500}.if-card__meta .contents{display:contents}.badge{border:1px solid var(--mt-border);background:var(--mt-surface-2);color:var(--mt-text-dim);font-family:var(--mt-mono);text-transform:uppercase;letter-spacing:.04em;border-radius:999px;margin-left:auto;padding:1px 7px;font-size:10px}:root{--mt-bg:var(--color-background-primary,#0b0d10);--mt-surface:var(--color-background-secondary,#14171c);--mt-surface-2:var(--color-background-tertiary,#1b1f26);--mt-border:var(--color-border-primary,#262b33);--mt-text:var(--color-text-primary,#e8eaed);--mt-text-dim:var(--color-text-secondary,#9aa3af);--mt-text-faint:var(--color-text-tertiary,#6b7280);--mt-accent:var(--color-accent-primary,#6ea8fe);--mt-good:#34d399;--mt-warn:#fbbf24;--mt-bad:#f87171;--mt-radius:var(--border-radius-md,14px);--mt-radius-sm:var(--border-radius-sm,9px);--mt-mono:var(--font-mono,ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace);--mt-sans:var(--font-sans,system-ui, -apple-system, "Segoe UI", sans-serif);--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}*{box-sizing:border-box}body{background:var(--mt-bg);color:var(--mt-text);font-family:var(--mt-sans);-webkit-font-smoothing:antialiased;margin:0;padding:16px;font-size:13px;line-height:1.5}.app{gap:14px;max-width:960px;margin:0 auto;display:grid}.hd{flex-wrap:wrap;align-items:center;gap:12px;display:flex}.hd__dot{background:var(--mt-good);width:9px;height:9px;box-shadow:0 0 0 4px color-mix(in srgb, var(--mt-good) 22%, transparent);border-radius:50%}.hd__title{letter-spacing:-.01em;margin:0;font-size:17px;font-weight:650}.hd__sub{color:var(--mt-text-dim);font-family:var(--mt-mono);margin:0;font-size:12px}.hd__spacer{flex:1}.pill{border:1px solid var(--mt-border);background:var(--mt-surface);color:var(--mt-text-dim);font-family:var(--mt-mono);border-radius:999px;align-items:center;gap:6px;padding:3px 9px;font-size:11px;display:inline-flex}.pill b{color:var(--mt-text);font-weight:600}.grid{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;display:grid}.card{background:linear-gradient(180deg, var(--mt-surface), var(--mt-surface-2));border:1px solid var(--mt-border);border-radius:var(--mt-radius);padding:14px}.card__label{color:var(--mt-text-dim);text-transform:uppercase;letter-spacing:.06em;margin:0 0 8px;font-size:11px}.card__value{font-family:var(--mt-mono);letter-spacing:-.01em;font-size:20px;font-weight:600}.toolbar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.toolbar .grow{flex:1;min-width:140px}.search{appearance:none;border:1px solid var(--mt-border);background:var(--mt-surface);width:100%;color:var(--mt-text);font:inherit;border-radius:var(--mt-radius-sm);padding:7px 11px;font-size:13px}.search:focus{border-color:var(--mt-accent);outline:none}.search::placeholder{color:var(--mt-text-faint)}.btn{appearance:none;border:1px solid var(--mt-border);background:var(--mt-surface);color:var(--mt-text);font:inherit;border-radius:var(--mt-radius-sm);cursor:pointer;white-space:nowrap;padding:6px 11px;font-size:12px;transition:border-color .15s,background .15s}.btn:hover{border-color:var(--mt-accent);background:var(--mt-surface-2)}.btn:disabled{opacity:.5;cursor:default}.btn.is-active{border-color:var(--mt-accent);color:var(--mt-accent)}.chip{border:1px solid var(--mt-border);background:var(--mt-surface);color:var(--mt-text-dim);font-family:var(--mt-mono);border-radius:999px;align-items:center;gap:4px;padding:1px 7px;font-size:11px;display:inline-flex}.chip.is-good{color:var(--mt-good);border-color:color-mix(in srgb, var(--mt-good) 45%, var(--mt-border))}.chip.is-warn{color:var(--mt-warn);border-color:color-mix(in srgb, var(--mt-warn) 45%, var(--mt-border))}.chip.is-bad{color:var(--mt-bad);border-color:color-mix(in srgb, var(--mt-bad) 45%, var(--mt-border))}.tablewrap{border:1px solid var(--mt-border);border-radius:var(--mt-radius);max-height:70vh;overflow:auto}table.tbl{border-collapse:collapse;width:100%;font-size:12px}table.tbl th,table.tbl td{text-align:left;border-bottom:1px solid color-mix(in srgb, var(--mt-border) 55%, transparent);white-space:nowrap;font-family:var(--mt-mono);padding:7px 12px}table.tbl thead th{z-index:1;background:var(--mt-surface-2);color:var(--mt-text-dim);cursor:pointer;-webkit-user-select:none;user-select:none;font-weight:600;position:sticky;top:0}table.tbl thead th:hover{color:var(--mt-text)}table.tbl thead th .arrow{color:var(--mt-accent);margin-left:4px}table.tbl tbody tr{cursor:pointer}table.tbl tbody tr:hover{background:color-mix(in srgb, var(--mt-accent) 8%, transparent)}table.tbl tbody tr.is-disabled td,table.tbl td.col-num{color:var(--mt-text-faint)}.kv__body{border:1px solid var(--mt-border);border-radius:var(--mt-radius);grid-template-columns:minmax(120px,.4fr) 1fr;display:grid;overflow:hidden}.kv__body>div{border-bottom:1px solid color-mix(in srgb, var(--mt-border) 55%, transparent);overflow-wrap:anywhere;min-width:0;font-size:12px;font-family:var(--mt-mono);padding:7px 14px}.kv__k{color:var(--mt-text-dim);background:color-mix(in srgb, var(--mt-surface) 60%, transparent)}.kv__v{color:var(--mt-text)}.drawer{border:1px solid var(--mt-accent);border-radius:var(--mt-radius);background:var(--mt-surface);gap:10px;padding:12px;display:grid}.drawer__hd{align-items:center;gap:8px;display:flex}.drawer__hd b{font-family:var(--mt-mono)}pre.raw{border:1px solid var(--mt-border);border-radius:var(--mt-radius);background:var(--mt-surface);color:var(--mt-text);font-family:var(--mt-mono);white-space:pre;max-height:70vh;margin:0;padding:14px;font-size:12px;overflow:auto}.foot{color:var(--mt-text-faint);font-size:11px;font-family:var(--mt-mono);flex-wrap:wrap;align-items:center;gap:10px;display:flex}.foot .grow{flex:1}.skeleton,.empty{color:var(--mt-text-faint);text-align:center;padding:40px 0}.count-pill b{color:var(--mt-accent)}table.tbl td.col-num,table.tbl th.col-num{width:1%}
13
+ @media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}.card__value small{color:var(--mt-text-dim);font-size:12px;font-weight:400}.gauge{align-items:center;gap:14px;display:flex}.gauge svg{flex:none}.gauge__track{stroke:var(--mt-surface-2)}.gauge__bar{stroke:var(--mt-accent);stroke-linecap:round;transform-origin:50%;transition:stroke-dashoffset .6s cubic-bezier(.2,.8,.2,1);transform:rotate(-90deg)}.gauge__pct{font-family:var(--mt-mono);fill:var(--mt-text);font-size:16px;font-weight:650}.gauge__meta{min-width:0}.gauge__meta .card__label{margin-bottom:4px}.gauge__meta small{color:var(--mt-text-faint);font-family:var(--mt-mono);font-size:11px}.is-good{stroke:var(--mt-good)}.is-warn{stroke:var(--mt-warn)}.is-bad{stroke:var(--mt-bad)}details.kv{background:var(--mt-surface);border:1px solid var(--mt-border);border-radius:var(--mt-radius);overflow:hidden}details.kv>summary{cursor:pointer;color:var(--mt-text-dim);-webkit-user-select:none;user-select:none;padding:12px 14px;font-weight:600;list-style:none}details.kv>summary::-webkit-details-marker{display:none}details.kv>summary:after{content:"▸";float:right;color:var(--mt-text-faint);transition:transform .2s}details.kv[open]>summary:after{transform:rotate(90deg)}.kv__body{border-top:1px solid var(--mt-border);grid-template-columns:minmax(120px,.4fr) 1fr;display:grid}.kv__body>div{border-bottom:1px solid color-mix(in srgb, var(--mt-border) 55%, transparent);overflow-wrap:anywhere;min-width:0;padding:7px 14px;font-size:12px}.kv__k{color:var(--mt-text-dim);font-family:var(--mt-mono)}.kv__v{font-family:var(--mt-mono);color:var(--mt-text)}.foot{color:var(--mt-text-faint);font-size:11px;font-family:var(--mt-mono);align-items:center;gap:10px;display:flex}.btn{appearance:none;border:1px solid var(--mt-border);background:var(--mt-surface);color:var(--mt-text);font:inherit;border-radius:var(--mt-radius-sm);cursor:pointer;padding:5px 11px;font-size:12px;transition:border-color .15s,background .15s}.skeleton{color:var(--mt-text-faint);text-align:center;padding:40px 0}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}table.tbl tbody tr.is-disabled td,table.tbl td.col-num{color:var(--mt-text-faint)}.act{font-family:var(--mt-mono);border:1px solid var(--mt-border);color:var(--mt-text-dim);border-radius:999px;padding:1px 8px;font-size:11px;display:inline-block}.act.is-accept{color:var(--mt-good);border-color:color-mix(in srgb, var(--mt-good) 45%, var(--mt-border))}.act.is-drop{color:var(--mt-bad);border-color:color-mix(in srgb, var(--mt-bad) 45%, var(--mt-border))}.act.is-jump{color:var(--mt-accent);border-color:color-mix(in srgb, var(--mt-accent) 45%, var(--mt-border))}.matchers{color:var(--mt-text-dim);max-width:340px;white-space:normal!important}.matchers b{color:var(--mt-text);font-weight:500}td.num{text-align:right;color:var(--mt-text-dim)}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}table.tbl tbody tr.is-disabled td,table.tbl td.col-num{color:var(--mt-text-faint)}.hd{align-items:center;gap:14px}.hd__meta{flex-direction:column;gap:6px;display:flex}.counts{flex-wrap:wrap;gap:6px;display:flex}.gauge{flex:none;width:64px;height:64px}.gauge__bg{fill:none;stroke:var(--mt-border);stroke-width:9px}.gauge__fg{fill:none;stroke-width:9px;stroke-linecap:round;stroke:var(--mt-good);transition:stroke-dasharray .4s}.gauge.is-warn .gauge__fg{stroke:var(--mt-warn)}.gauge.is-bad .gauge__fg{stroke:var(--mt-bad)}.gauge__num{fill:var(--mt-text);font:700 22px var(--mt-mono)}.is-good{color:var(--mt-good)}.is-warn{color:var(--mt-warn)}.is-bad{color:var(--mt-bad)}.chip.is-low{color:var(--mt-text-dim);border-color:var(--mt-border)}.f-list{flex-direction:column;gap:10px;margin-top:14px;display:flex}.f-card{border:1px solid var(--mt-border);border-radius:var(--mt-radius-sm);background:var(--mt-surface);border-left-width:3px;padding:11px 13px}.f-card.is-bad{border-left-color:var(--mt-bad)}.f-card.is-warn{border-left-color:var(--mt-warn)}.f-card.is-low{border-left-color:var(--mt-text-faint)}.f-head{flex-wrap:wrap;align-items:center;gap:9px;display:flex}.f-title{font-size:13px;font-weight:600}.f-where{font-family:var(--mt-mono);color:var(--mt-text-faint);font-size:11px}.f-body{margin-top:6px}.f-detail{color:var(--mt-text);margin:0 0 5px;font-size:13px;line-height:1.45}.f-fix{color:var(--mt-text-dim);margin:0;font-size:12px;line-height:1.45}.f-actions{margin-top:9px}.btn-danger{color:var(--mt-bad);border-color:color-mix(in srgb, var(--mt-bad) 45%, var(--mt-border))}.btn-danger:hover{border-color:var(--mt-bad);background:color-mix(in srgb, var(--mt-bad) 12%, transparent)}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}table.tbl tbody tr.is-disabled td,table.tbl td.col-num{color:var(--mt-text-faint)}.if-grid{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;display:grid}.if-card{gap:8px;display:grid}.if-card__top{align-items:center;gap:8px;display:flex}.if-card__name{font-family:var(--mt-mono);overflow-wrap:anywhere;font-size:14px;font-weight:650}.if-card.is-disabled{opacity:.6}.dot{background:var(--mt-text-faint);border-radius:50%;flex:none;width:9px;height:9px}.dot.is-up{background:var(--mt-good);box-shadow:0 0 0 4px color-mix(in srgb, var(--mt-good) 22%, transparent)}.dot.is-down{background:var(--mt-bad);box-shadow:0 0 0 4px color-mix(in srgb, var(--mt-bad) 18%, transparent)}.if-card__meta{font-family:var(--mt-mono);color:var(--mt-text-dim);grid-template-columns:auto 1fr;gap:2px 10px;font-size:11px;display:grid}.if-card__meta b{color:var(--mt-text);overflow-wrap:anywhere;font-weight:500}.if-card__meta .contents{display:contents}.badge{border:1px solid var(--mt-border);background:var(--mt-surface-2);color:var(--mt-text-dim);font-family:var(--mt-mono);text-transform:uppercase;letter-spacing:.04em;border-radius:999px;margin-left:auto;padding:1px 7px;font-size:10px}:root{--mt-bg:var(--color-background-primary,#0b0d10);--mt-surface:var(--color-background-secondary,#14171c);--mt-surface-2:var(--color-background-tertiary,#1b1f26);--mt-border:var(--color-border-primary,#262b33);--mt-text:var(--color-text-primary,#e8eaed);--mt-text-dim:var(--color-text-secondary,#9aa3af);--mt-text-faint:var(--color-text-tertiary,#6b7280);--mt-accent:var(--color-accent-primary,#6ea8fe);--mt-good:#34d399;--mt-warn:#fbbf24;--mt-bad:#f87171;--mt-radius:var(--border-radius-md,14px);--mt-radius-sm:var(--border-radius-sm,9px);--mt-mono:var(--font-mono,ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace);--mt-sans:var(--font-sans,system-ui, -apple-system, "Segoe UI", sans-serif);--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}*{box-sizing:border-box}body{background:var(--mt-bg);color:var(--mt-text);font-family:var(--mt-sans);-webkit-font-smoothing:antialiased;margin:0;padding:16px;font-size:13px;line-height:1.5}.app{gap:14px;max-width:960px;margin:0 auto;display:grid}.hd{flex-wrap:wrap;align-items:center;gap:12px;display:flex}.hd__dot{background:var(--mt-good);width:9px;height:9px;box-shadow:0 0 0 4px color-mix(in srgb, var(--mt-good) 22%, transparent);border-radius:50%}.hd__title{letter-spacing:-.01em;margin:0;font-size:17px;font-weight:650}.hd__sub{color:var(--mt-text-dim);font-family:var(--mt-mono);margin:0;font-size:12px}.hd__spacer{flex:1}.pill{border:1px solid var(--mt-border);background:var(--mt-surface);color:var(--mt-text-dim);font-family:var(--mt-mono);border-radius:999px;align-items:center;gap:6px;padding:3px 9px;font-size:11px;display:inline-flex}.pill b{color:var(--mt-text);font-weight:600}.grid{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;display:grid}.card{background:linear-gradient(180deg, var(--mt-surface), var(--mt-surface-2));border:1px solid var(--mt-border);border-radius:var(--mt-radius);padding:14px}.card__label{color:var(--mt-text-dim);text-transform:uppercase;letter-spacing:.06em;margin:0 0 8px;font-size:11px}.card__value{font-family:var(--mt-mono);letter-spacing:-.01em;font-size:20px;font-weight:600}.toolbar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.toolbar .grow{flex:1;min-width:140px}.search{appearance:none;border:1px solid var(--mt-border);background:var(--mt-surface);width:100%;color:var(--mt-text);font:inherit;border-radius:var(--mt-radius-sm);padding:7px 11px;font-size:13px}.search:focus{border-color:var(--mt-accent);outline:none}.search::placeholder{color:var(--mt-text-faint)}.btn{appearance:none;border:1px solid var(--mt-border);background:var(--mt-surface);color:var(--mt-text);font:inherit;border-radius:var(--mt-radius-sm);cursor:pointer;white-space:nowrap;padding:6px 11px;font-size:12px;transition:border-color .15s,background .15s}.btn:hover{border-color:var(--mt-accent);background:var(--mt-surface-2)}.btn:disabled{opacity:.5;cursor:default}.btn.is-active{border-color:var(--mt-accent);color:var(--mt-accent)}.chip{border:1px solid var(--mt-border);background:var(--mt-surface);color:var(--mt-text-dim);font-family:var(--mt-mono);border-radius:999px;align-items:center;gap:4px;padding:1px 7px;font-size:11px;display:inline-flex}.chip.is-good{color:var(--mt-good);border-color:color-mix(in srgb, var(--mt-good) 45%, var(--mt-border))}.chip.is-warn{color:var(--mt-warn);border-color:color-mix(in srgb, var(--mt-warn) 45%, var(--mt-border))}.chip.is-bad{color:var(--mt-bad);border-color:color-mix(in srgb, var(--mt-bad) 45%, var(--mt-border))}.tablewrap{border:1px solid var(--mt-border);border-radius:var(--mt-radius);max-height:70vh;overflow:auto}table.tbl{border-collapse:collapse;width:100%;font-size:12px}table.tbl th,table.tbl td{text-align:left;border-bottom:1px solid color-mix(in srgb, var(--mt-border) 55%, transparent);white-space:nowrap;font-family:var(--mt-mono);padding:7px 12px}table.tbl thead th{z-index:1;background:var(--mt-surface-2);color:var(--mt-text-dim);cursor:pointer;-webkit-user-select:none;user-select:none;font-weight:600;position:sticky;top:0}table.tbl thead th:hover{color:var(--mt-text)}table.tbl thead th .arrow{color:var(--mt-accent);margin-left:4px}table.tbl tbody tr{cursor:pointer}table.tbl tbody tr:hover{background:color-mix(in srgb, var(--mt-accent) 8%, transparent)}table.tbl tbody tr.is-disabled td,table.tbl td.col-num{color:var(--mt-text-faint)}.kv__body{border:1px solid var(--mt-border);border-radius:var(--mt-radius);grid-template-columns:minmax(120px,.4fr) 1fr;display:grid;overflow:hidden}.kv__body>div{border-bottom:1px solid color-mix(in srgb, var(--mt-border) 55%, transparent);overflow-wrap:anywhere;min-width:0;font-size:12px;font-family:var(--mt-mono);padding:7px 14px}.kv__k{color:var(--mt-text-dim);background:color-mix(in srgb, var(--mt-surface) 60%, transparent)}.kv__v{color:var(--mt-text)}.drawer{border:1px solid var(--mt-accent);border-radius:var(--mt-radius);background:var(--mt-surface);gap:10px;padding:12px;display:grid}.drawer__hd{align-items:center;gap:8px;display:flex}.drawer__hd b{font-family:var(--mt-mono)}pre.raw{border:1px solid var(--mt-border);border-radius:var(--mt-radius);background:var(--mt-surface);color:var(--mt-text);font-family:var(--mt-mono);white-space:pre;max-height:70vh;margin:0;padding:14px;font-size:12px;overflow:auto}.foot{color:var(--mt-text-faint);font-size:11px;font-family:var(--mt-mono);flex-wrap:wrap;align-items:center;gap:10px;display:flex}.foot .grow{flex:1}.skeleton,.empty{color:var(--mt-text-faint);text-align:center;padding:40px 0}.count-pill b{color:var(--mt-accent)}table.tbl td.col-num,table.tbl th.col-num{width:1%}
14
14
  /*$vite$:1*/
15
15
  </style>
16
16
  </head>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usex/mikrotik-mcp",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "description": "Bun-native MCP server for MikroTik RouterOS — 200+ tools over SSH for firewall, NAT, routing, DHCP, DNS, WireGuard, wireless, QoS and more.",
5
5
  "keywords": [
6
6
  "ai",
@@ -55,6 +55,7 @@
55
55
  "gen:docs": "bun run scripts/gen-tool-docs.ts",
56
56
  "gen": "bun run gen:schemas && bun run gen:docs",
57
57
  "start": "bun run src/cli.ts serve",
58
+ "discover": "bun run scripts/discover-macs.ts",
58
59
  "inspect": "bunx @modelcontextprotocol/inspector bun run src/cli.ts serve",
59
60
  "inspect:built": "bun run build && bunx @modelcontextprotocol/inspector bun dist/cli.js serve",
60
61
  "inspect:config": "bunx @modelcontextprotocol/inspector --config mcp-inspector.config.json --server mikrotik",
@@ -75,6 +76,7 @@
75
76
  "@modelcontextprotocol/ext-apps": "^1.7.4",
76
77
  "@modelcontextprotocol/sdk": "^1.29.0",
77
78
  "@tikoci/centrs": "^0.1.0",
79
+ "ipaddr.js": "^2.4.0",
78
80
  "ssh2": "^1.17.0",
79
81
  "zod": "^4.4.3"
80
82
  },
@@ -117,5 +119,5 @@
117
119
  "breaking change": "Breaking changes"
118
120
  }
119
121
  },
120
- "logo": "https://raw.githubusercontent.com/ali-master/mikrotik-mcp/main/assets/logo.svg"
122
+ "logo": "https://raw.githubusercontent.com/ali-master/mikrotik-mcp/master/assets/logo.svg"
121
123
  }
package/schemas/README.md CHANGED
@@ -4,11 +4,11 @@ Machine-readable JSON Schemas for `@usex/mikrotik-mcp`, **generated** from the
4
4
  TypeScript source by `scripts/gen-schemas.ts` (`bun run gen:schemas`). Do not
5
5
  edit by hand — regenerate instead.
6
6
 
7
- | File | Contents |
8
- |------|----------|
9
- | `config.schema.json` | The runtime configuration object (env vars / CLI flags). |
10
- | `tool-catalog.json` | Every one of the 649 tools: `name`, `risk`, `title`, `description`, and input JSON Schema. |
11
- | `tools/<name>.json` | The input JSON Schema for a single tool. |
7
+ | File | Contents |
8
+ | -------------------- | ------------------------------------------------------------------------------------------ |
9
+ | `config.schema.json` | The runtime configuration object (env vars / CLI flags). |
10
+ | `tool-catalog.json` | Every one of the 664 tools: `name`, `risk`, `title`, `description`, and input JSON Schema. |
11
+ | `tools/<name>.json` | The input JSON Schema for a single tool. |
12
12
 
13
13
  `risk` is derived from the MCP tool annotations:
14
14
  `read` · `write` · `write-idempotent` · `destructive` · `dangerous`.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "version": "2.1.0",
3
+ "version": "2.4.0",
4
4
  "generated": "by scripts/gen-schemas.ts — do not edit by hand",
5
- "toolCount": 649,
5
+ "toolCount": 664,
6
6
  "tools": [
7
7
  {
8
8
  "name": "list_interfaces",
@@ -10051,6 +10051,35 @@
10051
10051
  "additionalProperties": false
10052
10052
  }
10053
10053
  },
10054
+ {
10055
+ "name": "firewall_audit",
10056
+ "title": "Firewall Audit",
10057
+ "risk": "read",
10058
+ "annotations": {
10059
+ "readOnlyHint": true,
10060
+ "idempotentHint": true,
10061
+ "openWorldHint": false
10062
+ },
10063
+ "description": "Audits the firewall and explains it in plain language. Analyses the filter ruleset (and optionally NAT/mangle) for unreachable/shadowed rules, overly-broad accepts, a missing default-drop, duplicate rules, and dead rules with no packet hits. Returns a risk score and prioritised, plain-language findings with suggested fixes — and renders an interactive findings table (one-click disable) in MCP App hosts. Use when the user wants to review, harden or understand a router's firewall.",
10064
+ "inputSchema": {
10065
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
10066
+ "type": "object",
10067
+ "properties": {
10068
+ "include_nat": {
10069
+ "default": true,
10070
+ "description": "Also audit `/ip firewall nat`.",
10071
+ "type": "boolean"
10072
+ },
10073
+ "include_mangle": {
10074
+ "default": false,
10075
+ "description": "Also audit `/ip firewall mangle`.",
10076
+ "type": "boolean"
10077
+ }
10078
+ },
10079
+ "required": ["include_nat", "include_mangle"],
10080
+ "additionalProperties": false
10081
+ }
10082
+ },
10054
10083
  {
10055
10084
  "name": "list_certificates",
10056
10085
  "title": "List Certificates",
@@ -16366,6 +16395,92 @@
16366
16395
  "additionalProperties": false
16367
16396
  }
16368
16397
  },
16398
+ {
16399
+ "name": "list_neighbors",
16400
+ "title": "List Neighbors (MNDP)",
16401
+ "risk": "read",
16402
+ "annotations": {
16403
+ "readOnlyHint": true,
16404
+ "idempotentHint": true,
16405
+ "openWorldHint": false
16406
+ },
16407
+ "description": "Lists directly-attached devices discovered via MNDP/CDP/LLDP (`/ip neighbor`) — identity, MAC, IP, the local interface they were seen on, platform, board and version. This is the Layer-2 view of what is physically connected, including devices with no routable IP.",
16408
+ "inputSchema": {
16409
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
16410
+ "type": "object",
16411
+ "properties": {
16412
+ "interface_filter": {
16413
+ "description": "Match the local discovery interface.",
16414
+ "type": "string"
16415
+ },
16416
+ "identity_filter": {
16417
+ "description": "Match the neighbour's identity (substring).",
16418
+ "type": "string"
16419
+ },
16420
+ "address_filter": {
16421
+ "description": "Match the neighbour's IP address (substring).",
16422
+ "type": "string"
16423
+ },
16424
+ "mac_filter": {
16425
+ "description": "Match the neighbour's MAC address (substring).",
16426
+ "type": "string"
16427
+ }
16428
+ },
16429
+ "additionalProperties": false
16430
+ }
16431
+ },
16432
+ {
16433
+ "name": "get_neighbor_discovery_settings",
16434
+ "title": "Get Neighbor Discovery Settings",
16435
+ "risk": "read",
16436
+ "annotations": {
16437
+ "readOnlyHint": true,
16438
+ "idempotentHint": true,
16439
+ "openWorldHint": false
16440
+ },
16441
+ "description": "Shows neighbor-discovery settings (`/ip neighbor discovery-settings`): which interface-list participates in discovery and which protocols (MNDP/CDP/LLDP) are enabled.",
16442
+ "inputSchema": {
16443
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
16444
+ "type": "object",
16445
+ "properties": {},
16446
+ "additionalProperties": false
16447
+ }
16448
+ },
16449
+ {
16450
+ "name": "set_neighbor_discovery_settings",
16451
+ "title": "Set Neighbor Discovery Settings",
16452
+ "risk": "write-idempotent",
16453
+ "annotations": {
16454
+ "destructiveHint": false,
16455
+ "idempotentHint": true,
16456
+ "openWorldHint": false
16457
+ },
16458
+ "description": "Configures neighbor discovery (`/ip neighbor discovery-settings set`): the interface-list to discover on, the discovery mode (tx/rx), and which protocols to speak. Controls which devices appear in the topology map.",
16459
+ "inputSchema": {
16460
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
16461
+ "type": "object",
16462
+ "properties": {
16463
+ "discover_interface_list": {
16464
+ "description": "Interface-list to run discovery on, e.g. \"all\", \"LAN\", \"none\".",
16465
+ "type": "string"
16466
+ },
16467
+ "mode": {
16468
+ "description": "Whether the router transmits and/or receives discovery frames.",
16469
+ "type": "string",
16470
+ "enum": ["tx-only", "rx-only", "tx-and-rx"]
16471
+ },
16472
+ "protocol": {
16473
+ "description": "Comma-separated protocols, e.g. \"mndp,cdp,lldp\".",
16474
+ "type": "string"
16475
+ },
16476
+ "lldp_med_net_policy_vlan": {
16477
+ "description": "LLDP-MED network-policy VLAN, e.g. \"auto\" or a VLAN id.",
16478
+ "type": "string"
16479
+ }
16480
+ },
16481
+ "additionalProperties": false
16482
+ }
16483
+ },
16369
16484
  {
16370
16485
  "name": "get_bandwidth_server",
16371
16486
  "title": "Get Bandwidth Server",
@@ -16991,6 +17106,134 @@
16991
17106
  "additionalProperties": false
16992
17107
  }
16993
17108
  },
17109
+ {
17110
+ "name": "start_packet_capture",
17111
+ "title": "Start Packet Capture",
17112
+ "risk": "write",
17113
+ "annotations": {
17114
+ "destructiveHint": false,
17115
+ "openWorldHint": false
17116
+ },
17117
+ "description": "Starts a live packet capture: opens a TZSP receiver on this host and configures the device's `/tool sniffer` to stream mirrored packets to it. receiver_host is the IP THIS host has on the segment the device can reach (where TZSP is sent). Optional interface/protocol/port filters narrow what is mirrored. View packets live in the dashboard's Packet Capture panel or via packet_capture_status.",
17118
+ "inputSchema": {
17119
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
17120
+ "type": "object",
17121
+ "properties": {
17122
+ "receiver_host": {
17123
+ "type": "string",
17124
+ "description": "IP this host is reachable at from the device (the TZSP stream destination)."
17125
+ },
17126
+ "port": {
17127
+ "default": 37008,
17128
+ "type": "integer",
17129
+ "minimum": 1,
17130
+ "maximum": 65535
17131
+ },
17132
+ "interface": {
17133
+ "description": "Capture interface, or omit for all (`filter-interface`).",
17134
+ "type": "string"
17135
+ },
17136
+ "protocol": {
17137
+ "description": "Limit to an IP protocol, e.g. \"tcp\", \"icmp\".",
17138
+ "type": "string"
17139
+ },
17140
+ "port_filter": {
17141
+ "description": "Limit to a TCP/UDP port number.",
17142
+ "type": "string"
17143
+ }
17144
+ },
17145
+ "required": ["receiver_host", "port"],
17146
+ "additionalProperties": false
17147
+ }
17148
+ },
17149
+ {
17150
+ "name": "mirror_traffic_to_capture",
17151
+ "title": "Mirror Traffic to Capture",
17152
+ "risk": "write",
17153
+ "annotations": {
17154
+ "destructiveHint": false,
17155
+ "openWorldHint": false
17156
+ },
17157
+ "description": "Adds a surgical per-flow mirror: a firewall mangle `action=sniff-tzsp` rule that copies only matching packets to the capture receiver (the original traffic is untouched). Use after start_packet_capture to focus on one host/port/protocol. Rules are tagged for cleanup by stop_packet_capture.",
17158
+ "inputSchema": {
17159
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
17160
+ "type": "object",
17161
+ "properties": {
17162
+ "receiver_host": {
17163
+ "type": "string",
17164
+ "description": "TZSP stream destination (this host's IP)."
17165
+ },
17166
+ "port": {
17167
+ "default": 37008,
17168
+ "type": "integer",
17169
+ "minimum": 1,
17170
+ "maximum": 65535
17171
+ },
17172
+ "chain": {
17173
+ "default": "forward",
17174
+ "type": "string",
17175
+ "enum": ["forward", "input", "output", "prerouting", "postrouting"]
17176
+ },
17177
+ "src_address": {
17178
+ "type": "string"
17179
+ },
17180
+ "dst_address": {
17181
+ "type": "string"
17182
+ },
17183
+ "protocol": {
17184
+ "type": "string"
17185
+ },
17186
+ "dst_port": {
17187
+ "type": "string"
17188
+ }
17189
+ },
17190
+ "required": ["receiver_host", "port", "chain"],
17191
+ "additionalProperties": false
17192
+ }
17193
+ },
17194
+ {
17195
+ "name": "packet_capture_status",
17196
+ "title": "Packet Capture Status",
17197
+ "risk": "read",
17198
+ "annotations": {
17199
+ "readOnlyHint": true,
17200
+ "idempotentHint": true,
17201
+ "openWorldHint": false
17202
+ },
17203
+ "description": "Reports the live capture: whether the receiver is running, packet/byte totals, the protocol breakdown, top talkers, and the most recent decoded packets. Works without the dashboard.",
17204
+ "inputSchema": {
17205
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
17206
+ "type": "object",
17207
+ "properties": {
17208
+ "limit": {
17209
+ "default": 40,
17210
+ "description": "Recent packets to include.",
17211
+ "type": "integer",
17212
+ "minimum": 1,
17213
+ "maximum": 500
17214
+ }
17215
+ },
17216
+ "required": ["limit"],
17217
+ "additionalProperties": false
17218
+ }
17219
+ },
17220
+ {
17221
+ "name": "stop_packet_capture",
17222
+ "title": "Stop Packet Capture",
17223
+ "risk": "destructive",
17224
+ "annotations": {
17225
+ "destructiveHint": true,
17226
+ "idempotentHint": true,
17227
+ "openWorldHint": false
17228
+ },
17229
+ "description": "Stops the device sniffer + streaming, removes any capture mirror rules, and closes the host receiver. Returns the final capture summary.",
17230
+ "inputSchema": {
17231
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
17232
+ "type": "object",
17233
+ "properties": {},
17234
+ "additionalProperties": false
17235
+ }
17236
+ },
16994
17237
  {
16995
17238
  "name": "profile_cpu",
16996
17239
  "title": "Profile CPU",
@@ -19257,6 +19500,163 @@
19257
19500
  "additionalProperties": false
19258
19501
  }
19259
19502
  },
19503
+ {
19504
+ "name": "capture_config_snapshot",
19505
+ "title": "Capture Config Snapshot",
19506
+ "risk": "write",
19507
+ "annotations": {
19508
+ "destructiveHint": false,
19509
+ "openWorldHint": false
19510
+ },
19511
+ "description": "Captures the device's current configuration (`/export`) and stores it locally as a timestamped snapshot for later diffing/rollback reference. Sensitive values are hidden unless show_sensitive is set. By default an identical capture (no config change since the last snapshot) is skipped; set force to store it anyway. Optionally limit to one RouterOS section (e.g. \"ip firewall filter\").",
19512
+ "inputSchema": {
19513
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
19514
+ "type": "object",
19515
+ "properties": {
19516
+ "label": {
19517
+ "description": "Human label, e.g. 'pre-firewall-change'.",
19518
+ "type": "string"
19519
+ },
19520
+ "section": {
19521
+ "description": "RouterOS path without leading slash, e.g. \"ip firewall filter\". Omit for full config.",
19522
+ "type": "string"
19523
+ },
19524
+ "terse": {
19525
+ "default": true,
19526
+ "description": "Use `/export terse` (one self-contained line per item) for cleaner diffs.",
19527
+ "type": "boolean"
19528
+ },
19529
+ "show_sensitive": {
19530
+ "default": false,
19531
+ "type": "boolean"
19532
+ },
19533
+ "force": {
19534
+ "default": false,
19535
+ "type": "boolean"
19536
+ }
19537
+ },
19538
+ "required": ["terse", "show_sensitive", "force"],
19539
+ "additionalProperties": false
19540
+ }
19541
+ },
19542
+ {
19543
+ "name": "list_config_snapshots",
19544
+ "title": "List Config Snapshots",
19545
+ "risk": "read",
19546
+ "annotations": {
19547
+ "readOnlyHint": true,
19548
+ "idempotentHint": true,
19549
+ "openWorldHint": false
19550
+ },
19551
+ "description": "Lists stored configuration snapshots for the target device, newest first (metadata only — id, label, time, size, RouterOS version, content hash). Use get_config_snapshot for a body.",
19552
+ "inputSchema": {
19553
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
19554
+ "type": "object",
19555
+ "properties": {
19556
+ "limit": {
19557
+ "default": 50,
19558
+ "type": "integer",
19559
+ "minimum": 1,
19560
+ "maximum": 500
19561
+ }
19562
+ },
19563
+ "required": ["limit"],
19564
+ "additionalProperties": false
19565
+ }
19566
+ },
19567
+ {
19568
+ "name": "get_config_snapshot",
19569
+ "title": "Get Config Snapshot",
19570
+ "risk": "read",
19571
+ "annotations": {
19572
+ "readOnlyHint": true,
19573
+ "idempotentHint": true,
19574
+ "openWorldHint": false
19575
+ },
19576
+ "description": "Returns a stored configuration snapshot by id. With include_body=true (default) the full captured `/export` text is returned — this body is itself a RouterOS `.rsc` script suitable for review or manual re-application. Set include_body=false for metadata only.",
19577
+ "inputSchema": {
19578
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
19579
+ "type": "object",
19580
+ "properties": {
19581
+ "id": {
19582
+ "type": "string"
19583
+ },
19584
+ "include_body": {
19585
+ "default": true,
19586
+ "type": "boolean"
19587
+ }
19588
+ },
19589
+ "required": ["id", "include_body"],
19590
+ "additionalProperties": false
19591
+ }
19592
+ },
19593
+ {
19594
+ "name": "diff_config_snapshots",
19595
+ "title": "Diff Config Snapshots",
19596
+ "risk": "read",
19597
+ "annotations": {
19598
+ "readOnlyHint": true,
19599
+ "idempotentHint": true,
19600
+ "openWorldHint": false
19601
+ },
19602
+ "description": "Time-travel diff: compares two configurations and reports a unified diff (added/removed lines) plus a summary. Each of `from`/`to` may be `<id>`, `latest` (newest stored), or `live` (capture the device now). Typical uses: drift check (from=latest, to=live), or compare two stored snapshots by id. Volatile export header timestamps are ignored so unchanged configs diff clean.",
19603
+ "inputSchema": {
19604
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
19605
+ "type": "object",
19606
+ "properties": {
19607
+ "from": {
19608
+ "type": "string",
19609
+ "description": "Baseline side: `<id>`, `latest` (newest stored), or `live` (capture the device now)."
19610
+ },
19611
+ "to": {
19612
+ "default": "live",
19613
+ "description": "Comparison side: `<id>`, `latest` (newest stored), or `live` (capture the device now). Defaults to live.",
19614
+ "type": "string"
19615
+ },
19616
+ "context_lines": {
19617
+ "default": 3,
19618
+ "type": "integer",
19619
+ "minimum": 0,
19620
+ "maximum": 20
19621
+ },
19622
+ "max_output_lines": {
19623
+ "default": 800,
19624
+ "description": "Truncate the unified diff beyond this many lines.",
19625
+ "type": "integer",
19626
+ "minimum": 50,
19627
+ "maximum": 5000
19628
+ }
19629
+ },
19630
+ "required": ["from", "to", "context_lines", "max_output_lines"],
19631
+ "additionalProperties": false
19632
+ }
19633
+ },
19634
+ {
19635
+ "name": "remove_config_snapshot",
19636
+ "title": "Remove Config Snapshot",
19637
+ "risk": "destructive",
19638
+ "annotations": {
19639
+ "destructiveHint": true,
19640
+ "idempotentHint": true,
19641
+ "openWorldHint": false
19642
+ },
19643
+ "description": "Deletes stored configuration snapshots by id (local history only — never touches the device). Accepts one or more ids.",
19644
+ "inputSchema": {
19645
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
19646
+ "type": "object",
19647
+ "properties": {
19648
+ "ids": {
19649
+ "minItems": 1,
19650
+ "type": "array",
19651
+ "items": {
19652
+ "type": "string"
19653
+ }
19654
+ }
19655
+ },
19656
+ "required": ["ids"],
19657
+ "additionalProperties": false
19658
+ }
19659
+ },
19260
19660
  {
19261
19661
  "name": "s3_backup_status",
19262
19662
  "title": "S3 Backup Status",
@@ -19282,7 +19682,7 @@
19282
19682
  "destructiveHint": false,
19283
19683
  "openWorldHint": false
19284
19684
  },
19285
- "description": "Uploads a file from the device (e.g. a .backup or .rsc export) to the configured S3 bucket. The device streams it directly to S3 via a short-lived presigned URL.\n\nNotes:\n filename: the file on the device, e.g. 'daily.backup'.\n key: optional S3 object key; defaults to '<prefix>/<device>/<filename>' so each router's backups are organised separately.",
19685
+ "description": "Uploads a file from the device (e.g. a .backup or .rsc export) to the configured S3 bucket. The device streams it directly to S3 via a short-lived presigned URL.\n\nNotes:\n filename: the file on the device, e.g. 'daily.backup'.\n key: optional S3 object key; defaults to '<prefix>/<device>/<device-datetime>-<filename>' so each upload is organised per router and stamped with the DEVICE's local date-time (Jalali calendar in Tehran, Gregorian elsewhere) — so repeat uploads version instead of overwriting.",
19286
19686
  "inputSchema": {
19287
19687
  "$schema": "https://json-schema.org/draft/2020-12/schema",
19288
19688
  "type": "object",
@@ -19292,7 +19692,7 @@
19292
19692
  "description": "File on the device, e.g. 'daily.backup'"
19293
19693
  },
19294
19694
  "key": {
19295
- "description": "S3 object key (defaults to prefix + filename)",
19695
+ "description": "S3 object key (defaults to prefix + device-local datetime + filename)",
19296
19696
  "type": "string"
19297
19697
  },
19298
19698
  "expires_in": {
@@ -19554,6 +19954,67 @@
19554
19954
  "additionalProperties": false
19555
19955
  }
19556
19956
  },
19957
+ {
19958
+ "name": "plan_changes",
19959
+ "title": "Plan Changes (Dry-Run)",
19960
+ "risk": "read",
19961
+ "annotations": {
19962
+ "readOnlyHint": true,
19963
+ "idempotentHint": true,
19964
+ "openWorldHint": false
19965
+ },
19966
+ "description": "Previews a set of intended RouterOS commands WITHOUT touching the device — a 'terraform plan'. Returns ADD/MODIFY/REMOVE counts, a risk score, lock-out warnings (e.g. an input-chain drop or removing your management IP), and the steps reordered into a safe sequence (additive changes before destructive ones). Feed the same commands to apply_plan to execute them under Safe Mode. Provide commands as an array and/or a newline script.",
19967
+ "inputSchema": {
19968
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
19969
+ "type": "object",
19970
+ "properties": {
19971
+ "commands": {
19972
+ "description": "Intended RouterOS CLI commands.",
19973
+ "type": "array",
19974
+ "items": {
19975
+ "type": "string"
19976
+ }
19977
+ },
19978
+ "script": {
19979
+ "description": "Newline-delimited commands (alternative to `commands`).",
19980
+ "type": "string"
19981
+ }
19982
+ },
19983
+ "additionalProperties": false
19984
+ }
19985
+ },
19986
+ {
19987
+ "name": "apply_plan",
19988
+ "title": "Apply Plan (Safe Mode)",
19989
+ "risk": "dangerous",
19990
+ "annotations": {
19991
+ "destructiveHint": true,
19992
+ "openWorldHint": false
19993
+ },
19994
+ "description": "Executes intended RouterOS commands inside Safe Mode and reports the EXACT `/export` diff. With confirm=false (default) it applies, shows the diff, then rolls everything back — a true dry-run. With confirm=true it commits, but ONLY after verifying the device is still reachable, so a change that would lock you out auto-reverts instead. Steps run in the safe order from plan_changes. Safe Mode requires SSH (not available on MAC-Telnet devices).",
19995
+ "inputSchema": {
19996
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
19997
+ "type": "object",
19998
+ "properties": {
19999
+ "commands": {
20000
+ "type": "array",
20001
+ "items": {
20002
+ "type": "string"
20003
+ }
20004
+ },
20005
+ "script": {
20006
+ "type": "string"
20007
+ },
20008
+ "confirm": {
20009
+ "default": false,
20010
+ "description": "false = apply, show diff, roll back (dry-run). true = commit if still reachable.",
20011
+ "type": "boolean"
20012
+ }
20013
+ },
20014
+ "required": ["confirm"],
20015
+ "additionalProperties": false
20016
+ }
20017
+ },
19557
20018
  {
19558
20019
  "name": "show_system_dashboard",
19559
20020
  "title": "Device Dashboard",
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "apply_plan",
4
+ "type": "object",
5
+ "properties": {
6
+ "commands": {
7
+ "type": "array",
8
+ "items": {
9
+ "type": "string"
10
+ }
11
+ },
12
+ "script": {
13
+ "type": "string"
14
+ },
15
+ "confirm": {
16
+ "default": false,
17
+ "description": "false = apply, show diff, roll back (dry-run). true = commit if still reachable.",
18
+ "type": "boolean"
19
+ }
20
+ },
21
+ "required": ["confirm"],
22
+ "additionalProperties": false
23
+ }