@usex/mikrotik-mcp 3.57.0 → 3.59.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.
- package/dist/cli.js +84 -64
- package/dist/index.d.ts +5 -0
- package/dist/index.js +21 -15
- package/dist/shared/{cli-0ctwspf1.js → cli-2dyvnv9v.js} +1 -1
- package/dist/shared/{cli-thhk9f7n.js → cli-jq168zrj.js} +829 -597
- package/dist/shared/{library-jve65pzw.js → library-0zd2tej9.js} +1 -1
- package/dist/shared/{library-ymtf9zyk.js → library-21t1cncr.js} +828 -597
- package/dist/ui/aaa.html +1 -1
- package/dist/ui/connected-devices.html +1 -1
- package/dist/ui/dashboard.html +1 -1
- package/dist/ui/firewall-audit.html +1 -1
- package/dist/ui/firewall.html +1 -1
- package/dist/ui/interfaces.html +1 -1
- package/dist/ui/observability.html +1 -1
- package/dist/ui/records.html +1 -1
- package/package.json +1 -1
- package/schemas/README.md +5 -5
- package/schemas/config.schema.json +47 -10
- package/schemas/tool-catalog.json +2941 -736
- package/schemas/tools/check_server_pulse.json +12 -0
- package/schemas/tools/config_check_drift.json +5 -1
- package/schemas/tools/config_reconcile.json +3 -1
- package/schemas/tools/config_set_baseline.json +4 -1
- package/schemas/tools/correlate_events.json +4 -1
- package/schemas/tools/diagnose.json +3 -1
- package/schemas/tools/get_filter_rule.json +1 -1
- package/schemas/tools/memory_add_observations.json +7 -2
- package/schemas/tools/memory_create_entities.json +7 -2
- package/schemas/tools/memory_create_relations.json +8 -2
- package/schemas/tools/memory_delete_entities.json +3 -1
- package/schemas/tools/memory_delete_observations.json +7 -2
- package/schemas/tools/memory_delete_relations.json +8 -2
- package/schemas/tools/memory_open_nodes.json +3 -1
- package/schemas/tools/memory_search_nodes.json +3 -1
- package/schemas/tools/suggest_fix.json +3 -1
- package/schemas/tools/trace_path.json +5 -1
|
@@ -310,7 +310,7 @@ var McpServerSettingsSchema = z.object({
|
|
|
310
310
|
allowedOrigins: z.string().default(""),
|
|
311
311
|
corsOrigins: z.string().default(""),
|
|
312
312
|
toolPageSize: z.coerce.number().int().min(0).default(0),
|
|
313
|
-
appViews: z.boolean().default(
|
|
313
|
+
appViews: z.boolean().default(false)
|
|
314
314
|
});
|
|
315
315
|
var JumpHostSchema = z.object({
|
|
316
316
|
host: z.string(),
|
|
@@ -386,7 +386,8 @@ var MikrotikConfigSchema = z.object({
|
|
|
386
386
|
readOnly: z.boolean().default(false),
|
|
387
387
|
tools: ToolFilterSchema.default(() => ToolFilterSchema.parse({})),
|
|
388
388
|
memory: MemoryConfigSchema.default(() => MemoryConfigSchema.parse({})),
|
|
389
|
-
backupDir: z.string().optional()
|
|
389
|
+
backupDir: z.string().optional(),
|
|
390
|
+
disableUpdateCheck: z.boolean().default(false)
|
|
390
391
|
});
|
|
391
392
|
function env(...names) {
|
|
392
393
|
for (const n of names) {
|
|
@@ -522,6 +523,7 @@ function loadConfig(argv = process.argv.slice(2)) {
|
|
|
522
523
|
};
|
|
523
524
|
const isTruthy = (v) => /^(1|true|yes|on)$/i.test(v ?? "");
|
|
524
525
|
const readOnly = isTruthy(pick("read-only", "MIKROTIK_READ_ONLY"));
|
|
526
|
+
const disableUpdateCheck = isTruthy(pick("disable-update-check", "MIKROTIK_DISABLE_UPDATE_CHECK"));
|
|
525
527
|
const csv = (v) => v === undefined ? undefined : v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
526
528
|
const tools = {
|
|
527
529
|
enabledModules: csv(pick("tools-enabled-modules", "MIKROTIK_TOOLS__ENABLED_MODULES")),
|
|
@@ -561,6 +563,7 @@ function loadConfig(argv = process.argv.slice(2)) {
|
|
|
561
563
|
mcp,
|
|
562
564
|
dashboard,
|
|
563
565
|
readOnly,
|
|
566
|
+
disableUpdateCheck,
|
|
564
567
|
tools,
|
|
565
568
|
ssh,
|
|
566
569
|
memory,
|
|
@@ -2427,7 +2430,7 @@ function defineTool(def) {
|
|
|
2427
2430
|
handler: def.handler,
|
|
2428
2431
|
register(server, opts = {}) {
|
|
2429
2432
|
const { sendLog, deviceNames, deviceAliases, deviceDirectory: deviceDirectory2, appViews } = opts;
|
|
2430
|
-
const multiDevice = !!deviceNames && deviceNames.length > 1;
|
|
2433
|
+
const multiDevice = !def.noDevice && !!deviceNames && deviceNames.length > 1;
|
|
2431
2434
|
const { ui, auto } = appViews === false ? { ui: undefined, auto: false } : effectiveUi(def);
|
|
2432
2435
|
const selectorNames = multiDevice && deviceNames ? [...new Set([...deviceNames, ...deviceAliases ?? []])] : [];
|
|
2433
2436
|
let inputSchema = multiDevice ? {
|
|
@@ -8257,7 +8260,7 @@ var cache = null;
|
|
|
8257
8260
|
async function gateway() {
|
|
8258
8261
|
if (cache)
|
|
8259
8262
|
return cache;
|
|
8260
|
-
const { moduleCatalog } = await import("./library-
|
|
8263
|
+
const { moduleCatalog } = await import("./library-0zd2tej9.js");
|
|
8261
8264
|
const forIndex = [];
|
|
8262
8265
|
const byName = new Map;
|
|
8263
8266
|
for (const mod of moduleCatalog) {
|
|
@@ -24775,8 +24778,229 @@ ${result}`;
|
|
|
24775
24778
|
})
|
|
24776
24779
|
];
|
|
24777
24780
|
|
|
24778
|
-
// src/tools/
|
|
24781
|
+
// src/tools/server-pulse.ts
|
|
24779
24782
|
import { z as z104 } from "zod";
|
|
24783
|
+
|
|
24784
|
+
// src/core/update-check.ts
|
|
24785
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
|
|
24786
|
+
import { homedir as homedir2 } from "os";
|
|
24787
|
+
import { dirname as dirname4, join as join6 } from "path";
|
|
24788
|
+
|
|
24789
|
+
// src/version.ts
|
|
24790
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
24791
|
+
import { join as join5 } from "path";
|
|
24792
|
+
var pkg = JSON.parse(readFileSync5(join5(PROJECT_ROOT, "package.json"), "utf-8"));
|
|
24793
|
+
var VERSION = pkg.version ?? "0.0.0";
|
|
24794
|
+
var WEBSITE_URL = pkg.homepage ?? "";
|
|
24795
|
+
var LOGO_URL = pkg.logoIcon ?? "";
|
|
24796
|
+
var SERVER_TITLE = "MikroTik MCP";
|
|
24797
|
+
var SERVER_DESCRIPTION = pkg.description ?? "";
|
|
24798
|
+
var SERVER_NAME = "mikrotik-mcp";
|
|
24799
|
+
|
|
24800
|
+
// src/core/update-check.ts
|
|
24801
|
+
var GITHUB_API = "https://api.github.com/repos/ali-master/mikrotik-mcp/releases/latest";
|
|
24802
|
+
var MEMORY_CACHE_TTL = 15 * 60 * 1000;
|
|
24803
|
+
var FILE_CACHE_TTL = 6 * 60 * 60 * 1000;
|
|
24804
|
+
var CACHE_PATH = join6(homedir2(), ".mikrotik-mcp", "update-check.json");
|
|
24805
|
+
function compareVersions(a, b) {
|
|
24806
|
+
const pa = a.replace(/^v/, "").split(".").map(Number);
|
|
24807
|
+
const pb = b.replace(/^v/, "").split(".").map(Number);
|
|
24808
|
+
for (let i = 0;i < Math.max(pa.length, pb.length); i++) {
|
|
24809
|
+
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
24810
|
+
if (diff !== 0)
|
|
24811
|
+
return diff;
|
|
24812
|
+
}
|
|
24813
|
+
return 0;
|
|
24814
|
+
}
|
|
24815
|
+
var memoryCache = null;
|
|
24816
|
+
function loadFileCache(maxAge = FILE_CACHE_TTL) {
|
|
24817
|
+
try {
|
|
24818
|
+
const raw = readFileSync6(CACHE_PATH, "utf-8");
|
|
24819
|
+
const parsed = JSON.parse(raw);
|
|
24820
|
+
if (!parsed?.data?.version || typeof parsed.fetchedAt !== "number")
|
|
24821
|
+
return null;
|
|
24822
|
+
if (Date.now() - parsed.fetchedAt > maxAge)
|
|
24823
|
+
return null;
|
|
24824
|
+
return parsed.data;
|
|
24825
|
+
} catch {
|
|
24826
|
+
return null;
|
|
24827
|
+
}
|
|
24828
|
+
}
|
|
24829
|
+
function loadFileCacheSync() {
|
|
24830
|
+
return loadFileCache();
|
|
24831
|
+
}
|
|
24832
|
+
function saveFileCache(data) {
|
|
24833
|
+
try {
|
|
24834
|
+
const dir = dirname4(CACHE_PATH);
|
|
24835
|
+
if (!existsSync3(dir))
|
|
24836
|
+
mkdirSync4(dir, { recursive: true });
|
|
24837
|
+
writeFileSync2(CACHE_PATH, JSON.stringify({ data, fetchedAt: Date.now() }));
|
|
24838
|
+
} catch {}
|
|
24839
|
+
}
|
|
24840
|
+
async function fetchLatestRelease() {
|
|
24841
|
+
if (memoryCache && Date.now() - memoryCache.fetchedAt < MEMORY_CACHE_TTL) {
|
|
24842
|
+
return memoryCache.data;
|
|
24843
|
+
}
|
|
24844
|
+
const fileCached = loadFileCache();
|
|
24845
|
+
if (fileCached) {
|
|
24846
|
+
memoryCache = { data: fileCached, fetchedAt: Date.now() };
|
|
24847
|
+
return fileCached;
|
|
24848
|
+
}
|
|
24849
|
+
const res = await fetch(GITHUB_API, {
|
|
24850
|
+
headers: {
|
|
24851
|
+
accept: "application/vnd.github+json",
|
|
24852
|
+
"user-agent": `mikrotik-mcp/${VERSION}`
|
|
24853
|
+
}
|
|
24854
|
+
});
|
|
24855
|
+
if (!res.ok)
|
|
24856
|
+
throw new Error(`GitHub API ${res.status}`);
|
|
24857
|
+
const gh = await res.json();
|
|
24858
|
+
const latestVersion = gh.tag_name.replace(/^v/, "");
|
|
24859
|
+
const data = {
|
|
24860
|
+
version: latestVersion,
|
|
24861
|
+
name: gh.name || `v${latestVersion}`,
|
|
24862
|
+
body: gh.body || "",
|
|
24863
|
+
publishedAt: gh.published_at,
|
|
24864
|
+
url: gh.html_url,
|
|
24865
|
+
isNewer: compareVersions(latestVersion, VERSION) > 0,
|
|
24866
|
+
currentVersion: VERSION
|
|
24867
|
+
};
|
|
24868
|
+
memoryCache = { data, fetchedAt: Date.now() };
|
|
24869
|
+
saveFileCache(data);
|
|
24870
|
+
return data;
|
|
24871
|
+
}
|
|
24872
|
+
async function checkForUpdate() {
|
|
24873
|
+
try {
|
|
24874
|
+
const release = await fetchLatestRelease();
|
|
24875
|
+
return { release, checkedAt: Date.now(), fromCache: false };
|
|
24876
|
+
} catch (e) {
|
|
24877
|
+
const stale = loadFileCache(Infinity);
|
|
24878
|
+
if (stale) {
|
|
24879
|
+
return { release: stale, checkedAt: Date.now(), fromCache: true };
|
|
24880
|
+
}
|
|
24881
|
+
return {
|
|
24882
|
+
release: null,
|
|
24883
|
+
checkedAt: Date.now(),
|
|
24884
|
+
fromCache: false,
|
|
24885
|
+
error: e instanceof Error ? e.message : String(e)
|
|
24886
|
+
};
|
|
24887
|
+
}
|
|
24888
|
+
}
|
|
24889
|
+
function assessFreshness(current, latest) {
|
|
24890
|
+
const ca = current.replace(/^v/, "").split(".").map(Number);
|
|
24891
|
+
const la = latest.replace(/^v/, "").split(".").map(Number);
|
|
24892
|
+
const majorDiff = (la[0] ?? 0) - (ca[0] ?? 0);
|
|
24893
|
+
const minorDiff = (la[1] ?? 0) - (ca[1] ?? 0);
|
|
24894
|
+
const patchDiff = (la[2] ?? 0) - (ca[2] ?? 0);
|
|
24895
|
+
if (majorDiff > 0)
|
|
24896
|
+
return "ancient";
|
|
24897
|
+
if (minorDiff > 1)
|
|
24898
|
+
return "stale";
|
|
24899
|
+
if (minorDiff === 1)
|
|
24900
|
+
return "aging";
|
|
24901
|
+
if (patchDiff > 1)
|
|
24902
|
+
return "aging";
|
|
24903
|
+
return "fresh";
|
|
24904
|
+
}
|
|
24905
|
+
function updateSummaryLine(release) {
|
|
24906
|
+
if (!release.isNewer)
|
|
24907
|
+
return null;
|
|
24908
|
+
return `Server update available: MikroTik MCP v${release.version} ` + `(you are running v${VERSION}). ` + `Call check_server_pulse for release notes and upgrade commands, ` + `or upgrade directly: bun i -g @usex/mikrotik-mcp@latest`;
|
|
24909
|
+
}
|
|
24910
|
+
|
|
24911
|
+
// src/tools/server-pulse.ts
|
|
24912
|
+
var UPGRADE_COMMANDS = {
|
|
24913
|
+
bunx: "bunx @usex/mikrotik-mcp@latest",
|
|
24914
|
+
npx: "npx @usex/mikrotik-mcp@latest",
|
|
24915
|
+
"bun global": "bun add -g @usex/mikrotik-mcp@latest",
|
|
24916
|
+
"npm global": "npm install -g @usex/mikrotik-mcp@latest"
|
|
24917
|
+
};
|
|
24918
|
+
function formatUptime(seconds) {
|
|
24919
|
+
const d = Math.floor(seconds / 86400);
|
|
24920
|
+
const h = Math.floor(seconds % 86400 / 3600);
|
|
24921
|
+
const m = Math.floor(seconds % 3600 / 60);
|
|
24922
|
+
const s = seconds % 60;
|
|
24923
|
+
const parts = [];
|
|
24924
|
+
if (d)
|
|
24925
|
+
parts.push(`${d}d`);
|
|
24926
|
+
if (h)
|
|
24927
|
+
parts.push(`${h}h`);
|
|
24928
|
+
if (m)
|
|
24929
|
+
parts.push(`${m}m`);
|
|
24930
|
+
parts.push(`${s}s`);
|
|
24931
|
+
return parts.join(" ");
|
|
24932
|
+
}
|
|
24933
|
+
function freshnessLabel(f) {
|
|
24934
|
+
const labels = {
|
|
24935
|
+
fresh: "UP TO DATE",
|
|
24936
|
+
aging: "SLIGHTLY BEHIND",
|
|
24937
|
+
stale: "UPDATE RECOMMENDED",
|
|
24938
|
+
ancient: "CRITICAL UPDATE NEEDED"
|
|
24939
|
+
};
|
|
24940
|
+
return labels[f];
|
|
24941
|
+
}
|
|
24942
|
+
function timeAgo(iso) {
|
|
24943
|
+
const diff = Date.now() - new Date(iso).getTime();
|
|
24944
|
+
const days = Math.floor(diff / 86400000);
|
|
24945
|
+
if (days < 1)
|
|
24946
|
+
return "today";
|
|
24947
|
+
if (days === 1)
|
|
24948
|
+
return "yesterday";
|
|
24949
|
+
if (days < 30)
|
|
24950
|
+
return `${days} days ago`;
|
|
24951
|
+
if (days < 365)
|
|
24952
|
+
return `${Math.floor(days / 30)} months ago`;
|
|
24953
|
+
return `${Math.floor(days / 365)} years ago`;
|
|
24954
|
+
}
|
|
24955
|
+
var serverPulseTools = [
|
|
24956
|
+
defineTool({
|
|
24957
|
+
name: "check_server_pulse",
|
|
24958
|
+
title: "Server Pulse & Update Check",
|
|
24959
|
+
noDevice: true,
|
|
24960
|
+
annotations: READ,
|
|
24961
|
+
description: "Check the MCP server's own heartbeat: running version, whether a newer release " + "is available, release notes for the latest version, upgrade commands, and server " + "vitals (tool count, uptime). This is server self-awareness \u2014 no RouterOS device " + "is contacted. Call this when the user asks about the MCP server version, updates, " + "what's new, or 'is my server up to date'. Returns rich release notes from GitHub " + "so you can summarize what changed.",
|
|
24962
|
+
inputSchema: {
|
|
24963
|
+
include_release_notes: z104.boolean().optional().describe("Include the full GitHub release notes markdown (default true). " + "Set false for a compact version-only check.")
|
|
24964
|
+
},
|
|
24965
|
+
async handler(args) {
|
|
24966
|
+
const includeNotes = args.include_release_notes !== false;
|
|
24967
|
+
const result = await checkForUpdate();
|
|
24968
|
+
const uptime = Math.floor(process.uptime());
|
|
24969
|
+
const sections = [];
|
|
24970
|
+
const sep = "\u2500".repeat(50);
|
|
24971
|
+
sections.push(`SERVER PULSE \u2014 ${SERVER_TITLE} v${VERSION}`, sep, "Package: @usex/mikrotik-mcp", `Version: ${VERSION}`, `Uptime: ${formatUptime(uptime)}`, `Website: ${WEBSITE_URL}`);
|
|
24972
|
+
if (result.release) {
|
|
24973
|
+
const freshness = assessFreshness(VERSION, result.release.version);
|
|
24974
|
+
const label = freshnessLabel(freshness);
|
|
24975
|
+
const age = timeAgo(result.release.publishedAt);
|
|
24976
|
+
sections.push("", `UPDATE STATUS: ${label}`, sep, `Current: v${VERSION}`, `Latest: v${result.release.version} (${result.release.name})`, `Published: ${age}`, `Freshness: ${freshness.toUpperCase()}`);
|
|
24977
|
+
if (result.release.isNewer) {
|
|
24978
|
+
sections.push("", ">>> A newer version is available! <<<");
|
|
24979
|
+
} else {
|
|
24980
|
+
sections.push("", "You are running the latest version.");
|
|
24981
|
+
}
|
|
24982
|
+
if (result.release.isNewer) {
|
|
24983
|
+
sections.push("", "UPGRADE", sep);
|
|
24984
|
+
for (const [method, cmd] of Object.entries(UPGRADE_COMMANDS)) {
|
|
24985
|
+
sections.push(` ${method.padEnd(12)} ${cmd}`);
|
|
24986
|
+
}
|
|
24987
|
+
sections.push("", `Release: ${result.release.url}`);
|
|
24988
|
+
}
|
|
24989
|
+
if (includeNotes && result.release.body) {
|
|
24990
|
+
const notesHeader = result.release.isNewer ? `WHAT'S NEW IN v${result.release.version}` : `RELEASE NOTES \u2014 v${result.release.version}`;
|
|
24991
|
+
sections.push("", notesHeader, sep, result.release.body);
|
|
24992
|
+
}
|
|
24993
|
+
} else {
|
|
24994
|
+
sections.push("", "UPDATE STATUS: UNKNOWN", sep, `Could not check for updates${result.error ? `: ${result.error}` : "."}`, `Current version: v${VERSION}`, result.fromCache ? "(showing cached data)" : "(no cached data available \u2014 check network connectivity)");
|
|
24995
|
+
}
|
|
24996
|
+
return sections.join(`
|
|
24997
|
+
`);
|
|
24998
|
+
}
|
|
24999
|
+
})
|
|
25000
|
+
];
|
|
25001
|
+
|
|
25002
|
+
// src/tools/threat-feed.ts
|
|
25003
|
+
import { z as z105 } from "zod";
|
|
24780
25004
|
var FEED_TAG = "threat-feed";
|
|
24781
25005
|
var threatFeedTools = [
|
|
24782
25006
|
defineTool({
|
|
@@ -24785,12 +25009,12 @@ var threatFeedTools = [
|
|
|
24785
25009
|
annotations: WRITE,
|
|
24786
25010
|
description: "Subscribes the router to an external threat-intelligence IP feed: installs a `/system script` " + "that fetches `url` and imports it into the `address_list`, a `/system scheduler` that re-runs it " + "every `interval`, and (when `drop=true`) a raw pre-conntrack drop for that list \u2014 a self-updating " + "blocklist (e.g. Spamhaus DROP, tor exit nodes, your own deny list). `url` MUST point to a " + "RouterOS `.rsc` file that populates the address-list. DEFAULTS TO A DRY RUN (`apply=false`); set " + "`apply=true` to install. Script/scheduler/rule are named/tagged `threat-feed-<name>` so " + "remove_threat_feed can undo them. Returns the plan or a build report.",
|
|
24787
25011
|
inputSchema: {
|
|
24788
|
-
name:
|
|
24789
|
-
url:
|
|
24790
|
-
address_list:
|
|
24791
|
-
interval:
|
|
24792
|
-
drop:
|
|
24793
|
-
apply:
|
|
25012
|
+
name: z105.string().describe("Short feed id, e.g. 'spamhaus-drop'"),
|
|
25013
|
+
url: z105.string().describe("HTTPS URL of a RouterOS .rsc address-list file"),
|
|
25014
|
+
address_list: z105.string().default("threat-blocklist").describe("Address-list to populate"),
|
|
25015
|
+
interval: z105.string().default("1h").describe("How often to refresh the feed"),
|
|
25016
|
+
drop: z105.boolean().default(true).describe("Also add a raw drop rule for the address-list"),
|
|
25017
|
+
apply: z105.boolean().default(false).describe("false = preview (default); true = install")
|
|
24794
25018
|
},
|
|
24795
25019
|
async handler(a, ctx) {
|
|
24796
25020
|
const id = `${FEED_TAG}-${a.name}`;
|
|
@@ -24827,7 +25051,7 @@ ${plan}`;
|
|
|
24827
25051
|
title: "Remove Threat-Intel Feed",
|
|
24828
25052
|
annotations: DESTRUCTIVE,
|
|
24829
25053
|
description: "Removes a threat feed installed by subscribe_threat_feed: deletes its `/system scheduler` and " + "`/system script` (named `threat-feed-<name>`) and any raw drop rule tagged for it. Does NOT " + "flush the address-list entries themselves. Returns what was removed.",
|
|
24830
|
-
inputSchema: { name:
|
|
25054
|
+
inputSchema: { name: z105.string().describe("The feed id used when subscribing") },
|
|
24831
25055
|
async handler(a, ctx) {
|
|
24832
25056
|
const id = `${FEED_TAG}-${a.name}`;
|
|
24833
25057
|
ctx.info(`Removing threat feed ${id}`);
|
|
@@ -24849,7 +25073,7 @@ ${plan}`;
|
|
|
24849
25073
|
];
|
|
24850
25074
|
|
|
24851
25075
|
// src/tools/sstp.ts
|
|
24852
|
-
import { z as
|
|
25076
|
+
import { z as z106 } from "zod";
|
|
24853
25077
|
var sstpTools = [
|
|
24854
25078
|
defineTool({
|
|
24855
25079
|
name: "get_sstp_server",
|
|
@@ -24870,19 +25094,19 @@ ${result}`;
|
|
|
24870
25094
|
annotations: WRITE_IDEMPOTENT,
|
|
24871
25095
|
description: "Configure the global SSTP server listener (`/interface sstp-server server set`) \u2014 accepts/rejects incoming TLS VPN connections on this router. " + "Use to enable the server, bind a TLS certificate, change the TCP port, restrict authentication methods (comma-separated, e.g. `'mschap2,mschap1'`), set the default PPP profile, pin TLS version (`any` or `only-1.2`), or enforce client certificate verification. " + "This is a singleton write that modifies the server block, not a client interface. " + "To read the current server config use `get_sstp_server`. " + "To create outbound SSTP tunnels (this router dials out) use `create_sstp_client`; for L2TP outbound use `create_l2tp_client`, for OpenVPN use `create_ovpn_client`, for PPTP use `create_pptp_client`. " + "Returns the updated server block on success.",
|
|
24872
25096
|
inputSchema: {
|
|
24873
|
-
enabled:
|
|
24874
|
-
default_profile:
|
|
24875
|
-
authentication:
|
|
24876
|
-
certificate:
|
|
24877
|
-
port:
|
|
24878
|
-
tls_version:
|
|
24879
|
-
verify_client_certificate:
|
|
24880
|
-
pfs:
|
|
24881
|
-
force_aes:
|
|
24882
|
-
max_mtu:
|
|
24883
|
-
max_mru:
|
|
24884
|
-
mrru:
|
|
24885
|
-
keepalive_timeout:
|
|
25097
|
+
enabled: z106.boolean().optional(),
|
|
25098
|
+
default_profile: z106.string().optional(),
|
|
25099
|
+
authentication: z106.string().optional().describe("Comma-separated, e.g. 'mschap2,mschap1'"),
|
|
25100
|
+
certificate: z106.string().optional().describe("TLS certificate name"),
|
|
25101
|
+
port: z106.number().int().optional(),
|
|
25102
|
+
tls_version: z106.enum(["any", "only-1.2"]).optional(),
|
|
25103
|
+
verify_client_certificate: z106.boolean().optional(),
|
|
25104
|
+
pfs: z106.boolean().optional().describe("Enable Perfect Forward Secrecy"),
|
|
25105
|
+
force_aes: z106.boolean().optional().describe("Require clients to use AES ciphers"),
|
|
25106
|
+
max_mtu: z106.number().int().optional().describe("Maximum transmission unit"),
|
|
25107
|
+
max_mru: z106.number().int().optional().describe("Maximum receive unit"),
|
|
25108
|
+
mrru: z106.number().int().optional().describe("Max receive reconstructed unit for MP"),
|
|
25109
|
+
keepalive_timeout: z106.number().int().optional().describe("Seconds before an idle connection is considered down")
|
|
24886
25110
|
},
|
|
24887
25111
|
async handler(a, ctx) {
|
|
24888
25112
|
ctx.info("Configuring SSTP server");
|
|
@@ -24904,27 +25128,27 @@ ${details}`;
|
|
|
24904
25128
|
annotations: WRITE,
|
|
24905
25129
|
description: "Create an outbound SSTP client tunnel interface (`/interface sstp-client add`) so this router dials out to a remote SSTP server over TLS. " + "Use when this device must act as a VPN client, not the VPN server \u2014 for server-side settings use `set_sstp_server`. " + "`connect_to` is the remote server address (IP or DNS name); the TCP port is separate. " + "You may pass the port in `port` or inline as `host:port` in `connect_to` (it is split out " + "automatically \u2014 RouterOS rejects a port embedded in connect-to). SSTP defaults to 443. " + "For L2TP outbound tunnels use `create_l2tp_client`, for OpenVPN use `create_ovpn_client`, for PPTP use `create_pptp_client`. " + "Credentials are accepted but redacted from return values. " + "Returns the created interface detail (name, status, remote address); use the interface `name` with `get_sstp_client` or `remove_sstp_client`.",
|
|
24906
25130
|
inputSchema: {
|
|
24907
|
-
name:
|
|
24908
|
-
connect_to:
|
|
24909
|
-
port:
|
|
24910
|
-
user:
|
|
24911
|
-
password:
|
|
24912
|
-
profile:
|
|
24913
|
-
certificate:
|
|
24914
|
-
verify_server_certificate:
|
|
24915
|
-
authentication:
|
|
24916
|
-
tls_version:
|
|
24917
|
-
pfs:
|
|
24918
|
-
add_default_route:
|
|
24919
|
-
default_route_distance:
|
|
24920
|
-
dial_on_demand:
|
|
24921
|
-
max_mtu:
|
|
24922
|
-
max_mru:
|
|
24923
|
-
mrru:
|
|
24924
|
-
keepalive_timeout:
|
|
24925
|
-
http_proxy:
|
|
24926
|
-
comment:
|
|
24927
|
-
disabled:
|
|
25131
|
+
name: z106.string().describe("Name for the new SSTP client interface"),
|
|
25132
|
+
connect_to: z106.string().describe("Remote SSTP server address (IP or DNS name; host:port also accepted)"),
|
|
25133
|
+
port: z106.number().int().optional().describe("TCP port (default 443 if omitted)"),
|
|
25134
|
+
user: z106.string(),
|
|
25135
|
+
password: z106.string(),
|
|
25136
|
+
profile: z106.string().optional(),
|
|
25137
|
+
certificate: z106.string().optional().describe("Client TLS certificate name"),
|
|
25138
|
+
verify_server_certificate: z106.boolean().optional(),
|
|
25139
|
+
authentication: z106.string().optional().describe("Comma-separated, e.g. 'mschap2,mschap1'"),
|
|
25140
|
+
tls_version: z106.enum(["any", "only-1.2"]).optional(),
|
|
25141
|
+
pfs: z106.boolean().optional().describe("Enable Perfect Forward Secrecy"),
|
|
25142
|
+
add_default_route: z106.boolean().optional(),
|
|
25143
|
+
default_route_distance: z106.number().int().optional().describe("Distance of the auto-added default route"),
|
|
25144
|
+
dial_on_demand: z106.boolean().optional().describe("Connect only when traffic is sent over the tunnel"),
|
|
25145
|
+
max_mtu: z106.number().int().optional().describe("Maximum transmission unit"),
|
|
25146
|
+
max_mru: z106.number().int().optional().describe("Maximum receive unit"),
|
|
25147
|
+
mrru: z106.number().int().optional().describe("Max receive reconstructed unit for MP"),
|
|
25148
|
+
keepalive_timeout: z106.number().int().optional().describe("Seconds before an idle connection is considered down"),
|
|
25149
|
+
http_proxy: z106.string().optional(),
|
|
25150
|
+
comment: z106.string().optional(),
|
|
25151
|
+
disabled: z106.boolean().default(false)
|
|
24928
25152
|
},
|
|
24929
25153
|
async handler(a, ctx) {
|
|
24930
25154
|
ctx.info(`Creating SSTP client: name=${a.name}, connect_to=${a.connect_to}`);
|
|
@@ -24945,7 +25169,7 @@ ${redactSecrets(details)}` : "SSTP client creation completed but unable to verif
|
|
|
24945
25169
|
annotations: READ,
|
|
24946
25170
|
description: "List all outbound SSTP client tunnel interfaces (`/interface sstp-client print`), optionally narrowed by partial name match via `name_filter`. " + "Use to discover existing SSTP tunnels and their connection status before creating or removing one. " + "Passwords are redacted in the output. " + "For full detail on a single client use `get_sstp_client` with the interface name. " + "To inspect the inbound SSTP server config use `get_sstp_server`. " + "Returns a summary list of all matching SSTP client entries.",
|
|
24947
25171
|
inputSchema: {
|
|
24948
|
-
name_filter:
|
|
25172
|
+
name_filter: z106.string().optional().describe("Partial name match")
|
|
24949
25173
|
},
|
|
24950
25174
|
async handler(a, ctx) {
|
|
24951
25175
|
ctx.info("Listing SSTP clients");
|
|
@@ -24963,7 +25187,7 @@ ${redactSecrets(result)}`;
|
|
|
24963
25187
|
title: "Get SSTP Client Interface Detail",
|
|
24964
25188
|
annotations: READ,
|
|
24965
25189
|
description: "Return full detail for one SSTP client interface (`/interface sstp-client print detail where name=...`) by interface name \u2014 includes status, remote server address, TLS certificate, PPP profile, and connection options; passwords are redacted. " + "Use when you need the complete property set for a single tunnel rather than the summary list. " + "Use `list_sstp_clients` first to discover valid interface names. " + "For the inbound server configuration use `get_sstp_server`. " + "Returns the full detail block for the named interface, or a not-found message.",
|
|
24966
|
-
inputSchema: { name:
|
|
25190
|
+
inputSchema: { name: z106.string() },
|
|
24967
25191
|
async handler(a, ctx) {
|
|
24968
25192
|
ctx.info(`Getting SSTP client details: name=${a.name}`);
|
|
24969
25193
|
const result = await executeMikrotikCommand(`/interface sstp-client print detail where name="${a.name}"`, ctx);
|
|
@@ -24977,7 +25201,7 @@ ${redactSecrets(result)}`;
|
|
|
24977
25201
|
title: "Remove SSTP Client Interface",
|
|
24978
25202
|
annotations: DESTRUCTIVE,
|
|
24979
25203
|
description: "Permanently delete an SSTP client tunnel interface (`/interface sstp-client remove [find name=...]`) by interface name. " + "First verifies the interface exists (count-only check), then removes it; the tunnel is torn down immediately and the action is irreversible. " + "Use `list_sstp_clients` to confirm the interface name before calling this tool. " + "For L2TP, OpenVPN, or PPTP client interfaces see their respective tool scopes (`create_l2tp_client`, `create_ovpn_client`, `create_pptp_client`). " + "To deactivate the interface without deleting it use `disable_sstp_client` (re-activate with `enable_sstp_client`). " + "Returns a confirmation message on success or a not-found message if the name does not exist.",
|
|
24980
|
-
inputSchema: { name:
|
|
25204
|
+
inputSchema: { name: z106.string() },
|
|
24981
25205
|
async handler(a, ctx) {
|
|
24982
25206
|
ctx.info(`Removing SSTP client: name=${a.name}`);
|
|
24983
25207
|
const count = await executeMikrotikCommand(`/interface sstp-client print count-only where name="${a.name}"`, ctx);
|
|
@@ -24994,7 +25218,7 @@ ${redactSecrets(result)}`;
|
|
|
24994
25218
|
title: "Enable SSTP Client Interface",
|
|
24995
25219
|
annotations: WRITE_IDEMPOTENT,
|
|
24996
25220
|
description: "Enables a disabled SSTP client interface (`/interface sstp-client enable [find name=...]`), " + "causing the router to dial out and attempt the TLS connection to the remote SSTP server. " + "Use to activate a tunnel that was created disabled or stopped with `disable_sstp_client`. " + "For L2TP/PPTP/OpenVPN tunnels use their own enable tools. " + "Identifies the interface by name \u2014 create one with `create_sstp_client`.",
|
|
24997
|
-
inputSchema: { name:
|
|
25221
|
+
inputSchema: { name: z106.string() },
|
|
24998
25222
|
async handler(a, ctx) {
|
|
24999
25223
|
ctx.info(`Enabling SSTP client: name=${a.name}`);
|
|
25000
25224
|
const count = await executeMikrotikCommand(`/interface sstp-client print count-only where name="${a.name}"`, ctx);
|
|
@@ -25011,7 +25235,7 @@ ${redactSecrets(result)}`;
|
|
|
25011
25235
|
title: "Disable SSTP Client Interface",
|
|
25012
25236
|
annotations: WRITE_IDEMPOTENT,
|
|
25013
25237
|
description: "Disables an active SSTP client interface (`/interface sstp-client disable [find name=...]`), " + "tearing down the tunnel without removing its configuration. " + "Use to temporarily stop a tunnel while preserving its settings for later reuse. " + "To re-enable use `enable_sstp_client`; to permanently remove use `remove_sstp_client`.",
|
|
25014
|
-
inputSchema: { name:
|
|
25238
|
+
inputSchema: { name: z106.string() },
|
|
25015
25239
|
async handler(a, ctx) {
|
|
25016
25240
|
ctx.info(`Disabling SSTP client: name=${a.name}`);
|
|
25017
25241
|
const count = await executeMikrotikCommand(`/interface sstp-client print count-only where name="${a.name}"`, ctx);
|
|
@@ -25026,7 +25250,7 @@ ${redactSecrets(result)}`;
|
|
|
25026
25250
|
];
|
|
25027
25251
|
|
|
25028
25252
|
// src/tools/switch-settings.ts
|
|
25029
|
-
import { z as
|
|
25253
|
+
import { z as z107 } from "zod";
|
|
25030
25254
|
var switchSettingsTools = [
|
|
25031
25255
|
defineTool({
|
|
25032
25256
|
name: "list_switches",
|
|
@@ -25034,8 +25258,8 @@ var switchSettingsTools = [
|
|
|
25034
25258
|
annotations: READ,
|
|
25035
25259
|
description: "Lists hardware switch chips (`/interface ethernet switch`). " + "Use to discover switch chip names and types present on the device before targeting a chip with get_switch or update_switch. " + "Accepts optional `name_filter` and `type_filter` for partial-match filtering. " + "Returns chip name, type, and mirror/flow-control configuration for each matching entry; returns an empty message if none match.",
|
|
25036
25260
|
inputSchema: {
|
|
25037
|
-
name_filter:
|
|
25038
|
-
type_filter:
|
|
25261
|
+
name_filter: z107.string().optional().describe("Partial switch-name match"),
|
|
25262
|
+
type_filter: z107.string().optional().describe("Partial switch-type match")
|
|
25039
25263
|
},
|
|
25040
25264
|
async handler(a, ctx) {
|
|
25041
25265
|
ctx.info("Listing switches");
|
|
@@ -25056,7 +25280,7 @@ ${result}`;
|
|
|
25056
25280
|
annotations: READ,
|
|
25057
25281
|
description: "Fetches full detail for a single hardware switch chip (`/interface ethernet switch print detail`). " + "Use to inspect the current cpu-flow-control flag and mirror-source, mirror-target, and mirror-egress settings before modifying them with update_switch. " + "`switch_id` accepts the chip name (e.g. 'switch1') or the RouterOS `.id` returned by list_switches \u2014 tries `.id` lookup first, then falls back to name lookup. " + "Returns detailed chip settings or a not-found message.",
|
|
25058
25282
|
inputSchema: {
|
|
25059
|
-
switch_id:
|
|
25283
|
+
switch_id: z107.string().describe("Switch name (e.g. 'switch1') or RouterOS '.id'")
|
|
25060
25284
|
},
|
|
25061
25285
|
async handler(a, ctx) {
|
|
25062
25286
|
ctx.info(`Getting switch details: switch_id=${a.switch_id}`);
|
|
@@ -25080,14 +25304,14 @@ ${result}`;
|
|
|
25080
25304
|
|
|
25081
25305
|
` + "Returns updated switch details on success.",
|
|
25082
25306
|
inputSchema: {
|
|
25083
|
-
switch_id:
|
|
25084
|
-
name:
|
|
25085
|
-
cpu_flow_control:
|
|
25086
|
-
mirror_source:
|
|
25087
|
-
mirror_target:
|
|
25088
|
-
mirror_egress:
|
|
25089
|
-
mirror_egress_target:
|
|
25090
|
-
switch_all_ports:
|
|
25307
|
+
switch_id: z107.string().describe("Switch name (e.g. 'switch1') or RouterOS '.id'"),
|
|
25308
|
+
name: z107.string().optional().describe("Rename the switch"),
|
|
25309
|
+
cpu_flow_control: z107.boolean().optional(),
|
|
25310
|
+
mirror_source: z107.string().optional().describe("Source port to mirror, or 'none'"),
|
|
25311
|
+
mirror_target: z107.string().optional().describe("Monitor port, 'cpu', or 'none'"),
|
|
25312
|
+
mirror_egress: z107.string().optional().describe("Egress mirror source port (newer chips), or 'none'"),
|
|
25313
|
+
mirror_egress_target: z107.string().optional().describe("Egress mirror target port (88E6393X/88E6191X/88E6190 chips), or 'none'"),
|
|
25314
|
+
switch_all_ports: z107.boolean().optional().describe("Switch all ports together (RB450G/RB435G/RB850Gx2 only)")
|
|
25091
25315
|
},
|
|
25092
25316
|
async handler(a, ctx) {
|
|
25093
25317
|
ctx.info(`Updating switch: switch_id=${a.switch_id}`);
|
|
@@ -25110,9 +25334,9 @@ ${details}`;
|
|
|
25110
25334
|
];
|
|
25111
25335
|
|
|
25112
25336
|
// src/tools/switch-port.ts
|
|
25113
|
-
import { z as
|
|
25114
|
-
var VlanMode =
|
|
25115
|
-
var VlanHeader =
|
|
25337
|
+
import { z as z108 } from "zod";
|
|
25338
|
+
var VlanMode = z108.enum(["disabled", "optional", "enabled", "secure"]);
|
|
25339
|
+
var VlanHeader = z108.enum(["leave-as-is", "always-strip", "add-if-missing"]);
|
|
25116
25340
|
var switchPortTools = [
|
|
25117
25341
|
defineTool({
|
|
25118
25342
|
name: "list_switch_ports",
|
|
@@ -25120,8 +25344,8 @@ var switchPortTools = [
|
|
|
25120
25344
|
annotations: READ,
|
|
25121
25345
|
description: "List all switch chip ports (`/interface ethernet switch port print`) \u2014 the hardware-level " + "per-port VLAN configuration entries on RouterOS switch chips. " + "Use this to discover port names and their current vlan-mode, vlan-header, and " + "default-vlan-id (PVID) settings before updating them. " + "For a single port's full detail use get_switch_port; to change settings use update_switch_port. " + "Optional filters narrow results by partial port name or owning switch (e.g. 'switch1'). " + "Returns all matching port rows including VLAN mode, tag-header treatment, and PVID.",
|
|
25122
25346
|
inputSchema: {
|
|
25123
|
-
name_filter:
|
|
25124
|
-
switch_filter:
|
|
25347
|
+
name_filter: z108.string().optional().describe("Partial port-name match"),
|
|
25348
|
+
switch_filter: z108.string().optional().describe("Filter by owning switch, e.g. 'switch1'")
|
|
25125
25349
|
},
|
|
25126
25350
|
async handler(a, ctx) {
|
|
25127
25351
|
ctx.info("Listing switch ports");
|
|
@@ -25142,7 +25366,7 @@ ${result}`;
|
|
|
25142
25366
|
annotations: READ,
|
|
25143
25367
|
description: "Retrieve detailed settings for a single switch chip port (`/interface ethernet switch port print detail`) " + "by port name (e.g. 'ether1') or RouterOS '.id' from list_switch_ports. " + "Use this when you need the full attribute set of one port before updating it; " + "for all ports use list_switch_ports; to change settings use update_switch_port. " + "Returns a detailed view of vlan-mode, vlan-header, default-vlan-id, and force-vlan-id for the matched port.",
|
|
25144
25368
|
inputSchema: {
|
|
25145
|
-
port_id:
|
|
25369
|
+
port_id: z108.string().describe("Port name (e.g. 'ether1') or RouterOS '.id'")
|
|
25146
25370
|
},
|
|
25147
25371
|
async handler(a, ctx) {
|
|
25148
25372
|
ctx.info(`Getting switch port details: port_id=${a.port_id}`);
|
|
@@ -25168,11 +25392,11 @@ ${result}`;
|
|
|
25168
25392
|
` + ` 'always-strip', or 'add-if-missing'.
|
|
25169
25393
|
` + " default_vlan_id: PVID for untagged ingress ('auto', 'none', or a number).",
|
|
25170
25394
|
inputSchema: {
|
|
25171
|
-
port_id:
|
|
25172
|
-
default_vlan_id:
|
|
25395
|
+
port_id: z108.string().describe("Port name (e.g. 'ether1') or RouterOS '.id'"),
|
|
25396
|
+
default_vlan_id: z108.string().optional().describe("PVID: 'auto', 'none', or a VLAN id number"),
|
|
25173
25397
|
vlan_mode: VlanMode.optional(),
|
|
25174
25398
|
vlan_header: VlanHeader.optional(),
|
|
25175
|
-
force_vlan_id:
|
|
25399
|
+
force_vlan_id: z108.boolean().optional()
|
|
25176
25400
|
},
|
|
25177
25401
|
async handler(a, ctx) {
|
|
25178
25402
|
ctx.info(`Updating switch port: port_id=${a.port_id}`);
|
|
@@ -25194,7 +25418,7 @@ ${details}`;
|
|
|
25194
25418
|
];
|
|
25195
25419
|
|
|
25196
25420
|
// src/tools/switch-port-isolation.ts
|
|
25197
|
-
import { z as
|
|
25421
|
+
import { z as z109 } from "zod";
|
|
25198
25422
|
function selectorFor(id) {
|
|
25199
25423
|
return id.startsWith("*") ? `.id="${id}"` : `port="${id}"`;
|
|
25200
25424
|
}
|
|
@@ -25211,9 +25435,9 @@ var switchPortIsolationTools = [
|
|
|
25211
25435
|
` + ` port: source port to isolate, e.g. 'ether1'.
|
|
25212
25436
|
` + " forwarding_override_ports: comma-separated list of the ONLY ports this port " + " may forward to \u2014 all others are blocked in hardware.",
|
|
25213
25437
|
inputSchema: {
|
|
25214
|
-
port:
|
|
25215
|
-
forwarding_override_ports:
|
|
25216
|
-
comment:
|
|
25438
|
+
port: z109.string().describe("Source port to isolate, e.g. 'ether1'"),
|
|
25439
|
+
forwarding_override_ports: z109.string().describe("Comma-separated allowed destination ports"),
|
|
25440
|
+
comment: z109.string().optional()
|
|
25217
25441
|
},
|
|
25218
25442
|
async handler(a, ctx) {
|
|
25219
25443
|
ctx.info(`Adding switch port-isolation: port=${a.port}`);
|
|
@@ -25235,7 +25459,7 @@ ${details}` : "Switch port-isolation addition completed but unable to verify.";
|
|
|
25235
25459
|
|
|
25236
25460
|
` + "Returns a table of all matching entries; optionally filter by partial port name via port_filter.",
|
|
25237
25461
|
inputSchema: {
|
|
25238
|
-
port_filter:
|
|
25462
|
+
port_filter: z109.string().optional().describe("Partial source-port match")
|
|
25239
25463
|
},
|
|
25240
25464
|
async handler(a, ctx) {
|
|
25241
25465
|
ctx.info("Listing switch port-isolation entries");
|
|
@@ -25256,7 +25480,7 @@ ${result}`;
|
|
|
25256
25480
|
|
|
25257
25481
|
` + "Returns the full detail block for the matched entry, or a not-found message.",
|
|
25258
25482
|
inputSchema: {
|
|
25259
|
-
isolation_id:
|
|
25483
|
+
isolation_id: z109.string().describe("Source port name (e.g. 'ether1') or RouterOS '.id'")
|
|
25260
25484
|
},
|
|
25261
25485
|
async handler(a, ctx) {
|
|
25262
25486
|
ctx.info(`Getting switch port-isolation: isolation_id=${a.isolation_id}`);
|
|
@@ -25276,9 +25500,9 @@ ${result}`;
|
|
|
25276
25500
|
|
|
25277
25501
|
` + "Returns the entry's updated detail block.",
|
|
25278
25502
|
inputSchema: {
|
|
25279
|
-
isolation_id:
|
|
25280
|
-
forwarding_override_ports:
|
|
25281
|
-
comment:
|
|
25503
|
+
isolation_id: z109.string().describe("Source port name or RouterOS '.id'"),
|
|
25504
|
+
forwarding_override_ports: z109.string().optional().describe("Comma-separated allowed destination ports"),
|
|
25505
|
+
comment: z109.string().optional()
|
|
25282
25506
|
},
|
|
25283
25507
|
async handler(a, ctx) {
|
|
25284
25508
|
ctx.info(`Updating switch port-isolation: isolation_id=${a.isolation_id}`);
|
|
@@ -25307,7 +25531,7 @@ ${details}`;
|
|
|
25307
25531
|
|
|
25308
25532
|
` + "isolation_id accepts either the source port name (e.g. 'ether1') or the RouterOS `.id` " + "(e.g. '*1') from list_switch_port_isolation. Performs a count-only existence check before " + "removal and returns a not-found message if the entry does not exist. To add a new isolation rule " + "afterwards use add_switch_port_isolation; to only modify allowed ports use update_switch_port_isolation.",
|
|
25309
25533
|
inputSchema: {
|
|
25310
|
-
isolation_id:
|
|
25534
|
+
isolation_id: z109.string().describe("Source port name or RouterOS '.id'")
|
|
25311
25535
|
},
|
|
25312
25536
|
async handler(a, ctx) {
|
|
25313
25537
|
ctx.info(`Removing switch port-isolation: isolation_id=${a.isolation_id}`);
|
|
@@ -25324,7 +25548,7 @@ ${details}`;
|
|
|
25324
25548
|
];
|
|
25325
25549
|
|
|
25326
25550
|
// src/tools/switch-rule.ts
|
|
25327
|
-
import { z as
|
|
25551
|
+
import { z as z110 } from "zod";
|
|
25328
25552
|
var isDigits8 = (s) => /^\d+$/.test(s);
|
|
25329
25553
|
async function updateSwitchRule(a, ctx) {
|
|
25330
25554
|
ctx.info(`Updating switch rule: rule_id=${a.rule_id}`);
|
|
@@ -25391,32 +25615,32 @@ var switchRuleTools = [
|
|
|
25391
25615
|
` + ` rate: rate limit in bits/second.
|
|
25392
25616
|
` + " mac_protocol: e.g. 'ip', 'arp', 'vlan', or an EtherType number.",
|
|
25393
25617
|
inputSchema: {
|
|
25394
|
-
switch:
|
|
25395
|
-
ports:
|
|
25396
|
-
src_address:
|
|
25397
|
-
dst_address:
|
|
25398
|
-
src_address6:
|
|
25399
|
-
dst_address6:
|
|
25400
|
-
src_mac_address:
|
|
25401
|
-
dst_mac_address:
|
|
25402
|
-
src_port:
|
|
25403
|
-
dst_port:
|
|
25404
|
-
protocol:
|
|
25405
|
-
mac_protocol:
|
|
25406
|
-
vlan_header:
|
|
25407
|
-
vlan_id:
|
|
25408
|
-
vlan_priority:
|
|
25409
|
-
dscp:
|
|
25410
|
-
flow_label:
|
|
25411
|
-
new_dst_ports:
|
|
25412
|
-
new_vlan_id:
|
|
25413
|
-
new_vlan_priority:
|
|
25414
|
-
redirect_to_cpu:
|
|
25415
|
-
copy_to_cpu:
|
|
25416
|
-
mirror:
|
|
25417
|
-
rate:
|
|
25418
|
-
comment:
|
|
25419
|
-
disabled:
|
|
25618
|
+
switch: z110.string().describe("Owning switch chip, e.g. 'switch1'"),
|
|
25619
|
+
ports: z110.string().describe("Comma-separated source ports the rule matches"),
|
|
25620
|
+
src_address: z110.string().optional().describe("Source IP/mask"),
|
|
25621
|
+
dst_address: z110.string().optional().describe("Destination IP/mask"),
|
|
25622
|
+
src_address6: z110.string().optional().describe("Source IPv6 address/mask"),
|
|
25623
|
+
dst_address6: z110.string().optional().describe("Destination IPv6 address/mask"),
|
|
25624
|
+
src_mac_address: z110.string().optional().describe("Source MAC/mask"),
|
|
25625
|
+
dst_mac_address: z110.string().optional().describe("Destination MAC/mask"),
|
|
25626
|
+
src_port: z110.string().optional().describe("Layer-4 source port(s)"),
|
|
25627
|
+
dst_port: z110.string().optional().describe("Layer-4 destination port(s)"),
|
|
25628
|
+
protocol: z110.string().optional().describe("IP protocol, e.g. 'tcp'"),
|
|
25629
|
+
mac_protocol: z110.string().optional().describe("MAC protocol, e.g. 'ip', 'arp', 'vlan' or a number"),
|
|
25630
|
+
vlan_header: z110.enum(["any", "not-present", "present"]).optional().describe("Match on VLAN tag presence"),
|
|
25631
|
+
vlan_id: z110.string().optional(),
|
|
25632
|
+
vlan_priority: z110.string().optional(),
|
|
25633
|
+
dscp: z110.string().optional(),
|
|
25634
|
+
flow_label: z110.string().optional().describe("IPv6 flow label"),
|
|
25635
|
+
new_dst_ports: z110.string().optional().describe("Redirect target ports; empty string drops the traffic"),
|
|
25636
|
+
new_vlan_id: z110.string().optional(),
|
|
25637
|
+
new_vlan_priority: z110.string().optional(),
|
|
25638
|
+
redirect_to_cpu: z110.boolean().optional(),
|
|
25639
|
+
copy_to_cpu: z110.boolean().optional(),
|
|
25640
|
+
mirror: z110.boolean().optional(),
|
|
25641
|
+
rate: z110.string().optional().describe("Rate limit in bits/second"),
|
|
25642
|
+
comment: z110.string().optional(),
|
|
25643
|
+
disabled: z110.boolean().default(false)
|
|
25420
25644
|
},
|
|
25421
25645
|
async handler(a, ctx) {
|
|
25422
25646
|
ctx.info(`Adding switch rule: switch=${a.switch}, ports=${a.ports}`);
|
|
@@ -25450,9 +25674,9 @@ ${details}`;
|
|
|
25450
25674
|
annotations: READ,
|
|
25451
25675
|
description: "Lists all hardware switch ACL/redirect rules (`/interface ethernet switch rule print`) " + "on the switch chip. Use this to audit or discover existing rules before adding or updating. " + "Optional filters narrow by switch chip name, port name substring, or disabled-only status. " + "For software firewall rules use list_filter_rules; for NAT rules use list_nat_rules. " + "Returns a formatted table of all matching rules including their `.id` values needed by " + "get_switch_rule, update_switch_rule, remove_switch_rule, enable_switch_rule, and disable_switch_rule.",
|
|
25452
25676
|
inputSchema: {
|
|
25453
|
-
switch_filter:
|
|
25454
|
-
ports_filter:
|
|
25455
|
-
disabled_only:
|
|
25677
|
+
switch_filter: z110.string().optional(),
|
|
25678
|
+
ports_filter: z110.string().optional(),
|
|
25679
|
+
disabled_only: z110.boolean().default(false)
|
|
25456
25680
|
},
|
|
25457
25681
|
async handler(a, ctx) {
|
|
25458
25682
|
ctx.info("Listing switch rules");
|
|
@@ -25475,7 +25699,7 @@ ${result}`;
|
|
|
25475
25699
|
annotations: READ,
|
|
25476
25700
|
description: "Fetches full detail of a single hardware switch ACL/redirect rule " + "(`/interface ethernet switch rule print detail where .id=\u2026`). " + "Use this to inspect all match criteria and action fields of one rule. " + "`rule_id` takes the `.id` from list_switch_rules (e.g. '*1'). " + "For a tabular overview of all rules use list_switch_rules; " + "for software firewall rule detail use get_filter_rule.",
|
|
25477
25701
|
inputSchema: {
|
|
25478
|
-
rule_id:
|
|
25702
|
+
rule_id: z110.string().describe("RouterOS '.id', e.g. '*1' or '0'")
|
|
25479
25703
|
},
|
|
25480
25704
|
async handler(a, ctx) {
|
|
25481
25705
|
ctx.info(`Getting switch rule: rule_id=${a.rule_id}`);
|
|
@@ -25491,33 +25715,33 @@ ${result}`;
|
|
|
25491
25715
|
annotations: WRITE_IDEMPOTENT,
|
|
25492
25716
|
description: "Modifies an existing hardware switch ACL/redirect rule " + "(`/interface ethernet switch rule set`) by `.id`. " + "Use this to change match criteria (ports, addresses, VLAN, protocol) or actions " + "(redirect target ports, mirror, rate limit, disabled state). " + 'Pass an empty string ("") for any optional field to clear it. ' + "`rule_id` takes the `.id` from list_switch_rules. Returns the updated rule's full detail. " + "For software firewall rule edits use update_filter_rule; " + "to only toggle the enabled state use enable_switch_rule or disable_switch_rule.",
|
|
25493
25717
|
inputSchema: {
|
|
25494
|
-
rule_id:
|
|
25495
|
-
switch:
|
|
25496
|
-
ports:
|
|
25497
|
-
src_address:
|
|
25498
|
-
dst_address:
|
|
25499
|
-
src_address6:
|
|
25500
|
-
dst_address6:
|
|
25501
|
-
src_mac_address:
|
|
25502
|
-
dst_mac_address:
|
|
25503
|
-
src_port:
|
|
25504
|
-
dst_port:
|
|
25505
|
-
protocol:
|
|
25506
|
-
mac_protocol:
|
|
25507
|
-
vlan_header:
|
|
25508
|
-
vlan_id:
|
|
25509
|
-
vlan_priority:
|
|
25510
|
-
dscp:
|
|
25511
|
-
flow_label:
|
|
25512
|
-
new_dst_ports:
|
|
25513
|
-
new_vlan_id:
|
|
25514
|
-
new_vlan_priority:
|
|
25515
|
-
redirect_to_cpu:
|
|
25516
|
-
copy_to_cpu:
|
|
25517
|
-
mirror:
|
|
25518
|
-
rate:
|
|
25519
|
-
comment:
|
|
25520
|
-
disabled:
|
|
25718
|
+
rule_id: z110.string(),
|
|
25719
|
+
switch: z110.string().optional(),
|
|
25720
|
+
ports: z110.string().optional(),
|
|
25721
|
+
src_address: z110.string().optional(),
|
|
25722
|
+
dst_address: z110.string().optional(),
|
|
25723
|
+
src_address6: z110.string().optional(),
|
|
25724
|
+
dst_address6: z110.string().optional(),
|
|
25725
|
+
src_mac_address: z110.string().optional(),
|
|
25726
|
+
dst_mac_address: z110.string().optional(),
|
|
25727
|
+
src_port: z110.string().optional(),
|
|
25728
|
+
dst_port: z110.string().optional(),
|
|
25729
|
+
protocol: z110.string().optional(),
|
|
25730
|
+
mac_protocol: z110.string().optional(),
|
|
25731
|
+
vlan_header: z110.enum(["any", "not-present", "present"]).optional(),
|
|
25732
|
+
vlan_id: z110.string().optional(),
|
|
25733
|
+
vlan_priority: z110.string().optional(),
|
|
25734
|
+
dscp: z110.string().optional(),
|
|
25735
|
+
flow_label: z110.string().optional(),
|
|
25736
|
+
new_dst_ports: z110.string().optional(),
|
|
25737
|
+
new_vlan_id: z110.string().optional(),
|
|
25738
|
+
new_vlan_priority: z110.string().optional(),
|
|
25739
|
+
redirect_to_cpu: z110.boolean().optional(),
|
|
25740
|
+
copy_to_cpu: z110.boolean().optional(),
|
|
25741
|
+
mirror: z110.boolean().optional(),
|
|
25742
|
+
rate: z110.string().optional(),
|
|
25743
|
+
comment: z110.string().optional(),
|
|
25744
|
+
disabled: z110.boolean().optional()
|
|
25521
25745
|
},
|
|
25522
25746
|
async handler(a, ctx) {
|
|
25523
25747
|
return updateSwitchRule(a, ctx);
|
|
@@ -25528,7 +25752,7 @@ ${result}`;
|
|
|
25528
25752
|
title: "Remove Switch Chip ACL Rule",
|
|
25529
25753
|
annotations: DESTRUCTIVE,
|
|
25530
25754
|
description: "Permanently deletes a hardware switch ACL/redirect rule " + "(`/interface ethernet switch rule remove`) by `.id`. " + "Performs an existence check first and returns an error if the rule is not found. " + "`rule_id` takes the `.id` from list_switch_rules (e.g. '*1'). " + "To keep the rule but stop it from matching use disable_switch_rule instead. " + "For removing software firewall rules use remove_filter_rule.",
|
|
25531
|
-
inputSchema: { rule_id:
|
|
25755
|
+
inputSchema: { rule_id: z110.string() },
|
|
25532
25756
|
async handler(a, ctx) {
|
|
25533
25757
|
ctx.info(`Removing switch rule: rule_id=${a.rule_id}`);
|
|
25534
25758
|
const count = await executeMikrotikCommand(`/interface ethernet switch rule print count-only where .id=${a.rule_id}`, ctx);
|
|
@@ -25545,7 +25769,7 @@ ${result}`;
|
|
|
25545
25769
|
title: "Enable Switch Chip ACL Rule",
|
|
25546
25770
|
annotations: WRITE_IDEMPOTENT,
|
|
25547
25771
|
description: "Re-enables a previously disabled hardware switch ACL/redirect rule " + "(`/interface ethernet switch rule set \u2026 disabled=no`). " + "Use this to activate a rule without recreating it. " + "`rule_id` takes the `.id` from list_switch_rules (e.g. '*1'). " + "To deactivate a rule without deleting it use disable_switch_rule; " + "to permanently delete use remove_switch_rule. Returns the updated rule's full detail.",
|
|
25548
|
-
inputSchema: { rule_id:
|
|
25772
|
+
inputSchema: { rule_id: z110.string() },
|
|
25549
25773
|
async handler(a, ctx) {
|
|
25550
25774
|
return updateSwitchRule({ rule_id: a.rule_id, disabled: false }, ctx);
|
|
25551
25775
|
}
|
|
@@ -25555,7 +25779,7 @@ ${result}`;
|
|
|
25555
25779
|
title: "Disable Switch Chip ACL Rule",
|
|
25556
25780
|
annotations: WRITE_IDEMPOTENT,
|
|
25557
25781
|
description: "Deactivates a hardware switch ACL/redirect rule without deleting it " + "(`/interface ethernet switch rule set \u2026 disabled=yes`). " + "Use this to temporarily suspend a rule's match/action while preserving its configuration. " + "`rule_id` takes the `.id` from list_switch_rules (e.g. '*1'). " + "To reactivate the rule use enable_switch_rule; to permanently delete use remove_switch_rule. " + "Returns the updated rule's full detail.",
|
|
25558
|
-
inputSchema: { rule_id:
|
|
25782
|
+
inputSchema: { rule_id: z110.string() },
|
|
25559
25783
|
async handler(a, ctx) {
|
|
25560
25784
|
return updateSwitchRule({ rule_id: a.rule_id, disabled: true }, ctx);
|
|
25561
25785
|
}
|
|
@@ -25563,7 +25787,7 @@ ${result}`;
|
|
|
25563
25787
|
];
|
|
25564
25788
|
|
|
25565
25789
|
// src/tools/system-config.ts
|
|
25566
|
-
import { z as
|
|
25790
|
+
import { z as z111 } from "zod";
|
|
25567
25791
|
var systemConfigTools = [
|
|
25568
25792
|
defineTool({
|
|
25569
25793
|
name: "list_system_console",
|
|
@@ -25610,7 +25834,7 @@ ${result}`;
|
|
|
25610
25834
|
annotations: WRITE_IDEMPOTENT,
|
|
25611
25835
|
description: "Writes the global LED behaviour settings (`/system leds settings set`). " + "Use to enable dark mode by scheduling all LEDs off. " + "For per-LED trigger assignments use `list_leds`; to read current settings use `get_leds_settings`. " + "Accepts `all_leds_off`: `never` | `immediate` | `after-1h` | `after-1min`. " + "Returns the updated settings on success.",
|
|
25612
25836
|
inputSchema: {
|
|
25613
|
-
all_leds_off:
|
|
25837
|
+
all_leds_off: z111.enum(["never", "immediate", "after-1h", "after-1min"]).optional().describe("When to turn all LEDs off (dark mode)")
|
|
25614
25838
|
},
|
|
25615
25839
|
async handler(a, ctx) {
|
|
25616
25840
|
ctx.info("Setting LED settings");
|
|
@@ -25660,8 +25884,8 @@ ${result}`;
|
|
|
25660
25884
|
annotations: WRITE_IDEMPOTENT,
|
|
25661
25885
|
description: "Writes the system-wide login banner text (`/system note set`). " + "Use to set or clear the message displayed to users at login. " + "To read the current note use `get_note`. " + "Accepts optional `note` (text string) and `show_at_login` (boolean). " + "Returns the updated note on success.",
|
|
25662
25886
|
inputSchema: {
|
|
25663
|
-
note:
|
|
25664
|
-
show_at_login:
|
|
25887
|
+
note: z111.string().optional().describe("The note text to display"),
|
|
25888
|
+
show_at_login: z111.boolean().optional().describe("Show the note on login")
|
|
25665
25889
|
},
|
|
25666
25890
|
async handler(a, ctx) {
|
|
25667
25891
|
ctx.info("Setting system note");
|
|
@@ -25698,13 +25922,13 @@ ${result}`;
|
|
|
25698
25922
|
annotations: WRITE_IDEMPOTENT,
|
|
25699
25923
|
description: "Writes the device's built-in NTP *server* settings (`/system ntp server set`, RouterOS 7+). " + "Use to enable the router as a time server for LAN clients via broadcast, multicast, or manycast. " + "This tool configures the local NTP *server* role; to set upstream NTP *client* sources " + "use the NTP client tools in the system module. " + "Accepts `enabled`, `broadcast`, `multicast`, `manycast` (booleans) and `broadcast_address` (string). " + "Returns the updated server configuration on success.",
|
|
25700
25924
|
inputSchema: {
|
|
25701
|
-
enabled:
|
|
25702
|
-
broadcast:
|
|
25703
|
-
multicast:
|
|
25704
|
-
manycast:
|
|
25705
|
-
broadcast_address:
|
|
25706
|
-
use_local_clock:
|
|
25707
|
-
local_clock_stratum:
|
|
25925
|
+
enabled: z111.boolean().optional().describe("Enable or disable the NTP server"),
|
|
25926
|
+
broadcast: z111.boolean().optional(),
|
|
25927
|
+
multicast: z111.boolean().optional(),
|
|
25928
|
+
manycast: z111.boolean().optional(),
|
|
25929
|
+
broadcast_address: z111.string().optional().describe("Broadcast address for NTP broadcasts"),
|
|
25930
|
+
use_local_clock: z111.boolean().optional().describe("Serve time from the device's local clock as reference"),
|
|
25931
|
+
local_clock_stratum: z111.number().int().optional().describe("Stratum advertised when using the local clock (1-15)")
|
|
25708
25932
|
},
|
|
25709
25933
|
async handler(a, ctx) {
|
|
25710
25934
|
ctx.info("Setting NTP server configuration");
|
|
@@ -25727,8 +25951,8 @@ ${details}`;
|
|
|
25727
25951
|
annotations: WRITE,
|
|
25728
25952
|
description: "Changes the password of the currently authenticated user (`/password`). " + "Use to rotate the login credential without touching other user accounts; " + "passwords are never echoed in the response. " + "To manage other users' accounts or create new users use `add_user`. " + "Requires `old_password` and `new_password`; returns success or a rejection message (no credentials logged).",
|
|
25729
25953
|
inputSchema: {
|
|
25730
|
-
old_password:
|
|
25731
|
-
new_password:
|
|
25954
|
+
old_password: z111.string().describe("The current password"),
|
|
25955
|
+
new_password: z111.string().describe("The new password to set")
|
|
25732
25956
|
},
|
|
25733
25957
|
async handler(a, ctx) {
|
|
25734
25958
|
ctx.info("Changing device password");
|
|
@@ -25745,7 +25969,7 @@ ${details}`;
|
|
|
25745
25969
|
annotations: READ,
|
|
25746
25970
|
description: "Lists the physical serial ports registered on the device (`/port print`). " + "Use to discover available serial ports and their current line settings before reconfiguring. " + "For auto-login rules tied to a serial port use `list_special_login`; " + "for console session entries use `list_system_console`. " + "Accepts optional `name_filter` for partial name match. " + "Returns port entries or an empty message when none match.",
|
|
25747
25971
|
inputSchema: {
|
|
25748
|
-
name_filter:
|
|
25972
|
+
name_filter: z111.string().optional().describe("Partial port name match")
|
|
25749
25973
|
},
|
|
25750
25974
|
async handler(a, ctx) {
|
|
25751
25975
|
ctx.info("Listing serial ports");
|
|
@@ -25764,7 +25988,7 @@ ${result}`;
|
|
|
25764
25988
|
annotations: READ,
|
|
25765
25989
|
description: "Reads detailed settings for a named serial port (`/port print detail where name=...`). " + "Use to inspect baud rate, parity, data/stop bits, and flow control for a specific port. " + "For an overview of all ports use `list_ports`; to change settings use `set_port`. " + "Requires `name` (e.g. `serial0`). Returns full detail for the named port.",
|
|
25766
25990
|
inputSchema: {
|
|
25767
|
-
name:
|
|
25991
|
+
name: z111.string().describe("Serial port name, e.g. 'serial0'")
|
|
25768
25992
|
},
|
|
25769
25993
|
async handler(a, ctx) {
|
|
25770
25994
|
ctx.info(`Getting serial port details: name=${a.name}`);
|
|
@@ -25780,12 +26004,12 @@ ${result}`;
|
|
|
25780
26004
|
annotations: WRITE_IDEMPOTENT,
|
|
25781
26005
|
description: "Writes line settings for a named serial port (`/port set [find name=...]`). " + "Use to change baud rate, data bits, parity, stop bits, or flow control on a serial port. " + "To read current settings first use `get_port`; for a list of all ports use `list_ports`. " + "Requires `name` (e.g. `serial0`), plus optional `baud_rate` (e.g. `115200` or `auto`), " + "`data_bits`, `parity` (`none`|`odd`|`even`), `stop_bits`, " + "`flow_control` (`none`|`hardware`|`xon-xoff`). " + "Returns the updated port detail on success.",
|
|
25782
26006
|
inputSchema: {
|
|
25783
|
-
name:
|
|
25784
|
-
baud_rate:
|
|
25785
|
-
data_bits:
|
|
25786
|
-
parity:
|
|
25787
|
-
stop_bits:
|
|
25788
|
-
flow_control:
|
|
26007
|
+
name: z111.string().describe("Serial port name to update"),
|
|
26008
|
+
baud_rate: z111.string().optional().describe("e.g. '115200' or 'auto'"),
|
|
26009
|
+
data_bits: z111.number().int().optional(),
|
|
26010
|
+
parity: z111.enum(["none", "odd", "even"]).optional(),
|
|
26011
|
+
stop_bits: z111.number().int().optional(),
|
|
26012
|
+
flow_control: z111.enum(["none", "hardware", "xon-xoff"]).optional()
|
|
25789
26013
|
},
|
|
25790
26014
|
async handler(a, ctx) {
|
|
25791
26015
|
ctx.info(`Setting serial port: name=${a.name}`);
|
|
@@ -25824,12 +26048,12 @@ ${result}`;
|
|
|
25824
26048
|
annotations: DANGEROUS,
|
|
25825
26049
|
description: "Sends a factory-reset command to the device (`/system reset-configuration`). " + "Use ONLY to wipe the entire configuration and reboot into defaults \u2014 " + "the SSH connection will drop immediately after and all config will be lost. " + "Requires `confirm=true`; without it the command is blocked. " + "Optional: `keep_users` (preserve user accounts), `no_defaults` (skip loading default config), " + "`skip_backup` (skip automatic pre-reset backup), `caps_mode` (reset into CAPsMAN-managed CAP mode), " + "`run_after_reset` (script to execute post-reboot). " + "This operation is irreversible \u2014 there is no undo.",
|
|
25826
26050
|
inputSchema: {
|
|
25827
|
-
confirm:
|
|
25828
|
-
keep_users:
|
|
25829
|
-
no_defaults:
|
|
25830
|
-
skip_backup:
|
|
25831
|
-
caps_mode:
|
|
25832
|
-
run_after_reset:
|
|
26051
|
+
confirm: z111.boolean().describe("Must be true to actually ERASE the configuration"),
|
|
26052
|
+
keep_users: z111.boolean().optional().describe("Keep existing user accounts after reset"),
|
|
26053
|
+
no_defaults: z111.boolean().optional().describe("Do not load the default configuration"),
|
|
26054
|
+
skip_backup: z111.boolean().optional().describe("Skip the automatic backup before reset"),
|
|
26055
|
+
caps_mode: z111.boolean().optional().describe("Reset into CAPsMAN-managed CAP mode instead of standalone"),
|
|
26056
|
+
run_after_reset: z111.string().optional().describe("Script file to run after reset")
|
|
25833
26057
|
},
|
|
25834
26058
|
async handler(a, ctx) {
|
|
25835
26059
|
if (!a.confirm)
|
|
@@ -25874,12 +26098,12 @@ ${result}`;
|
|
|
25874
26098
|
annotations: WRITE_IDEMPOTENT,
|
|
25875
26099
|
description: "Writes the hardware/software watchdog timer settings (`/system watchdog set`). " + "Use to enable automatic reboots when the device becomes unresponsive " + "(triggered when pings to `watch_address` fail). " + "To read current settings use `get_watchdog`. " + "Accepts `watchdog_timer` (enable HW watchdog), `watch_address` (IP to ping), " + "`ping_timeout` (e.g. `1m`), `no_ping_delay` (e.g. `5m`), " + "`automatic_supout` (generate diagnostic file on crash), " + "`auto_send_supout` (email the diagnostic). " + "Returns the updated watchdog configuration on success.",
|
|
25876
26100
|
inputSchema: {
|
|
25877
|
-
watchdog_timer:
|
|
25878
|
-
watch_address:
|
|
25879
|
-
ping_timeout:
|
|
25880
|
-
no_ping_delay:
|
|
25881
|
-
automatic_supout:
|
|
25882
|
-
auto_send_supout:
|
|
26101
|
+
watchdog_timer: z111.boolean().optional().describe("Enable the hardware watchdog timer"),
|
|
26102
|
+
watch_address: z111.string().optional().describe("Address to ping; reboot if unreachable"),
|
|
26103
|
+
ping_timeout: z111.string().optional().describe("e.g. '1m'"),
|
|
26104
|
+
no_ping_delay: z111.string().optional().describe("e.g. '5m'"),
|
|
26105
|
+
automatic_supout: z111.boolean().optional().describe("Generate a supout.rif on software failure"),
|
|
26106
|
+
auto_send_supout: z111.boolean().optional().describe("Email the generated supout.rif")
|
|
25883
26107
|
},
|
|
25884
26108
|
async handler(a, ctx) {
|
|
25885
26109
|
ctx.info("Setting watchdog configuration");
|
|
@@ -25899,7 +26123,7 @@ ${details}`;
|
|
|
25899
26123
|
];
|
|
25900
26124
|
|
|
25901
26125
|
// src/tools/system.ts
|
|
25902
|
-
import { z as
|
|
26126
|
+
import { z as z112 } from "zod";
|
|
25903
26127
|
var systemTools = [
|
|
25904
26128
|
defineTool({
|
|
25905
26129
|
name: "get_system_identity",
|
|
@@ -25920,7 +26144,7 @@ ${result}`;
|
|
|
25920
26144
|
annotations: WRITE,
|
|
25921
26145
|
description: "Set the system hostname (`/system identity set`) \u2014 the name shown in neighbor discovery, " + "Winbox title bar, and SSH prompts. " + "To read the current value use `get_system_identity`. " + "Returns the updated identity after the change.",
|
|
25922
26146
|
inputSchema: {
|
|
25923
|
-
name:
|
|
26147
|
+
name: z112.string().describe("New system identity / hostname")
|
|
25924
26148
|
},
|
|
25925
26149
|
async handler(a, ctx) {
|
|
25926
26150
|
ctx.info(`Setting system identity: name=${a.name}`);
|
|
@@ -25992,10 +26216,10 @@ ${result}`;
|
|
|
25992
26216
|
annotations: WRITE,
|
|
25993
26217
|
description: "Set the system date, time, and/or time-zone (`/system clock set`). " + "Provide at least one of `time_zone_name` (e.g. `'Europe/Amsterdam'` or `'manual'`), " + "`date` (e.g. `'jun/19/2026'`), or `time` (e.g. `'13:45:00'`). " + "For automatic time synchronization configure NTP with `set_ntp_client`. " + "Returns the updated clock after the change.",
|
|
25994
26218
|
inputSchema: {
|
|
25995
|
-
time_zone_name:
|
|
25996
|
-
date:
|
|
25997
|
-
time:
|
|
25998
|
-
time_zone_autodetect:
|
|
26219
|
+
time_zone_name: z112.string().optional().describe("e.g. 'Europe/Amsterdam' or 'manual'"),
|
|
26220
|
+
date: z112.string().optional().describe("e.g. 'jun/19/2026'"),
|
|
26221
|
+
time: z112.string().optional().describe("e.g. '13:45:00'"),
|
|
26222
|
+
time_zone_autodetect: z112.boolean().optional().describe("Auto-detect the time zone from the public IP")
|
|
25999
26223
|
},
|
|
26000
26224
|
async handler(a, ctx) {
|
|
26001
26225
|
ctx.info("Setting system clock");
|
|
@@ -26030,10 +26254,10 @@ ${result}`;
|
|
|
26030
26254
|
annotations: WRITE,
|
|
26031
26255
|
description: "Configure the NTP client (`/system ntp client set`) \u2014 enable or disable it " + "and set the server list as a comma-separated string (e.g. `'0.pool.ntp.org,1.pool.ntp.org'`). " + "To read current NTP status use `get_ntp_client`; " + "to set the clock manually instead use `set_system_clock`. " + "Returns the updated NTP client configuration after the change.",
|
|
26032
26256
|
inputSchema: {
|
|
26033
|
-
enabled:
|
|
26034
|
-
servers:
|
|
26035
|
-
mode:
|
|
26036
|
-
vrf:
|
|
26257
|
+
enabled: z112.boolean().optional().describe("Enable or disable the NTP client"),
|
|
26258
|
+
servers: z112.string().optional().describe("Comma-separated NTP server list"),
|
|
26259
|
+
mode: z112.enum(["unicast", "broadcast", "multicast", "manycast"]).optional().describe("NTP client operating mode"),
|
|
26260
|
+
vrf: z112.string().optional().describe("VRF the NTP client operates in (e.g. 'main')")
|
|
26037
26261
|
},
|
|
26038
26262
|
async handler(a, ctx) {
|
|
26039
26263
|
ctx.info("Setting NTP client configuration");
|
|
@@ -26092,7 +26316,7 @@ ${result}`;
|
|
|
26092
26316
|
annotations: DANGEROUS,
|
|
26093
26317
|
description: "Send a reboot command to the device (`/system reboot`). " + "This is a high-blast-radius action: all connections drop and the device is offline for " + "1-2 minutes while it restarts. " + "Must pass `confirm=true` or the command is rejected without touching the device. " + "For a permanent power-off use `shutdown_system`.",
|
|
26094
26318
|
inputSchema: {
|
|
26095
|
-
confirm:
|
|
26319
|
+
confirm: z112.boolean().describe("Must be true to actually reboot the device")
|
|
26096
26320
|
},
|
|
26097
26321
|
async handler(a, ctx) {
|
|
26098
26322
|
if (!a.confirm)
|
|
@@ -26108,7 +26332,7 @@ ${result}`;
|
|
|
26108
26332
|
annotations: DANGEROUS,
|
|
26109
26333
|
description: "Power off the device (`/system shutdown`). " + "This is a high-blast-radius action: all connections drop and the device remains offline " + "until physically powered on again. " + "Must pass `confirm=true` or the command is rejected without touching the device. " + "For a temporary restart use `reboot_system`.",
|
|
26110
26334
|
inputSchema: {
|
|
26111
|
-
confirm:
|
|
26335
|
+
confirm: z112.boolean().describe("Must be true to actually shut down the device")
|
|
26112
26336
|
},
|
|
26113
26337
|
async handler(a, ctx) {
|
|
26114
26338
|
if (!a.confirm)
|
|
@@ -26121,10 +26345,10 @@ ${result}`;
|
|
|
26121
26345
|
];
|
|
26122
26346
|
|
|
26123
26347
|
// src/tools/tunnels.ts
|
|
26124
|
-
import { z as
|
|
26125
|
-
var DontFragment =
|
|
26126
|
-
var Arp =
|
|
26127
|
-
var VtepsIpVersion =
|
|
26348
|
+
import { z as z113 } from "zod";
|
|
26349
|
+
var DontFragment = z113.enum(["inherit", "no"]);
|
|
26350
|
+
var Arp = z113.enum(["disabled", "enabled", "local-proxy-arp", "proxy-arp", "reply-only"]);
|
|
26351
|
+
var VtepsIpVersion = z113.enum(["ipv4", "ipv6"]);
|
|
26128
26352
|
var tunnelTools = [
|
|
26129
26353
|
defineTool({
|
|
26130
26354
|
name: "create_gre_tunnel",
|
|
@@ -26132,18 +26356,18 @@ var tunnelTools = [
|
|
|
26132
26356
|
annotations: WRITE,
|
|
26133
26357
|
description: "Creates an IPv4 GRE (Generic Routing Encapsulation) L3 tunnel interface (`/interface gre`)." + " Use to encapsulate routed traffic between two endpoints for site-to-site connectivity when IPsec encryption is not needed." + " GRE is L3-only and not bridgeable; for bridgeable L2 Ethernet-over-IP tunnels use create_eoip_tunnel;" + " for raw IP-in-IP with less overhead use create_ipip_tunnel; for L2 VXLAN overlays use create_vxlan_tunnel;" + " for VPN client interfaces use create_l2tp_client, create_pptp_client, create_sstp_client, or create_ovpn_client." + " Keepalive format: '<interval>,<retries>', e.g. '10s,3'." + " Returns the created interface detail including name, remote-address, and run-time status.",
|
|
26134
26358
|
inputSchema: {
|
|
26135
|
-
name:
|
|
26136
|
-
remote_address:
|
|
26137
|
-
local_address:
|
|
26138
|
-
keepalive:
|
|
26359
|
+
name: z113.string().describe("Name for the new GRE tunnel interface, e.g. 'gre-to-hq'"),
|
|
26360
|
+
remote_address: z113.string().describe("Remote endpoint IP address"),
|
|
26361
|
+
local_address: z113.string().optional().describe("Local endpoint IP address"),
|
|
26362
|
+
keepalive: z113.string().optional().describe("Keepalive interval/retries, e.g. '10s,3'"),
|
|
26139
26363
|
dont_fragment: DontFragment.optional().describe("Don't-fragment behavior"),
|
|
26140
|
-
clamp_tcp_mss:
|
|
26141
|
-
allow_fast_path:
|
|
26142
|
-
ipsec_secret:
|
|
26143
|
-
dscp:
|
|
26144
|
-
mtu:
|
|
26145
|
-
comment:
|
|
26146
|
-
disabled:
|
|
26364
|
+
clamp_tcp_mss: z113.boolean().optional().describe("Clamp TCP MSS to the tunnel MTU"),
|
|
26365
|
+
allow_fast_path: z113.boolean().optional().describe("Allow FastPath processing for this tunnel"),
|
|
26366
|
+
ipsec_secret: z113.string().optional().describe("Pre-shared key to auto-create an IPsec policy securing the tunnel"),
|
|
26367
|
+
dscp: z113.string().optional().describe("DSCP for encapsulated packets: 'inherit' or 0-63"),
|
|
26368
|
+
mtu: z113.number().int().optional(),
|
|
26369
|
+
comment: z113.string().optional(),
|
|
26370
|
+
disabled: z113.boolean().default(false)
|
|
26147
26371
|
},
|
|
26148
26372
|
async handler(a, ctx) {
|
|
26149
26373
|
ctx.info(`Creating GRE tunnel: name=${a.name}, remote_address=${a.remote_address}`);
|
|
@@ -26163,7 +26387,7 @@ ${details}` : "GRE tunnel creation completed but unable to verify.";
|
|
|
26163
26387
|
annotations: READ,
|
|
26164
26388
|
description: "Lists all GRE tunnel interfaces (`/interface gre print`)." + " Use to inventory or audit existing GRE tunnels and their remote endpoints." + " Supports optional partial name filter via name_filter." + " For full detail on one tunnel use get_gre_tunnel; for IPIP tunnels use list_ipip_tunnels;" + " for EoIP tunnels use list_eoip_tunnels; for VXLAN use list_vxlan_tunnels." + " Returns name, remote-address, local-address, MTU, and run-time status for each interface.",
|
|
26165
26389
|
inputSchema: {
|
|
26166
|
-
name_filter:
|
|
26390
|
+
name_filter: z113.string().optional().describe("Partial name match")
|
|
26167
26391
|
},
|
|
26168
26392
|
async handler(a, ctx) {
|
|
26169
26393
|
ctx.info("Listing GRE tunnels");
|
|
@@ -26181,7 +26405,7 @@ ${result}`;
|
|
|
26181
26405
|
title: "Get GRE Tunnel Interface Detail",
|
|
26182
26406
|
annotations: READ,
|
|
26183
26407
|
description: "Fetches full detail for a single GRE tunnel interface by name (`/interface gre print detail where name=...`)." + " Use to inspect all parameters of one tunnel \u2014 remote-address, local-address, keepalive, MTU, dont-fragment, and status." + " For a summary list of all GRE tunnels use list_gre_tunnels." + " For IPIP detail use get_ipip_tunnel; for EoIP detail use get_eoip_tunnel; for VXLAN detail use get_vxlan_tunnel." + " Returns the complete property set for the named interface, or a not-found message.",
|
|
26184
|
-
inputSchema: { name:
|
|
26408
|
+
inputSchema: { name: z113.string() },
|
|
26185
26409
|
async handler(a, ctx) {
|
|
26186
26410
|
ctx.info(`Getting GRE tunnel details: name=${a.name}`);
|
|
26187
26411
|
const result = await executeMikrotikCommand(`/interface gre print detail where name="${a.name}"`, ctx);
|
|
@@ -26195,7 +26419,7 @@ ${result}`;
|
|
|
26195
26419
|
title: "Remove GRE Tunnel Interface",
|
|
26196
26420
|
annotations: DESTRUCTIVE,
|
|
26197
26421
|
description: "Permanently deletes a GRE tunnel interface by name (`/interface gre remove [find name=...]`)." + " Verifies existence via count-only before removal and returns a not-found message if the interface does not exist." + " This is destructive and immediately disconnects any traffic using the tunnel." + " For IPIP removal use remove_ipip_tunnel; for EoIP use remove_eoip_tunnel; for VXLAN use remove_vxlan_tunnel.",
|
|
26198
|
-
inputSchema: { name:
|
|
26422
|
+
inputSchema: { name: z113.string() },
|
|
26199
26423
|
async handler(a, ctx) {
|
|
26200
26424
|
ctx.info(`Removing GRE tunnel: name=${a.name}`);
|
|
26201
26425
|
const count = await executeMikrotikCommand(`/interface gre print count-only where name="${a.name}"`, ctx);
|
|
@@ -26213,18 +26437,18 @@ ${result}`;
|
|
|
26213
26437
|
annotations: WRITE,
|
|
26214
26438
|
description: "Creates an IPv4 IPIP (IP-in-IP) L3 tunnel interface (`/interface ipip`)." + " Use for lightweight point-to-point IP encapsulation with minimal overhead when GRE's extra header byte is undesirable." + " IPIP is L3-only and not bridgeable; for GRE encapsulation (with dont-fragment support) use create_gre_tunnel;" + " for L2 Ethernet-over-IP tunnels use create_eoip_tunnel; for VXLAN L2 overlays use create_vxlan_tunnel." + " Keepalive format: '<interval>,<retries>', e.g. '10s,3'." + " Returns the created interface detail including name, remote-address, and run-time status.",
|
|
26215
26439
|
inputSchema: {
|
|
26216
|
-
name:
|
|
26217
|
-
remote_address:
|
|
26218
|
-
local_address:
|
|
26219
|
-
keepalive:
|
|
26440
|
+
name: z113.string().describe("Name for the new IPIP tunnel interface, e.g. 'ipip-to-hq'"),
|
|
26441
|
+
remote_address: z113.string().describe("Remote endpoint IP address"),
|
|
26442
|
+
local_address: z113.string().optional().describe("Local endpoint IP address"),
|
|
26443
|
+
keepalive: z113.string().optional().describe("Keepalive interval/retries, e.g. '10s,3'"),
|
|
26220
26444
|
dont_fragment: DontFragment.optional().describe("Don't-fragment behavior"),
|
|
26221
|
-
clamp_tcp_mss:
|
|
26222
|
-
allow_fast_path:
|
|
26223
|
-
ipsec_secret:
|
|
26224
|
-
dscp:
|
|
26225
|
-
mtu:
|
|
26226
|
-
comment:
|
|
26227
|
-
disabled:
|
|
26445
|
+
clamp_tcp_mss: z113.boolean().optional().describe("Clamp TCP MSS to the tunnel MTU"),
|
|
26446
|
+
allow_fast_path: z113.boolean().optional().describe("Allow FastPath processing for this tunnel"),
|
|
26447
|
+
ipsec_secret: z113.string().optional().describe("Pre-shared key to auto-create an IPsec policy securing the tunnel"),
|
|
26448
|
+
dscp: z113.string().optional().describe("DSCP for encapsulated packets: 'inherit' or 0-63"),
|
|
26449
|
+
mtu: z113.number().int().optional(),
|
|
26450
|
+
comment: z113.string().optional(),
|
|
26451
|
+
disabled: z113.boolean().default(false)
|
|
26228
26452
|
},
|
|
26229
26453
|
async handler(a, ctx) {
|
|
26230
26454
|
ctx.info(`Creating IPIP tunnel: name=${a.name}, remote_address=${a.remote_address}`);
|
|
@@ -26244,7 +26468,7 @@ ${details}` : "IPIP tunnel creation completed but unable to verify.";
|
|
|
26244
26468
|
annotations: READ,
|
|
26245
26469
|
description: "Lists all IPIP tunnel interfaces (`/interface ipip print`)." + " Use to inventory existing IPIP tunnels and their remote endpoints." + " Supports optional partial name filter via name_filter." + " For full detail on one tunnel use get_ipip_tunnel; for GRE tunnels use list_gre_tunnels;" + " for EoIP tunnels use list_eoip_tunnels; for VXLAN use list_vxlan_tunnels." + " Returns name, remote-address, local-address, MTU, and run-time status for each interface.",
|
|
26246
26470
|
inputSchema: {
|
|
26247
|
-
name_filter:
|
|
26471
|
+
name_filter: z113.string().optional().describe("Partial name match")
|
|
26248
26472
|
},
|
|
26249
26473
|
async handler(a, ctx) {
|
|
26250
26474
|
ctx.info("Listing IPIP tunnels");
|
|
@@ -26262,7 +26486,7 @@ ${result}`;
|
|
|
26262
26486
|
title: "Get IPIP Tunnel Interface Detail",
|
|
26263
26487
|
annotations: READ,
|
|
26264
26488
|
description: "Fetches full detail for a single IPIP tunnel interface by name (`/interface ipip print detail where name=...`)." + " Use to inspect all parameters of one tunnel \u2014 remote-address, local-address, keepalive, MTU, and status." + " For a summary list of all IPIP tunnels use list_ipip_tunnels." + " For GRE detail use get_gre_tunnel; for EoIP detail use get_eoip_tunnel; for VXLAN detail use get_vxlan_tunnel." + " Returns the complete property set for the named interface, or a not-found message.",
|
|
26265
|
-
inputSchema: { name:
|
|
26489
|
+
inputSchema: { name: z113.string() },
|
|
26266
26490
|
async handler(a, ctx) {
|
|
26267
26491
|
ctx.info(`Getting IPIP tunnel details: name=${a.name}`);
|
|
26268
26492
|
const result = await executeMikrotikCommand(`/interface ipip print detail where name="${a.name}"`, ctx);
|
|
@@ -26276,7 +26500,7 @@ ${result}`;
|
|
|
26276
26500
|
title: "Remove IPIP Tunnel Interface",
|
|
26277
26501
|
annotations: DESTRUCTIVE,
|
|
26278
26502
|
description: "Permanently deletes an IPIP tunnel interface by name (`/interface ipip remove [find name=...]`)." + " Verifies existence via count-only before removal and returns a not-found message if the interface does not exist." + " This is destructive and immediately disconnects any traffic using the tunnel." + " For GRE removal use remove_gre_tunnel; for EoIP use remove_eoip_tunnel; for VXLAN use remove_vxlan_tunnel.",
|
|
26279
|
-
inputSchema: { name:
|
|
26503
|
+
inputSchema: { name: z113.string() },
|
|
26280
26504
|
async handler(a, ctx) {
|
|
26281
26505
|
ctx.info(`Removing IPIP tunnel: name=${a.name}`);
|
|
26282
26506
|
const count = await executeMikrotikCommand(`/interface ipip print count-only where name="${a.name}"`, ctx);
|
|
@@ -26294,22 +26518,22 @@ ${result}`;
|
|
|
26294
26518
|
annotations: WRITE,
|
|
26295
26519
|
description: "Creates an EoIP (Ethernet over IP) L2 tunnel interface (`/interface eoip`)." + " Use when you need a bridgeable L2 link between two MikroTik devices \u2014 traffic appears as raw Ethernet frames over IP." + " Each tunnel requires a unique tunnel_id (0-65535) that must match identically on both peers; mismatched IDs are the most common misconfiguration." + " EoIP is MikroTik-proprietary \u2014 both endpoints must run RouterOS." + " For L3-only encapsulation use create_gre_tunnel or create_ipip_tunnel; for open-standard L2 overlays use create_vxlan_tunnel." + " Keepalive format: '<interval>,<retries>', e.g. '10s,3'." + " Returns the created interface detail including name, remote-address, tunnel-id, and run-time status.",
|
|
26296
26520
|
inputSchema: {
|
|
26297
|
-
name:
|
|
26298
|
-
remote_address:
|
|
26299
|
-
tunnel_id:
|
|
26300
|
-
local_address:
|
|
26301
|
-
keepalive:
|
|
26521
|
+
name: z113.string().describe("Name for the new EoIP tunnel interface, e.g. 'eoip-to-hq'"),
|
|
26522
|
+
remote_address: z113.string().describe("Remote endpoint IP address"),
|
|
26523
|
+
tunnel_id: z113.number().int().describe("Unique tunnel ID, must match on both peers"),
|
|
26524
|
+
local_address: z113.string().optional().describe("Local endpoint IP address"),
|
|
26525
|
+
keepalive: z113.string().optional().describe("Keepalive interval/retries, e.g. '10s,3'"),
|
|
26302
26526
|
dont_fragment: DontFragment.optional().describe("Don't-fragment behavior"),
|
|
26303
|
-
clamp_tcp_mss:
|
|
26304
|
-
allow_fast_path:
|
|
26305
|
-
ipsec_secret:
|
|
26306
|
-
dscp:
|
|
26307
|
-
mac_address:
|
|
26527
|
+
clamp_tcp_mss: z113.boolean().optional().describe("Clamp TCP MSS to the tunnel MTU"),
|
|
26528
|
+
allow_fast_path: z113.boolean().optional().describe("Allow FastPath processing for this tunnel"),
|
|
26529
|
+
ipsec_secret: z113.string().optional().describe("Pre-shared key to auto-create an IPsec policy securing the tunnel"),
|
|
26530
|
+
dscp: z113.string().optional().describe("DSCP for encapsulated packets: 'inherit' or 0-63"),
|
|
26531
|
+
mac_address: z113.string().optional().describe("MAC address of the EoIP interface"),
|
|
26308
26532
|
arp: Arp.optional().describe("Address Resolution Protocol mode for the interface"),
|
|
26309
|
-
arp_timeout:
|
|
26310
|
-
mtu:
|
|
26311
|
-
comment:
|
|
26312
|
-
disabled:
|
|
26533
|
+
arp_timeout: z113.string().optional().describe("ARP entry timeout, e.g. '30s' or 'auto'"),
|
|
26534
|
+
mtu: z113.number().int().optional(),
|
|
26535
|
+
comment: z113.string().optional(),
|
|
26536
|
+
disabled: z113.boolean().default(false)
|
|
26313
26537
|
},
|
|
26314
26538
|
async handler(a, ctx) {
|
|
26315
26539
|
ctx.info(`Creating EoIP tunnel: name=${a.name}, remote_address=${a.remote_address}, tunnel_id=${a.tunnel_id}`);
|
|
@@ -26329,7 +26553,7 @@ ${details}` : "EoIP tunnel creation completed but unable to verify.";
|
|
|
26329
26553
|
annotations: READ,
|
|
26330
26554
|
description: "Lists all EoIP tunnel interfaces (`/interface eoip print`)." + " Use to inventory existing EoIP tunnels and check their tunnel-id assignments to detect duplicates or mismatches." + " Supports optional partial name filter via name_filter." + " For full detail on one tunnel use get_eoip_tunnel; for GRE tunnels use list_gre_tunnels;" + " for IPIP tunnels use list_ipip_tunnels; for VXLAN use list_vxlan_tunnels." + " Returns name, remote-address, tunnel-id, MTU, and run-time status for each interface.",
|
|
26331
26555
|
inputSchema: {
|
|
26332
|
-
name_filter:
|
|
26556
|
+
name_filter: z113.string().optional().describe("Partial name match")
|
|
26333
26557
|
},
|
|
26334
26558
|
async handler(a, ctx) {
|
|
26335
26559
|
ctx.info("Listing EoIP tunnels");
|
|
@@ -26347,7 +26571,7 @@ ${result}`;
|
|
|
26347
26571
|
title: "Get EoIP Tunnel Interface Detail",
|
|
26348
26572
|
annotations: READ,
|
|
26349
26573
|
description: "Fetches full detail for a single EoIP tunnel interface by name (`/interface eoip print detail where name=...`)." + " Use to inspect the tunnel-id, remote-address, local-address, keepalive, MTU, and status of one tunnel." + " For a summary list of all EoIP tunnels use list_eoip_tunnels." + " For GRE detail use get_gre_tunnel; for IPIP detail use get_ipip_tunnel; for VXLAN detail use get_vxlan_tunnel." + " Returns the complete property set for the named interface, or a not-found message.",
|
|
26350
|
-
inputSchema: { name:
|
|
26574
|
+
inputSchema: { name: z113.string() },
|
|
26351
26575
|
async handler(a, ctx) {
|
|
26352
26576
|
ctx.info(`Getting EoIP tunnel details: name=${a.name}`);
|
|
26353
26577
|
const result = await executeMikrotikCommand(`/interface eoip print detail where name="${a.name}"`, ctx);
|
|
@@ -26361,7 +26585,7 @@ ${result}`;
|
|
|
26361
26585
|
title: "Remove EoIP Tunnel Interface",
|
|
26362
26586
|
annotations: DESTRUCTIVE,
|
|
26363
26587
|
description: "Permanently deletes an EoIP tunnel interface by name (`/interface eoip remove [find name=...]`)." + " Verifies existence via count-only before removal and returns a not-found message if the interface does not exist." + " This is destructive and immediately severs the L2 bridge link using this tunnel." + " For GRE removal use remove_gre_tunnel; for IPIP use remove_ipip_tunnel; for VXLAN use remove_vxlan_tunnel.",
|
|
26364
|
-
inputSchema: { name:
|
|
26588
|
+
inputSchema: { name: z113.string() },
|
|
26365
26589
|
async handler(a, ctx) {
|
|
26366
26590
|
ctx.info(`Removing EoIP tunnel: name=${a.name}`);
|
|
26367
26591
|
const count = await executeMikrotikCommand(`/interface eoip print count-only where name="${a.name}"`, ctx);
|
|
@@ -26379,21 +26603,21 @@ ${result}`;
|
|
|
26379
26603
|
annotations: WRITE,
|
|
26380
26604
|
description: "Creates a VXLAN (Virtual Extensible LAN) L2 overlay interface (`/interface vxlan`)." + " Use to build scalable L2 overlays across L3 networks \u2014 the VNI (VXLAN Network Identifier) scopes the broadcast domain, suited for multi-tenant or data-centre scenarios." + " VXLAN is an open standard and works with non-MikroTik peers; for MikroTik-proprietary L2 tunnels use create_eoip_tunnel;" + " for L3-only encapsulation use create_gre_tunnel or create_ipip_tunnel." + " UDP port defaults to 8472; VNI must match on all participating VTEPs." + " Returns the created interface detail including name, VNI, port, and run-time status.",
|
|
26381
26605
|
inputSchema: {
|
|
26382
|
-
name:
|
|
26383
|
-
vni:
|
|
26384
|
-
port:
|
|
26385
|
-
local_address:
|
|
26386
|
-
interface:
|
|
26387
|
-
group:
|
|
26606
|
+
name: z113.string().describe("Name for the new VXLAN interface, e.g. 'vxlan1'"),
|
|
26607
|
+
vni: z113.number().int().describe("VXLAN Network Identifier (VNI)"),
|
|
26608
|
+
port: z113.number().int().default(8472).describe("UDP port (default 8472)"),
|
|
26609
|
+
local_address: z113.string().optional().describe("Local source IP address"),
|
|
26610
|
+
interface: z113.string().optional().describe("Source interface"),
|
|
26611
|
+
group: z113.string().optional().describe("Multicast group address for broadcast/unknown-unicast flooding"),
|
|
26388
26612
|
vteps_ip_version: VtepsIpVersion.optional().describe("IP version used for VTEP addressing"),
|
|
26389
|
-
mac_address:
|
|
26613
|
+
mac_address: z113.string().optional().describe("MAC address of the VXLAN interface"),
|
|
26390
26614
|
arp: Arp.optional().describe("Address Resolution Protocol mode for the interface"),
|
|
26391
|
-
arp_timeout:
|
|
26392
|
-
max_fdb_size:
|
|
26393
|
-
allow_fast_path:
|
|
26394
|
-
mtu:
|
|
26395
|
-
comment:
|
|
26396
|
-
disabled:
|
|
26615
|
+
arp_timeout: z113.string().optional().describe("ARP entry timeout, e.g. '30s' or 'auto'"),
|
|
26616
|
+
max_fdb_size: z113.number().int().optional().describe("Maximum forwarding database (FDB) size"),
|
|
26617
|
+
allow_fast_path: z113.boolean().optional().describe("Allow FastPath processing for this interface"),
|
|
26618
|
+
mtu: z113.number().int().optional(),
|
|
26619
|
+
comment: z113.string().optional(),
|
|
26620
|
+
disabled: z113.boolean().default(false)
|
|
26397
26621
|
},
|
|
26398
26622
|
async handler(a, ctx) {
|
|
26399
26623
|
ctx.info(`Creating VXLAN tunnel: name=${a.name}, vni=${a.vni}`);
|
|
@@ -26413,7 +26637,7 @@ ${details}` : "VXLAN tunnel creation completed but unable to verify.";
|
|
|
26413
26637
|
annotations: READ,
|
|
26414
26638
|
description: "Lists all VXLAN interfaces (`/interface vxlan print`)." + " Use to inventory existing VXLAN overlays and check their VNI and UDP port assignments." + " Supports optional partial name filter via name_filter." + " For full detail on one interface use get_vxlan_tunnel; for EoIP tunnels use list_eoip_tunnels;" + " for GRE tunnels use list_gre_tunnels; for IPIP tunnels use list_ipip_tunnels." + " Returns name, VNI, port, local-address, MTU, and run-time status for each interface.",
|
|
26415
26639
|
inputSchema: {
|
|
26416
|
-
name_filter:
|
|
26640
|
+
name_filter: z113.string().optional().describe("Partial name match")
|
|
26417
26641
|
},
|
|
26418
26642
|
async handler(a, ctx) {
|
|
26419
26643
|
ctx.info("Listing VXLAN tunnels");
|
|
@@ -26431,7 +26655,7 @@ ${result}`;
|
|
|
26431
26655
|
title: "Get VXLAN Tunnel Interface Detail",
|
|
26432
26656
|
annotations: READ,
|
|
26433
26657
|
description: "Fetches full detail for a single VXLAN interface by name (`/interface vxlan print detail where name=...`)." + " Use to inspect the VNI, UDP port, local-address, source interface, MTU, and status of one VXLAN interface." + " For a summary list of all VXLAN interfaces use list_vxlan_tunnels." + " For EoIP detail use get_eoip_tunnel; for GRE detail use get_gre_tunnel; for IPIP detail use get_ipip_tunnel." + " Returns the complete property set for the named interface, or a not-found message.",
|
|
26434
|
-
inputSchema: { name:
|
|
26658
|
+
inputSchema: { name: z113.string() },
|
|
26435
26659
|
async handler(a, ctx) {
|
|
26436
26660
|
ctx.info(`Getting VXLAN tunnel details: name=${a.name}`);
|
|
26437
26661
|
const result = await executeMikrotikCommand(`/interface vxlan print detail where name="${a.name}"`, ctx);
|
|
@@ -26445,7 +26669,7 @@ ${result}`;
|
|
|
26445
26669
|
title: "Remove VXLAN Tunnel Interface",
|
|
26446
26670
|
annotations: DESTRUCTIVE,
|
|
26447
26671
|
description: "Permanently deletes a VXLAN interface by name (`/interface vxlan remove [find name=...]`)." + " Verifies existence via count-only before removal and returns a not-found message if the interface does not exist." + " This is destructive and immediately severs all L2 overlay traffic using this VNI endpoint." + " For EoIP removal use remove_eoip_tunnel; for GRE use remove_gre_tunnel; for IPIP use remove_ipip_tunnel.",
|
|
26448
|
-
inputSchema: { name:
|
|
26672
|
+
inputSchema: { name: z113.string() },
|
|
26449
26673
|
async handler(a, ctx) {
|
|
26450
26674
|
ctx.info(`Removing VXLAN tunnel: name=${a.name}`);
|
|
26451
26675
|
const count = await executeMikrotikCommand(`/interface vxlan print count-only where name="${a.name}"`, ctx);
|
|
@@ -26460,7 +26684,7 @@ ${result}`;
|
|
|
26460
26684
|
];
|
|
26461
26685
|
|
|
26462
26686
|
// src/tools/user-manager.ts
|
|
26463
|
-
import { z as
|
|
26687
|
+
import { z as z114 } from "zod";
|
|
26464
26688
|
var NOT_AVAILABLE3 = "User Manager is not available on this device (package not installed).";
|
|
26465
26689
|
var userManagerTools = [
|
|
26466
26690
|
defineTool({
|
|
@@ -26484,12 +26708,12 @@ ${result}`;
|
|
|
26484
26708
|
annotations: WRITE_IDEMPOTENT,
|
|
26485
26709
|
description: "Updates the global User Manager daemon configuration (`/user-manager set`) \u2014 toggle the" + " built-in RADIUS server on/off (`enabled`), set the TLS certificate, or enable the" + " profile/payment subsystem (`use_profiles`). Applies changes idempotently to the single" + " global settings entry; returns the full updated settings after applying. For per-user" + " changes use update_user_manager_user; for profile creation use add_user_manager_profile.",
|
|
26486
26710
|
inputSchema: {
|
|
26487
|
-
enabled:
|
|
26488
|
-
certificate:
|
|
26489
|
-
radsec_certificate:
|
|
26490
|
-
accounting_port:
|
|
26491
|
-
authentication_port:
|
|
26492
|
-
use_profiles:
|
|
26711
|
+
enabled: z114.boolean().optional().describe("Enable or disable the User Manager server"),
|
|
26712
|
+
certificate: z114.string().optional().describe("TLS certificate name for RADIUS over TLS"),
|
|
26713
|
+
radsec_certificate: z114.string().optional().describe("Certificate name for RadSec (RADIUS over TLS)"),
|
|
26714
|
+
accounting_port: z114.number().int().optional().describe("UDP port for RADIUS accounting"),
|
|
26715
|
+
authentication_port: z114.number().int().optional().describe("UDP port for RADIUS authentication"),
|
|
26716
|
+
use_profiles: z114.boolean().optional().describe("Enable the profile/payment subsystem")
|
|
26493
26717
|
},
|
|
26494
26718
|
async handler(a, ctx) {
|
|
26495
26719
|
ctx.info("Updating User Manager settings");
|
|
@@ -26513,15 +26737,15 @@ ${details}`;
|
|
|
26513
26737
|
annotations: WRITE,
|
|
26514
26738
|
description: "Creates a new user in the User Manager RADIUS database (`/user-manager user add`) \u2014 for" + " hotspot, PPP, or 802.1X authentication managed by the built-in RADIUS server. Not for" + " local router login accounts; for those use add_user. Supply `name` and `password`;" + " optionally set `group`, `shared_users` (max simultaneous sessions), and custom RADIUS" + " `attributes`. Returns the created user's detail with secrets redacted.",
|
|
26515
26739
|
inputSchema: {
|
|
26516
|
-
name:
|
|
26517
|
-
password:
|
|
26518
|
-
group:
|
|
26519
|
-
shared_users:
|
|
26520
|
-
attributes:
|
|
26521
|
-
caller_id:
|
|
26522
|
-
otp_secret:
|
|
26523
|
-
comment:
|
|
26524
|
-
disabled:
|
|
26740
|
+
name: z114.string().describe("Login name for the user"),
|
|
26741
|
+
password: z114.string().describe("Login password for the user"),
|
|
26742
|
+
group: z114.string().optional(),
|
|
26743
|
+
shared_users: z114.number().int().optional().describe("Max simultaneous sessions"),
|
|
26744
|
+
attributes: z114.string().optional().describe("Custom RADIUS attributes"),
|
|
26745
|
+
caller_id: z114.string().optional().describe("Caller ID the user is restricted to (e.g. MAC)"),
|
|
26746
|
+
otp_secret: z114.string().optional().describe("Base32 OTP shared secret for two-factor auth"),
|
|
26747
|
+
comment: z114.string().optional(),
|
|
26748
|
+
disabled: z114.boolean().default(false)
|
|
26525
26749
|
},
|
|
26526
26750
|
async handler(a, ctx) {
|
|
26527
26751
|
ctx.info(`Adding User Manager user: name=${a.name}`);
|
|
@@ -26543,7 +26767,7 @@ ${redactSecrets(details)}` : "User Manager user creation completed but unable to
|
|
|
26543
26767
|
annotations: READ,
|
|
26544
26768
|
description: "Returns all users in the User Manager RADIUS database (`/user-manager user print`) \u2014 the" + " accounts that authenticate against the built-in RADIUS server for hotspot, PPP, or 802.1X." + " Optionally filter by partial `name_filter`. Not for local router login accounts; for those" + " use list_users. Returns user list with secrets redacted; for full" + " single-user detail use get_user_manager_user.",
|
|
26545
26769
|
inputSchema: {
|
|
26546
|
-
name_filter:
|
|
26770
|
+
name_filter: z114.string().optional().describe("Partial name match")
|
|
26547
26771
|
},
|
|
26548
26772
|
async handler(a, ctx) {
|
|
26549
26773
|
ctx.info("Listing User Manager users");
|
|
@@ -26563,7 +26787,7 @@ ${redactSecrets(result)}`;
|
|
|
26563
26787
|
title: "Get User Manager RADIUS User Detail",
|
|
26564
26788
|
annotations: READ,
|
|
26565
26789
|
description: "Returns full detail for a single User Manager RADIUS user" + " (`/user-manager user print detail where name=`) \u2014 all fields including group," + " shared-users limit, RADIUS attributes, and status, with secrets redacted. Use when you" + " need the complete record for one user by exact name. To browse all users use" + " list_user_manager_users; to modify the record use update_user_manager_user.",
|
|
26566
|
-
inputSchema: { name:
|
|
26790
|
+
inputSchema: { name: z114.string() },
|
|
26567
26791
|
async handler(a, ctx) {
|
|
26568
26792
|
ctx.info(`Getting User Manager user details: name=${a.name}`);
|
|
26569
26793
|
const result = await executeMikrotikCommand(`/user-manager user print detail where name="${a.name}"`, ctx);
|
|
@@ -26580,16 +26804,16 @@ ${redactSecrets(result)}`;
|
|
|
26580
26804
|
annotations: WRITE_IDEMPOTENT,
|
|
26581
26805
|
description: "Modifies an existing User Manager RADIUS user (`/user-manager user set [find name=...]`)" + " \u2014 change name, password, group, shared-users limit, RADIUS attributes, comment, or" + " enabled/disabled state. Locate the user by its current `name` (from" + " list_user_manager_users or get_user_manager_user). Returns the updated record with" + " secrets redacted. To permanently delete the user use remove_user_manager_user.",
|
|
26582
26806
|
inputSchema: {
|
|
26583
|
-
name:
|
|
26584
|
-
new_name:
|
|
26585
|
-
password:
|
|
26586
|
-
group:
|
|
26587
|
-
shared_users:
|
|
26588
|
-
attributes:
|
|
26589
|
-
caller_id:
|
|
26590
|
-
otp_secret:
|
|
26591
|
-
comment:
|
|
26592
|
-
disabled:
|
|
26807
|
+
name: z114.string().describe("Current name of the user to update"),
|
|
26808
|
+
new_name: z114.string().optional(),
|
|
26809
|
+
password: z114.string().optional(),
|
|
26810
|
+
group: z114.string().optional(),
|
|
26811
|
+
shared_users: z114.number().int().optional(),
|
|
26812
|
+
attributes: z114.string().optional(),
|
|
26813
|
+
caller_id: z114.string().optional().describe("Caller ID the user is restricted to (e.g. MAC)"),
|
|
26814
|
+
otp_secret: z114.string().optional().describe("Base32 OTP shared secret for two-factor auth"),
|
|
26815
|
+
comment: z114.string().optional(),
|
|
26816
|
+
disabled: z114.boolean().optional()
|
|
26593
26817
|
},
|
|
26594
26818
|
async handler(a, ctx) {
|
|
26595
26819
|
ctx.info(`Updating User Manager user: name=${a.name}`);
|
|
@@ -26613,7 +26837,7 @@ ${redactSecrets(details)}`;
|
|
|
26613
26837
|
title: "Remove User Manager RADIUS User",
|
|
26614
26838
|
annotations: DESTRUCTIVE,
|
|
26615
26839
|
description: "Permanently deletes a User Manager RADIUS user (`/user-manager user remove [find name=...]`)" + " \u2014 verifies the user exists via count-only check first, then removes them. Does NOT" + " automatically remove the user's profile assignments; check list_user_manager_user_profiles" + " first. To disable without deleting use update_user_manager_user with `disabled=true`.",
|
|
26616
|
-
inputSchema: { name:
|
|
26840
|
+
inputSchema: { name: z114.string() },
|
|
26617
26841
|
async handler(a, ctx) {
|
|
26618
26842
|
ctx.info(`Removing User Manager user: name=${a.name}`);
|
|
26619
26843
|
const count = await executeMikrotikCommand(`/user-manager user print count-only where name="${a.name}"`, ctx);
|
|
@@ -26633,13 +26857,13 @@ ${redactSecrets(details)}`;
|
|
|
26633
26857
|
annotations: WRITE,
|
|
26634
26858
|
description: "Creates a new User Manager service/billing profile (`/user-manager profile add`) \u2014 a named" + " plan template that defines validity period (e.g. '30d'), price, and session override" + " limits (`starts_when`, `override_shared_users`) that can be assigned to users. Profiles are" + " templates only; to link a profile to a specific user use assign_user_manager_profile. For" + " rate/quota constraints attach a limitation (add_user_manager_limitation). Returns the" + " created profile's detail.",
|
|
26635
26859
|
inputSchema: {
|
|
26636
|
-
name:
|
|
26637
|
-
name_for_users:
|
|
26638
|
-
validity:
|
|
26639
|
-
price:
|
|
26640
|
-
starts_when:
|
|
26641
|
-
override_shared_users:
|
|
26642
|
-
comment:
|
|
26860
|
+
name: z114.string().describe("Profile name"),
|
|
26861
|
+
name_for_users: z114.string().optional().describe("Display name shown to users"),
|
|
26862
|
+
validity: z114.string().optional().describe("Validity period, e.g. '30d'"),
|
|
26863
|
+
price: z114.number().optional(),
|
|
26864
|
+
starts_when: z114.enum(["assigned", "first-auth"]).optional(),
|
|
26865
|
+
override_shared_users: z114.string().optional(),
|
|
26866
|
+
comment: z114.string().optional()
|
|
26643
26867
|
},
|
|
26644
26868
|
async handler(a, ctx) {
|
|
26645
26869
|
ctx.info(`Adding User Manager profile: name=${a.name}`);
|
|
@@ -26661,7 +26885,7 @@ ${details}` : "User Manager profile creation completed but unable to verify.";
|
|
|
26661
26885
|
annotations: READ,
|
|
26662
26886
|
description: "Returns all User Manager service/billing profile templates (`/user-manager profile print`)" + " \u2014 the named plans defining validity, price, and session limits. Optionally filter by" + " partial `name_filter`. Not the same as user-profile assignments; to see which profiles" + " are linked to which users use list_user_manager_user_profiles. Returns profile list.",
|
|
26663
26887
|
inputSchema: {
|
|
26664
|
-
name_filter:
|
|
26888
|
+
name_filter: z114.string().optional().describe("Partial name match")
|
|
26665
26889
|
},
|
|
26666
26890
|
async handler(a, ctx) {
|
|
26667
26891
|
ctx.info("Listing User Manager profiles");
|
|
@@ -26681,7 +26905,7 @@ ${result}`;
|
|
|
26681
26905
|
title: "Remove User Manager Service Profile",
|
|
26682
26906
|
annotations: DESTRUCTIVE,
|
|
26683
26907
|
description: "Permanently deletes a User Manager service/billing profile" + " (`/user-manager profile remove [find name=...]`) \u2014 verifies existence via count-only check" + " first, then removes the plan template. Does NOT automatically remove existing user-profile" + " assignments that reference this profile; check list_user_manager_user_profiles before" + " removing to avoid orphaned assignments. For creating a profile use add_user_manager_profile.",
|
|
26684
|
-
inputSchema: { name:
|
|
26908
|
+
inputSchema: { name: z114.string() },
|
|
26685
26909
|
async handler(a, ctx) {
|
|
26686
26910
|
ctx.info(`Removing User Manager profile: name=${a.name}`);
|
|
26687
26911
|
const count = await executeMikrotikCommand(`/user-manager profile print count-only where name="${a.name}"`, ctx);
|
|
@@ -26701,8 +26925,8 @@ ${result}`;
|
|
|
26701
26925
|
annotations: WRITE,
|
|
26702
26926
|
description: "Creates a user-profile assignment in User Manager (`/user-manager user-profile add`) \u2014" + " links an existing service profile plan to a specific user so the user inherits the plan's" + " limits (rate, transfer, validity). Both `user` and `profile` must already exist; to create" + " a user use add_user_manager_user; to create a profile use add_user_manager_profile. To view" + " existing assignments use list_user_manager_user_profiles.",
|
|
26703
26927
|
inputSchema: {
|
|
26704
|
-
user:
|
|
26705
|
-
profile:
|
|
26928
|
+
user: z114.string().describe("User to assign the profile to"),
|
|
26929
|
+
profile: z114.string().describe("Profile to assign")
|
|
26706
26930
|
},
|
|
26707
26931
|
async handler(a, ctx) {
|
|
26708
26932
|
ctx.info(`Assigning profile '${a.profile}' to user '${a.user}'`);
|
|
@@ -26723,7 +26947,7 @@ ${result}`;
|
|
|
26723
26947
|
annotations: READ,
|
|
26724
26948
|
description: "Returns all User Manager user-to-profile assignment records" + " (`/user-manager user-profile print`) \u2014 shows which service profile plan is linked to each" + " user. Optionally filter by partial `user_filter`. Not the same as listing profile" + " definitions; for the plan templates themselves use list_user_manager_profiles. To create an" + " assignment use assign_user_manager_profile.",
|
|
26725
26949
|
inputSchema: {
|
|
26726
|
-
user_filter:
|
|
26950
|
+
user_filter: z114.string().optional().describe("Partial user match")
|
|
26727
26951
|
},
|
|
26728
26952
|
async handler(a, ctx) {
|
|
26729
26953
|
ctx.info("Listing User Manager user-profiles");
|
|
@@ -26744,13 +26968,13 @@ ${result}`;
|
|
|
26744
26968
|
annotations: WRITE,
|
|
26745
26969
|
description: "Registers a new RADIUS client (router or NAS device) in User Manager" + " (`/user-manager router add`) \u2014 the network device that forwards authentication requests to" + " this built-in RADIUS server. Requires a friendly `name`, the client's IP `address`, and a" + " `shared_secret`; optionally set the CoA port. Not related to IP routing; for routing table" + " entries use add_route. Returns the created entry with secrets redacted.",
|
|
26746
26970
|
inputSchema: {
|
|
26747
|
-
name:
|
|
26748
|
-
address:
|
|
26749
|
-
shared_secret:
|
|
26750
|
-
coa_port:
|
|
26751
|
-
protocol:
|
|
26752
|
-
comment:
|
|
26753
|
-
disabled:
|
|
26971
|
+
name: z114.string().describe("Friendly name for the RADIUS client"),
|
|
26972
|
+
address: z114.string().describe("IP address of the RADIUS client"),
|
|
26973
|
+
shared_secret: z114.string().describe("Shared secret for the RADIUS client"),
|
|
26974
|
+
coa_port: z114.number().int().optional().describe("Change-of-Authorization port"),
|
|
26975
|
+
protocol: z114.string().optional().describe("RADIUS transport protocol for this client (e.g. radius, radsec)"),
|
|
26976
|
+
comment: z114.string().optional(),
|
|
26977
|
+
disabled: z114.boolean().default(false)
|
|
26754
26978
|
},
|
|
26755
26979
|
async handler(a, ctx) {
|
|
26756
26980
|
ctx.info(`Adding User Manager router: name=${a.name}, address=${a.address}`);
|
|
@@ -26772,7 +26996,7 @@ ${redactSecrets(details)}` : "User Manager router creation completed but unable
|
|
|
26772
26996
|
annotations: READ,
|
|
26773
26997
|
description: "Returns all RADIUS clients (routers/NAS devices) registered in User Manager" + " (`/user-manager router print`) \u2014 the devices authorized to forward authentication requests" + " to this built-in RADIUS server. Optionally filter by partial `name_filter`. Not related to" + " IP routing; for routing table entries use list_routes. Returns entries with secrets redacted.",
|
|
26774
26998
|
inputSchema: {
|
|
26775
|
-
name_filter:
|
|
26999
|
+
name_filter: z114.string().optional().describe("Partial name match")
|
|
26776
27000
|
},
|
|
26777
27001
|
async handler(a, ctx) {
|
|
26778
27002
|
ctx.info("Listing User Manager routers");
|
|
@@ -26792,7 +27016,7 @@ ${redactSecrets(result)}`;
|
|
|
26792
27016
|
title: "Remove User Manager RADIUS Client (Router/NAS)",
|
|
26793
27017
|
annotations: DESTRUCTIVE,
|
|
26794
27018
|
description: "Permanently removes a RADIUS client (router/NAS) from User Manager" + " (`/user-manager router remove [find name=...]`) \u2014 verifies existence via count-only check" + " first, then deletes the entry. The device will no longer be able to forward authentication" + " requests to this RADIUS server after removal. Not related to IP routing; for routing table" + " management use remove_route.",
|
|
26795
|
-
inputSchema: { name:
|
|
27019
|
+
inputSchema: { name: z114.string() },
|
|
26796
27020
|
async handler(a, ctx) {
|
|
26797
27021
|
ctx.info(`Removing User Manager router: name=${a.name}`);
|
|
26798
27022
|
const count = await executeMikrotikCommand(`/user-manager router print count-only where name="${a.name}"`, ctx);
|
|
@@ -26812,25 +27036,25 @@ ${redactSecrets(result)}`;
|
|
|
26812
27036
|
annotations: WRITE,
|
|
26813
27037
|
description: "Creates a new User Manager limitation template (`/user-manager limitation add`) \u2014 a reusable" + " named set of rate and quota constraints: download rate (`rate_limit_rx`, e.g. '10M')," + " upload rate (`rate_limit_tx`), total transfer cap (`transfer_limit`, e.g. '10G'), and" + " uptime cap (`uptime_limit`, e.g. '1d'). Limitations are templates attached to profiles, not" + " users directly; for service plan templates use add_user_manager_profile. Returns the created" + " limitation's detail.",
|
|
26814
27038
|
inputSchema: {
|
|
26815
|
-
name:
|
|
26816
|
-
rate_limit_rx:
|
|
26817
|
-
rate_limit_tx:
|
|
26818
|
-
rate_limit_min_rx:
|
|
26819
|
-
rate_limit_min_tx:
|
|
26820
|
-
rate_limit_burst_rx:
|
|
26821
|
-
rate_limit_burst_tx:
|
|
26822
|
-
rate_limit_burst_threshold_rx:
|
|
26823
|
-
rate_limit_burst_threshold_tx:
|
|
26824
|
-
rate_limit_burst_time_rx:
|
|
26825
|
-
rate_limit_burst_time_tx:
|
|
26826
|
-
rate_limit_priority:
|
|
26827
|
-
download_limit:
|
|
26828
|
-
upload_limit:
|
|
26829
|
-
transfer_limit:
|
|
26830
|
-
uptime_limit:
|
|
26831
|
-
reset_counters_interval:
|
|
26832
|
-
reset_counters_start_time:
|
|
26833
|
-
comment:
|
|
27039
|
+
name: z114.string().describe("Limitation name"),
|
|
27040
|
+
rate_limit_rx: z114.string().optional().describe("Download rate limit, e.g. '10M'"),
|
|
27041
|
+
rate_limit_tx: z114.string().optional().describe("Upload rate limit, e.g. '10M'"),
|
|
27042
|
+
rate_limit_min_rx: z114.string().optional().describe("Guaranteed (CIR) download rate, e.g. '2M'"),
|
|
27043
|
+
rate_limit_min_tx: z114.string().optional().describe("Guaranteed (CIR) upload rate, e.g. '2M'"),
|
|
27044
|
+
rate_limit_burst_rx: z114.string().optional().describe("Download burst rate, e.g. '20M'"),
|
|
27045
|
+
rate_limit_burst_tx: z114.string().optional().describe("Upload burst rate, e.g. '20M'"),
|
|
27046
|
+
rate_limit_burst_threshold_rx: z114.string().optional().describe("Download burst threshold rate"),
|
|
27047
|
+
rate_limit_burst_threshold_tx: z114.string().optional().describe("Upload burst threshold rate"),
|
|
27048
|
+
rate_limit_burst_time_rx: z114.string().optional().describe("Download burst time, e.g. '10s'"),
|
|
27049
|
+
rate_limit_burst_time_tx: z114.string().optional().describe("Upload burst time, e.g. '10s'"),
|
|
27050
|
+
rate_limit_priority: z114.number().int().optional().describe("Queue priority (1-8)"),
|
|
27051
|
+
download_limit: z114.string().optional().describe("Download transfer cap in bytes, e.g. '5G'"),
|
|
27052
|
+
upload_limit: z114.string().optional().describe("Upload transfer cap in bytes, e.g. '5G'"),
|
|
27053
|
+
transfer_limit: z114.string().optional().describe("Total transfer cap, e.g. '10G'"),
|
|
27054
|
+
uptime_limit: z114.string().optional().describe("Uptime cap, e.g. '1d'"),
|
|
27055
|
+
reset_counters_interval: z114.string().optional().describe("Interval to auto-reset usage counters"),
|
|
27056
|
+
reset_counters_start_time: z114.string().optional().describe("Start time for counter reset interval"),
|
|
27057
|
+
comment: z114.string().optional()
|
|
26834
27058
|
},
|
|
26835
27059
|
async handler(a, ctx) {
|
|
26836
27060
|
ctx.info(`Adding User Manager limitation: name=${a.name}`);
|
|
@@ -26852,7 +27076,7 @@ ${details}` : "User Manager limitation creation completed but unable to verify."
|
|
|
26852
27076
|
annotations: READ,
|
|
26853
27077
|
description: "Returns all User Manager limitation templates (`/user-manager limitation print`) \u2014 the named" + " rate/quota constraint definitions (rate-limit-rx/tx, transfer-limit, uptime-limit) that can" + " be attached to service profiles. Optionally filter by partial `name_filter`. Limitations are" + " distinct from profile plan templates; for those use list_user_manager_profiles.",
|
|
26854
27078
|
inputSchema: {
|
|
26855
|
-
name_filter:
|
|
27079
|
+
name_filter: z114.string().optional().describe("Partial name match")
|
|
26856
27080
|
},
|
|
26857
27081
|
async handler(a, ctx) {
|
|
26858
27082
|
ctx.info("Listing User Manager limitations");
|
|
@@ -26872,7 +27096,7 @@ ${result}`;
|
|
|
26872
27096
|
title: "Remove User Manager Limitation Template",
|
|
26873
27097
|
annotations: DESTRUCTIVE,
|
|
26874
27098
|
description: "Permanently deletes a User Manager limitation template" + " (`/user-manager limitation remove [find name=...]`) \u2014 verifies existence via count-only" + " check first, then removes the constraint definition. Does NOT check whether the limitation" + " is still referenced by any profiles; verify with list_user_manager_profiles before removing" + " to avoid orphaned references. For listing limitations use list_user_manager_limitations.",
|
|
26875
|
-
inputSchema: { name:
|
|
27099
|
+
inputSchema: { name: z114.string() },
|
|
26876
27100
|
async handler(a, ctx) {
|
|
26877
27101
|
ctx.info(`Removing User Manager limitation: name=${a.name}`);
|
|
26878
27102
|
const count = await executeMikrotikCommand(`/user-manager limitation print count-only where name="${a.name}"`, ctx);
|
|
@@ -26892,8 +27116,8 @@ ${result}`;
|
|
|
26892
27116
|
annotations: READ,
|
|
26893
27117
|
description: "Returns User Manager RADIUS accounting session records (`/user-manager session print`) \u2014 the" + " log of authentication and accounting events for users connecting through registered RADIUS" + " clients. Optionally filter by partial `user_filter` or restrict to currently active sessions" + " with `active_only=true`. Returns session data including bytes transferred, uptime, and" + " status. For the user accounts themselves use list_user_manager_users; for registered RADIUS" + " clients use list_user_manager_routers.",
|
|
26894
27118
|
inputSchema: {
|
|
26895
|
-
user_filter:
|
|
26896
|
-
active_only:
|
|
27119
|
+
user_filter: z114.string().optional().describe("Partial user match"),
|
|
27120
|
+
active_only: z114.boolean().default(false).describe("Only show currently active sessions")
|
|
26897
27121
|
},
|
|
26898
27122
|
async handler(a, ctx) {
|
|
26899
27123
|
ctx.info("Listing User Manager sessions");
|
|
@@ -26913,7 +27137,7 @@ ${result}`;
|
|
|
26913
27137
|
];
|
|
26914
27138
|
|
|
26915
27139
|
// src/tools/users.ts
|
|
26916
|
-
import { z as
|
|
27140
|
+
import { z as z115 } from "zod";
|
|
26917
27141
|
var VALID_POLICIES = [
|
|
26918
27142
|
"local",
|
|
26919
27143
|
"telnet",
|
|
@@ -26970,12 +27194,12 @@ var userTools = [
|
|
|
26970
27194
|
annotations: WRITE,
|
|
26971
27195
|
description: "Create a local user account (`/user add`) \u2014 grants interactive access to the router via SSH, Winbox, web, telnet, or API. " + "The `group` parameter (default: `read`) sets permissions; built-in groups are `read`, `write`, `full`; use `add_user_group` to create custom groups. " + "Use `address` to restrict login to a specific IP/subnet. For PPP/dial-in credentials use `create_ppp_secret` instead. " + "Returns the created account's full detail including its `.id`.",
|
|
26972
27196
|
inputSchema: {
|
|
26973
|
-
name:
|
|
26974
|
-
password:
|
|
26975
|
-
group:
|
|
26976
|
-
address:
|
|
26977
|
-
comment:
|
|
26978
|
-
disabled:
|
|
27197
|
+
name: z115.string(),
|
|
27198
|
+
password: z115.string(),
|
|
27199
|
+
group: z115.string().default("read"),
|
|
27200
|
+
address: z115.string().optional(),
|
|
27201
|
+
comment: z115.string().optional(),
|
|
27202
|
+
disabled: z115.boolean().default(false)
|
|
26979
27203
|
},
|
|
26980
27204
|
async handler(a, ctx) {
|
|
26981
27205
|
ctx.info(`Adding user: name=${a.name}, group=${a.group}`);
|
|
@@ -27007,10 +27231,10 @@ ${redactSecrets(details)}`;
|
|
|
27007
27231
|
annotations: READ,
|
|
27008
27232
|
description: "List local router user accounts (`/user print`) \u2014 shows each account's group, address restriction, and enabled/disabled state. " + "Supports optional filters: `name_filter` (name substring match), `group_filter` (exact group name), `disabled_only`. " + "Note: `active_only` is accepted by the schema but is not applied as a filter \u2014 it has no effect on the output. " + "Passwords are redacted from output. For currently logged-in sessions use `get_active_users`. For PPP dial-in secrets use `create_ppp_secret`.",
|
|
27009
27233
|
inputSchema: {
|
|
27010
|
-
name_filter:
|
|
27011
|
-
group_filter:
|
|
27012
|
-
disabled_only:
|
|
27013
|
-
active_only:
|
|
27234
|
+
name_filter: z115.string().optional(),
|
|
27235
|
+
group_filter: z115.string().optional(),
|
|
27236
|
+
disabled_only: z115.boolean().default(false),
|
|
27237
|
+
active_only: z115.boolean().default(false)
|
|
27014
27238
|
},
|
|
27015
27239
|
async handler(a, ctx) {
|
|
27016
27240
|
ctx.info(`Listing users with filters: name=${a.name_filter}, group=${a.group_filter}`);
|
|
@@ -27034,7 +27258,7 @@ ${redactSecrets(result)}`;
|
|
|
27034
27258
|
title: "Get Local User Account Details",
|
|
27035
27259
|
annotations: READ,
|
|
27036
27260
|
description: "Fetch full detail for a single local user account (`/user print detail where name=...`). " + "Identified by login `name`. Passwords are redacted from output. " + "For all accounts use `list_users`; for currently active sessions use `get_active_users`.",
|
|
27037
|
-
inputSchema: { name:
|
|
27261
|
+
inputSchema: { name: z115.string() },
|
|
27038
27262
|
async handler(a, ctx) {
|
|
27039
27263
|
ctx.info(`Getting user details: name=${a.name}`);
|
|
27040
27264
|
const result = await executeMikrotikCommand(`/user print detail where name="${a.name}"`, ctx);
|
|
@@ -27051,13 +27275,13 @@ ${redactSecrets(result)}`;
|
|
|
27051
27275
|
annotations: WRITE_IDEMPOTENT,
|
|
27052
27276
|
description: "Modify a local user account (`/user set [find name=...]`). " + "Can change login name (`new_name`), `password`, `group`, allowed source `address` (pass empty string to remove address restriction), `comment`, or `disabled` state. " + "For toggling enabled/disabled state only, prefer `enable_user` or `disable_user`. " + "Returns the updated user detail with passwords redacted.",
|
|
27053
27277
|
inputSchema: {
|
|
27054
|
-
name:
|
|
27055
|
-
new_name:
|
|
27056
|
-
password:
|
|
27057
|
-
group:
|
|
27058
|
-
address:
|
|
27059
|
-
comment:
|
|
27060
|
-
disabled:
|
|
27278
|
+
name: z115.string(),
|
|
27279
|
+
new_name: z115.string().optional(),
|
|
27280
|
+
password: z115.string().optional(),
|
|
27281
|
+
group: z115.string().optional(),
|
|
27282
|
+
address: z115.string().optional(),
|
|
27283
|
+
comment: z115.string().optional(),
|
|
27284
|
+
disabled: z115.boolean().optional()
|
|
27061
27285
|
},
|
|
27062
27286
|
async handler(a, ctx) {
|
|
27063
27287
|
return runUpdateUser(a, ctx);
|
|
@@ -27068,7 +27292,7 @@ ${redactSecrets(result)}`;
|
|
|
27068
27292
|
title: "Remove Local User Account",
|
|
27069
27293
|
annotations: DESTRUCTIVE,
|
|
27070
27294
|
description: "Permanently delete a local user account (`/user remove [find name=...]`). " + "Refuses to remove the built-in `admin` account. Verifies the user exists before removing. " + "To temporarily block access without deleting use `disable_user`. To end a live session without deleting the account use `disconnect_user`.",
|
|
27071
|
-
inputSchema: { name:
|
|
27295
|
+
inputSchema: { name: z115.string() },
|
|
27072
27296
|
async handler(a, ctx) {
|
|
27073
27297
|
ctx.info(`Removing user: name=${a.name}`);
|
|
27074
27298
|
if (a.name.toLowerCase() === "admin")
|
|
@@ -27087,7 +27311,7 @@ ${redactSecrets(result)}`;
|
|
|
27087
27311
|
title: "Disable Local User Account",
|
|
27088
27312
|
annotations: WRITE_IDEMPOTENT,
|
|
27089
27313
|
description: "Disable a local user account (`/user set [find name=...] disabled=yes`), preventing new logins without deleting the account. " + "To re-enable use `enable_user`. For a full attribute update use `update_user`. To permanently delete the account use `remove_user`.",
|
|
27090
|
-
inputSchema: { name:
|
|
27314
|
+
inputSchema: { name: z115.string() },
|
|
27091
27315
|
async handler(a, ctx) {
|
|
27092
27316
|
return runUpdateUser({ name: a.name, disabled: true }, ctx);
|
|
27093
27317
|
}
|
|
@@ -27097,7 +27321,7 @@ ${redactSecrets(result)}`;
|
|
|
27097
27321
|
title: "Enable Local User Account",
|
|
27098
27322
|
annotations: WRITE_IDEMPOTENT,
|
|
27099
27323
|
description: "Re-enable a previously disabled local user account (`/user set [find name=...] disabled=no`). " + "To disable use `disable_user`. For a full attribute update use `update_user`.",
|
|
27100
|
-
inputSchema: { name:
|
|
27324
|
+
inputSchema: { name: z115.string() },
|
|
27101
27325
|
async handler(a, ctx) {
|
|
27102
27326
|
return runUpdateUser({ name: a.name, disabled: false }, ctx);
|
|
27103
27327
|
}
|
|
@@ -27108,10 +27332,10 @@ ${redactSecrets(result)}`;
|
|
|
27108
27332
|
annotations: WRITE,
|
|
27109
27333
|
description: "Create a custom user group (`/user group add`) that defines a named permission policy for router access. " + "`policy` is a list of permissions to grant from: local, telnet, ssh, ftp, reboot, read, write, policy, test, winbox, password, web, sniff, sensitive, api, romon, dude, tikapp, rest-api. " + "The built-in groups (`read`, `write`, `full`) already exist on the device; this tool does not guard against those names \u2014 attempting to create a group with a duplicate name will be rejected by the device. Assign users to the new group via `add_user` or `update_user`. " + "Returns the created group's full detail.",
|
|
27110
27334
|
inputSchema: {
|
|
27111
|
-
name:
|
|
27112
|
-
policy:
|
|
27113
|
-
skin:
|
|
27114
|
-
comment:
|
|
27335
|
+
name: z115.string(),
|
|
27336
|
+
policy: z115.array(z115.string()),
|
|
27337
|
+
skin: z115.string().optional(),
|
|
27338
|
+
comment: z115.string().optional()
|
|
27115
27339
|
},
|
|
27116
27340
|
async handler(a, ctx) {
|
|
27117
27341
|
ctx.info(`Adding user group: name=${a.name}`);
|
|
@@ -27148,8 +27372,8 @@ ${details}`;
|
|
|
27148
27372
|
annotations: READ,
|
|
27149
27373
|
description: "List all user groups (`/user group print`), including built-in groups (`read`, `write`, `full`) and custom ones, showing their policy sets. " + "Supports optional filters: `name_filter` (name substring), `policy_filter` (policy substring). " + "To see individual user accounts use `list_users`; to see which users belong to a specific group use `list_users` with `group_filter`.",
|
|
27150
27374
|
inputSchema: {
|
|
27151
|
-
name_filter:
|
|
27152
|
-
policy_filter:
|
|
27375
|
+
name_filter: z115.string().optional(),
|
|
27376
|
+
policy_filter: z115.string().optional()
|
|
27153
27377
|
},
|
|
27154
27378
|
async handler(a, ctx) {
|
|
27155
27379
|
ctx.info(`Listing user groups with filters: name=${a.name_filter}`);
|
|
@@ -27171,7 +27395,7 @@ ${result}`;
|
|
|
27171
27395
|
title: "Get User Group Details",
|
|
27172
27396
|
annotations: READ,
|
|
27173
27397
|
description: "Fetch full detail for a single user group (`/user group print detail where name=...`), showing its complete policy list and skin setting. " + "For all groups use `list_user_groups`. To see which users belong to this group use `list_users` with `group_filter`.",
|
|
27174
|
-
inputSchema: { name:
|
|
27398
|
+
inputSchema: { name: z115.string() },
|
|
27175
27399
|
async handler(a, ctx) {
|
|
27176
27400
|
ctx.info(`Getting user group details: name=${a.name}`);
|
|
27177
27401
|
const result = await executeMikrotikCommand(`/user group print detail where name="${a.name}"`, ctx);
|
|
@@ -27188,11 +27412,11 @@ ${result}`;
|
|
|
27188
27412
|
annotations: WRITE_IDEMPOTENT,
|
|
27189
27413
|
description: "Modify a custom user group (`/user group set [find name=...]`). " + "Can change group name (`new_name`), `policy` list, `skin`, or `comment`. " + "Refuses to modify built-in groups (`read`, `write`, `full`). " + "Valid policies: local, telnet, ssh, ftp, reboot, read, write, policy, test, winbox, password, web, sniff, sensitive, api, romon, dude, tikapp, rest-api. " + "Returns the updated group detail.",
|
|
27190
27414
|
inputSchema: {
|
|
27191
|
-
name:
|
|
27192
|
-
new_name:
|
|
27193
|
-
policy:
|
|
27194
|
-
skin:
|
|
27195
|
-
comment:
|
|
27415
|
+
name: z115.string(),
|
|
27416
|
+
new_name: z115.string().optional(),
|
|
27417
|
+
policy: z115.array(z115.string()).optional(),
|
|
27418
|
+
skin: z115.string().optional(),
|
|
27419
|
+
comment: z115.string().optional()
|
|
27196
27420
|
},
|
|
27197
27421
|
async handler(a, ctx) {
|
|
27198
27422
|
ctx.info(`Updating user group: name=${a.name}`);
|
|
@@ -27225,7 +27449,7 @@ ${details}`;
|
|
|
27225
27449
|
title: "Remove User Group",
|
|
27226
27450
|
annotations: DESTRUCTIVE,
|
|
27227
27451
|
description: "Delete a custom user group (`/user group remove [find name=...]`). " + "Refuses to remove built-in groups (`read`, `write`, `full`). " + "Checks that no users are currently assigned to the group \u2014 reassign or remove those users first via `update_user` or `remove_user`. " + "To remove individual user accounts use `remove_user`.",
|
|
27228
|
-
inputSchema: { name:
|
|
27452
|
+
inputSchema: { name: z115.string() },
|
|
27229
27453
|
async handler(a, ctx) {
|
|
27230
27454
|
ctx.info(`Removing user group: name=${a.name}`);
|
|
27231
27455
|
if (BUILTIN_GROUPS.includes(a.name))
|
|
@@ -27263,7 +27487,7 @@ ${result}`;
|
|
|
27263
27487
|
title: "Disconnect Active User Session",
|
|
27264
27488
|
annotations: DESTRUCTIVE,
|
|
27265
27489
|
description: "Forcibly terminate an active user session (`/user active remove <user_id>`). " + "`user_id` is the `.id` from `get_active_users`. " + "Does NOT delete the user account \u2014 to delete the account use `remove_user`. To prevent future logins without deleting use `disable_user`.",
|
|
27266
|
-
inputSchema: { user_id:
|
|
27490
|
+
inputSchema: { user_id: z115.string() },
|
|
27267
27491
|
async handler(a, ctx) {
|
|
27268
27492
|
ctx.info(`Disconnecting user: user_id=${a.user_id}`);
|
|
27269
27493
|
const result = await executeMikrotikCommand(`/user active remove ${a.user_id}`, ctx);
|
|
@@ -27277,7 +27501,7 @@ ${result}`;
|
|
|
27277
27501
|
title: "Export User Configuration to File",
|
|
27278
27502
|
annotations: READ,
|
|
27279
27503
|
description: "Export the router's user accounts and user-group configuration as a RouterOS script (`/user export file=<filename>`). " + "The file is saved on the router's flash storage as `<filename>.rsc`. If `filename` is omitted, defaults to `user_config`. " + "The exported script can be used to restore user accounts on another device.",
|
|
27280
|
-
inputSchema: { filename:
|
|
27504
|
+
inputSchema: { filename: z115.string().optional() },
|
|
27281
27505
|
async handler(a, ctx) {
|
|
27282
27506
|
ctx.info("Exporting user configuration");
|
|
27283
27507
|
const filename = a.filename || "user_config";
|
|
@@ -27293,8 +27517,8 @@ ${result}`;
|
|
|
27293
27517
|
annotations: WRITE,
|
|
27294
27518
|
description: "Import an SSH public key for a user (`/user ssh-keys import user=... public-key-file=...`), enabling key-based SSH authentication in addition to password login. " + "`key_file` must be the path to a public key file already present on the router's filesystem. " + "To list a user's existing keys use `list_user_ssh_keys`; to remove a key use `remove_user_ssh_key`.",
|
|
27295
27519
|
inputSchema: {
|
|
27296
|
-
username:
|
|
27297
|
-
key_file:
|
|
27520
|
+
username: z115.string(),
|
|
27521
|
+
key_file: z115.string()
|
|
27298
27522
|
},
|
|
27299
27523
|
async handler(a, ctx) {
|
|
27300
27524
|
ctx.info(`Setting SSH keys for user: ${a.username}`);
|
|
@@ -27311,7 +27535,7 @@ ${result}`;
|
|
|
27311
27535
|
title: "List User SSH Keys",
|
|
27312
27536
|
annotations: READ,
|
|
27313
27537
|
description: "List SSH public keys registered for a specific user (`/user ssh-keys print where user=...`). " + "Returns each key's `.id`, which is required by `remove_user_ssh_key`. To add a key use `set_user_ssh_keys`.",
|
|
27314
|
-
inputSchema: { username:
|
|
27538
|
+
inputSchema: { username: z115.string() },
|
|
27315
27539
|
async handler(a, ctx) {
|
|
27316
27540
|
ctx.info(`Listing SSH keys for user: ${a.username}`);
|
|
27317
27541
|
const result = await executeMikrotikCommand(`/user ssh-keys print where user="${a.username}"`, ctx);
|
|
@@ -27327,7 +27551,7 @@ ${result}`;
|
|
|
27327
27551
|
title: "Remove User SSH Key",
|
|
27328
27552
|
annotations: DESTRUCTIVE,
|
|
27329
27553
|
description: "Delete a specific SSH public key (`/user ssh-keys remove <key_id>`). " + "`key_id` is the `.id` from `list_user_ssh_keys`. " + "Does NOT disable the user's password-based login \u2014 to block all logins use `disable_user`; to delete the account use `remove_user`.",
|
|
27330
|
-
inputSchema: { key_id:
|
|
27554
|
+
inputSchema: { key_id: z115.string() },
|
|
27331
27555
|
async handler(a, ctx) {
|
|
27332
27556
|
ctx.info(`Removing SSH key: key_id=${a.key_id}`);
|
|
27333
27557
|
const result = await executeMikrotikCommand(`/user ssh-keys remove ${a.key_id}`, ctx);
|
|
@@ -27339,7 +27563,7 @@ ${result}`;
|
|
|
27339
27563
|
];
|
|
27340
27564
|
|
|
27341
27565
|
// src/tools/vlan-designer.ts
|
|
27342
|
-
import { z as
|
|
27566
|
+
import { z as z116 } from "zod";
|
|
27343
27567
|
function defaultRange2(subnet) {
|
|
27344
27568
|
const o = subnet.split("/")[0].split(".");
|
|
27345
27569
|
return `${o[0]}.${o[1]}.${o[2]}.10-${o[0]}.${o[1]}.${o[2]}.254`;
|
|
@@ -27351,18 +27575,18 @@ var vlanDesignerTools = [
|
|
|
27351
27575
|
annotations: DANGEROUS,
|
|
27352
27576
|
description: "Stands up a complete isolated network segment in one call: a VLAN interface on the bridge, its " + "gateway IP, a DHCP server + pool + network, optional internet access (srcnat masquerade), and " + "inter-VLAN isolation firewall rules \u2014 e.g. 'a guest VLAN that reaches the internet but not the " + "LAN'. DEFAULTS TO A DRY RUN (`apply=false`) showing every command grouped; set `apply=true` to " + "build it. Bridge VLAN tagging is added when `tagged_ports`/`untagged_ports` are given (requires " + "bridge vlan-filtering). Isolation drops forward traffic from this subnet to each `isolate_from` " + "subnet. Returns the plan or a build report.",
|
|
27353
27577
|
inputSchema: {
|
|
27354
|
-
vlan_id:
|
|
27355
|
-
name:
|
|
27356
|
-
subnet:
|
|
27357
|
-
gateway:
|
|
27358
|
-
bridge:
|
|
27359
|
-
tagged_ports:
|
|
27360
|
-
untagged_ports:
|
|
27361
|
-
dhcp:
|
|
27362
|
-
dhcp_range:
|
|
27363
|
-
internet:
|
|
27364
|
-
isolate_from:
|
|
27365
|
-
apply:
|
|
27578
|
+
vlan_id: z116.number().int().min(1).max(4094),
|
|
27579
|
+
name: z116.string().describe("Name for the VLAN interface, e.g. 'guest'"),
|
|
27580
|
+
subnet: z116.string().describe("CIDR for the segment, e.g. '192.168.30.0/24'"),
|
|
27581
|
+
gateway: z116.string().describe("Router's address in the segment, e.g. '192.168.30.1'"),
|
|
27582
|
+
bridge: z116.string().default("bridge").describe("Bridge to put the VLAN on"),
|
|
27583
|
+
tagged_ports: z116.string().optional().describe("Comma-separated trunk/tagged ports (+ the bridge)"),
|
|
27584
|
+
untagged_ports: z116.string().optional().describe("Comma-separated access/untagged ports"),
|
|
27585
|
+
dhcp: z116.boolean().default(true).describe("Create a DHCP server + pool for the segment"),
|
|
27586
|
+
dhcp_range: z116.string().optional().describe("Pool range; defaults to .10\u2013.254 of the subnet"),
|
|
27587
|
+
internet: z116.boolean().default(true).describe("Allow internet access via srcnat masquerade"),
|
|
27588
|
+
isolate_from: z116.array(z116.string()).optional().describe("Subnets this segment must NOT reach, e.g. ['192.168.1.0/24']"),
|
|
27589
|
+
apply: z116.boolean().default(false).describe("false = preview (default); true = build")
|
|
27366
27590
|
},
|
|
27367
27591
|
async handler(a, ctx) {
|
|
27368
27592
|
const prefix = a.subnet.split("/")[1] ?? "24";
|
|
@@ -27435,9 +27659,9 @@ Review partial segment (the VLAN may exist without DHCP/firewall).`;
|
|
|
27435
27659
|
];
|
|
27436
27660
|
|
|
27437
27661
|
// src/tools/vlan.ts
|
|
27438
|
-
import { z as
|
|
27439
|
-
var ArpMode2 =
|
|
27440
|
-
var LoopProtect =
|
|
27662
|
+
import { z as z117 } from "zod";
|
|
27663
|
+
var ArpMode2 = z117.enum(["enabled", "disabled", "proxy-arp", "reply-only"]);
|
|
27664
|
+
var LoopProtect = z117.enum(["default", "on", "off"]);
|
|
27441
27665
|
var vlanTools = [
|
|
27442
27666
|
defineTool({
|
|
27443
27667
|
name: "create_vlan_interface",
|
|
@@ -27445,18 +27669,18 @@ var vlanTools = [
|
|
|
27445
27669
|
annotations: WRITE,
|
|
27446
27670
|
description: "Creates an 802.1Q VLAN sub-interface (`/interface vlan`) on a specified parent physical or bridge interface." + " Use this to segment layer-2 traffic by VLAN ID (1\u20134094); set `use_service_tag=true` for 802.1ad QinQ double-tagging." + " For listing existing VLAN interfaces use `list_vlan_interfaces`; for editing an existing VLAN use `update_vlan_interface`." + " Returns the created interface's full detail including its name, which is the identifier accepted by `get_vlan_interface`, `update_vlan_interface`, and `remove_vlan_interface`." + " ARP mode accepts: enabled (default), disabled, proxy-arp, reply-only.",
|
|
27447
27671
|
inputSchema: {
|
|
27448
|
-
name:
|
|
27449
|
-
vlan_id:
|
|
27450
|
-
interface:
|
|
27451
|
-
comment:
|
|
27452
|
-
disabled:
|
|
27453
|
-
mtu:
|
|
27454
|
-
use_service_tag:
|
|
27672
|
+
name: z117.string().describe("Name for the new VLAN interface, e.g. 'vlan100'"),
|
|
27673
|
+
vlan_id: z117.number().int().min(1).max(4094).describe("802.1Q VLAN ID (1-4094)"),
|
|
27674
|
+
interface: z117.string().describe("Parent interface, e.g. 'ether1' or 'bridge'"),
|
|
27675
|
+
comment: z117.string().optional(),
|
|
27676
|
+
disabled: z117.boolean().default(false),
|
|
27677
|
+
mtu: z117.number().int().optional(),
|
|
27678
|
+
use_service_tag: z117.boolean().default(false).describe("Use 802.1ad service tag (QinQ)"),
|
|
27455
27679
|
arp: ArpMode2.default("enabled"),
|
|
27456
|
-
arp_timeout:
|
|
27680
|
+
arp_timeout: z117.string().optional(),
|
|
27457
27681
|
loop_protect: LoopProtect.optional().describe("Loop protection: default, on, off"),
|
|
27458
|
-
loop_protect_disable_time:
|
|
27459
|
-
loop_protect_send_interval:
|
|
27682
|
+
loop_protect_disable_time: z117.string().optional().describe("Time to disable interface on loop detection, e.g. '5m' (0 = forever)"),
|
|
27683
|
+
loop_protect_send_interval: z117.string().optional().describe("Interval between loop-protect probe packets, e.g. '5s'")
|
|
27460
27684
|
},
|
|
27461
27685
|
async handler(a, ctx) {
|
|
27462
27686
|
ctx.info(`Creating VLAN interface: name=${a.name}, vlan_id=${a.vlan_id}, interface=${a.interface}`);
|
|
@@ -27476,10 +27700,10 @@ ${details}` : "VLAN interface creation completed but unable to verify.";
|
|
|
27476
27700
|
annotations: READ,
|
|
27477
27701
|
description: "Lists all 802.1Q VLAN sub-interfaces (`/interface vlan print`) with optional filters by name substring, VLAN ID, parent interface, or disabled state." + " Use to discover existing VLANs and obtain interface names for `get_vlan_interface`, `update_vlan_interface`, or `remove_vlan_interface`." + " For a single interface's full property detail use `get_vlan_interface`." + " Returns a table of matching VLAN interfaces, or a not-found message when no entries match the filters.",
|
|
27478
27702
|
inputSchema: {
|
|
27479
|
-
name_filter:
|
|
27480
|
-
vlan_id_filter:
|
|
27481
|
-
interface_filter:
|
|
27482
|
-
disabled_only:
|
|
27703
|
+
name_filter: z117.string().optional().describe("Partial name match"),
|
|
27704
|
+
vlan_id_filter: z117.number().int().optional(),
|
|
27705
|
+
interface_filter: z117.string().optional().describe("Exact parent interface name"),
|
|
27706
|
+
disabled_only: z117.boolean().default(false)
|
|
27483
27707
|
},
|
|
27484
27708
|
async handler(a, ctx) {
|
|
27485
27709
|
ctx.info("Listing VLAN interfaces");
|
|
@@ -27503,7 +27727,7 @@ ${result}`;
|
|
|
27503
27727
|
title: "Get VLAN Interface Details",
|
|
27504
27728
|
annotations: READ,
|
|
27505
27729
|
description: 'Returns full detail for a single named VLAN interface (`/interface vlan print detail where name="..."`), including VLAN ID, parent interface, ARP mode, MTU, and running state.' + " Use when you already know the exact interface name and need all properties." + " For searching across all VLANs or filtering by parent interface or VLAN ID use `list_vlan_interfaces`.",
|
|
27506
|
-
inputSchema: { name:
|
|
27730
|
+
inputSchema: { name: z117.string() },
|
|
27507
27731
|
async handler(a, ctx) {
|
|
27508
27732
|
ctx.info(`Getting VLAN interface details: name=${a.name}`);
|
|
27509
27733
|
const result = await executeMikrotikCommand(`/interface vlan print detail where name="${a.name}"`, ctx);
|
|
@@ -27518,19 +27742,19 @@ ${result}`;
|
|
|
27518
27742
|
annotations: WRITE_IDEMPOTENT,
|
|
27519
27743
|
description: 'Modifies properties of an existing VLAN sub-interface (`/interface vlan set [find name="..."]`).' + " Accepts any subset of the create parameters; omit fields to leave them unchanged." + " Supply the current `name` from `list_vlan_interfaces` or `get_vlan_interface`; use `new_name` to rename the interface." + " For creating a new VLAN interface use `create_vlan_interface`; to permanently delete use `remove_vlan_interface`." + " Returns the updated interface's full detail after applying the change." + " ARP mode accepts: enabled, disabled, proxy-arp, reply-only.",
|
|
27520
27744
|
inputSchema: {
|
|
27521
|
-
name:
|
|
27522
|
-
new_name:
|
|
27523
|
-
vlan_id:
|
|
27524
|
-
interface:
|
|
27525
|
-
comment:
|
|
27526
|
-
disabled:
|
|
27527
|
-
mtu:
|
|
27528
|
-
use_service_tag:
|
|
27745
|
+
name: z117.string().describe("Current name of the VLAN interface to update"),
|
|
27746
|
+
new_name: z117.string().optional(),
|
|
27747
|
+
vlan_id: z117.number().int().min(1).max(4094).optional(),
|
|
27748
|
+
interface: z117.string().optional(),
|
|
27749
|
+
comment: z117.string().optional(),
|
|
27750
|
+
disabled: z117.boolean().optional(),
|
|
27751
|
+
mtu: z117.number().int().optional(),
|
|
27752
|
+
use_service_tag: z117.boolean().optional(),
|
|
27529
27753
|
arp: ArpMode2.optional(),
|
|
27530
|
-
arp_timeout:
|
|
27754
|
+
arp_timeout: z117.string().optional(),
|
|
27531
27755
|
loop_protect: LoopProtect.optional().describe("Loop protection: default, on, off"),
|
|
27532
|
-
loop_protect_disable_time:
|
|
27533
|
-
loop_protect_send_interval:
|
|
27756
|
+
loop_protect_disable_time: z117.string().optional().describe("Time to disable interface on loop detection, e.g. '5m' (0 = forever)"),
|
|
27757
|
+
loop_protect_send_interval: z117.string().optional().describe("Interval between loop-protect probe packets, e.g. '5s'")
|
|
27534
27758
|
},
|
|
27535
27759
|
async handler(a, ctx) {
|
|
27536
27760
|
ctx.info(`Updating VLAN interface: name=${a.name}`);
|
|
@@ -27552,7 +27776,7 @@ ${details}`;
|
|
|
27552
27776
|
title: "Remove VLAN Interface",
|
|
27553
27777
|
annotations: DESTRUCTIVE,
|
|
27554
27778
|
description: 'Permanently deletes a VLAN sub-interface (`/interface vlan remove [find name="..."]`) after confirming it exists via a count-only check.' + " Supply the interface `name` from `list_vlan_interfaces` or `get_vlan_interface`." + " Removing a VLAN interface also removes IP addresses assigned to it; firewall rules and other configuration that reference it by name are not automatically deleted and will remain as orphaned, ineffective entries." + " To disable a VLAN temporarily without deleting it use `update_vlan_interface` with `disabled=true`.",
|
|
27555
|
-
inputSchema: { name:
|
|
27779
|
+
inputSchema: { name: z117.string() },
|
|
27556
27780
|
async handler(a, ctx) {
|
|
27557
27781
|
ctx.info(`Removing VLAN interface: name=${a.name}`);
|
|
27558
27782
|
const count = await executeMikrotikCommand(`/interface vlan print count-only where name="${a.name}"`, ctx);
|
|
@@ -27567,7 +27791,7 @@ ${details}`;
|
|
|
27567
27791
|
];
|
|
27568
27792
|
|
|
27569
27793
|
// src/tools/wireguard-mesh.ts
|
|
27570
|
-
import { z as
|
|
27794
|
+
import { z as z118 } from "zod";
|
|
27571
27795
|
function meshAddress(prefix, index) {
|
|
27572
27796
|
const [net, len = "24"] = prefix.split("/");
|
|
27573
27797
|
const octets = net.split(".");
|
|
@@ -27584,16 +27808,16 @@ var wireguardMeshTools = [
|
|
|
27584
27808
|
annotations: DANGEROUS,
|
|
27585
27809
|
description: "Stands up a WireGuard VPN across several configured devices in ONE call: ensures a WireGuard " + "interface on each, reads each device's public key, assigns every device a mesh address from " + "`address_prefix`, then wires the peers between routers \u2014 `topology=full-mesh` connects every " + "pair, `hub-spoke` connects the `hub` to each spoke \u2014 distributing public keys automatically. " + "Endpoints default to each device's configured host (override per device via `endpoints`); add " + "each site's LAN subnet via `allowed_lans` to route it through the tunnel. DEFAULTS TO A DRY RUN " + "(`apply=false`) that shows the full plan; set `apply=true` to build it. Operates across " + "MULTIPLE devices, so it is not affected by the single `device` selector. SSH devices only " + "(needs to read public keys). Returns the plan, or a per-device build report.",
|
|
27586
27810
|
inputSchema: {
|
|
27587
|
-
devices:
|
|
27588
|
-
address_prefix:
|
|
27589
|
-
interface:
|
|
27590
|
-
listen_port:
|
|
27591
|
-
topology:
|
|
27592
|
-
hub:
|
|
27593
|
-
endpoints:
|
|
27594
|
-
allowed_lans:
|
|
27595
|
-
persistent_keepalive:
|
|
27596
|
-
apply:
|
|
27811
|
+
devices: z118.array(z118.string()).min(2).describe("Configured device names to include in the mesh (2+)"),
|
|
27812
|
+
address_prefix: z118.string().default("10.20.0.0/24").describe("Mesh subnet; each device gets <prefix>.<index+1> on its WireGuard interface"),
|
|
27813
|
+
interface: z118.string().default("wg-mesh").describe("WireGuard interface name to create/use"),
|
|
27814
|
+
listen_port: z118.number().int().default(13231),
|
|
27815
|
+
topology: z118.enum(["full-mesh", "hub-spoke"]).default("full-mesh"),
|
|
27816
|
+
hub: z118.string().optional().describe("Hub device name (required when topology=hub-spoke)"),
|
|
27817
|
+
endpoints: z118.record(z118.string(), z118.string()).optional().describe('Per-device public endpoint host override, e.g. {"site-a":"a.example.com"}'),
|
|
27818
|
+
allowed_lans: z118.record(z118.string(), z118.string()).optional().describe('Per-device LAN subnet to route through the tunnel, e.g. {"site-a":"192.168.10.0/24"}'),
|
|
27819
|
+
persistent_keepalive: z118.string().default("25s"),
|
|
27820
|
+
apply: z118.boolean().default(false).describe("false = preview the plan (default); true = build")
|
|
27597
27821
|
},
|
|
27598
27822
|
async handler(a, ctx) {
|
|
27599
27823
|
const devices = a.devices;
|
|
@@ -27684,7 +27908,7 @@ Check handshakes per device with get_wireguard_peers / list_wireguard_peers.`;
|
|
|
27684
27908
|
|
|
27685
27909
|
// src/tools/vpn-onboard.ts
|
|
27686
27910
|
import { generateKeyPairSync } from "crypto";
|
|
27687
|
-
import { z as
|
|
27911
|
+
import { z as z119 } from "zod";
|
|
27688
27912
|
function generateWireGuardKeypair() {
|
|
27689
27913
|
const { privateKey, publicKey } = generateKeyPairSync("x25519");
|
|
27690
27914
|
const priv = privateKey.export({ type: "pkcs8", format: "der" });
|
|
@@ -27701,13 +27925,13 @@ var vpnOnboardTools = [
|
|
|
27701
27925
|
annotations: WRITE,
|
|
27702
27926
|
description: "Generates a ready-to-use WireGuard remote-access profile for one user: creates a client " + "keypair, adds the peer to the server `interface` (allowed-address = the client's tunnel IP), " + "reads the server's public key, and returns a complete client .conf to paste into the WireGuard " + "app or a QR generator. The peer is tagged `vpn-user: <user>` so revoke_wireguard_user can remove " + "it. NOTE: the returned config contains the client PRIVATE key (required to connect) \u2014 handle it " + "securely. `endpoint` is the server's public host:port; `allowed_ips` controls split vs full " + "tunnel. SSH devices only. Returns the client config.",
|
|
27703
27927
|
inputSchema: {
|
|
27704
|
-
interface:
|
|
27705
|
-
user:
|
|
27706
|
-
address:
|
|
27707
|
-
endpoint:
|
|
27708
|
-
dns:
|
|
27709
|
-
allowed_ips:
|
|
27710
|
-
keepalive:
|
|
27928
|
+
interface: z119.string().describe("Existing WireGuard SERVER interface, e.g. 'wg-server'"),
|
|
27929
|
+
user: z119.string().describe("User/device label, e.g. 'alice-laptop'"),
|
|
27930
|
+
address: z119.string().describe("Tunnel IP to assign the client, e.g. '10.20.0.50'"),
|
|
27931
|
+
endpoint: z119.string().describe("Server public endpoint host:port, e.g. 'vpn.example.com:13231'"),
|
|
27932
|
+
dns: z119.string().optional().describe("DNS for the client, e.g. '10.20.0.1'"),
|
|
27933
|
+
allowed_ips: z119.string().default("0.0.0.0/0").describe("Client AllowedIPs: '0.0.0.0/0' full-tunnel, or a LAN subnet for split-tunnel"),
|
|
27934
|
+
keepalive: z119.string().default("25").describe("PersistentKeepalive seconds")
|
|
27711
27935
|
},
|
|
27712
27936
|
async handler(a, ctx) {
|
|
27713
27937
|
ctx.info(`Onboarding WireGuard user '${a.user}' on ${a.interface}`);
|
|
@@ -27745,7 +27969,7 @@ ${config}`;
|
|
|
27745
27969
|
title: "Revoke WireGuard Remote User",
|
|
27746
27970
|
annotations: DESTRUCTIVE,
|
|
27747
27971
|
description: "Revokes a remote-access user created by onboard_wireguard_user: removes the WireGuard peer " + "tagged `vpn-user: <user>` from the server, immediately cutting their access. Returns whether a " + "peer was removed.",
|
|
27748
|
-
inputSchema: { user:
|
|
27972
|
+
inputSchema: { user: z119.string().describe("The user label used at onboarding") },
|
|
27749
27973
|
async handler(a, ctx) {
|
|
27750
27974
|
const count = await executeMikrotikCommand(`/interface wireguard peers print count-only where comment="vpn-user: ${a.user}"`, ctx);
|
|
27751
27975
|
if (count.trim() === "0")
|
|
@@ -27759,7 +27983,7 @@ ${config}`;
|
|
|
27759
27983
|
];
|
|
27760
27984
|
|
|
27761
27985
|
// src/tools/wireguard.ts
|
|
27762
|
-
import { z as
|
|
27986
|
+
import { z as z120 } from "zod";
|
|
27763
27987
|
var wireguardTools = [
|
|
27764
27988
|
defineTool({
|
|
27765
27989
|
name: "create_wireguard_interface",
|
|
@@ -27767,12 +27991,12 @@ var wireguardTools = [
|
|
|
27767
27991
|
annotations: WRITE,
|
|
27768
27992
|
description: "Creates a WireGuard tunnel interface (`/interface wireguard`) \u2014 the local VPN endpoint" + " with a UDP listen port and private key. Use this to establish the server-side or site-to-site" + " WireGuard interface before adding remote peers with add_wireguard_peer." + " For IPsec tunnels use create_ipsec_peer; for L2TP use create_l2tp_client;" + " for OpenVPN use create_ovpn_client. Returns the created interface's detail including" + " its name and RouterOS-generated public key.",
|
|
27769
27993
|
inputSchema: {
|
|
27770
|
-
name:
|
|
27771
|
-
listen_port:
|
|
27772
|
-
private_key:
|
|
27773
|
-
mtu:
|
|
27774
|
-
comment:
|
|
27775
|
-
disabled:
|
|
27994
|
+
name: z120.string(),
|
|
27995
|
+
listen_port: z120.number().int().optional(),
|
|
27996
|
+
private_key: z120.string().optional(),
|
|
27997
|
+
mtu: z120.number().int().optional(),
|
|
27998
|
+
comment: z120.string().optional(),
|
|
27999
|
+
disabled: z120.boolean().default(false)
|
|
27776
28000
|
},
|
|
27777
28001
|
async handler(a, ctx) {
|
|
27778
28002
|
ctx.info(`Creating WireGuard interface: name=${a.name}`);
|
|
@@ -27792,9 +28016,9 @@ ${details}` : "WireGuard interface created successfully.";
|
|
|
27792
28016
|
annotations: READ,
|
|
27793
28017
|
description: "`list_wireguard_interfaces` \u2014 READ / list / show / inspect all WireGuard tunnel interfaces" + " (`/interface wireguard print`). The go-to tool to read the current WireGuard state on a" + " device. Returns each interface's name, listen-port, public-key, MTU, and running/disabled" + " status. Filter by name substring (name_filter), disabled-only, or running-only." + " For one interface's full detail use get_wireguard_interface; for the peer table use" + " list_wireguard_peers; for interfaces AND peers in one call use get_wireguard_status.",
|
|
27794
28018
|
inputSchema: {
|
|
27795
|
-
name_filter:
|
|
27796
|
-
disabled_only:
|
|
27797
|
-
running_only:
|
|
28019
|
+
name_filter: z120.string().optional(),
|
|
28020
|
+
disabled_only: z120.boolean().default(false),
|
|
28021
|
+
running_only: z120.boolean().default(false)
|
|
27798
28022
|
},
|
|
27799
28023
|
async handler(a, ctx) {
|
|
27800
28024
|
ctx.info("Listing WireGuard interfaces");
|
|
@@ -27816,7 +28040,7 @@ ${result}`;
|
|
|
27816
28040
|
title: "Get WireGuard Interface Details",
|
|
27817
28041
|
annotations: READ,
|
|
27818
28042
|
description: "`get_wireguard_interface` \u2014 READ / get / show the full detail of ONE WireGuard tunnel interface" + " (`/interface wireguard print detail`) looked up by name. Returns listen-port, private-key," + " public-key, MTU, running state, and comment. To list all interfaces use" + " list_wireguard_interfaces; for that interface's peers use list_wireguard_peers; for" + " interfaces AND peers in one call use get_wireguard_status.",
|
|
27819
|
-
inputSchema: { name:
|
|
28043
|
+
inputSchema: { name: z120.string() },
|
|
27820
28044
|
async handler(a, ctx) {
|
|
27821
28045
|
ctx.info(`Getting WireGuard interface details: name=${a.name}`);
|
|
27822
28046
|
const result = await executeMikrotikCommand(`/interface wireguard print detail where name="${a.name}"`, ctx);
|
|
@@ -27831,7 +28055,7 @@ ${result}`;
|
|
|
27831
28055
|
annotations: READ,
|
|
27832
28056
|
description: "`get_wireguard_status` \u2014 READ the current WireGuard state on a device in ONE call: ALL tunnel" + " interfaces AND ALL peers together. Use this FIRST to inspect / show / check WireGuard before" + " changing anything (e.g. to read public keys, see which side initiates, or confirm the tunnel" + " is up). Interfaces report name, listen-port, public-key, MTU and running state; peers report" + " .id, interface, public-key, allowed-address, endpoint/current-endpoint, last-handshake time" + " and rx/tx bytes. Combines list_wireguard_interfaces + list_wireguard_peers; optionally filter" + " both to one interface with interface_filter.",
|
|
27833
28057
|
inputSchema: {
|
|
27834
|
-
interface_filter:
|
|
28058
|
+
interface_filter: z120.string().optional().describe("Limit to one interface name, e.g. 'wg-mesh'")
|
|
27835
28059
|
},
|
|
27836
28060
|
async handler(a, ctx) {
|
|
27837
28061
|
ctx.info("Reading WireGuard status (interfaces + peers)");
|
|
@@ -27856,13 +28080,13 @@ ${peerBlock}`;
|
|
|
27856
28080
|
annotations: WRITE_IDEMPOTENT,
|
|
27857
28081
|
description: "Modifies settings on an existing WireGuard tunnel interface (`/interface wireguard set [find name=]`)" + " \u2014 rename (new_name), change listen-port, rotate private-key, adjust MTU, or toggle disabled state." + " Only supplied fields are changed; omitted fields are left as-is." + " For updating remote peers use update_wireguard_peer." + " Returns the updated interface's detail.",
|
|
27858
28082
|
inputSchema: {
|
|
27859
|
-
name:
|
|
27860
|
-
new_name:
|
|
27861
|
-
listen_port:
|
|
27862
|
-
private_key:
|
|
27863
|
-
mtu:
|
|
27864
|
-
comment:
|
|
27865
|
-
disabled:
|
|
28083
|
+
name: z120.string(),
|
|
28084
|
+
new_name: z120.string().optional(),
|
|
28085
|
+
listen_port: z120.number().int().optional(),
|
|
28086
|
+
private_key: z120.string().optional(),
|
|
28087
|
+
mtu: z120.number().int().optional(),
|
|
28088
|
+
comment: z120.string().optional(),
|
|
28089
|
+
disabled: z120.boolean().optional()
|
|
27866
28090
|
},
|
|
27867
28091
|
async handler(a, ctx) {
|
|
27868
28092
|
ctx.info(`Updating WireGuard interface: name=${a.name}`);
|
|
@@ -27885,7 +28109,7 @@ ${details}`;
|
|
|
27885
28109
|
title: "Remove WireGuard Interface",
|
|
27886
28110
|
annotations: DESTRUCTIVE,
|
|
27887
28111
|
description: "Permanently deletes a WireGuard tunnel interface (`/interface wireguard remove`) by name." + " Verifies existence first with count-only; removing the interface also removes all its associated peers." + " For removing only a specific peer without touching the interface use remove_wireguard_peer.",
|
|
27888
|
-
inputSchema: { name:
|
|
28112
|
+
inputSchema: { name: z120.string() },
|
|
27889
28113
|
async handler(a, ctx) {
|
|
27890
28114
|
ctx.info(`Removing WireGuard interface: name=${a.name}`);
|
|
27891
28115
|
const count = await executeMikrotikCommand(`/interface wireguard print count-only where name="${a.name}"`, ctx);
|
|
@@ -27902,7 +28126,7 @@ ${details}`;
|
|
|
27902
28126
|
title: "Enable WireGuard Interface",
|
|
27903
28127
|
annotations: WRITE_IDEMPOTENT,
|
|
27904
28128
|
description: "Enables a disabled WireGuard tunnel interface (`/interface wireguard enable`) by name," + " allowing it to accept and establish tunnel connections." + " For enabling a specific peer without affecting the interface use enable_wireguard_peer." + " To undo, use disable_wireguard_interface.",
|
|
27905
|
-
inputSchema: { name:
|
|
28129
|
+
inputSchema: { name: z120.string() },
|
|
27906
28130
|
async handler(a, ctx) {
|
|
27907
28131
|
ctx.info(`Enabling WireGuard interface: name=${a.name}`);
|
|
27908
28132
|
const result = await executeMikrotikCommand(`/interface wireguard enable [find name="${a.name}"]`, ctx);
|
|
@@ -27916,7 +28140,7 @@ ${details}`;
|
|
|
27916
28140
|
title: "Disable WireGuard Interface",
|
|
27917
28141
|
annotations: WRITE_IDEMPOTENT,
|
|
27918
28142
|
description: "Disables a WireGuard tunnel interface (`/interface wireguard disable`) by name," + " stopping all tunnel traffic through it without removing the interface or its peers." + " For disabling only a specific peer use disable_wireguard_peer." + " To re-enable use enable_wireguard_interface.",
|
|
27919
|
-
inputSchema: { name:
|
|
28143
|
+
inputSchema: { name: z120.string() },
|
|
27920
28144
|
async handler(a, ctx) {
|
|
27921
28145
|
ctx.info(`Disabling WireGuard interface: name=${a.name}`);
|
|
27922
28146
|
const result = await executeMikrotikCommand(`/interface wireguard disable [find name="${a.name}"]`, ctx);
|
|
@@ -27936,23 +28160,23 @@ ${details}`;
|
|
|
27936
28160
|
` + ` endpoint_address: remote host IP or hostname e.g. "203.0.113.1" (omit for road-warrior clients that dial in)
|
|
27937
28161
|
` + ' persistent_keepalive: seconds as string e.g. "25"',
|
|
27938
28162
|
inputSchema: {
|
|
27939
|
-
interface:
|
|
27940
|
-
public_key:
|
|
27941
|
-
allowed_address:
|
|
27942
|
-
endpoint_address:
|
|
27943
|
-
endpoint_port:
|
|
27944
|
-
preshared_key:
|
|
27945
|
-
persistent_keepalive:
|
|
27946
|
-
name:
|
|
27947
|
-
private_key:
|
|
27948
|
-
responder:
|
|
27949
|
-
client_address:
|
|
27950
|
-
client_dns:
|
|
27951
|
-
client_endpoint:
|
|
27952
|
-
client_keepalive:
|
|
27953
|
-
client_listen_port:
|
|
27954
|
-
comment:
|
|
27955
|
-
disabled:
|
|
28163
|
+
interface: z120.string(),
|
|
28164
|
+
public_key: z120.string(),
|
|
28165
|
+
allowed_address: z120.string().describe('CIDR, comma-separated for multiple e.g. "10.0.0.2/32" or "10.0.0.0/24,192.168.0.0/24"'),
|
|
28166
|
+
endpoint_address: z120.string().optional().describe('remote host IP or hostname e.g. "203.0.113.1"'),
|
|
28167
|
+
endpoint_port: z120.number().int().optional(),
|
|
28168
|
+
preshared_key: z120.string().optional(),
|
|
28169
|
+
persistent_keepalive: z120.string().optional().describe('seconds as string e.g. "25"'),
|
|
28170
|
+
name: z120.string().optional().describe("optional peer name label"),
|
|
28171
|
+
private_key: z120.string().optional().describe("peer's private key (lets the router generate this peer's client config)"),
|
|
28172
|
+
responder: z120.boolean().optional().describe("only respond to handshakes, never initiate (for road-warrior clients)"),
|
|
28173
|
+
client_address: z120.string().optional().describe("client tunnel address(es) for the generated client config"),
|
|
28174
|
+
client_dns: z120.string().optional().describe("DNS server(s) written into the generated client config"),
|
|
28175
|
+
client_endpoint: z120.string().optional().describe("server endpoint host[:port] written into the generated client config"),
|
|
28176
|
+
client_keepalive: z120.string().optional().describe('client persistent-keepalive for the generated config e.g. "25s"'),
|
|
28177
|
+
client_listen_port: z120.number().int().optional().describe("listen-port written into the generated client config"),
|
|
28178
|
+
comment: z120.string().optional(),
|
|
28179
|
+
disabled: z120.boolean().default(false)
|
|
27956
28180
|
},
|
|
27957
28181
|
async handler(a, ctx) {
|
|
27958
28182
|
ctx.info(`Adding WireGuard peer: interface=${a.interface}, public_key=${a.public_key.slice(0, 12)}...`);
|
|
@@ -27972,8 +28196,8 @@ ${details}` : "WireGuard peer added successfully.";
|
|
|
27972
28196
|
annotations: READ,
|
|
27973
28197
|
description: "`list_wireguard_peers` \u2014 READ / list / show / inspect all WireGuard peers" + " (`/interface wireguard peers print`). Use this to read which peers are configured and" + " whether the tunnel is up (handshake). Returns each peer's .id, interface, public-key," + " allowed-address, endpoint/current-endpoint, last-handshake time, and rx/tx byte counters." + " Filter by interface name (interface_filter) or disabled-only. For the interface table use" + " list_wireguard_interfaces; for one peer's full detail use get_wireguard_peer; for interfaces" + " AND peers in one call use get_wireguard_status. Use the .id from this output with" + " update_wireguard_peer, remove_wireguard_peer, enable_wireguard_peer, or disable_wireguard_peer.",
|
|
27974
28198
|
inputSchema: {
|
|
27975
|
-
interface_filter:
|
|
27976
|
-
disabled_only:
|
|
28199
|
+
interface_filter: z120.string().optional(),
|
|
28200
|
+
disabled_only: z120.boolean().default(false)
|
|
27977
28201
|
},
|
|
27978
28202
|
async handler(a, ctx) {
|
|
27979
28203
|
ctx.info("Listing WireGuard peers");
|
|
@@ -27997,7 +28221,7 @@ ${result}`;
|
|
|
27997
28221
|
` + `Notes:
|
|
27998
28222
|
` + ' peer_id: the .id from list_wireguard_peers, format "*N" or "N" e.g. "*2"',
|
|
27999
28223
|
inputSchema: {
|
|
28000
|
-
peer_id:
|
|
28224
|
+
peer_id: z120.string().describe('"*N" or "N" from list output e.g. "*2"')
|
|
28001
28225
|
},
|
|
28002
28226
|
async handler(a, ctx) {
|
|
28003
28227
|
ctx.info(`Getting WireGuard peer details: peer_id=${a.peer_id}`);
|
|
@@ -28019,22 +28243,22 @@ ${result}`;
|
|
|
28019
28243
|
` + ` persistent_keepalive: seconds as string e.g. "25"
|
|
28020
28244
|
` + ' Pass "" for endpoint_address or preshared_key to clear them.',
|
|
28021
28245
|
inputSchema: {
|
|
28022
|
-
peer_id:
|
|
28023
|
-
allowed_address:
|
|
28024
|
-
endpoint_address:
|
|
28025
|
-
endpoint_port:
|
|
28026
|
-
preshared_key:
|
|
28027
|
-
persistent_keepalive:
|
|
28028
|
-
name:
|
|
28029
|
-
private_key:
|
|
28030
|
-
responder:
|
|
28031
|
-
client_address:
|
|
28032
|
-
client_dns:
|
|
28033
|
-
client_endpoint:
|
|
28034
|
-
client_keepalive:
|
|
28035
|
-
client_listen_port:
|
|
28036
|
-
comment:
|
|
28037
|
-
disabled:
|
|
28246
|
+
peer_id: z120.string().describe('"*N" or "N" from list output e.g. "*2"'),
|
|
28247
|
+
allowed_address: z120.string().optional(),
|
|
28248
|
+
endpoint_address: z120.string().optional(),
|
|
28249
|
+
endpoint_port: z120.number().int().optional(),
|
|
28250
|
+
preshared_key: z120.string().optional(),
|
|
28251
|
+
persistent_keepalive: z120.string().optional(),
|
|
28252
|
+
name: z120.string().optional().describe("optional peer name label"),
|
|
28253
|
+
private_key: z120.string().optional().describe("peer's private key (lets the router generate this peer's client config)"),
|
|
28254
|
+
responder: z120.boolean().optional().describe("only respond to handshakes, never initiate"),
|
|
28255
|
+
client_address: z120.string().optional().describe("client tunnel address(es) for the generated client config"),
|
|
28256
|
+
client_dns: z120.string().optional().describe("DNS server(s) written into the generated client config"),
|
|
28257
|
+
client_endpoint: z120.string().optional().describe("server endpoint host[:port] written into the generated client config"),
|
|
28258
|
+
client_keepalive: z120.string().optional().describe('client persistent-keepalive for the generated config e.g. "25s"'),
|
|
28259
|
+
client_listen_port: z120.number().int().optional().describe("listen-port written into the generated client config"),
|
|
28260
|
+
comment: z120.string().optional(),
|
|
28261
|
+
disabled: z120.boolean().optional()
|
|
28038
28262
|
},
|
|
28039
28263
|
async handler(a, ctx) {
|
|
28040
28264
|
ctx.info(`Updating WireGuard peer: peer_id=${a.peer_id}`);
|
|
@@ -28060,7 +28284,7 @@ ${details}`;
|
|
|
28060
28284
|
` + `Notes:
|
|
28061
28285
|
` + ' peer_id: the .id from list_wireguard_peers, format "*N" or "N" e.g. "*2"',
|
|
28062
28286
|
inputSchema: {
|
|
28063
|
-
peer_id:
|
|
28287
|
+
peer_id: z120.string().describe('"*N" or "N" from list output e.g. "*2"')
|
|
28064
28288
|
},
|
|
28065
28289
|
async handler(a, ctx) {
|
|
28066
28290
|
ctx.info(`Removing WireGuard peer: peer_id=${a.peer_id}`);
|
|
@@ -28082,7 +28306,7 @@ ${details}`;
|
|
|
28082
28306
|
` + `Notes:
|
|
28083
28307
|
` + ' peer_id: the .id from list_wireguard_peers, format "*N" or "N" e.g. "*2"',
|
|
28084
28308
|
inputSchema: {
|
|
28085
|
-
peer_id:
|
|
28309
|
+
peer_id: z120.string().describe('"*N" or "N" from list output e.g. "*2"')
|
|
28086
28310
|
},
|
|
28087
28311
|
async handler(a, ctx) {
|
|
28088
28312
|
ctx.info(`Enabling WireGuard peer: peer_id=${a.peer_id}`);
|
|
@@ -28101,7 +28325,7 @@ ${details}`;
|
|
|
28101
28325
|
` + `Notes:
|
|
28102
28326
|
` + ' peer_id: the .id from list_wireguard_peers, format "*N" or "N" e.g. "*2"',
|
|
28103
28327
|
inputSchema: {
|
|
28104
|
-
peer_id:
|
|
28328
|
+
peer_id: z120.string().describe('"*N" or "N" from list output e.g. "*2"')
|
|
28105
28329
|
},
|
|
28106
28330
|
async handler(a, ctx) {
|
|
28107
28331
|
ctx.info(`Disabling WireGuard peer: peer_id=${a.peer_id}`);
|
|
@@ -28121,14 +28345,14 @@ ${details}`;
|
|
|
28121
28345
|
` + ` allowed_ips: CIDRs routed through the tunnel by the client, default "0.0.0.0/0" (all IPv4 traffic; add ::/0 to also route IPv6)
|
|
28122
28346
|
` + " persistent_keepalive: seconds integer, default 25",
|
|
28123
28347
|
inputSchema: {
|
|
28124
|
-
client_private_key:
|
|
28125
|
-
client_address:
|
|
28126
|
-
server_public_key:
|
|
28127
|
-
server_endpoint:
|
|
28128
|
-
server_port:
|
|
28129
|
-
allowed_ips:
|
|
28130
|
-
dns:
|
|
28131
|
-
persistent_keepalive:
|
|
28348
|
+
client_private_key: z120.string(),
|
|
28349
|
+
client_address: z120.string(),
|
|
28350
|
+
server_public_key: z120.string(),
|
|
28351
|
+
server_endpoint: z120.string(),
|
|
28352
|
+
server_port: z120.number().int().default(51820),
|
|
28353
|
+
allowed_ips: z120.string().default("0.0.0.0/0"),
|
|
28354
|
+
dns: z120.string().optional(),
|
|
28355
|
+
persistent_keepalive: z120.number().int().default(25)
|
|
28132
28356
|
},
|
|
28133
28357
|
async handler(a, ctx) {
|
|
28134
28358
|
ctx.info("Generating WireGuard client configuration");
|
|
@@ -28162,7 +28386,7 @@ ${details}`;
|
|
|
28162
28386
|
];
|
|
28163
28387
|
|
|
28164
28388
|
// src/tools/wireless.ts
|
|
28165
|
-
import { z as
|
|
28389
|
+
import { z as z121 } from "zod";
|
|
28166
28390
|
var V7_WIFI = ["/interface wifi", "/interface wifiwave2"];
|
|
28167
28391
|
function commandUnsupported2(result) {
|
|
28168
28392
|
const t = result.toLowerCase();
|
|
@@ -28193,12 +28417,12 @@ var wirelessTools = [
|
|
|
28193
28417
|
annotations: WRITE,
|
|
28194
28418
|
description: "Creates a wireless interface (`/interface wifi`, `/interface wifiwave2`, `/interface wireless`, or `/interface wlan` \u2014 auto-detected per device). " + "Use to add a new AP or station interface to the device. " + "On RouterOS v7 accepts name, ssid, disabled, and comment; on v6/legacy also requires radio_name (e.g. `wlan1`) and optionally accepts mode (default `ap-bridge`), frequency, band, channel_width, and security_profile. " + "To modify an existing interface use update_wireless_interface; to see current interfaces use list_wireless_interfaces. " + "Returns the created interface's full detail print including its `.id`.",
|
|
28195
28419
|
inputSchema: {
|
|
28196
|
-
name:
|
|
28197
|
-
ssid:
|
|
28198
|
-
disabled:
|
|
28199
|
-
comment:
|
|
28200
|
-
radio_name:
|
|
28201
|
-
mode:
|
|
28420
|
+
name: z121.string(),
|
|
28421
|
+
ssid: z121.string().optional(),
|
|
28422
|
+
disabled: z121.boolean().default(false),
|
|
28423
|
+
comment: z121.string().optional(),
|
|
28424
|
+
radio_name: z121.string().optional().describe("Required for legacy wireless systems, e.g. 'wlan1'"),
|
|
28425
|
+
mode: z121.enum([
|
|
28202
28426
|
"ap-bridge",
|
|
28203
28427
|
"bridge",
|
|
28204
28428
|
"station",
|
|
@@ -28208,8 +28432,8 @@ var wirelessTools = [
|
|
|
28208
28432
|
"ap-bridge-wds",
|
|
28209
28433
|
"alignment-only"
|
|
28210
28434
|
]).optional(),
|
|
28211
|
-
frequency:
|
|
28212
|
-
band:
|
|
28435
|
+
frequency: z121.string().optional(),
|
|
28436
|
+
band: z121.enum([
|
|
28213
28437
|
"2ghz-b",
|
|
28214
28438
|
"2ghz-b/g",
|
|
28215
28439
|
"2ghz-b/g/n",
|
|
@@ -28221,24 +28445,24 @@ var wirelessTools = [
|
|
|
28221
28445
|
"5ghz-n",
|
|
28222
28446
|
"5ghz-ac"
|
|
28223
28447
|
]).optional(),
|
|
28224
|
-
channel_width:
|
|
28225
|
-
security_profile:
|
|
28226
|
-
mtu:
|
|
28227
|
-
arp:
|
|
28228
|
-
hide_ssid:
|
|
28229
|
-
wireless_protocol:
|
|
28230
|
-
scan_list:
|
|
28231
|
-
frequency_mode:
|
|
28232
|
-
country:
|
|
28233
|
-
antenna_gain:
|
|
28234
|
-
wds_mode:
|
|
28235
|
-
wds_default_bridge:
|
|
28236
|
-
default_authentication:
|
|
28237
|
-
default_forwarding:
|
|
28238
|
-
tx_power:
|
|
28239
|
-
tx_power_mode:
|
|
28240
|
-
distance:
|
|
28241
|
-
disconnect_timeout:
|
|
28448
|
+
channel_width: z121.enum(["20mhz", "40mhz", "80mhz", "160mhz", "20/40mhz-eC", "20/40mhz-Ce"]).optional(),
|
|
28449
|
+
security_profile: z121.string().optional(),
|
|
28450
|
+
mtu: z121.number().int().optional().describe("Interface MTU in bytes"),
|
|
28451
|
+
arp: z121.enum(["disabled", "enabled", "proxy-arp", "reply-only", "local-proxy-arp"]).optional().describe("ARP mode for the interface"),
|
|
28452
|
+
hide_ssid: z121.boolean().optional().describe("Legacy: do not broadcast the SSID in beacons (AP modes)"),
|
|
28453
|
+
wireless_protocol: z121.string().optional().describe("Legacy: wireless protocol, e.g. '802.11', 'nv2', 'nstreme'"),
|
|
28454
|
+
scan_list: z121.string().optional().describe("Legacy: frequencies/ranges to scan (e.g. 'default' or '5180-5320')"),
|
|
28455
|
+
frequency_mode: z121.enum(["manual-txpower", "regulatory-domain", "superchannel"]).optional().describe("Legacy: regulatory frequency mode"),
|
|
28456
|
+
country: z121.string().optional().describe("Legacy: regulatory country setting (e.g. 'united states')"),
|
|
28457
|
+
antenna_gain: z121.number().int().optional().describe("Legacy: antenna gain in dBi used for tx-power calculations"),
|
|
28458
|
+
wds_mode: z121.enum(["disabled", "dynamic", "dynamic-mesh", "static", "static-mesh"]).optional().describe("Legacy: WDS mode"),
|
|
28459
|
+
wds_default_bridge: z121.string().optional().describe("Legacy: bridge that dynamic WDS interfaces are added to"),
|
|
28460
|
+
default_authentication: z121.boolean().optional().describe("Legacy: allow clients not in the access-list to authenticate"),
|
|
28461
|
+
default_forwarding: z121.boolean().optional().describe("Legacy: allow client-to-client forwarding by default"),
|
|
28462
|
+
tx_power: z121.number().int().optional().describe("Legacy: manual transmit power in dBm"),
|
|
28463
|
+
tx_power_mode: z121.enum(["default", "card-rates", "all-rates-fixed", "manual-table"]).optional().describe("Legacy: how tx-power is determined"),
|
|
28464
|
+
distance: z121.string().optional().describe("Legacy: link distance ('dynamic', 'indoors', or a km value)"),
|
|
28465
|
+
disconnect_timeout: z121.string().optional().describe("Legacy: time before a non-responding client is disconnected")
|
|
28242
28466
|
},
|
|
28243
28467
|
async handler(a, ctx) {
|
|
28244
28468
|
ctx.info(`Creating wireless interface: name=${a.name}, ssid=${a.ssid}`);
|
|
@@ -28270,9 +28494,9 @@ ${details}`;
|
|
|
28270
28494
|
annotations: READ,
|
|
28271
28495
|
description: "Lists all wireless interfaces (`/interface wifi`, `/interface wifiwave2`, `/interface wireless`, `/interface wlan`) \u2014 probes every supported command path and aggregates results. " + "Filters by name_filter (substring match), disabled_only, or running_only. " + "For full property detail on a single interface use get_wireless_interface; to see currently connected clients use get_wireless_registration_table. " + "Falls back to `/interface print` with debugging info when no wireless interfaces match, to help identify the correct path on the device.",
|
|
28272
28496
|
inputSchema: {
|
|
28273
|
-
name_filter:
|
|
28274
|
-
disabled_only:
|
|
28275
|
-
running_only:
|
|
28497
|
+
name_filter: z121.string().optional(),
|
|
28498
|
+
disabled_only: z121.boolean().default(false),
|
|
28499
|
+
running_only: z121.boolean().default(false)
|
|
28276
28500
|
},
|
|
28277
28501
|
async handler(a, ctx) {
|
|
28278
28502
|
ctx.info(`Listing wireless interfaces with filters: name=${a.name_filter}`);
|
|
@@ -28326,7 +28550,7 @@ NOTE: If you see wireless interfaces above, they might be using a different comm
|
|
|
28326
28550
|
title: "Get Wireless Interface Details",
|
|
28327
28551
|
annotations: READ,
|
|
28328
28552
|
description: "Retrieves the full detail of one named wireless interface (`<auto-detected path> print detail where name=...`), " + "probing `/interface wifi`, `/interface wifiwave2`, `/interface wireless`, and `/interface wlan` in order. " + "Use when you need all properties of a single interface; for a summary of all interfaces use list_wireless_interfaces. " + "Returns the complete property set for the named interface, or an error if not found.",
|
|
28329
|
-
inputSchema: { name:
|
|
28553
|
+
inputSchema: { name: z121.string() },
|
|
28330
28554
|
async handler(a, ctx) {
|
|
28331
28555
|
ctx.info(`Getting wireless interface details: name=${a.name}`);
|
|
28332
28556
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
@@ -28345,7 +28569,7 @@ ${result}`;
|
|
|
28345
28569
|
title: "Remove Wireless Interface",
|
|
28346
28570
|
annotations: DESTRUCTIVE,
|
|
28347
28571
|
description: "Permanently deletes a named wireless interface (`<auto-detected path> remove [find name=...]`). " + "Verifies the interface exists first (count-only check) and returns an error if not found. " + "This action is irreversible \u2014 to keep the interface but stop traffic use disable_wireless_interface; " + "for property changes only use update_wireless_interface.",
|
|
28348
|
-
inputSchema: { name:
|
|
28572
|
+
inputSchema: { name: z121.string() },
|
|
28349
28573
|
async handler(a, ctx) {
|
|
28350
28574
|
ctx.info(`Removing wireless interface: name=${a.name}`);
|
|
28351
28575
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
@@ -28365,7 +28589,7 @@ ${result}`;
|
|
|
28365
28589
|
title: "Enable Wireless Interface",
|
|
28366
28590
|
annotations: WRITE_IDEMPOTENT,
|
|
28367
28591
|
description: "Enables a named wireless interface that is currently disabled (`<auto-detected path> enable [find name=...]`). " + "Idempotent \u2014 safe to call on an already-enabled interface. " + "For the reverse operation use disable_wireless_interface; to change other settings at the same time use update_wireless_interface. " + "Obtain the interface name from list_wireless_interfaces.",
|
|
28368
|
-
inputSchema: { name:
|
|
28592
|
+
inputSchema: { name: z121.string() },
|
|
28369
28593
|
async handler(a, ctx) {
|
|
28370
28594
|
ctx.info(`Enabling wireless interface: ${a.name}`);
|
|
28371
28595
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
@@ -28382,7 +28606,7 @@ ${result}`;
|
|
|
28382
28606
|
title: "Disable Wireless Interface",
|
|
28383
28607
|
annotations: WRITE_IDEMPOTENT,
|
|
28384
28608
|
description: "Disables a named wireless interface without removing it (`<auto-detected path> disable [find name=...]`). " + "Idempotent \u2014 safe to call on an already-disabled interface. " + "For the reverse operation use enable_wireless_interface; to delete the interface permanently use remove_wireless_interface. " + "Obtain the interface name from list_wireless_interfaces.",
|
|
28385
|
-
inputSchema: { name:
|
|
28609
|
+
inputSchema: { name: z121.string() },
|
|
28386
28610
|
async handler(a, ctx) {
|
|
28387
28611
|
ctx.info(`Disabling wireless interface: ${a.name}`);
|
|
28388
28612
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
@@ -28400,8 +28624,8 @@ ${result}`;
|
|
|
28400
28624
|
annotations: READ,
|
|
28401
28625
|
description: "Scans for visible nearby wireless networks/SSIDs/APs in range (`<auto-detected path> scan <interface> duration=<n>`). " + "Use to discover external networks \u2014 not to list connected clients. " + "For currently associated client stations use get_wireless_registration_table instead. " + "`interface` is the local wireless interface name to scan from (e.g. `wlan1`); `duration` is scan time in seconds (default 5). " + "Returns raw scan output from the device.",
|
|
28402
28626
|
inputSchema: {
|
|
28403
|
-
interface:
|
|
28404
|
-
duration:
|
|
28627
|
+
interface: z121.string(),
|
|
28628
|
+
duration: z121.number().int().default(5)
|
|
28405
28629
|
},
|
|
28406
28630
|
async handler(a, ctx) {
|
|
28407
28631
|
ctx.info(`Scanning wireless networks on interface: ${a.interface}`);
|
|
@@ -28423,7 +28647,7 @@ ${result}`;
|
|
|
28423
28647
|
annotations: READ,
|
|
28424
28648
|
description: "Retrieves the wireless registration table \u2014 the list of client stations currently associated to this AP (`<auto-detected path> registration-table print [where interface=...]`). " + "Each row is an actively connected wireless client with its MAC address, signal strength, and statistics. " + "To discover nearby external APs/SSIDs instead use scan_wireless_networks. " + "Optionally filter by interface name; omit to return all clients across all wireless interfaces.",
|
|
28425
28649
|
inputSchema: {
|
|
28426
|
-
interface:
|
|
28650
|
+
interface: z121.string().optional()
|
|
28427
28651
|
},
|
|
28428
28652
|
async handler(a, ctx) {
|
|
28429
28653
|
ctx.info(`Getting wireless registration table for interface: ${a.interface}`);
|
|
@@ -28485,7 +28709,7 @@ For legacy systems:
|
|
|
28485
28709
|
title: "Create Wireless Security Profile (Legacy v6 Only \u2014 Not Implemented)",
|
|
28486
28710
|
annotations: WRITE,
|
|
28487
28711
|
description: "Stub for creating a `/interface wireless security-profiles` entry \u2014 a RouterOS v6 concept that does not exist in v7. " + "On RouterOS v7 devices (`/interface wifi` or `/interface wifiwave2`) always returns a not-supported message; security is configured directly on the interface. " + "On v6 this is also not implemented and returns an error. " + "For v6 interface creation with a security profile use create_wireless_interface (security_profile arg); for v7, security is configured directly on the interface but is not exposed by this server's wireless tools.",
|
|
28488
|
-
inputSchema: { name:
|
|
28712
|
+
inputSchema: { name: z121.string() },
|
|
28489
28713
|
async handler(_a, ctx) {
|
|
28490
28714
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
28491
28715
|
if (interfaceType && V7_WIFI.includes(interfaceType)) {
|
|
@@ -28512,7 +28736,7 @@ For legacy systems:
|
|
|
28512
28736
|
title: "Get Wireless Security Profile (Legacy v6 Only \u2014 Not Implemented)",
|
|
28513
28737
|
annotations: READ,
|
|
28514
28738
|
description: "Stub for retrieving a named `/interface wireless security-profiles` entry \u2014 a RouterOS v6 concept that does not exist in v7. " + "On RouterOS v7 devices always returns a not-supported message; on v6 also not implemented. " + "Use get_wireless_interface to inspect the security settings on a v7 wireless interface instead.",
|
|
28515
|
-
inputSchema: { name:
|
|
28739
|
+
inputSchema: { name: z121.string() },
|
|
28516
28740
|
async handler(_a, ctx) {
|
|
28517
28741
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
28518
28742
|
if (interfaceType && V7_WIFI.includes(interfaceType)) {
|
|
@@ -28526,7 +28750,7 @@ For legacy systems:
|
|
|
28526
28750
|
title: "Remove Wireless Security Profile (Legacy v6 Only \u2014 Not Implemented)",
|
|
28527
28751
|
annotations: DESTRUCTIVE,
|
|
28528
28752
|
description: "Stub for deleting a named `/interface wireless security-profiles` entry \u2014 a RouterOS v6 concept that does not exist in v7. " + "On RouterOS v7 devices always returns a not-supported message; on v6 also not implemented. " + "To delete a wireless interface entirely use remove_wireless_interface; to change security settings use update_wireless_interface.",
|
|
28529
|
-
inputSchema: { name:
|
|
28753
|
+
inputSchema: { name: z121.string() },
|
|
28530
28754
|
async handler(_a, ctx) {
|
|
28531
28755
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
28532
28756
|
if (interfaceType && V7_WIFI.includes(interfaceType)) {
|
|
@@ -28541,8 +28765,8 @@ For legacy systems:
|
|
|
28541
28765
|
annotations: WRITE,
|
|
28542
28766
|
description: "Stub for assigning a named security profile to a v6 `/interface wireless` interface \u2014 a RouterOS v6 concept that does not exist in v7. " + "On RouterOS v7 devices always returns a not-supported message because security is set directly on the interface. " + "On v6 also not implemented. " + "To update a wireless interface's settings on supported versions use update_wireless_interface.",
|
|
28543
28767
|
inputSchema: {
|
|
28544
|
-
interface_name:
|
|
28545
|
-
security_profile:
|
|
28768
|
+
interface_name: z121.string(),
|
|
28769
|
+
security_profile: z121.string()
|
|
28546
28770
|
},
|
|
28547
28771
|
async handler(_a, ctx) {
|
|
28548
28772
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
@@ -28583,7 +28807,7 @@ For legacy systems:
|
|
|
28583
28807
|
title: "Remove Wireless Access List Entry (Legacy v6 Only \u2014 Not Implemented)",
|
|
28584
28808
|
annotations: DESTRUCTIVE,
|
|
28585
28809
|
description: "Stub for removing a `/interface wireless access-list` entry by ID \u2014 a RouterOS v6 concept. " + "On RouterOS v7 devices always returns a not-supported message; on v6 also not implemented. " + "The entry_id would take the `.id` from list_wireless_access_list if that were implemented. " + "For v7 access control use list_filter_rules and remove_filter_rule instead.",
|
|
28586
|
-
inputSchema: { entry_id:
|
|
28810
|
+
inputSchema: { entry_id: z121.string() },
|
|
28587
28811
|
async handler(_a, ctx) {
|
|
28588
28812
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
28589
28813
|
if (interfaceType && V7_WIFI.includes(interfaceType)) {
|
|
@@ -28598,31 +28822,31 @@ For legacy systems:
|
|
|
28598
28822
|
annotations: WRITE_IDEMPOTENT,
|
|
28599
28823
|
description: "Updates settings on an existing named wireless interface (`<auto-detected path> set [find name=...] ...`). " + "Supports renaming (new_name), changing SSID, toggling disabled state, and updating comment. " + "Verifies the interface exists before applying; returns 'No updates specified.' if no optional fields are provided. " + "To only enable or disable the interface prefer enable_wireless_interface or disable_wireless_interface; " + "to create a new interface use create_wireless_interface; to delete one use remove_wireless_interface. " + "Returns the updated interface's full detail print.",
|
|
28600
28824
|
inputSchema: {
|
|
28601
|
-
name:
|
|
28602
|
-
new_name:
|
|
28603
|
-
ssid:
|
|
28604
|
-
disabled:
|
|
28605
|
-
comment:
|
|
28606
|
-
mtu:
|
|
28607
|
-
arp:
|
|
28608
|
-
hide_ssid:
|
|
28609
|
-
wireless_protocol:
|
|
28610
|
-
scan_list:
|
|
28611
|
-
frequency:
|
|
28612
|
-
band:
|
|
28613
|
-
channel_width:
|
|
28614
|
-
frequency_mode:
|
|
28615
|
-
country:
|
|
28616
|
-
antenna_gain:
|
|
28617
|
-
wds_mode:
|
|
28618
|
-
wds_default_bridge:
|
|
28619
|
-
default_authentication:
|
|
28620
|
-
default_forwarding:
|
|
28621
|
-
tx_power:
|
|
28622
|
-
tx_power_mode:
|
|
28623
|
-
distance:
|
|
28624
|
-
disconnect_timeout:
|
|
28625
|
-
security_profile:
|
|
28825
|
+
name: z121.string(),
|
|
28826
|
+
new_name: z121.string().optional(),
|
|
28827
|
+
ssid: z121.string().optional(),
|
|
28828
|
+
disabled: z121.boolean().optional(),
|
|
28829
|
+
comment: z121.string().optional(),
|
|
28830
|
+
mtu: z121.number().int().optional().describe("Interface MTU in bytes"),
|
|
28831
|
+
arp: z121.enum(["disabled", "enabled", "proxy-arp", "reply-only", "local-proxy-arp"]).optional().describe("ARP mode for the interface"),
|
|
28832
|
+
hide_ssid: z121.boolean().optional().describe("Legacy: do not broadcast the SSID in beacons (AP modes)"),
|
|
28833
|
+
wireless_protocol: z121.string().optional().describe("Legacy: wireless protocol, e.g. '802.11', 'nv2', 'nstreme'"),
|
|
28834
|
+
scan_list: z121.string().optional().describe("Legacy: frequencies/ranges to scan (e.g. 'default' or '5180-5320')"),
|
|
28835
|
+
frequency: z121.string().optional().describe("Legacy: operating frequency in MHz"),
|
|
28836
|
+
band: z121.string().optional().describe("Legacy: band, e.g. '2ghz-b/g/n' or '5ghz-a/n/ac'"),
|
|
28837
|
+
channel_width: z121.enum(["20mhz", "40mhz", "80mhz", "160mhz", "20/40mhz-eC", "20/40mhz-Ce"]).optional().describe("Legacy: channel width"),
|
|
28838
|
+
frequency_mode: z121.enum(["manual-txpower", "regulatory-domain", "superchannel"]).optional().describe("Legacy: regulatory frequency mode"),
|
|
28839
|
+
country: z121.string().optional().describe("Legacy: regulatory country setting (e.g. 'united states')"),
|
|
28840
|
+
antenna_gain: z121.number().int().optional().describe("Legacy: antenna gain in dBi used for tx-power calculations"),
|
|
28841
|
+
wds_mode: z121.enum(["disabled", "dynamic", "dynamic-mesh", "static", "static-mesh"]).optional().describe("Legacy: WDS mode"),
|
|
28842
|
+
wds_default_bridge: z121.string().optional().describe("Legacy: bridge that dynamic WDS interfaces are added to"),
|
|
28843
|
+
default_authentication: z121.boolean().optional().describe("Legacy: allow clients not in the access-list to authenticate"),
|
|
28844
|
+
default_forwarding: z121.boolean().optional().describe("Legacy: allow client-to-client forwarding by default"),
|
|
28845
|
+
tx_power: z121.number().int().optional().describe("Legacy: manual transmit power in dBm"),
|
|
28846
|
+
tx_power_mode: z121.enum(["default", "card-rates", "all-rates-fixed", "manual-table"]).optional().describe("Legacy: how tx-power is determined"),
|
|
28847
|
+
distance: z121.string().optional().describe("Legacy: link distance ('dynamic', 'indoors', or a km value)"),
|
|
28848
|
+
disconnect_timeout: z121.string().optional().describe("Legacy: time before a non-responding client is disconnected"),
|
|
28849
|
+
security_profile: z121.string().optional().describe("Legacy: name of the security profile to apply")
|
|
28626
28850
|
},
|
|
28627
28851
|
async handler(a, ctx) {
|
|
28628
28852
|
ctx.info(`Updating wireless interface: name=${a.name}`);
|
|
@@ -28651,7 +28875,7 @@ ${details}`;
|
|
|
28651
28875
|
annotations: READ,
|
|
28652
28876
|
description: "Lists all available regulatory country codes for wireless configuration " + "(`<auto-detected path> country print`). Each entry shows the country name/code and the " + "regulatory constraints it implies (allowed frequencies, max TX power, DFS rules, etc.). " + "Use this to discover valid values before setting a country on a wireless interface.",
|
|
28653
28877
|
inputSchema: {
|
|
28654
|
-
search:
|
|
28878
|
+
search: z121.string().optional().describe("Optional search string to filter countries by name or code.")
|
|
28655
28879
|
},
|
|
28656
28880
|
async handler(a, ctx) {
|
|
28657
28881
|
ctx.info("Listing Wi-Fi regulatory countries");
|
|
@@ -28678,7 +28902,7 @@ ${result}`;
|
|
|
28678
28902
|
];
|
|
28679
28903
|
|
|
28680
28904
|
// src/tools/wifi-optimizer.ts
|
|
28681
|
-
import { z as
|
|
28905
|
+
import { z as z122 } from "zod";
|
|
28682
28906
|
function pickBestFrequency(monitor) {
|
|
28683
28907
|
const cands = [];
|
|
28684
28908
|
for (const line of monitor.split(`
|
|
@@ -28699,9 +28923,9 @@ var wifiOptimizerTools = [
|
|
|
28699
28923
|
annotations: WRITE,
|
|
28700
28924
|
description: "Runs an RF survey on a wireless radio (`/interface wireless frequency-monitor`, blocking for " + "`duration`), finds the least-congested channel, and reports a before/after. DEFAULTS TO A DRY " + "RUN (`apply=false`) \u2014 it surveys and recommends; set `apply=true` to set the radio to the best " + "frequency (`/interface wireless set`). Targets the LEGACY wireless stack; for wifiwave2 " + "(`/interface wifi`) tune via those tools. Returns the per-channel usage finding and the chosen " + "frequency.",
|
|
28701
28925
|
inputSchema: {
|
|
28702
|
-
interface:
|
|
28703
|
-
duration:
|
|
28704
|
-
apply:
|
|
28926
|
+
interface: z122.string().describe("Wireless interface, e.g. 'wlan1'"),
|
|
28927
|
+
duration: z122.string().default("5").describe("Survey duration in seconds"),
|
|
28928
|
+
apply: z122.boolean().default(false).describe("false = survey & recommend (default); true = set it")
|
|
28705
28929
|
},
|
|
28706
28930
|
async handler(a, ctx) {
|
|
28707
28931
|
ctx.info(`Wi-Fi survey on ${a.interface} for ${a.duration}s`);
|
|
@@ -28726,16 +28950,16 @@ ${monitor.trim() || "(empty)"}`;
|
|
|
28726
28950
|
];
|
|
28727
28951
|
|
|
28728
28952
|
// src/tools/memory.ts
|
|
28729
|
-
import { z as
|
|
28730
|
-
var EntityInput =
|
|
28731
|
-
name:
|
|
28732
|
-
entityType:
|
|
28733
|
-
observations:
|
|
28953
|
+
import { z as z123 } from "zod";
|
|
28954
|
+
var EntityInput = z123.object({
|
|
28955
|
+
name: z123.string().describe("Unique name of the entity"),
|
|
28956
|
+
entityType: z123.string().describe("Type/category of the entity (e.g. 'router', 'subnet', 'person')"),
|
|
28957
|
+
observations: z123.array(z123.string()).optional().describe("Initial observations (facts) to attach")
|
|
28734
28958
|
});
|
|
28735
|
-
var RelationInput =
|
|
28736
|
-
from:
|
|
28737
|
-
to:
|
|
28738
|
-
relationType:
|
|
28959
|
+
var RelationInput = z123.object({
|
|
28960
|
+
from: z123.string().describe("Source entity name"),
|
|
28961
|
+
to: z123.string().describe("Target entity name"),
|
|
28962
|
+
relationType: z123.string().describe("Relation type in active voice (e.g. 'manages', 'connects_to', 'depends_on')")
|
|
28739
28963
|
});
|
|
28740
28964
|
var memoryTools = [
|
|
28741
28965
|
defineTool({
|
|
@@ -28744,7 +28968,7 @@ var memoryTools = [
|
|
|
28744
28968
|
annotations: WRITE,
|
|
28745
28969
|
description: "Create one or more new entities in the persistent knowledge graph. Each entity has a " + "unique name, a type (e.g. 'router', 'subnet', 'vlan', 'person', 'config_pattern'), " + "and optional initial observations. Entities that already exist are silently skipped. " + "Use this to record things the AI learns about the network, devices, users, or patterns.",
|
|
28746
28970
|
inputSchema: {
|
|
28747
|
-
entities:
|
|
28971
|
+
entities: z123.array(EntityInput).min(1).describe("Entities to create")
|
|
28748
28972
|
},
|
|
28749
28973
|
async handler(args) {
|
|
28750
28974
|
const store3 = await getMemoryStore();
|
|
@@ -28762,7 +28986,7 @@ ${created.map((e) => ` - ${e.name} (${e.entityType})`).join(`
|
|
|
28762
28986
|
annotations: WRITE,
|
|
28763
28987
|
description: "Create directed relations between existing entities in the knowledge graph. Both " + "endpoint entities must already exist. Use active voice for relation types (e.g. " + "'manages', 'connects_to', 'provides_dhcp_for', 'part_of'). Duplicate relations " + "are silently skipped.",
|
|
28764
28988
|
inputSchema: {
|
|
28765
|
-
relations:
|
|
28989
|
+
relations: z123.array(RelationInput).min(1).describe("Relations to create")
|
|
28766
28990
|
},
|
|
28767
28991
|
async handler(args) {
|
|
28768
28992
|
const store3 = await getMemoryStore();
|
|
@@ -28780,9 +29004,9 @@ ${created.map((r) => ` - ${r.from} --[${r.relationType}]--> ${r.to}`).join(`
|
|
|
28780
29004
|
annotations: WRITE,
|
|
28781
29005
|
description: "Add new observations (discrete facts) to existing entities in the knowledge graph. " + "Each observation is a string (e.g. 'runs RouterOS 7.16', 'has 4 ether ports', " + "'managed by John'). Duplicate observations on the same entity are silently skipped. " + "The entity must already exist.",
|
|
28782
29006
|
inputSchema: {
|
|
28783
|
-
observations:
|
|
28784
|
-
entityName:
|
|
28785
|
-
contents:
|
|
29007
|
+
observations: z123.array(z123.object({
|
|
29008
|
+
entityName: z123.string().describe("Name of the existing entity"),
|
|
29009
|
+
contents: z123.array(z123.string()).min(1).describe("Observations to add")
|
|
28786
29010
|
})).min(1)
|
|
28787
29011
|
},
|
|
28788
29012
|
async handler(args) {
|
|
@@ -28802,7 +29026,7 @@ ${lines.join(`
|
|
|
28802
29026
|
annotations: DESTRUCTIVE,
|
|
28803
29027
|
description: "Remove entities from the knowledge graph. This also deletes all their observations " + "and any relations where they appear as an endpoint (cascade delete).",
|
|
28804
29028
|
inputSchema: {
|
|
28805
|
-
entityNames:
|
|
29029
|
+
entityNames: z123.array(z123.string()).min(1).describe("Names of entities to delete")
|
|
28806
29030
|
},
|
|
28807
29031
|
async handler(args) {
|
|
28808
29032
|
const store3 = await getMemoryStore();
|
|
@@ -28816,9 +29040,9 @@ ${lines.join(`
|
|
|
28816
29040
|
annotations: DESTRUCTIVE,
|
|
28817
29041
|
description: "Remove specific observations from entities in the knowledge graph. The entity " + "itself is kept; only the named observation strings are removed.",
|
|
28818
29042
|
inputSchema: {
|
|
28819
|
-
deletions:
|
|
28820
|
-
entityName:
|
|
28821
|
-
observations:
|
|
29043
|
+
deletions: z123.array(z123.object({
|
|
29044
|
+
entityName: z123.string().describe("Entity to remove observations from"),
|
|
29045
|
+
observations: z123.array(z123.string()).min(1).describe("Exact observation strings to delete")
|
|
28822
29046
|
})).min(1)
|
|
28823
29047
|
},
|
|
28824
29048
|
async handler(args) {
|
|
@@ -28833,7 +29057,7 @@ ${lines.join(`
|
|
|
28833
29057
|
annotations: DESTRUCTIVE,
|
|
28834
29058
|
description: "Remove specific relations from the knowledge graph. Each relation is identified " + "by its (from, to, relationType) triple.",
|
|
28835
29059
|
inputSchema: {
|
|
28836
|
-
relations:
|
|
29060
|
+
relations: z123.array(RelationInput).min(1).describe("Relations to delete")
|
|
28837
29061
|
},
|
|
28838
29062
|
async handler(args) {
|
|
28839
29063
|
const store3 = await getMemoryStore();
|
|
@@ -28861,8 +29085,8 @@ ${lines.join(`
|
|
|
28861
29085
|
annotations: READ,
|
|
28862
29086
|
description: "Search for entities in the knowledge graph by name, type, or observation content. " + "Returns matching entities with their observations, plus any relations where at " + "least one endpoint is in the result set.",
|
|
28863
29087
|
inputSchema: {
|
|
28864
|
-
query:
|
|
28865
|
-
limit:
|
|
29088
|
+
query: z123.string().describe("Search term \u2014 matched against entity names, types, and observation content"),
|
|
29089
|
+
limit: z123.number().int().positive().optional().describe("Max entities to return (default 50)")
|
|
28866
29090
|
},
|
|
28867
29091
|
async handler(args) {
|
|
28868
29092
|
const store3 = await getMemoryStore();
|
|
@@ -28878,7 +29102,7 @@ ${lines.join(`
|
|
|
28878
29102
|
annotations: READ,
|
|
28879
29103
|
description: "Retrieve specific entities by exact name from the knowledge graph, with all their " + "observations and any relations where at least one endpoint is in the requested set.",
|
|
28880
29104
|
inputSchema: {
|
|
28881
|
-
names:
|
|
29105
|
+
names: z123.array(z123.string()).min(1).describe("Exact entity names to retrieve")
|
|
28882
29106
|
},
|
|
28883
29107
|
async handler(args) {
|
|
28884
29108
|
const store3 = await getMemoryStore();
|
|
@@ -28899,6 +29123,13 @@ var moduleCatalog = [
|
|
|
28899
29123
|
description: "Always-discoverable meta-tools that make the whole catalog reachable when the host can't " + "surface a specific tool: search by intent (`find_tools`), inspect a schema (`describe_tool`), " + "and run any tool by name with full validation (`invoke_tool`).",
|
|
28900
29124
|
tools: toolGatewayTools
|
|
28901
29125
|
},
|
|
29126
|
+
{
|
|
29127
|
+
label: "Server Pulse",
|
|
29128
|
+
slug: "server-pulse",
|
|
29129
|
+
group: "Discovery & Meta",
|
|
29130
|
+
description: "Server self-awareness: running version, update availability, release notes, " + "upgrade path, and server vitals. No RouterOS device is contacted.",
|
|
29131
|
+
tools: serverPulseTools
|
|
29132
|
+
},
|
|
28902
29133
|
{
|
|
28903
29134
|
label: "RouterOS CLI",
|
|
28904
29135
|
slug: "raw-command",
|
|
@@ -29755,7 +29986,7 @@ var moduleCatalog = [
|
|
|
29755
29986
|
}
|
|
29756
29987
|
];
|
|
29757
29988
|
var allToolModules = moduleCatalog.map((m) => m.tools);
|
|
29758
|
-
var ALWAYS_ON_MODULES = new Set(["tool-gateway", "memory"]);
|
|
29989
|
+
var ALWAYS_ON_MODULES = new Set(["tool-gateway", "memory", "server-pulse"]);
|
|
29759
29990
|
function selectToolModules(filter = {}, catalog = moduleCatalog) {
|
|
29760
29991
|
const lc = (xs) => new Set((xs ?? []).map((s) => s.toLowerCase()));
|
|
29761
29992
|
const enabledModules = lc(filter.enabledModules);
|
|
@@ -29776,4 +30007,4 @@ function selectToolModules(filter = {}, catalog = moduleCatalog) {
|
|
|
29776
30007
|
}).map((m) => m.tools);
|
|
29777
30008
|
}
|
|
29778
30009
|
|
|
29779
|
-
export { DeviceConfigSchema, MikrotikConfigSchema, loadConfig, logger, MikroTikSSHClient, setConfig, getConfig, listDevices, deviceLabels, resolveDeviceName, deviceDirectory, getDevice, SafeModeManager, getSafeModeManager, executeMikrotikCommand, defineTool, registerTools, PROMPTS_DIR,
|
|
30010
|
+
export { DeviceConfigSchema, MikrotikConfigSchema, loadConfig, logger, MikroTikSSHClient, setConfig, getConfig, listDevices, deviceLabels, resolveDeviceName, deviceDirectory, getDevice, SafeModeManager, getSafeModeManager, executeMikrotikCommand, defineTool, registerTools, PROMPTS_DIR, registerUiResources, VERSION, WEBSITE_URL, LOGO_URL, SERVER_TITLE, SERVER_DESCRIPTION, SERVER_NAME, loadFileCacheSync, updateSummaryLine, moduleCatalog, allToolModules, ALWAYS_ON_MODULES, selectToolModules };
|