@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) {
|
|
@@ -525,6 +526,7 @@ function loadConfig(argv = process.argv.slice(2)) {
|
|
|
525
526
|
};
|
|
526
527
|
const isTruthy = (v) => /^(1|true|yes|on)$/i.test(v ?? "");
|
|
527
528
|
const readOnly = isTruthy(pick("read-only", "MIKROTIK_READ_ONLY"));
|
|
529
|
+
const disableUpdateCheck = isTruthy(pick("disable-update-check", "MIKROTIK_DISABLE_UPDATE_CHECK"));
|
|
528
530
|
const csv = (v) => v === undefined ? undefined : v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
529
531
|
const tools = {
|
|
530
532
|
enabledModules: csv(pick("tools-enabled-modules", "MIKROTIK_TOOLS__ENABLED_MODULES")),
|
|
@@ -564,6 +566,7 @@ function loadConfig(argv = process.argv.slice(2)) {
|
|
|
564
566
|
mcp,
|
|
565
567
|
dashboard,
|
|
566
568
|
readOnly,
|
|
569
|
+
disableUpdateCheck,
|
|
567
570
|
tools,
|
|
568
571
|
ssh,
|
|
569
572
|
memory,
|
|
@@ -2475,7 +2478,7 @@ function defineTool(def) {
|
|
|
2475
2478
|
handler: def.handler,
|
|
2476
2479
|
register(server, opts = {}) {
|
|
2477
2480
|
const { sendLog, deviceNames, deviceAliases, deviceDirectory: deviceDirectory2, appViews } = opts;
|
|
2478
|
-
const multiDevice = !!deviceNames && deviceNames.length > 1;
|
|
2481
|
+
const multiDevice = !def.noDevice && !!deviceNames && deviceNames.length > 1;
|
|
2479
2482
|
const { ui, auto } = appViews === false ? { ui: undefined, auto: false } : effectiveUi(def);
|
|
2480
2483
|
const selectorNames = multiDevice && deviceNames ? [...new Set([...deviceNames, ...deviceAliases ?? []])] : [];
|
|
2481
2484
|
let inputSchema = multiDevice ? {
|
|
@@ -8327,7 +8330,7 @@ var cache = null;
|
|
|
8327
8330
|
async function gateway() {
|
|
8328
8331
|
if (cache)
|
|
8329
8332
|
return cache;
|
|
8330
|
-
const { moduleCatalog } = await import("./cli-
|
|
8333
|
+
const { moduleCatalog } = await import("./cli-2dyvnv9v.js");
|
|
8331
8334
|
const forIndex = [];
|
|
8332
8335
|
const byName = new Map;
|
|
8333
8336
|
for (const mod of moduleCatalog) {
|
|
@@ -24845,8 +24848,230 @@ ${result}`;
|
|
|
24845
24848
|
})
|
|
24846
24849
|
];
|
|
24847
24850
|
|
|
24848
|
-
// src/tools/
|
|
24851
|
+
// src/tools/server-pulse.ts
|
|
24849
24852
|
import { z as z104 } from "zod";
|
|
24853
|
+
|
|
24854
|
+
// src/core/update-check.ts
|
|
24855
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
|
|
24856
|
+
import { homedir as homedir2 } from "os";
|
|
24857
|
+
import { dirname as dirname4, join as join6 } from "path";
|
|
24858
|
+
|
|
24859
|
+
// src/version.ts
|
|
24860
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
24861
|
+
import { join as join5 } from "path";
|
|
24862
|
+
var pkg = JSON.parse(readFileSync5(join5(PROJECT_ROOT, "package.json"), "utf-8"));
|
|
24863
|
+
var VERSION = pkg.version ?? "0.0.0";
|
|
24864
|
+
var WEBSITE_URL = pkg.homepage ?? "";
|
|
24865
|
+
var LOGO_URL = pkg.logoIcon ?? "";
|
|
24866
|
+
var SERVER_TITLE = "MikroTik MCP";
|
|
24867
|
+
var SERVER_DESCRIPTION = pkg.description ?? "";
|
|
24868
|
+
var SERVER_NAME = "mikrotik-mcp";
|
|
24869
|
+
var PKG_META = pkg;
|
|
24870
|
+
|
|
24871
|
+
// src/core/update-check.ts
|
|
24872
|
+
var GITHUB_API = "https://api.github.com/repos/ali-master/mikrotik-mcp/releases/latest";
|
|
24873
|
+
var MEMORY_CACHE_TTL = 15 * 60 * 1000;
|
|
24874
|
+
var FILE_CACHE_TTL = 6 * 60 * 60 * 1000;
|
|
24875
|
+
var CACHE_PATH = join6(homedir2(), ".mikrotik-mcp", "update-check.json");
|
|
24876
|
+
function compareVersions(a, b) {
|
|
24877
|
+
const pa = a.replace(/^v/, "").split(".").map(Number);
|
|
24878
|
+
const pb = b.replace(/^v/, "").split(".").map(Number);
|
|
24879
|
+
for (let i = 0;i < Math.max(pa.length, pb.length); i++) {
|
|
24880
|
+
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
24881
|
+
if (diff !== 0)
|
|
24882
|
+
return diff;
|
|
24883
|
+
}
|
|
24884
|
+
return 0;
|
|
24885
|
+
}
|
|
24886
|
+
var memoryCache = null;
|
|
24887
|
+
function loadFileCache(maxAge = FILE_CACHE_TTL) {
|
|
24888
|
+
try {
|
|
24889
|
+
const raw = readFileSync6(CACHE_PATH, "utf-8");
|
|
24890
|
+
const parsed = JSON.parse(raw);
|
|
24891
|
+
if (!parsed?.data?.version || typeof parsed.fetchedAt !== "number")
|
|
24892
|
+
return null;
|
|
24893
|
+
if (Date.now() - parsed.fetchedAt > maxAge)
|
|
24894
|
+
return null;
|
|
24895
|
+
return parsed.data;
|
|
24896
|
+
} catch {
|
|
24897
|
+
return null;
|
|
24898
|
+
}
|
|
24899
|
+
}
|
|
24900
|
+
function loadFileCacheSync() {
|
|
24901
|
+
return loadFileCache();
|
|
24902
|
+
}
|
|
24903
|
+
function saveFileCache(data) {
|
|
24904
|
+
try {
|
|
24905
|
+
const dir = dirname4(CACHE_PATH);
|
|
24906
|
+
if (!existsSync3(dir))
|
|
24907
|
+
mkdirSync4(dir, { recursive: true });
|
|
24908
|
+
writeFileSync2(CACHE_PATH, JSON.stringify({ data, fetchedAt: Date.now() }));
|
|
24909
|
+
} catch {}
|
|
24910
|
+
}
|
|
24911
|
+
async function fetchLatestRelease() {
|
|
24912
|
+
if (memoryCache && Date.now() - memoryCache.fetchedAt < MEMORY_CACHE_TTL) {
|
|
24913
|
+
return memoryCache.data;
|
|
24914
|
+
}
|
|
24915
|
+
const fileCached = loadFileCache();
|
|
24916
|
+
if (fileCached) {
|
|
24917
|
+
memoryCache = { data: fileCached, fetchedAt: Date.now() };
|
|
24918
|
+
return fileCached;
|
|
24919
|
+
}
|
|
24920
|
+
const res = await fetch(GITHUB_API, {
|
|
24921
|
+
headers: {
|
|
24922
|
+
accept: "application/vnd.github+json",
|
|
24923
|
+
"user-agent": `mikrotik-mcp/${VERSION}`
|
|
24924
|
+
}
|
|
24925
|
+
});
|
|
24926
|
+
if (!res.ok)
|
|
24927
|
+
throw new Error(`GitHub API ${res.status}`);
|
|
24928
|
+
const gh = await res.json();
|
|
24929
|
+
const latestVersion = gh.tag_name.replace(/^v/, "");
|
|
24930
|
+
const data = {
|
|
24931
|
+
version: latestVersion,
|
|
24932
|
+
name: gh.name || `v${latestVersion}`,
|
|
24933
|
+
body: gh.body || "",
|
|
24934
|
+
publishedAt: gh.published_at,
|
|
24935
|
+
url: gh.html_url,
|
|
24936
|
+
isNewer: compareVersions(latestVersion, VERSION) > 0,
|
|
24937
|
+
currentVersion: VERSION
|
|
24938
|
+
};
|
|
24939
|
+
memoryCache = { data, fetchedAt: Date.now() };
|
|
24940
|
+
saveFileCache(data);
|
|
24941
|
+
return data;
|
|
24942
|
+
}
|
|
24943
|
+
async function checkForUpdate() {
|
|
24944
|
+
try {
|
|
24945
|
+
const release = await fetchLatestRelease();
|
|
24946
|
+
return { release, checkedAt: Date.now(), fromCache: false };
|
|
24947
|
+
} catch (e) {
|
|
24948
|
+
const stale = loadFileCache(Infinity);
|
|
24949
|
+
if (stale) {
|
|
24950
|
+
return { release: stale, checkedAt: Date.now(), fromCache: true };
|
|
24951
|
+
}
|
|
24952
|
+
return {
|
|
24953
|
+
release: null,
|
|
24954
|
+
checkedAt: Date.now(),
|
|
24955
|
+
fromCache: false,
|
|
24956
|
+
error: e instanceof Error ? e.message : String(e)
|
|
24957
|
+
};
|
|
24958
|
+
}
|
|
24959
|
+
}
|
|
24960
|
+
function assessFreshness(current, latest) {
|
|
24961
|
+
const ca = current.replace(/^v/, "").split(".").map(Number);
|
|
24962
|
+
const la = latest.replace(/^v/, "").split(".").map(Number);
|
|
24963
|
+
const majorDiff = (la[0] ?? 0) - (ca[0] ?? 0);
|
|
24964
|
+
const minorDiff = (la[1] ?? 0) - (ca[1] ?? 0);
|
|
24965
|
+
const patchDiff = (la[2] ?? 0) - (ca[2] ?? 0);
|
|
24966
|
+
if (majorDiff > 0)
|
|
24967
|
+
return "ancient";
|
|
24968
|
+
if (minorDiff > 1)
|
|
24969
|
+
return "stale";
|
|
24970
|
+
if (minorDiff === 1)
|
|
24971
|
+
return "aging";
|
|
24972
|
+
if (patchDiff > 1)
|
|
24973
|
+
return "aging";
|
|
24974
|
+
return "fresh";
|
|
24975
|
+
}
|
|
24976
|
+
function updateSummaryLine(release) {
|
|
24977
|
+
if (!release.isNewer)
|
|
24978
|
+
return null;
|
|
24979
|
+
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`;
|
|
24980
|
+
}
|
|
24981
|
+
|
|
24982
|
+
// src/tools/server-pulse.ts
|
|
24983
|
+
var UPGRADE_COMMANDS = {
|
|
24984
|
+
bunx: "bunx @usex/mikrotik-mcp@latest",
|
|
24985
|
+
npx: "npx @usex/mikrotik-mcp@latest",
|
|
24986
|
+
"bun global": "bun add -g @usex/mikrotik-mcp@latest",
|
|
24987
|
+
"npm global": "npm install -g @usex/mikrotik-mcp@latest"
|
|
24988
|
+
};
|
|
24989
|
+
function formatUptime(seconds) {
|
|
24990
|
+
const d = Math.floor(seconds / 86400);
|
|
24991
|
+
const h = Math.floor(seconds % 86400 / 3600);
|
|
24992
|
+
const m = Math.floor(seconds % 3600 / 60);
|
|
24993
|
+
const s = seconds % 60;
|
|
24994
|
+
const parts = [];
|
|
24995
|
+
if (d)
|
|
24996
|
+
parts.push(`${d}d`);
|
|
24997
|
+
if (h)
|
|
24998
|
+
parts.push(`${h}h`);
|
|
24999
|
+
if (m)
|
|
25000
|
+
parts.push(`${m}m`);
|
|
25001
|
+
parts.push(`${s}s`);
|
|
25002
|
+
return parts.join(" ");
|
|
25003
|
+
}
|
|
25004
|
+
function freshnessLabel(f) {
|
|
25005
|
+
const labels = {
|
|
25006
|
+
fresh: "UP TO DATE",
|
|
25007
|
+
aging: "SLIGHTLY BEHIND",
|
|
25008
|
+
stale: "UPDATE RECOMMENDED",
|
|
25009
|
+
ancient: "CRITICAL UPDATE NEEDED"
|
|
25010
|
+
};
|
|
25011
|
+
return labels[f];
|
|
25012
|
+
}
|
|
25013
|
+
function timeAgo(iso) {
|
|
25014
|
+
const diff = Date.now() - new Date(iso).getTime();
|
|
25015
|
+
const days = Math.floor(diff / 86400000);
|
|
25016
|
+
if (days < 1)
|
|
25017
|
+
return "today";
|
|
25018
|
+
if (days === 1)
|
|
25019
|
+
return "yesterday";
|
|
25020
|
+
if (days < 30)
|
|
25021
|
+
return `${days} days ago`;
|
|
25022
|
+
if (days < 365)
|
|
25023
|
+
return `${Math.floor(days / 30)} months ago`;
|
|
25024
|
+
return `${Math.floor(days / 365)} years ago`;
|
|
25025
|
+
}
|
|
25026
|
+
var serverPulseTools = [
|
|
25027
|
+
defineTool({
|
|
25028
|
+
name: "check_server_pulse",
|
|
25029
|
+
title: "Server Pulse & Update Check",
|
|
25030
|
+
noDevice: true,
|
|
25031
|
+
annotations: READ,
|
|
25032
|
+
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.",
|
|
25033
|
+
inputSchema: {
|
|
25034
|
+
include_release_notes: z104.boolean().optional().describe("Include the full GitHub release notes markdown (default true). " + "Set false for a compact version-only check.")
|
|
25035
|
+
},
|
|
25036
|
+
async handler(args) {
|
|
25037
|
+
const includeNotes = args.include_release_notes !== false;
|
|
25038
|
+
const result = await checkForUpdate();
|
|
25039
|
+
const uptime = Math.floor(process.uptime());
|
|
25040
|
+
const sections = [];
|
|
25041
|
+
const sep = "\u2500".repeat(50);
|
|
25042
|
+
sections.push(`SERVER PULSE \u2014 ${SERVER_TITLE} v${VERSION}`, sep, "Package: @usex/mikrotik-mcp", `Version: ${VERSION}`, `Uptime: ${formatUptime(uptime)}`, `Website: ${WEBSITE_URL}`);
|
|
25043
|
+
if (result.release) {
|
|
25044
|
+
const freshness = assessFreshness(VERSION, result.release.version);
|
|
25045
|
+
const label = freshnessLabel(freshness);
|
|
25046
|
+
const age = timeAgo(result.release.publishedAt);
|
|
25047
|
+
sections.push("", `UPDATE STATUS: ${label}`, sep, `Current: v${VERSION}`, `Latest: v${result.release.version} (${result.release.name})`, `Published: ${age}`, `Freshness: ${freshness.toUpperCase()}`);
|
|
25048
|
+
if (result.release.isNewer) {
|
|
25049
|
+
sections.push("", ">>> A newer version is available! <<<");
|
|
25050
|
+
} else {
|
|
25051
|
+
sections.push("", "You are running the latest version.");
|
|
25052
|
+
}
|
|
25053
|
+
if (result.release.isNewer) {
|
|
25054
|
+
sections.push("", "UPGRADE", sep);
|
|
25055
|
+
for (const [method, cmd] of Object.entries(UPGRADE_COMMANDS)) {
|
|
25056
|
+
sections.push(` ${method.padEnd(12)} ${cmd}`);
|
|
25057
|
+
}
|
|
25058
|
+
sections.push("", `Release: ${result.release.url}`);
|
|
25059
|
+
}
|
|
25060
|
+
if (includeNotes && result.release.body) {
|
|
25061
|
+
const notesHeader = result.release.isNewer ? `WHAT'S NEW IN v${result.release.version}` : `RELEASE NOTES \u2014 v${result.release.version}`;
|
|
25062
|
+
sections.push("", notesHeader, sep, result.release.body);
|
|
25063
|
+
}
|
|
25064
|
+
} else {
|
|
25065
|
+
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)");
|
|
25066
|
+
}
|
|
25067
|
+
return sections.join(`
|
|
25068
|
+
`);
|
|
25069
|
+
}
|
|
25070
|
+
})
|
|
25071
|
+
];
|
|
25072
|
+
|
|
25073
|
+
// src/tools/threat-feed.ts
|
|
25074
|
+
import { z as z105 } from "zod";
|
|
24850
25075
|
var FEED_TAG = "threat-feed";
|
|
24851
25076
|
var threatFeedTools = [
|
|
24852
25077
|
defineTool({
|
|
@@ -24855,12 +25080,12 @@ var threatFeedTools = [
|
|
|
24855
25080
|
annotations: WRITE,
|
|
24856
25081
|
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.",
|
|
24857
25082
|
inputSchema: {
|
|
24858
|
-
name:
|
|
24859
|
-
url:
|
|
24860
|
-
address_list:
|
|
24861
|
-
interval:
|
|
24862
|
-
drop:
|
|
24863
|
-
apply:
|
|
25083
|
+
name: z105.string().describe("Short feed id, e.g. 'spamhaus-drop'"),
|
|
25084
|
+
url: z105.string().describe("HTTPS URL of a RouterOS .rsc address-list file"),
|
|
25085
|
+
address_list: z105.string().default("threat-blocklist").describe("Address-list to populate"),
|
|
25086
|
+
interval: z105.string().default("1h").describe("How often to refresh the feed"),
|
|
25087
|
+
drop: z105.boolean().default(true).describe("Also add a raw drop rule for the address-list"),
|
|
25088
|
+
apply: z105.boolean().default(false).describe("false = preview (default); true = install")
|
|
24864
25089
|
},
|
|
24865
25090
|
async handler(a, ctx) {
|
|
24866
25091
|
const id = `${FEED_TAG}-${a.name}`;
|
|
@@ -24897,7 +25122,7 @@ ${plan}`;
|
|
|
24897
25122
|
title: "Remove Threat-Intel Feed",
|
|
24898
25123
|
annotations: DESTRUCTIVE,
|
|
24899
25124
|
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.",
|
|
24900
|
-
inputSchema: { name:
|
|
25125
|
+
inputSchema: { name: z105.string().describe("The feed id used when subscribing") },
|
|
24901
25126
|
async handler(a, ctx) {
|
|
24902
25127
|
const id = `${FEED_TAG}-${a.name}`;
|
|
24903
25128
|
ctx.info(`Removing threat feed ${id}`);
|
|
@@ -24919,7 +25144,7 @@ ${plan}`;
|
|
|
24919
25144
|
];
|
|
24920
25145
|
|
|
24921
25146
|
// src/tools/sstp.ts
|
|
24922
|
-
import { z as
|
|
25147
|
+
import { z as z106 } from "zod";
|
|
24923
25148
|
var sstpTools = [
|
|
24924
25149
|
defineTool({
|
|
24925
25150
|
name: "get_sstp_server",
|
|
@@ -24940,19 +25165,19 @@ ${result}`;
|
|
|
24940
25165
|
annotations: WRITE_IDEMPOTENT,
|
|
24941
25166
|
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.",
|
|
24942
25167
|
inputSchema: {
|
|
24943
|
-
enabled:
|
|
24944
|
-
default_profile:
|
|
24945
|
-
authentication:
|
|
24946
|
-
certificate:
|
|
24947
|
-
port:
|
|
24948
|
-
tls_version:
|
|
24949
|
-
verify_client_certificate:
|
|
24950
|
-
pfs:
|
|
24951
|
-
force_aes:
|
|
24952
|
-
max_mtu:
|
|
24953
|
-
max_mru:
|
|
24954
|
-
mrru:
|
|
24955
|
-
keepalive_timeout:
|
|
25168
|
+
enabled: z106.boolean().optional(),
|
|
25169
|
+
default_profile: z106.string().optional(),
|
|
25170
|
+
authentication: z106.string().optional().describe("Comma-separated, e.g. 'mschap2,mschap1'"),
|
|
25171
|
+
certificate: z106.string().optional().describe("TLS certificate name"),
|
|
25172
|
+
port: z106.number().int().optional(),
|
|
25173
|
+
tls_version: z106.enum(["any", "only-1.2"]).optional(),
|
|
25174
|
+
verify_client_certificate: z106.boolean().optional(),
|
|
25175
|
+
pfs: z106.boolean().optional().describe("Enable Perfect Forward Secrecy"),
|
|
25176
|
+
force_aes: z106.boolean().optional().describe("Require clients to use AES ciphers"),
|
|
25177
|
+
max_mtu: z106.number().int().optional().describe("Maximum transmission unit"),
|
|
25178
|
+
max_mru: z106.number().int().optional().describe("Maximum receive unit"),
|
|
25179
|
+
mrru: z106.number().int().optional().describe("Max receive reconstructed unit for MP"),
|
|
25180
|
+
keepalive_timeout: z106.number().int().optional().describe("Seconds before an idle connection is considered down")
|
|
24956
25181
|
},
|
|
24957
25182
|
async handler(a, ctx) {
|
|
24958
25183
|
ctx.info("Configuring SSTP server");
|
|
@@ -24974,27 +25199,27 @@ ${details}`;
|
|
|
24974
25199
|
annotations: WRITE,
|
|
24975
25200
|
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`.",
|
|
24976
25201
|
inputSchema: {
|
|
24977
|
-
name:
|
|
24978
|
-
connect_to:
|
|
24979
|
-
port:
|
|
24980
|
-
user:
|
|
24981
|
-
password:
|
|
24982
|
-
profile:
|
|
24983
|
-
certificate:
|
|
24984
|
-
verify_server_certificate:
|
|
24985
|
-
authentication:
|
|
24986
|
-
tls_version:
|
|
24987
|
-
pfs:
|
|
24988
|
-
add_default_route:
|
|
24989
|
-
default_route_distance:
|
|
24990
|
-
dial_on_demand:
|
|
24991
|
-
max_mtu:
|
|
24992
|
-
max_mru:
|
|
24993
|
-
mrru:
|
|
24994
|
-
keepalive_timeout:
|
|
24995
|
-
http_proxy:
|
|
24996
|
-
comment:
|
|
24997
|
-
disabled:
|
|
25202
|
+
name: z106.string().describe("Name for the new SSTP client interface"),
|
|
25203
|
+
connect_to: z106.string().describe("Remote SSTP server address (IP or DNS name; host:port also accepted)"),
|
|
25204
|
+
port: z106.number().int().optional().describe("TCP port (default 443 if omitted)"),
|
|
25205
|
+
user: z106.string(),
|
|
25206
|
+
password: z106.string(),
|
|
25207
|
+
profile: z106.string().optional(),
|
|
25208
|
+
certificate: z106.string().optional().describe("Client TLS certificate name"),
|
|
25209
|
+
verify_server_certificate: z106.boolean().optional(),
|
|
25210
|
+
authentication: z106.string().optional().describe("Comma-separated, e.g. 'mschap2,mschap1'"),
|
|
25211
|
+
tls_version: z106.enum(["any", "only-1.2"]).optional(),
|
|
25212
|
+
pfs: z106.boolean().optional().describe("Enable Perfect Forward Secrecy"),
|
|
25213
|
+
add_default_route: z106.boolean().optional(),
|
|
25214
|
+
default_route_distance: z106.number().int().optional().describe("Distance of the auto-added default route"),
|
|
25215
|
+
dial_on_demand: z106.boolean().optional().describe("Connect only when traffic is sent over the tunnel"),
|
|
25216
|
+
max_mtu: z106.number().int().optional().describe("Maximum transmission unit"),
|
|
25217
|
+
max_mru: z106.number().int().optional().describe("Maximum receive unit"),
|
|
25218
|
+
mrru: z106.number().int().optional().describe("Max receive reconstructed unit for MP"),
|
|
25219
|
+
keepalive_timeout: z106.number().int().optional().describe("Seconds before an idle connection is considered down"),
|
|
25220
|
+
http_proxy: z106.string().optional(),
|
|
25221
|
+
comment: z106.string().optional(),
|
|
25222
|
+
disabled: z106.boolean().default(false)
|
|
24998
25223
|
},
|
|
24999
25224
|
async handler(a, ctx) {
|
|
25000
25225
|
ctx.info(`Creating SSTP client: name=${a.name}, connect_to=${a.connect_to}`);
|
|
@@ -25015,7 +25240,7 @@ ${redactSecrets(details)}` : "SSTP client creation completed but unable to verif
|
|
|
25015
25240
|
annotations: READ,
|
|
25016
25241
|
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.",
|
|
25017
25242
|
inputSchema: {
|
|
25018
|
-
name_filter:
|
|
25243
|
+
name_filter: z106.string().optional().describe("Partial name match")
|
|
25019
25244
|
},
|
|
25020
25245
|
async handler(a, ctx) {
|
|
25021
25246
|
ctx.info("Listing SSTP clients");
|
|
@@ -25033,7 +25258,7 @@ ${redactSecrets(result)}`;
|
|
|
25033
25258
|
title: "Get SSTP Client Interface Detail",
|
|
25034
25259
|
annotations: READ,
|
|
25035
25260
|
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.",
|
|
25036
|
-
inputSchema: { name:
|
|
25261
|
+
inputSchema: { name: z106.string() },
|
|
25037
25262
|
async handler(a, ctx) {
|
|
25038
25263
|
ctx.info(`Getting SSTP client details: name=${a.name}`);
|
|
25039
25264
|
const result = await executeMikrotikCommand(`/interface sstp-client print detail where name="${a.name}"`, ctx);
|
|
@@ -25047,7 +25272,7 @@ ${redactSecrets(result)}`;
|
|
|
25047
25272
|
title: "Remove SSTP Client Interface",
|
|
25048
25273
|
annotations: DESTRUCTIVE,
|
|
25049
25274
|
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.",
|
|
25050
|
-
inputSchema: { name:
|
|
25275
|
+
inputSchema: { name: z106.string() },
|
|
25051
25276
|
async handler(a, ctx) {
|
|
25052
25277
|
ctx.info(`Removing SSTP client: name=${a.name}`);
|
|
25053
25278
|
const count = await executeMikrotikCommand(`/interface sstp-client print count-only where name="${a.name}"`, ctx);
|
|
@@ -25064,7 +25289,7 @@ ${redactSecrets(result)}`;
|
|
|
25064
25289
|
title: "Enable SSTP Client Interface",
|
|
25065
25290
|
annotations: WRITE_IDEMPOTENT,
|
|
25066
25291
|
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`.",
|
|
25067
|
-
inputSchema: { name:
|
|
25292
|
+
inputSchema: { name: z106.string() },
|
|
25068
25293
|
async handler(a, ctx) {
|
|
25069
25294
|
ctx.info(`Enabling SSTP client: name=${a.name}`);
|
|
25070
25295
|
const count = await executeMikrotikCommand(`/interface sstp-client print count-only where name="${a.name}"`, ctx);
|
|
@@ -25081,7 +25306,7 @@ ${redactSecrets(result)}`;
|
|
|
25081
25306
|
title: "Disable SSTP Client Interface",
|
|
25082
25307
|
annotations: WRITE_IDEMPOTENT,
|
|
25083
25308
|
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`.",
|
|
25084
|
-
inputSchema: { name:
|
|
25309
|
+
inputSchema: { name: z106.string() },
|
|
25085
25310
|
async handler(a, ctx) {
|
|
25086
25311
|
ctx.info(`Disabling SSTP client: name=${a.name}`);
|
|
25087
25312
|
const count = await executeMikrotikCommand(`/interface sstp-client print count-only where name="${a.name}"`, ctx);
|
|
@@ -25096,7 +25321,7 @@ ${redactSecrets(result)}`;
|
|
|
25096
25321
|
];
|
|
25097
25322
|
|
|
25098
25323
|
// src/tools/switch-settings.ts
|
|
25099
|
-
import { z as
|
|
25324
|
+
import { z as z107 } from "zod";
|
|
25100
25325
|
var switchSettingsTools = [
|
|
25101
25326
|
defineTool({
|
|
25102
25327
|
name: "list_switches",
|
|
@@ -25104,8 +25329,8 @@ var switchSettingsTools = [
|
|
|
25104
25329
|
annotations: READ,
|
|
25105
25330
|
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.",
|
|
25106
25331
|
inputSchema: {
|
|
25107
|
-
name_filter:
|
|
25108
|
-
type_filter:
|
|
25332
|
+
name_filter: z107.string().optional().describe("Partial switch-name match"),
|
|
25333
|
+
type_filter: z107.string().optional().describe("Partial switch-type match")
|
|
25109
25334
|
},
|
|
25110
25335
|
async handler(a, ctx) {
|
|
25111
25336
|
ctx.info("Listing switches");
|
|
@@ -25126,7 +25351,7 @@ ${result}`;
|
|
|
25126
25351
|
annotations: READ,
|
|
25127
25352
|
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.",
|
|
25128
25353
|
inputSchema: {
|
|
25129
|
-
switch_id:
|
|
25354
|
+
switch_id: z107.string().describe("Switch name (e.g. 'switch1') or RouterOS '.id'")
|
|
25130
25355
|
},
|
|
25131
25356
|
async handler(a, ctx) {
|
|
25132
25357
|
ctx.info(`Getting switch details: switch_id=${a.switch_id}`);
|
|
@@ -25150,14 +25375,14 @@ ${result}`;
|
|
|
25150
25375
|
|
|
25151
25376
|
` + "Returns updated switch details on success.",
|
|
25152
25377
|
inputSchema: {
|
|
25153
|
-
switch_id:
|
|
25154
|
-
name:
|
|
25155
|
-
cpu_flow_control:
|
|
25156
|
-
mirror_source:
|
|
25157
|
-
mirror_target:
|
|
25158
|
-
mirror_egress:
|
|
25159
|
-
mirror_egress_target:
|
|
25160
|
-
switch_all_ports:
|
|
25378
|
+
switch_id: z107.string().describe("Switch name (e.g. 'switch1') or RouterOS '.id'"),
|
|
25379
|
+
name: z107.string().optional().describe("Rename the switch"),
|
|
25380
|
+
cpu_flow_control: z107.boolean().optional(),
|
|
25381
|
+
mirror_source: z107.string().optional().describe("Source port to mirror, or 'none'"),
|
|
25382
|
+
mirror_target: z107.string().optional().describe("Monitor port, 'cpu', or 'none'"),
|
|
25383
|
+
mirror_egress: z107.string().optional().describe("Egress mirror source port (newer chips), or 'none'"),
|
|
25384
|
+
mirror_egress_target: z107.string().optional().describe("Egress mirror target port (88E6393X/88E6191X/88E6190 chips), or 'none'"),
|
|
25385
|
+
switch_all_ports: z107.boolean().optional().describe("Switch all ports together (RB450G/RB435G/RB850Gx2 only)")
|
|
25161
25386
|
},
|
|
25162
25387
|
async handler(a, ctx) {
|
|
25163
25388
|
ctx.info(`Updating switch: switch_id=${a.switch_id}`);
|
|
@@ -25180,9 +25405,9 @@ ${details}`;
|
|
|
25180
25405
|
];
|
|
25181
25406
|
|
|
25182
25407
|
// src/tools/switch-port.ts
|
|
25183
|
-
import { z as
|
|
25184
|
-
var VlanMode =
|
|
25185
|
-
var VlanHeader =
|
|
25408
|
+
import { z as z108 } from "zod";
|
|
25409
|
+
var VlanMode = z108.enum(["disabled", "optional", "enabled", "secure"]);
|
|
25410
|
+
var VlanHeader = z108.enum(["leave-as-is", "always-strip", "add-if-missing"]);
|
|
25186
25411
|
var switchPortTools = [
|
|
25187
25412
|
defineTool({
|
|
25188
25413
|
name: "list_switch_ports",
|
|
@@ -25190,8 +25415,8 @@ var switchPortTools = [
|
|
|
25190
25415
|
annotations: READ,
|
|
25191
25416
|
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.",
|
|
25192
25417
|
inputSchema: {
|
|
25193
|
-
name_filter:
|
|
25194
|
-
switch_filter:
|
|
25418
|
+
name_filter: z108.string().optional().describe("Partial port-name match"),
|
|
25419
|
+
switch_filter: z108.string().optional().describe("Filter by owning switch, e.g. 'switch1'")
|
|
25195
25420
|
},
|
|
25196
25421
|
async handler(a, ctx) {
|
|
25197
25422
|
ctx.info("Listing switch ports");
|
|
@@ -25212,7 +25437,7 @@ ${result}`;
|
|
|
25212
25437
|
annotations: READ,
|
|
25213
25438
|
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.",
|
|
25214
25439
|
inputSchema: {
|
|
25215
|
-
port_id:
|
|
25440
|
+
port_id: z108.string().describe("Port name (e.g. 'ether1') or RouterOS '.id'")
|
|
25216
25441
|
},
|
|
25217
25442
|
async handler(a, ctx) {
|
|
25218
25443
|
ctx.info(`Getting switch port details: port_id=${a.port_id}`);
|
|
@@ -25238,11 +25463,11 @@ ${result}`;
|
|
|
25238
25463
|
` + ` 'always-strip', or 'add-if-missing'.
|
|
25239
25464
|
` + " default_vlan_id: PVID for untagged ingress ('auto', 'none', or a number).",
|
|
25240
25465
|
inputSchema: {
|
|
25241
|
-
port_id:
|
|
25242
|
-
default_vlan_id:
|
|
25466
|
+
port_id: z108.string().describe("Port name (e.g. 'ether1') or RouterOS '.id'"),
|
|
25467
|
+
default_vlan_id: z108.string().optional().describe("PVID: 'auto', 'none', or a VLAN id number"),
|
|
25243
25468
|
vlan_mode: VlanMode.optional(),
|
|
25244
25469
|
vlan_header: VlanHeader.optional(),
|
|
25245
|
-
force_vlan_id:
|
|
25470
|
+
force_vlan_id: z108.boolean().optional()
|
|
25246
25471
|
},
|
|
25247
25472
|
async handler(a, ctx) {
|
|
25248
25473
|
ctx.info(`Updating switch port: port_id=${a.port_id}`);
|
|
@@ -25264,7 +25489,7 @@ ${details}`;
|
|
|
25264
25489
|
];
|
|
25265
25490
|
|
|
25266
25491
|
// src/tools/switch-port-isolation.ts
|
|
25267
|
-
import { z as
|
|
25492
|
+
import { z as z109 } from "zod";
|
|
25268
25493
|
function selectorFor(id) {
|
|
25269
25494
|
return id.startsWith("*") ? `.id="${id}"` : `port="${id}"`;
|
|
25270
25495
|
}
|
|
@@ -25281,9 +25506,9 @@ var switchPortIsolationTools = [
|
|
|
25281
25506
|
` + ` port: source port to isolate, e.g. 'ether1'.
|
|
25282
25507
|
` + " forwarding_override_ports: comma-separated list of the ONLY ports this port " + " may forward to \u2014 all others are blocked in hardware.",
|
|
25283
25508
|
inputSchema: {
|
|
25284
|
-
port:
|
|
25285
|
-
forwarding_override_ports:
|
|
25286
|
-
comment:
|
|
25509
|
+
port: z109.string().describe("Source port to isolate, e.g. 'ether1'"),
|
|
25510
|
+
forwarding_override_ports: z109.string().describe("Comma-separated allowed destination ports"),
|
|
25511
|
+
comment: z109.string().optional()
|
|
25287
25512
|
},
|
|
25288
25513
|
async handler(a, ctx) {
|
|
25289
25514
|
ctx.info(`Adding switch port-isolation: port=${a.port}`);
|
|
@@ -25305,7 +25530,7 @@ ${details}` : "Switch port-isolation addition completed but unable to verify.";
|
|
|
25305
25530
|
|
|
25306
25531
|
` + "Returns a table of all matching entries; optionally filter by partial port name via port_filter.",
|
|
25307
25532
|
inputSchema: {
|
|
25308
|
-
port_filter:
|
|
25533
|
+
port_filter: z109.string().optional().describe("Partial source-port match")
|
|
25309
25534
|
},
|
|
25310
25535
|
async handler(a, ctx) {
|
|
25311
25536
|
ctx.info("Listing switch port-isolation entries");
|
|
@@ -25326,7 +25551,7 @@ ${result}`;
|
|
|
25326
25551
|
|
|
25327
25552
|
` + "Returns the full detail block for the matched entry, or a not-found message.",
|
|
25328
25553
|
inputSchema: {
|
|
25329
|
-
isolation_id:
|
|
25554
|
+
isolation_id: z109.string().describe("Source port name (e.g. 'ether1') or RouterOS '.id'")
|
|
25330
25555
|
},
|
|
25331
25556
|
async handler(a, ctx) {
|
|
25332
25557
|
ctx.info(`Getting switch port-isolation: isolation_id=${a.isolation_id}`);
|
|
@@ -25346,9 +25571,9 @@ ${result}`;
|
|
|
25346
25571
|
|
|
25347
25572
|
` + "Returns the entry's updated detail block.",
|
|
25348
25573
|
inputSchema: {
|
|
25349
|
-
isolation_id:
|
|
25350
|
-
forwarding_override_ports:
|
|
25351
|
-
comment:
|
|
25574
|
+
isolation_id: z109.string().describe("Source port name or RouterOS '.id'"),
|
|
25575
|
+
forwarding_override_ports: z109.string().optional().describe("Comma-separated allowed destination ports"),
|
|
25576
|
+
comment: z109.string().optional()
|
|
25352
25577
|
},
|
|
25353
25578
|
async handler(a, ctx) {
|
|
25354
25579
|
ctx.info(`Updating switch port-isolation: isolation_id=${a.isolation_id}`);
|
|
@@ -25377,7 +25602,7 @@ ${details}`;
|
|
|
25377
25602
|
|
|
25378
25603
|
` + "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.",
|
|
25379
25604
|
inputSchema: {
|
|
25380
|
-
isolation_id:
|
|
25605
|
+
isolation_id: z109.string().describe("Source port name or RouterOS '.id'")
|
|
25381
25606
|
},
|
|
25382
25607
|
async handler(a, ctx) {
|
|
25383
25608
|
ctx.info(`Removing switch port-isolation: isolation_id=${a.isolation_id}`);
|
|
@@ -25394,7 +25619,7 @@ ${details}`;
|
|
|
25394
25619
|
];
|
|
25395
25620
|
|
|
25396
25621
|
// src/tools/switch-rule.ts
|
|
25397
|
-
import { z as
|
|
25622
|
+
import { z as z110 } from "zod";
|
|
25398
25623
|
var isDigits8 = (s) => /^\d+$/.test(s);
|
|
25399
25624
|
async function updateSwitchRule(a, ctx) {
|
|
25400
25625
|
ctx.info(`Updating switch rule: rule_id=${a.rule_id}`);
|
|
@@ -25461,32 +25686,32 @@ var switchRuleTools = [
|
|
|
25461
25686
|
` + ` rate: rate limit in bits/second.
|
|
25462
25687
|
` + " mac_protocol: e.g. 'ip', 'arp', 'vlan', or an EtherType number.",
|
|
25463
25688
|
inputSchema: {
|
|
25464
|
-
switch:
|
|
25465
|
-
ports:
|
|
25466
|
-
src_address:
|
|
25467
|
-
dst_address:
|
|
25468
|
-
src_address6:
|
|
25469
|
-
dst_address6:
|
|
25470
|
-
src_mac_address:
|
|
25471
|
-
dst_mac_address:
|
|
25472
|
-
src_port:
|
|
25473
|
-
dst_port:
|
|
25474
|
-
protocol:
|
|
25475
|
-
mac_protocol:
|
|
25476
|
-
vlan_header:
|
|
25477
|
-
vlan_id:
|
|
25478
|
-
vlan_priority:
|
|
25479
|
-
dscp:
|
|
25480
|
-
flow_label:
|
|
25481
|
-
new_dst_ports:
|
|
25482
|
-
new_vlan_id:
|
|
25483
|
-
new_vlan_priority:
|
|
25484
|
-
redirect_to_cpu:
|
|
25485
|
-
copy_to_cpu:
|
|
25486
|
-
mirror:
|
|
25487
|
-
rate:
|
|
25488
|
-
comment:
|
|
25489
|
-
disabled:
|
|
25689
|
+
switch: z110.string().describe("Owning switch chip, e.g. 'switch1'"),
|
|
25690
|
+
ports: z110.string().describe("Comma-separated source ports the rule matches"),
|
|
25691
|
+
src_address: z110.string().optional().describe("Source IP/mask"),
|
|
25692
|
+
dst_address: z110.string().optional().describe("Destination IP/mask"),
|
|
25693
|
+
src_address6: z110.string().optional().describe("Source IPv6 address/mask"),
|
|
25694
|
+
dst_address6: z110.string().optional().describe("Destination IPv6 address/mask"),
|
|
25695
|
+
src_mac_address: z110.string().optional().describe("Source MAC/mask"),
|
|
25696
|
+
dst_mac_address: z110.string().optional().describe("Destination MAC/mask"),
|
|
25697
|
+
src_port: z110.string().optional().describe("Layer-4 source port(s)"),
|
|
25698
|
+
dst_port: z110.string().optional().describe("Layer-4 destination port(s)"),
|
|
25699
|
+
protocol: z110.string().optional().describe("IP protocol, e.g. 'tcp'"),
|
|
25700
|
+
mac_protocol: z110.string().optional().describe("MAC protocol, e.g. 'ip', 'arp', 'vlan' or a number"),
|
|
25701
|
+
vlan_header: z110.enum(["any", "not-present", "present"]).optional().describe("Match on VLAN tag presence"),
|
|
25702
|
+
vlan_id: z110.string().optional(),
|
|
25703
|
+
vlan_priority: z110.string().optional(),
|
|
25704
|
+
dscp: z110.string().optional(),
|
|
25705
|
+
flow_label: z110.string().optional().describe("IPv6 flow label"),
|
|
25706
|
+
new_dst_ports: z110.string().optional().describe("Redirect target ports; empty string drops the traffic"),
|
|
25707
|
+
new_vlan_id: z110.string().optional(),
|
|
25708
|
+
new_vlan_priority: z110.string().optional(),
|
|
25709
|
+
redirect_to_cpu: z110.boolean().optional(),
|
|
25710
|
+
copy_to_cpu: z110.boolean().optional(),
|
|
25711
|
+
mirror: z110.boolean().optional(),
|
|
25712
|
+
rate: z110.string().optional().describe("Rate limit in bits/second"),
|
|
25713
|
+
comment: z110.string().optional(),
|
|
25714
|
+
disabled: z110.boolean().default(false)
|
|
25490
25715
|
},
|
|
25491
25716
|
async handler(a, ctx) {
|
|
25492
25717
|
ctx.info(`Adding switch rule: switch=${a.switch}, ports=${a.ports}`);
|
|
@@ -25520,9 +25745,9 @@ ${details}`;
|
|
|
25520
25745
|
annotations: READ,
|
|
25521
25746
|
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.",
|
|
25522
25747
|
inputSchema: {
|
|
25523
|
-
switch_filter:
|
|
25524
|
-
ports_filter:
|
|
25525
|
-
disabled_only:
|
|
25748
|
+
switch_filter: z110.string().optional(),
|
|
25749
|
+
ports_filter: z110.string().optional(),
|
|
25750
|
+
disabled_only: z110.boolean().default(false)
|
|
25526
25751
|
},
|
|
25527
25752
|
async handler(a, ctx) {
|
|
25528
25753
|
ctx.info("Listing switch rules");
|
|
@@ -25545,7 +25770,7 @@ ${result}`;
|
|
|
25545
25770
|
annotations: READ,
|
|
25546
25771
|
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.",
|
|
25547
25772
|
inputSchema: {
|
|
25548
|
-
rule_id:
|
|
25773
|
+
rule_id: z110.string().describe("RouterOS '.id', e.g. '*1' or '0'")
|
|
25549
25774
|
},
|
|
25550
25775
|
async handler(a, ctx) {
|
|
25551
25776
|
ctx.info(`Getting switch rule: rule_id=${a.rule_id}`);
|
|
@@ -25561,33 +25786,33 @@ ${result}`;
|
|
|
25561
25786
|
annotations: WRITE_IDEMPOTENT,
|
|
25562
25787
|
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.",
|
|
25563
25788
|
inputSchema: {
|
|
25564
|
-
rule_id:
|
|
25565
|
-
switch:
|
|
25566
|
-
ports:
|
|
25567
|
-
src_address:
|
|
25568
|
-
dst_address:
|
|
25569
|
-
src_address6:
|
|
25570
|
-
dst_address6:
|
|
25571
|
-
src_mac_address:
|
|
25572
|
-
dst_mac_address:
|
|
25573
|
-
src_port:
|
|
25574
|
-
dst_port:
|
|
25575
|
-
protocol:
|
|
25576
|
-
mac_protocol:
|
|
25577
|
-
vlan_header:
|
|
25578
|
-
vlan_id:
|
|
25579
|
-
vlan_priority:
|
|
25580
|
-
dscp:
|
|
25581
|
-
flow_label:
|
|
25582
|
-
new_dst_ports:
|
|
25583
|
-
new_vlan_id:
|
|
25584
|
-
new_vlan_priority:
|
|
25585
|
-
redirect_to_cpu:
|
|
25586
|
-
copy_to_cpu:
|
|
25587
|
-
mirror:
|
|
25588
|
-
rate:
|
|
25589
|
-
comment:
|
|
25590
|
-
disabled:
|
|
25789
|
+
rule_id: z110.string(),
|
|
25790
|
+
switch: z110.string().optional(),
|
|
25791
|
+
ports: z110.string().optional(),
|
|
25792
|
+
src_address: z110.string().optional(),
|
|
25793
|
+
dst_address: z110.string().optional(),
|
|
25794
|
+
src_address6: z110.string().optional(),
|
|
25795
|
+
dst_address6: z110.string().optional(),
|
|
25796
|
+
src_mac_address: z110.string().optional(),
|
|
25797
|
+
dst_mac_address: z110.string().optional(),
|
|
25798
|
+
src_port: z110.string().optional(),
|
|
25799
|
+
dst_port: z110.string().optional(),
|
|
25800
|
+
protocol: z110.string().optional(),
|
|
25801
|
+
mac_protocol: z110.string().optional(),
|
|
25802
|
+
vlan_header: z110.enum(["any", "not-present", "present"]).optional(),
|
|
25803
|
+
vlan_id: z110.string().optional(),
|
|
25804
|
+
vlan_priority: z110.string().optional(),
|
|
25805
|
+
dscp: z110.string().optional(),
|
|
25806
|
+
flow_label: z110.string().optional(),
|
|
25807
|
+
new_dst_ports: z110.string().optional(),
|
|
25808
|
+
new_vlan_id: z110.string().optional(),
|
|
25809
|
+
new_vlan_priority: z110.string().optional(),
|
|
25810
|
+
redirect_to_cpu: z110.boolean().optional(),
|
|
25811
|
+
copy_to_cpu: z110.boolean().optional(),
|
|
25812
|
+
mirror: z110.boolean().optional(),
|
|
25813
|
+
rate: z110.string().optional(),
|
|
25814
|
+
comment: z110.string().optional(),
|
|
25815
|
+
disabled: z110.boolean().optional()
|
|
25591
25816
|
},
|
|
25592
25817
|
async handler(a, ctx) {
|
|
25593
25818
|
return updateSwitchRule(a, ctx);
|
|
@@ -25598,7 +25823,7 @@ ${result}`;
|
|
|
25598
25823
|
title: "Remove Switch Chip ACL Rule",
|
|
25599
25824
|
annotations: DESTRUCTIVE,
|
|
25600
25825
|
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.",
|
|
25601
|
-
inputSchema: { rule_id:
|
|
25826
|
+
inputSchema: { rule_id: z110.string() },
|
|
25602
25827
|
async handler(a, ctx) {
|
|
25603
25828
|
ctx.info(`Removing switch rule: rule_id=${a.rule_id}`);
|
|
25604
25829
|
const count = await executeMikrotikCommand(`/interface ethernet switch rule print count-only where .id=${a.rule_id}`, ctx);
|
|
@@ -25615,7 +25840,7 @@ ${result}`;
|
|
|
25615
25840
|
title: "Enable Switch Chip ACL Rule",
|
|
25616
25841
|
annotations: WRITE_IDEMPOTENT,
|
|
25617
25842
|
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.",
|
|
25618
|
-
inputSchema: { rule_id:
|
|
25843
|
+
inputSchema: { rule_id: z110.string() },
|
|
25619
25844
|
async handler(a, ctx) {
|
|
25620
25845
|
return updateSwitchRule({ rule_id: a.rule_id, disabled: false }, ctx);
|
|
25621
25846
|
}
|
|
@@ -25625,7 +25850,7 @@ ${result}`;
|
|
|
25625
25850
|
title: "Disable Switch Chip ACL Rule",
|
|
25626
25851
|
annotations: WRITE_IDEMPOTENT,
|
|
25627
25852
|
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.",
|
|
25628
|
-
inputSchema: { rule_id:
|
|
25853
|
+
inputSchema: { rule_id: z110.string() },
|
|
25629
25854
|
async handler(a, ctx) {
|
|
25630
25855
|
return updateSwitchRule({ rule_id: a.rule_id, disabled: true }, ctx);
|
|
25631
25856
|
}
|
|
@@ -25633,7 +25858,7 @@ ${result}`;
|
|
|
25633
25858
|
];
|
|
25634
25859
|
|
|
25635
25860
|
// src/tools/system-config.ts
|
|
25636
|
-
import { z as
|
|
25861
|
+
import { z as z111 } from "zod";
|
|
25637
25862
|
var systemConfigTools = [
|
|
25638
25863
|
defineTool({
|
|
25639
25864
|
name: "list_system_console",
|
|
@@ -25680,7 +25905,7 @@ ${result}`;
|
|
|
25680
25905
|
annotations: WRITE_IDEMPOTENT,
|
|
25681
25906
|
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.",
|
|
25682
25907
|
inputSchema: {
|
|
25683
|
-
all_leds_off:
|
|
25908
|
+
all_leds_off: z111.enum(["never", "immediate", "after-1h", "after-1min"]).optional().describe("When to turn all LEDs off (dark mode)")
|
|
25684
25909
|
},
|
|
25685
25910
|
async handler(a, ctx) {
|
|
25686
25911
|
ctx.info("Setting LED settings");
|
|
@@ -25730,8 +25955,8 @@ ${result}`;
|
|
|
25730
25955
|
annotations: WRITE_IDEMPOTENT,
|
|
25731
25956
|
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.",
|
|
25732
25957
|
inputSchema: {
|
|
25733
|
-
note:
|
|
25734
|
-
show_at_login:
|
|
25958
|
+
note: z111.string().optional().describe("The note text to display"),
|
|
25959
|
+
show_at_login: z111.boolean().optional().describe("Show the note on login")
|
|
25735
25960
|
},
|
|
25736
25961
|
async handler(a, ctx) {
|
|
25737
25962
|
ctx.info("Setting system note");
|
|
@@ -25768,13 +25993,13 @@ ${result}`;
|
|
|
25768
25993
|
annotations: WRITE_IDEMPOTENT,
|
|
25769
25994
|
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.",
|
|
25770
25995
|
inputSchema: {
|
|
25771
|
-
enabled:
|
|
25772
|
-
broadcast:
|
|
25773
|
-
multicast:
|
|
25774
|
-
manycast:
|
|
25775
|
-
broadcast_address:
|
|
25776
|
-
use_local_clock:
|
|
25777
|
-
local_clock_stratum:
|
|
25996
|
+
enabled: z111.boolean().optional().describe("Enable or disable the NTP server"),
|
|
25997
|
+
broadcast: z111.boolean().optional(),
|
|
25998
|
+
multicast: z111.boolean().optional(),
|
|
25999
|
+
manycast: z111.boolean().optional(),
|
|
26000
|
+
broadcast_address: z111.string().optional().describe("Broadcast address for NTP broadcasts"),
|
|
26001
|
+
use_local_clock: z111.boolean().optional().describe("Serve time from the device's local clock as reference"),
|
|
26002
|
+
local_clock_stratum: z111.number().int().optional().describe("Stratum advertised when using the local clock (1-15)")
|
|
25778
26003
|
},
|
|
25779
26004
|
async handler(a, ctx) {
|
|
25780
26005
|
ctx.info("Setting NTP server configuration");
|
|
@@ -25797,8 +26022,8 @@ ${details}`;
|
|
|
25797
26022
|
annotations: WRITE,
|
|
25798
26023
|
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).",
|
|
25799
26024
|
inputSchema: {
|
|
25800
|
-
old_password:
|
|
25801
|
-
new_password:
|
|
26025
|
+
old_password: z111.string().describe("The current password"),
|
|
26026
|
+
new_password: z111.string().describe("The new password to set")
|
|
25802
26027
|
},
|
|
25803
26028
|
async handler(a, ctx) {
|
|
25804
26029
|
ctx.info("Changing device password");
|
|
@@ -25815,7 +26040,7 @@ ${details}`;
|
|
|
25815
26040
|
annotations: READ,
|
|
25816
26041
|
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.",
|
|
25817
26042
|
inputSchema: {
|
|
25818
|
-
name_filter:
|
|
26043
|
+
name_filter: z111.string().optional().describe("Partial port name match")
|
|
25819
26044
|
},
|
|
25820
26045
|
async handler(a, ctx) {
|
|
25821
26046
|
ctx.info("Listing serial ports");
|
|
@@ -25834,7 +26059,7 @@ ${result}`;
|
|
|
25834
26059
|
annotations: READ,
|
|
25835
26060
|
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.",
|
|
25836
26061
|
inputSchema: {
|
|
25837
|
-
name:
|
|
26062
|
+
name: z111.string().describe("Serial port name, e.g. 'serial0'")
|
|
25838
26063
|
},
|
|
25839
26064
|
async handler(a, ctx) {
|
|
25840
26065
|
ctx.info(`Getting serial port details: name=${a.name}`);
|
|
@@ -25850,12 +26075,12 @@ ${result}`;
|
|
|
25850
26075
|
annotations: WRITE_IDEMPOTENT,
|
|
25851
26076
|
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.",
|
|
25852
26077
|
inputSchema: {
|
|
25853
|
-
name:
|
|
25854
|
-
baud_rate:
|
|
25855
|
-
data_bits:
|
|
25856
|
-
parity:
|
|
25857
|
-
stop_bits:
|
|
25858
|
-
flow_control:
|
|
26078
|
+
name: z111.string().describe("Serial port name to update"),
|
|
26079
|
+
baud_rate: z111.string().optional().describe("e.g. '115200' or 'auto'"),
|
|
26080
|
+
data_bits: z111.number().int().optional(),
|
|
26081
|
+
parity: z111.enum(["none", "odd", "even"]).optional(),
|
|
26082
|
+
stop_bits: z111.number().int().optional(),
|
|
26083
|
+
flow_control: z111.enum(["none", "hardware", "xon-xoff"]).optional()
|
|
25859
26084
|
},
|
|
25860
26085
|
async handler(a, ctx) {
|
|
25861
26086
|
ctx.info(`Setting serial port: name=${a.name}`);
|
|
@@ -25894,12 +26119,12 @@ ${result}`;
|
|
|
25894
26119
|
annotations: DANGEROUS,
|
|
25895
26120
|
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.",
|
|
25896
26121
|
inputSchema: {
|
|
25897
|
-
confirm:
|
|
25898
|
-
keep_users:
|
|
25899
|
-
no_defaults:
|
|
25900
|
-
skip_backup:
|
|
25901
|
-
caps_mode:
|
|
25902
|
-
run_after_reset:
|
|
26122
|
+
confirm: z111.boolean().describe("Must be true to actually ERASE the configuration"),
|
|
26123
|
+
keep_users: z111.boolean().optional().describe("Keep existing user accounts after reset"),
|
|
26124
|
+
no_defaults: z111.boolean().optional().describe("Do not load the default configuration"),
|
|
26125
|
+
skip_backup: z111.boolean().optional().describe("Skip the automatic backup before reset"),
|
|
26126
|
+
caps_mode: z111.boolean().optional().describe("Reset into CAPsMAN-managed CAP mode instead of standalone"),
|
|
26127
|
+
run_after_reset: z111.string().optional().describe("Script file to run after reset")
|
|
25903
26128
|
},
|
|
25904
26129
|
async handler(a, ctx) {
|
|
25905
26130
|
if (!a.confirm)
|
|
@@ -25944,12 +26169,12 @@ ${result}`;
|
|
|
25944
26169
|
annotations: WRITE_IDEMPOTENT,
|
|
25945
26170
|
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.",
|
|
25946
26171
|
inputSchema: {
|
|
25947
|
-
watchdog_timer:
|
|
25948
|
-
watch_address:
|
|
25949
|
-
ping_timeout:
|
|
25950
|
-
no_ping_delay:
|
|
25951
|
-
automatic_supout:
|
|
25952
|
-
auto_send_supout:
|
|
26172
|
+
watchdog_timer: z111.boolean().optional().describe("Enable the hardware watchdog timer"),
|
|
26173
|
+
watch_address: z111.string().optional().describe("Address to ping; reboot if unreachable"),
|
|
26174
|
+
ping_timeout: z111.string().optional().describe("e.g. '1m'"),
|
|
26175
|
+
no_ping_delay: z111.string().optional().describe("e.g. '5m'"),
|
|
26176
|
+
automatic_supout: z111.boolean().optional().describe("Generate a supout.rif on software failure"),
|
|
26177
|
+
auto_send_supout: z111.boolean().optional().describe("Email the generated supout.rif")
|
|
25953
26178
|
},
|
|
25954
26179
|
async handler(a, ctx) {
|
|
25955
26180
|
ctx.info("Setting watchdog configuration");
|
|
@@ -25969,7 +26194,7 @@ ${details}`;
|
|
|
25969
26194
|
];
|
|
25970
26195
|
|
|
25971
26196
|
// src/tools/system.ts
|
|
25972
|
-
import { z as
|
|
26197
|
+
import { z as z112 } from "zod";
|
|
25973
26198
|
var systemTools = [
|
|
25974
26199
|
defineTool({
|
|
25975
26200
|
name: "get_system_identity",
|
|
@@ -25990,7 +26215,7 @@ ${result}`;
|
|
|
25990
26215
|
annotations: WRITE,
|
|
25991
26216
|
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.",
|
|
25992
26217
|
inputSchema: {
|
|
25993
|
-
name:
|
|
26218
|
+
name: z112.string().describe("New system identity / hostname")
|
|
25994
26219
|
},
|
|
25995
26220
|
async handler(a, ctx) {
|
|
25996
26221
|
ctx.info(`Setting system identity: name=${a.name}`);
|
|
@@ -26062,10 +26287,10 @@ ${result}`;
|
|
|
26062
26287
|
annotations: WRITE,
|
|
26063
26288
|
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.",
|
|
26064
26289
|
inputSchema: {
|
|
26065
|
-
time_zone_name:
|
|
26066
|
-
date:
|
|
26067
|
-
time:
|
|
26068
|
-
time_zone_autodetect:
|
|
26290
|
+
time_zone_name: z112.string().optional().describe("e.g. 'Europe/Amsterdam' or 'manual'"),
|
|
26291
|
+
date: z112.string().optional().describe("e.g. 'jun/19/2026'"),
|
|
26292
|
+
time: z112.string().optional().describe("e.g. '13:45:00'"),
|
|
26293
|
+
time_zone_autodetect: z112.boolean().optional().describe("Auto-detect the time zone from the public IP")
|
|
26069
26294
|
},
|
|
26070
26295
|
async handler(a, ctx) {
|
|
26071
26296
|
ctx.info("Setting system clock");
|
|
@@ -26100,10 +26325,10 @@ ${result}`;
|
|
|
26100
26325
|
annotations: WRITE,
|
|
26101
26326
|
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.",
|
|
26102
26327
|
inputSchema: {
|
|
26103
|
-
enabled:
|
|
26104
|
-
servers:
|
|
26105
|
-
mode:
|
|
26106
|
-
vrf:
|
|
26328
|
+
enabled: z112.boolean().optional().describe("Enable or disable the NTP client"),
|
|
26329
|
+
servers: z112.string().optional().describe("Comma-separated NTP server list"),
|
|
26330
|
+
mode: z112.enum(["unicast", "broadcast", "multicast", "manycast"]).optional().describe("NTP client operating mode"),
|
|
26331
|
+
vrf: z112.string().optional().describe("VRF the NTP client operates in (e.g. 'main')")
|
|
26107
26332
|
},
|
|
26108
26333
|
async handler(a, ctx) {
|
|
26109
26334
|
ctx.info("Setting NTP client configuration");
|
|
@@ -26162,7 +26387,7 @@ ${result}`;
|
|
|
26162
26387
|
annotations: DANGEROUS,
|
|
26163
26388
|
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`.",
|
|
26164
26389
|
inputSchema: {
|
|
26165
|
-
confirm:
|
|
26390
|
+
confirm: z112.boolean().describe("Must be true to actually reboot the device")
|
|
26166
26391
|
},
|
|
26167
26392
|
async handler(a, ctx) {
|
|
26168
26393
|
if (!a.confirm)
|
|
@@ -26178,7 +26403,7 @@ ${result}`;
|
|
|
26178
26403
|
annotations: DANGEROUS,
|
|
26179
26404
|
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`.",
|
|
26180
26405
|
inputSchema: {
|
|
26181
|
-
confirm:
|
|
26406
|
+
confirm: z112.boolean().describe("Must be true to actually shut down the device")
|
|
26182
26407
|
},
|
|
26183
26408
|
async handler(a, ctx) {
|
|
26184
26409
|
if (!a.confirm)
|
|
@@ -26191,10 +26416,10 @@ ${result}`;
|
|
|
26191
26416
|
];
|
|
26192
26417
|
|
|
26193
26418
|
// src/tools/tunnels.ts
|
|
26194
|
-
import { z as
|
|
26195
|
-
var DontFragment =
|
|
26196
|
-
var Arp =
|
|
26197
|
-
var VtepsIpVersion =
|
|
26419
|
+
import { z as z113 } from "zod";
|
|
26420
|
+
var DontFragment = z113.enum(["inherit", "no"]);
|
|
26421
|
+
var Arp = z113.enum(["disabled", "enabled", "local-proxy-arp", "proxy-arp", "reply-only"]);
|
|
26422
|
+
var VtepsIpVersion = z113.enum(["ipv4", "ipv6"]);
|
|
26198
26423
|
var tunnelTools = [
|
|
26199
26424
|
defineTool({
|
|
26200
26425
|
name: "create_gre_tunnel",
|
|
@@ -26202,18 +26427,18 @@ var tunnelTools = [
|
|
|
26202
26427
|
annotations: WRITE,
|
|
26203
26428
|
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.",
|
|
26204
26429
|
inputSchema: {
|
|
26205
|
-
name:
|
|
26206
|
-
remote_address:
|
|
26207
|
-
local_address:
|
|
26208
|
-
keepalive:
|
|
26430
|
+
name: z113.string().describe("Name for the new GRE tunnel interface, e.g. 'gre-to-hq'"),
|
|
26431
|
+
remote_address: z113.string().describe("Remote endpoint IP address"),
|
|
26432
|
+
local_address: z113.string().optional().describe("Local endpoint IP address"),
|
|
26433
|
+
keepalive: z113.string().optional().describe("Keepalive interval/retries, e.g. '10s,3'"),
|
|
26209
26434
|
dont_fragment: DontFragment.optional().describe("Don't-fragment behavior"),
|
|
26210
|
-
clamp_tcp_mss:
|
|
26211
|
-
allow_fast_path:
|
|
26212
|
-
ipsec_secret:
|
|
26213
|
-
dscp:
|
|
26214
|
-
mtu:
|
|
26215
|
-
comment:
|
|
26216
|
-
disabled:
|
|
26435
|
+
clamp_tcp_mss: z113.boolean().optional().describe("Clamp TCP MSS to the tunnel MTU"),
|
|
26436
|
+
allow_fast_path: z113.boolean().optional().describe("Allow FastPath processing for this tunnel"),
|
|
26437
|
+
ipsec_secret: z113.string().optional().describe("Pre-shared key to auto-create an IPsec policy securing the tunnel"),
|
|
26438
|
+
dscp: z113.string().optional().describe("DSCP for encapsulated packets: 'inherit' or 0-63"),
|
|
26439
|
+
mtu: z113.number().int().optional(),
|
|
26440
|
+
comment: z113.string().optional(),
|
|
26441
|
+
disabled: z113.boolean().default(false)
|
|
26217
26442
|
},
|
|
26218
26443
|
async handler(a, ctx) {
|
|
26219
26444
|
ctx.info(`Creating GRE tunnel: name=${a.name}, remote_address=${a.remote_address}`);
|
|
@@ -26233,7 +26458,7 @@ ${details}` : "GRE tunnel creation completed but unable to verify.";
|
|
|
26233
26458
|
annotations: READ,
|
|
26234
26459
|
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.",
|
|
26235
26460
|
inputSchema: {
|
|
26236
|
-
name_filter:
|
|
26461
|
+
name_filter: z113.string().optional().describe("Partial name match")
|
|
26237
26462
|
},
|
|
26238
26463
|
async handler(a, ctx) {
|
|
26239
26464
|
ctx.info("Listing GRE tunnels");
|
|
@@ -26251,7 +26476,7 @@ ${result}`;
|
|
|
26251
26476
|
title: "Get GRE Tunnel Interface Detail",
|
|
26252
26477
|
annotations: READ,
|
|
26253
26478
|
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.",
|
|
26254
|
-
inputSchema: { name:
|
|
26479
|
+
inputSchema: { name: z113.string() },
|
|
26255
26480
|
async handler(a, ctx) {
|
|
26256
26481
|
ctx.info(`Getting GRE tunnel details: name=${a.name}`);
|
|
26257
26482
|
const result = await executeMikrotikCommand(`/interface gre print detail where name="${a.name}"`, ctx);
|
|
@@ -26265,7 +26490,7 @@ ${result}`;
|
|
|
26265
26490
|
title: "Remove GRE Tunnel Interface",
|
|
26266
26491
|
annotations: DESTRUCTIVE,
|
|
26267
26492
|
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.",
|
|
26268
|
-
inputSchema: { name:
|
|
26493
|
+
inputSchema: { name: z113.string() },
|
|
26269
26494
|
async handler(a, ctx) {
|
|
26270
26495
|
ctx.info(`Removing GRE tunnel: name=${a.name}`);
|
|
26271
26496
|
const count = await executeMikrotikCommand(`/interface gre print count-only where name="${a.name}"`, ctx);
|
|
@@ -26283,18 +26508,18 @@ ${result}`;
|
|
|
26283
26508
|
annotations: WRITE,
|
|
26284
26509
|
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.",
|
|
26285
26510
|
inputSchema: {
|
|
26286
|
-
name:
|
|
26287
|
-
remote_address:
|
|
26288
|
-
local_address:
|
|
26289
|
-
keepalive:
|
|
26511
|
+
name: z113.string().describe("Name for the new IPIP tunnel interface, e.g. 'ipip-to-hq'"),
|
|
26512
|
+
remote_address: z113.string().describe("Remote endpoint IP address"),
|
|
26513
|
+
local_address: z113.string().optional().describe("Local endpoint IP address"),
|
|
26514
|
+
keepalive: z113.string().optional().describe("Keepalive interval/retries, e.g. '10s,3'"),
|
|
26290
26515
|
dont_fragment: DontFragment.optional().describe("Don't-fragment behavior"),
|
|
26291
|
-
clamp_tcp_mss:
|
|
26292
|
-
allow_fast_path:
|
|
26293
|
-
ipsec_secret:
|
|
26294
|
-
dscp:
|
|
26295
|
-
mtu:
|
|
26296
|
-
comment:
|
|
26297
|
-
disabled:
|
|
26516
|
+
clamp_tcp_mss: z113.boolean().optional().describe("Clamp TCP MSS to the tunnel MTU"),
|
|
26517
|
+
allow_fast_path: z113.boolean().optional().describe("Allow FastPath processing for this tunnel"),
|
|
26518
|
+
ipsec_secret: z113.string().optional().describe("Pre-shared key to auto-create an IPsec policy securing the tunnel"),
|
|
26519
|
+
dscp: z113.string().optional().describe("DSCP for encapsulated packets: 'inherit' or 0-63"),
|
|
26520
|
+
mtu: z113.number().int().optional(),
|
|
26521
|
+
comment: z113.string().optional(),
|
|
26522
|
+
disabled: z113.boolean().default(false)
|
|
26298
26523
|
},
|
|
26299
26524
|
async handler(a, ctx) {
|
|
26300
26525
|
ctx.info(`Creating IPIP tunnel: name=${a.name}, remote_address=${a.remote_address}`);
|
|
@@ -26314,7 +26539,7 @@ ${details}` : "IPIP tunnel creation completed but unable to verify.";
|
|
|
26314
26539
|
annotations: READ,
|
|
26315
26540
|
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.",
|
|
26316
26541
|
inputSchema: {
|
|
26317
|
-
name_filter:
|
|
26542
|
+
name_filter: z113.string().optional().describe("Partial name match")
|
|
26318
26543
|
},
|
|
26319
26544
|
async handler(a, ctx) {
|
|
26320
26545
|
ctx.info("Listing IPIP tunnels");
|
|
@@ -26332,7 +26557,7 @@ ${result}`;
|
|
|
26332
26557
|
title: "Get IPIP Tunnel Interface Detail",
|
|
26333
26558
|
annotations: READ,
|
|
26334
26559
|
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.",
|
|
26335
|
-
inputSchema: { name:
|
|
26560
|
+
inputSchema: { name: z113.string() },
|
|
26336
26561
|
async handler(a, ctx) {
|
|
26337
26562
|
ctx.info(`Getting IPIP tunnel details: name=${a.name}`);
|
|
26338
26563
|
const result = await executeMikrotikCommand(`/interface ipip print detail where name="${a.name}"`, ctx);
|
|
@@ -26346,7 +26571,7 @@ ${result}`;
|
|
|
26346
26571
|
title: "Remove IPIP Tunnel Interface",
|
|
26347
26572
|
annotations: DESTRUCTIVE,
|
|
26348
26573
|
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.",
|
|
26349
|
-
inputSchema: { name:
|
|
26574
|
+
inputSchema: { name: z113.string() },
|
|
26350
26575
|
async handler(a, ctx) {
|
|
26351
26576
|
ctx.info(`Removing IPIP tunnel: name=${a.name}`);
|
|
26352
26577
|
const count = await executeMikrotikCommand(`/interface ipip print count-only where name="${a.name}"`, ctx);
|
|
@@ -26364,22 +26589,22 @@ ${result}`;
|
|
|
26364
26589
|
annotations: WRITE,
|
|
26365
26590
|
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.",
|
|
26366
26591
|
inputSchema: {
|
|
26367
|
-
name:
|
|
26368
|
-
remote_address:
|
|
26369
|
-
tunnel_id:
|
|
26370
|
-
local_address:
|
|
26371
|
-
keepalive:
|
|
26592
|
+
name: z113.string().describe("Name for the new EoIP tunnel interface, e.g. 'eoip-to-hq'"),
|
|
26593
|
+
remote_address: z113.string().describe("Remote endpoint IP address"),
|
|
26594
|
+
tunnel_id: z113.number().int().describe("Unique tunnel ID, must match on both peers"),
|
|
26595
|
+
local_address: z113.string().optional().describe("Local endpoint IP address"),
|
|
26596
|
+
keepalive: z113.string().optional().describe("Keepalive interval/retries, e.g. '10s,3'"),
|
|
26372
26597
|
dont_fragment: DontFragment.optional().describe("Don't-fragment behavior"),
|
|
26373
|
-
clamp_tcp_mss:
|
|
26374
|
-
allow_fast_path:
|
|
26375
|
-
ipsec_secret:
|
|
26376
|
-
dscp:
|
|
26377
|
-
mac_address:
|
|
26598
|
+
clamp_tcp_mss: z113.boolean().optional().describe("Clamp TCP MSS to the tunnel MTU"),
|
|
26599
|
+
allow_fast_path: z113.boolean().optional().describe("Allow FastPath processing for this tunnel"),
|
|
26600
|
+
ipsec_secret: z113.string().optional().describe("Pre-shared key to auto-create an IPsec policy securing the tunnel"),
|
|
26601
|
+
dscp: z113.string().optional().describe("DSCP for encapsulated packets: 'inherit' or 0-63"),
|
|
26602
|
+
mac_address: z113.string().optional().describe("MAC address of the EoIP interface"),
|
|
26378
26603
|
arp: Arp.optional().describe("Address Resolution Protocol mode for the interface"),
|
|
26379
|
-
arp_timeout:
|
|
26380
|
-
mtu:
|
|
26381
|
-
comment:
|
|
26382
|
-
disabled:
|
|
26604
|
+
arp_timeout: z113.string().optional().describe("ARP entry timeout, e.g. '30s' or 'auto'"),
|
|
26605
|
+
mtu: z113.number().int().optional(),
|
|
26606
|
+
comment: z113.string().optional(),
|
|
26607
|
+
disabled: z113.boolean().default(false)
|
|
26383
26608
|
},
|
|
26384
26609
|
async handler(a, ctx) {
|
|
26385
26610
|
ctx.info(`Creating EoIP tunnel: name=${a.name}, remote_address=${a.remote_address}, tunnel_id=${a.tunnel_id}`);
|
|
@@ -26399,7 +26624,7 @@ ${details}` : "EoIP tunnel creation completed but unable to verify.";
|
|
|
26399
26624
|
annotations: READ,
|
|
26400
26625
|
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.",
|
|
26401
26626
|
inputSchema: {
|
|
26402
|
-
name_filter:
|
|
26627
|
+
name_filter: z113.string().optional().describe("Partial name match")
|
|
26403
26628
|
},
|
|
26404
26629
|
async handler(a, ctx) {
|
|
26405
26630
|
ctx.info("Listing EoIP tunnels");
|
|
@@ -26417,7 +26642,7 @@ ${result}`;
|
|
|
26417
26642
|
title: "Get EoIP Tunnel Interface Detail",
|
|
26418
26643
|
annotations: READ,
|
|
26419
26644
|
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.",
|
|
26420
|
-
inputSchema: { name:
|
|
26645
|
+
inputSchema: { name: z113.string() },
|
|
26421
26646
|
async handler(a, ctx) {
|
|
26422
26647
|
ctx.info(`Getting EoIP tunnel details: name=${a.name}`);
|
|
26423
26648
|
const result = await executeMikrotikCommand(`/interface eoip print detail where name="${a.name}"`, ctx);
|
|
@@ -26431,7 +26656,7 @@ ${result}`;
|
|
|
26431
26656
|
title: "Remove EoIP Tunnel Interface",
|
|
26432
26657
|
annotations: DESTRUCTIVE,
|
|
26433
26658
|
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.",
|
|
26434
|
-
inputSchema: { name:
|
|
26659
|
+
inputSchema: { name: z113.string() },
|
|
26435
26660
|
async handler(a, ctx) {
|
|
26436
26661
|
ctx.info(`Removing EoIP tunnel: name=${a.name}`);
|
|
26437
26662
|
const count = await executeMikrotikCommand(`/interface eoip print count-only where name="${a.name}"`, ctx);
|
|
@@ -26449,21 +26674,21 @@ ${result}`;
|
|
|
26449
26674
|
annotations: WRITE,
|
|
26450
26675
|
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.",
|
|
26451
26676
|
inputSchema: {
|
|
26452
|
-
name:
|
|
26453
|
-
vni:
|
|
26454
|
-
port:
|
|
26455
|
-
local_address:
|
|
26456
|
-
interface:
|
|
26457
|
-
group:
|
|
26677
|
+
name: z113.string().describe("Name for the new VXLAN interface, e.g. 'vxlan1'"),
|
|
26678
|
+
vni: z113.number().int().describe("VXLAN Network Identifier (VNI)"),
|
|
26679
|
+
port: z113.number().int().default(8472).describe("UDP port (default 8472)"),
|
|
26680
|
+
local_address: z113.string().optional().describe("Local source IP address"),
|
|
26681
|
+
interface: z113.string().optional().describe("Source interface"),
|
|
26682
|
+
group: z113.string().optional().describe("Multicast group address for broadcast/unknown-unicast flooding"),
|
|
26458
26683
|
vteps_ip_version: VtepsIpVersion.optional().describe("IP version used for VTEP addressing"),
|
|
26459
|
-
mac_address:
|
|
26684
|
+
mac_address: z113.string().optional().describe("MAC address of the VXLAN interface"),
|
|
26460
26685
|
arp: Arp.optional().describe("Address Resolution Protocol mode for the interface"),
|
|
26461
|
-
arp_timeout:
|
|
26462
|
-
max_fdb_size:
|
|
26463
|
-
allow_fast_path:
|
|
26464
|
-
mtu:
|
|
26465
|
-
comment:
|
|
26466
|
-
disabled:
|
|
26686
|
+
arp_timeout: z113.string().optional().describe("ARP entry timeout, e.g. '30s' or 'auto'"),
|
|
26687
|
+
max_fdb_size: z113.number().int().optional().describe("Maximum forwarding database (FDB) size"),
|
|
26688
|
+
allow_fast_path: z113.boolean().optional().describe("Allow FastPath processing for this interface"),
|
|
26689
|
+
mtu: z113.number().int().optional(),
|
|
26690
|
+
comment: z113.string().optional(),
|
|
26691
|
+
disabled: z113.boolean().default(false)
|
|
26467
26692
|
},
|
|
26468
26693
|
async handler(a, ctx) {
|
|
26469
26694
|
ctx.info(`Creating VXLAN tunnel: name=${a.name}, vni=${a.vni}`);
|
|
@@ -26483,7 +26708,7 @@ ${details}` : "VXLAN tunnel creation completed but unable to verify.";
|
|
|
26483
26708
|
annotations: READ,
|
|
26484
26709
|
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.",
|
|
26485
26710
|
inputSchema: {
|
|
26486
|
-
name_filter:
|
|
26711
|
+
name_filter: z113.string().optional().describe("Partial name match")
|
|
26487
26712
|
},
|
|
26488
26713
|
async handler(a, ctx) {
|
|
26489
26714
|
ctx.info("Listing VXLAN tunnels");
|
|
@@ -26501,7 +26726,7 @@ ${result}`;
|
|
|
26501
26726
|
title: "Get VXLAN Tunnel Interface Detail",
|
|
26502
26727
|
annotations: READ,
|
|
26503
26728
|
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.",
|
|
26504
|
-
inputSchema: { name:
|
|
26729
|
+
inputSchema: { name: z113.string() },
|
|
26505
26730
|
async handler(a, ctx) {
|
|
26506
26731
|
ctx.info(`Getting VXLAN tunnel details: name=${a.name}`);
|
|
26507
26732
|
const result = await executeMikrotikCommand(`/interface vxlan print detail where name="${a.name}"`, ctx);
|
|
@@ -26515,7 +26740,7 @@ ${result}`;
|
|
|
26515
26740
|
title: "Remove VXLAN Tunnel Interface",
|
|
26516
26741
|
annotations: DESTRUCTIVE,
|
|
26517
26742
|
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.",
|
|
26518
|
-
inputSchema: { name:
|
|
26743
|
+
inputSchema: { name: z113.string() },
|
|
26519
26744
|
async handler(a, ctx) {
|
|
26520
26745
|
ctx.info(`Removing VXLAN tunnel: name=${a.name}`);
|
|
26521
26746
|
const count = await executeMikrotikCommand(`/interface vxlan print count-only where name="${a.name}"`, ctx);
|
|
@@ -26530,7 +26755,7 @@ ${result}`;
|
|
|
26530
26755
|
];
|
|
26531
26756
|
|
|
26532
26757
|
// src/tools/user-manager.ts
|
|
26533
|
-
import { z as
|
|
26758
|
+
import { z as z114 } from "zod";
|
|
26534
26759
|
var NOT_AVAILABLE3 = "User Manager is not available on this device (package not installed).";
|
|
26535
26760
|
var userManagerTools = [
|
|
26536
26761
|
defineTool({
|
|
@@ -26554,12 +26779,12 @@ ${result}`;
|
|
|
26554
26779
|
annotations: WRITE_IDEMPOTENT,
|
|
26555
26780
|
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.",
|
|
26556
26781
|
inputSchema: {
|
|
26557
|
-
enabled:
|
|
26558
|
-
certificate:
|
|
26559
|
-
radsec_certificate:
|
|
26560
|
-
accounting_port:
|
|
26561
|
-
authentication_port:
|
|
26562
|
-
use_profiles:
|
|
26782
|
+
enabled: z114.boolean().optional().describe("Enable or disable the User Manager server"),
|
|
26783
|
+
certificate: z114.string().optional().describe("TLS certificate name for RADIUS over TLS"),
|
|
26784
|
+
radsec_certificate: z114.string().optional().describe("Certificate name for RadSec (RADIUS over TLS)"),
|
|
26785
|
+
accounting_port: z114.number().int().optional().describe("UDP port for RADIUS accounting"),
|
|
26786
|
+
authentication_port: z114.number().int().optional().describe("UDP port for RADIUS authentication"),
|
|
26787
|
+
use_profiles: z114.boolean().optional().describe("Enable the profile/payment subsystem")
|
|
26563
26788
|
},
|
|
26564
26789
|
async handler(a, ctx) {
|
|
26565
26790
|
ctx.info("Updating User Manager settings");
|
|
@@ -26583,15 +26808,15 @@ ${details}`;
|
|
|
26583
26808
|
annotations: WRITE,
|
|
26584
26809
|
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.",
|
|
26585
26810
|
inputSchema: {
|
|
26586
|
-
name:
|
|
26587
|
-
password:
|
|
26588
|
-
group:
|
|
26589
|
-
shared_users:
|
|
26590
|
-
attributes:
|
|
26591
|
-
caller_id:
|
|
26592
|
-
otp_secret:
|
|
26593
|
-
comment:
|
|
26594
|
-
disabled:
|
|
26811
|
+
name: z114.string().describe("Login name for the user"),
|
|
26812
|
+
password: z114.string().describe("Login password for the user"),
|
|
26813
|
+
group: z114.string().optional(),
|
|
26814
|
+
shared_users: z114.number().int().optional().describe("Max simultaneous sessions"),
|
|
26815
|
+
attributes: z114.string().optional().describe("Custom RADIUS attributes"),
|
|
26816
|
+
caller_id: z114.string().optional().describe("Caller ID the user is restricted to (e.g. MAC)"),
|
|
26817
|
+
otp_secret: z114.string().optional().describe("Base32 OTP shared secret for two-factor auth"),
|
|
26818
|
+
comment: z114.string().optional(),
|
|
26819
|
+
disabled: z114.boolean().default(false)
|
|
26595
26820
|
},
|
|
26596
26821
|
async handler(a, ctx) {
|
|
26597
26822
|
ctx.info(`Adding User Manager user: name=${a.name}`);
|
|
@@ -26613,7 +26838,7 @@ ${redactSecrets(details)}` : "User Manager user creation completed but unable to
|
|
|
26613
26838
|
annotations: READ,
|
|
26614
26839
|
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.",
|
|
26615
26840
|
inputSchema: {
|
|
26616
|
-
name_filter:
|
|
26841
|
+
name_filter: z114.string().optional().describe("Partial name match")
|
|
26617
26842
|
},
|
|
26618
26843
|
async handler(a, ctx) {
|
|
26619
26844
|
ctx.info("Listing User Manager users");
|
|
@@ -26633,7 +26858,7 @@ ${redactSecrets(result)}`;
|
|
|
26633
26858
|
title: "Get User Manager RADIUS User Detail",
|
|
26634
26859
|
annotations: READ,
|
|
26635
26860
|
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.",
|
|
26636
|
-
inputSchema: { name:
|
|
26861
|
+
inputSchema: { name: z114.string() },
|
|
26637
26862
|
async handler(a, ctx) {
|
|
26638
26863
|
ctx.info(`Getting User Manager user details: name=${a.name}`);
|
|
26639
26864
|
const result = await executeMikrotikCommand(`/user-manager user print detail where name="${a.name}"`, ctx);
|
|
@@ -26650,16 +26875,16 @@ ${redactSecrets(result)}`;
|
|
|
26650
26875
|
annotations: WRITE_IDEMPOTENT,
|
|
26651
26876
|
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.",
|
|
26652
26877
|
inputSchema: {
|
|
26653
|
-
name:
|
|
26654
|
-
new_name:
|
|
26655
|
-
password:
|
|
26656
|
-
group:
|
|
26657
|
-
shared_users:
|
|
26658
|
-
attributes:
|
|
26659
|
-
caller_id:
|
|
26660
|
-
otp_secret:
|
|
26661
|
-
comment:
|
|
26662
|
-
disabled:
|
|
26878
|
+
name: z114.string().describe("Current name of the user to update"),
|
|
26879
|
+
new_name: z114.string().optional(),
|
|
26880
|
+
password: z114.string().optional(),
|
|
26881
|
+
group: z114.string().optional(),
|
|
26882
|
+
shared_users: z114.number().int().optional(),
|
|
26883
|
+
attributes: z114.string().optional(),
|
|
26884
|
+
caller_id: z114.string().optional().describe("Caller ID the user is restricted to (e.g. MAC)"),
|
|
26885
|
+
otp_secret: z114.string().optional().describe("Base32 OTP shared secret for two-factor auth"),
|
|
26886
|
+
comment: z114.string().optional(),
|
|
26887
|
+
disabled: z114.boolean().optional()
|
|
26663
26888
|
},
|
|
26664
26889
|
async handler(a, ctx) {
|
|
26665
26890
|
ctx.info(`Updating User Manager user: name=${a.name}`);
|
|
@@ -26683,7 +26908,7 @@ ${redactSecrets(details)}`;
|
|
|
26683
26908
|
title: "Remove User Manager RADIUS User",
|
|
26684
26909
|
annotations: DESTRUCTIVE,
|
|
26685
26910
|
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`.",
|
|
26686
|
-
inputSchema: { name:
|
|
26911
|
+
inputSchema: { name: z114.string() },
|
|
26687
26912
|
async handler(a, ctx) {
|
|
26688
26913
|
ctx.info(`Removing User Manager user: name=${a.name}`);
|
|
26689
26914
|
const count = await executeMikrotikCommand(`/user-manager user print count-only where name="${a.name}"`, ctx);
|
|
@@ -26703,13 +26928,13 @@ ${redactSecrets(details)}`;
|
|
|
26703
26928
|
annotations: WRITE,
|
|
26704
26929
|
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.",
|
|
26705
26930
|
inputSchema: {
|
|
26706
|
-
name:
|
|
26707
|
-
name_for_users:
|
|
26708
|
-
validity:
|
|
26709
|
-
price:
|
|
26710
|
-
starts_when:
|
|
26711
|
-
override_shared_users:
|
|
26712
|
-
comment:
|
|
26931
|
+
name: z114.string().describe("Profile name"),
|
|
26932
|
+
name_for_users: z114.string().optional().describe("Display name shown to users"),
|
|
26933
|
+
validity: z114.string().optional().describe("Validity period, e.g. '30d'"),
|
|
26934
|
+
price: z114.number().optional(),
|
|
26935
|
+
starts_when: z114.enum(["assigned", "first-auth"]).optional(),
|
|
26936
|
+
override_shared_users: z114.string().optional(),
|
|
26937
|
+
comment: z114.string().optional()
|
|
26713
26938
|
},
|
|
26714
26939
|
async handler(a, ctx) {
|
|
26715
26940
|
ctx.info(`Adding User Manager profile: name=${a.name}`);
|
|
@@ -26731,7 +26956,7 @@ ${details}` : "User Manager profile creation completed but unable to verify.";
|
|
|
26731
26956
|
annotations: READ,
|
|
26732
26957
|
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.",
|
|
26733
26958
|
inputSchema: {
|
|
26734
|
-
name_filter:
|
|
26959
|
+
name_filter: z114.string().optional().describe("Partial name match")
|
|
26735
26960
|
},
|
|
26736
26961
|
async handler(a, ctx) {
|
|
26737
26962
|
ctx.info("Listing User Manager profiles");
|
|
@@ -26751,7 +26976,7 @@ ${result}`;
|
|
|
26751
26976
|
title: "Remove User Manager Service Profile",
|
|
26752
26977
|
annotations: DESTRUCTIVE,
|
|
26753
26978
|
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.",
|
|
26754
|
-
inputSchema: { name:
|
|
26979
|
+
inputSchema: { name: z114.string() },
|
|
26755
26980
|
async handler(a, ctx) {
|
|
26756
26981
|
ctx.info(`Removing User Manager profile: name=${a.name}`);
|
|
26757
26982
|
const count = await executeMikrotikCommand(`/user-manager profile print count-only where name="${a.name}"`, ctx);
|
|
@@ -26771,8 +26996,8 @@ ${result}`;
|
|
|
26771
26996
|
annotations: WRITE,
|
|
26772
26997
|
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.",
|
|
26773
26998
|
inputSchema: {
|
|
26774
|
-
user:
|
|
26775
|
-
profile:
|
|
26999
|
+
user: z114.string().describe("User to assign the profile to"),
|
|
27000
|
+
profile: z114.string().describe("Profile to assign")
|
|
26776
27001
|
},
|
|
26777
27002
|
async handler(a, ctx) {
|
|
26778
27003
|
ctx.info(`Assigning profile '${a.profile}' to user '${a.user}'`);
|
|
@@ -26793,7 +27018,7 @@ ${result}`;
|
|
|
26793
27018
|
annotations: READ,
|
|
26794
27019
|
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.",
|
|
26795
27020
|
inputSchema: {
|
|
26796
|
-
user_filter:
|
|
27021
|
+
user_filter: z114.string().optional().describe("Partial user match")
|
|
26797
27022
|
},
|
|
26798
27023
|
async handler(a, ctx) {
|
|
26799
27024
|
ctx.info("Listing User Manager user-profiles");
|
|
@@ -26814,13 +27039,13 @@ ${result}`;
|
|
|
26814
27039
|
annotations: WRITE,
|
|
26815
27040
|
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.",
|
|
26816
27041
|
inputSchema: {
|
|
26817
|
-
name:
|
|
26818
|
-
address:
|
|
26819
|
-
shared_secret:
|
|
26820
|
-
coa_port:
|
|
26821
|
-
protocol:
|
|
26822
|
-
comment:
|
|
26823
|
-
disabled:
|
|
27042
|
+
name: z114.string().describe("Friendly name for the RADIUS client"),
|
|
27043
|
+
address: z114.string().describe("IP address of the RADIUS client"),
|
|
27044
|
+
shared_secret: z114.string().describe("Shared secret for the RADIUS client"),
|
|
27045
|
+
coa_port: z114.number().int().optional().describe("Change-of-Authorization port"),
|
|
27046
|
+
protocol: z114.string().optional().describe("RADIUS transport protocol for this client (e.g. radius, radsec)"),
|
|
27047
|
+
comment: z114.string().optional(),
|
|
27048
|
+
disabled: z114.boolean().default(false)
|
|
26824
27049
|
},
|
|
26825
27050
|
async handler(a, ctx) {
|
|
26826
27051
|
ctx.info(`Adding User Manager router: name=${a.name}, address=${a.address}`);
|
|
@@ -26842,7 +27067,7 @@ ${redactSecrets(details)}` : "User Manager router creation completed but unable
|
|
|
26842
27067
|
annotations: READ,
|
|
26843
27068
|
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.",
|
|
26844
27069
|
inputSchema: {
|
|
26845
|
-
name_filter:
|
|
27070
|
+
name_filter: z114.string().optional().describe("Partial name match")
|
|
26846
27071
|
},
|
|
26847
27072
|
async handler(a, ctx) {
|
|
26848
27073
|
ctx.info("Listing User Manager routers");
|
|
@@ -26862,7 +27087,7 @@ ${redactSecrets(result)}`;
|
|
|
26862
27087
|
title: "Remove User Manager RADIUS Client (Router/NAS)",
|
|
26863
27088
|
annotations: DESTRUCTIVE,
|
|
26864
27089
|
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.",
|
|
26865
|
-
inputSchema: { name:
|
|
27090
|
+
inputSchema: { name: z114.string() },
|
|
26866
27091
|
async handler(a, ctx) {
|
|
26867
27092
|
ctx.info(`Removing User Manager router: name=${a.name}`);
|
|
26868
27093
|
const count = await executeMikrotikCommand(`/user-manager router print count-only where name="${a.name}"`, ctx);
|
|
@@ -26882,25 +27107,25 @@ ${redactSecrets(result)}`;
|
|
|
26882
27107
|
annotations: WRITE,
|
|
26883
27108
|
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.",
|
|
26884
27109
|
inputSchema: {
|
|
26885
|
-
name:
|
|
26886
|
-
rate_limit_rx:
|
|
26887
|
-
rate_limit_tx:
|
|
26888
|
-
rate_limit_min_rx:
|
|
26889
|
-
rate_limit_min_tx:
|
|
26890
|
-
rate_limit_burst_rx:
|
|
26891
|
-
rate_limit_burst_tx:
|
|
26892
|
-
rate_limit_burst_threshold_rx:
|
|
26893
|
-
rate_limit_burst_threshold_tx:
|
|
26894
|
-
rate_limit_burst_time_rx:
|
|
26895
|
-
rate_limit_burst_time_tx:
|
|
26896
|
-
rate_limit_priority:
|
|
26897
|
-
download_limit:
|
|
26898
|
-
upload_limit:
|
|
26899
|
-
transfer_limit:
|
|
26900
|
-
uptime_limit:
|
|
26901
|
-
reset_counters_interval:
|
|
26902
|
-
reset_counters_start_time:
|
|
26903
|
-
comment:
|
|
27110
|
+
name: z114.string().describe("Limitation name"),
|
|
27111
|
+
rate_limit_rx: z114.string().optional().describe("Download rate limit, e.g. '10M'"),
|
|
27112
|
+
rate_limit_tx: z114.string().optional().describe("Upload rate limit, e.g. '10M'"),
|
|
27113
|
+
rate_limit_min_rx: z114.string().optional().describe("Guaranteed (CIR) download rate, e.g. '2M'"),
|
|
27114
|
+
rate_limit_min_tx: z114.string().optional().describe("Guaranteed (CIR) upload rate, e.g. '2M'"),
|
|
27115
|
+
rate_limit_burst_rx: z114.string().optional().describe("Download burst rate, e.g. '20M'"),
|
|
27116
|
+
rate_limit_burst_tx: z114.string().optional().describe("Upload burst rate, e.g. '20M'"),
|
|
27117
|
+
rate_limit_burst_threshold_rx: z114.string().optional().describe("Download burst threshold rate"),
|
|
27118
|
+
rate_limit_burst_threshold_tx: z114.string().optional().describe("Upload burst threshold rate"),
|
|
27119
|
+
rate_limit_burst_time_rx: z114.string().optional().describe("Download burst time, e.g. '10s'"),
|
|
27120
|
+
rate_limit_burst_time_tx: z114.string().optional().describe("Upload burst time, e.g. '10s'"),
|
|
27121
|
+
rate_limit_priority: z114.number().int().optional().describe("Queue priority (1-8)"),
|
|
27122
|
+
download_limit: z114.string().optional().describe("Download transfer cap in bytes, e.g. '5G'"),
|
|
27123
|
+
upload_limit: z114.string().optional().describe("Upload transfer cap in bytes, e.g. '5G'"),
|
|
27124
|
+
transfer_limit: z114.string().optional().describe("Total transfer cap, e.g. '10G'"),
|
|
27125
|
+
uptime_limit: z114.string().optional().describe("Uptime cap, e.g. '1d'"),
|
|
27126
|
+
reset_counters_interval: z114.string().optional().describe("Interval to auto-reset usage counters"),
|
|
27127
|
+
reset_counters_start_time: z114.string().optional().describe("Start time for counter reset interval"),
|
|
27128
|
+
comment: z114.string().optional()
|
|
26904
27129
|
},
|
|
26905
27130
|
async handler(a, ctx) {
|
|
26906
27131
|
ctx.info(`Adding User Manager limitation: name=${a.name}`);
|
|
@@ -26922,7 +27147,7 @@ ${details}` : "User Manager limitation creation completed but unable to verify."
|
|
|
26922
27147
|
annotations: READ,
|
|
26923
27148
|
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.",
|
|
26924
27149
|
inputSchema: {
|
|
26925
|
-
name_filter:
|
|
27150
|
+
name_filter: z114.string().optional().describe("Partial name match")
|
|
26926
27151
|
},
|
|
26927
27152
|
async handler(a, ctx) {
|
|
26928
27153
|
ctx.info("Listing User Manager limitations");
|
|
@@ -26942,7 +27167,7 @@ ${result}`;
|
|
|
26942
27167
|
title: "Remove User Manager Limitation Template",
|
|
26943
27168
|
annotations: DESTRUCTIVE,
|
|
26944
27169
|
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.",
|
|
26945
|
-
inputSchema: { name:
|
|
27170
|
+
inputSchema: { name: z114.string() },
|
|
26946
27171
|
async handler(a, ctx) {
|
|
26947
27172
|
ctx.info(`Removing User Manager limitation: name=${a.name}`);
|
|
26948
27173
|
const count = await executeMikrotikCommand(`/user-manager limitation print count-only where name="${a.name}"`, ctx);
|
|
@@ -26962,8 +27187,8 @@ ${result}`;
|
|
|
26962
27187
|
annotations: READ,
|
|
26963
27188
|
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.",
|
|
26964
27189
|
inputSchema: {
|
|
26965
|
-
user_filter:
|
|
26966
|
-
active_only:
|
|
27190
|
+
user_filter: z114.string().optional().describe("Partial user match"),
|
|
27191
|
+
active_only: z114.boolean().default(false).describe("Only show currently active sessions")
|
|
26967
27192
|
},
|
|
26968
27193
|
async handler(a, ctx) {
|
|
26969
27194
|
ctx.info("Listing User Manager sessions");
|
|
@@ -26983,7 +27208,7 @@ ${result}`;
|
|
|
26983
27208
|
];
|
|
26984
27209
|
|
|
26985
27210
|
// src/tools/users.ts
|
|
26986
|
-
import { z as
|
|
27211
|
+
import { z as z115 } from "zod";
|
|
26987
27212
|
var VALID_POLICIES = [
|
|
26988
27213
|
"local",
|
|
26989
27214
|
"telnet",
|
|
@@ -27040,12 +27265,12 @@ var userTools = [
|
|
|
27040
27265
|
annotations: WRITE,
|
|
27041
27266
|
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`.",
|
|
27042
27267
|
inputSchema: {
|
|
27043
|
-
name:
|
|
27044
|
-
password:
|
|
27045
|
-
group:
|
|
27046
|
-
address:
|
|
27047
|
-
comment:
|
|
27048
|
-
disabled:
|
|
27268
|
+
name: z115.string(),
|
|
27269
|
+
password: z115.string(),
|
|
27270
|
+
group: z115.string().default("read"),
|
|
27271
|
+
address: z115.string().optional(),
|
|
27272
|
+
comment: z115.string().optional(),
|
|
27273
|
+
disabled: z115.boolean().default(false)
|
|
27049
27274
|
},
|
|
27050
27275
|
async handler(a, ctx) {
|
|
27051
27276
|
ctx.info(`Adding user: name=${a.name}, group=${a.group}`);
|
|
@@ -27077,10 +27302,10 @@ ${redactSecrets(details)}`;
|
|
|
27077
27302
|
annotations: READ,
|
|
27078
27303
|
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`.",
|
|
27079
27304
|
inputSchema: {
|
|
27080
|
-
name_filter:
|
|
27081
|
-
group_filter:
|
|
27082
|
-
disabled_only:
|
|
27083
|
-
active_only:
|
|
27305
|
+
name_filter: z115.string().optional(),
|
|
27306
|
+
group_filter: z115.string().optional(),
|
|
27307
|
+
disabled_only: z115.boolean().default(false),
|
|
27308
|
+
active_only: z115.boolean().default(false)
|
|
27084
27309
|
},
|
|
27085
27310
|
async handler(a, ctx) {
|
|
27086
27311
|
ctx.info(`Listing users with filters: name=${a.name_filter}, group=${a.group_filter}`);
|
|
@@ -27104,7 +27329,7 @@ ${redactSecrets(result)}`;
|
|
|
27104
27329
|
title: "Get Local User Account Details",
|
|
27105
27330
|
annotations: READ,
|
|
27106
27331
|
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`.",
|
|
27107
|
-
inputSchema: { name:
|
|
27332
|
+
inputSchema: { name: z115.string() },
|
|
27108
27333
|
async handler(a, ctx) {
|
|
27109
27334
|
ctx.info(`Getting user details: name=${a.name}`);
|
|
27110
27335
|
const result = await executeMikrotikCommand(`/user print detail where name="${a.name}"`, ctx);
|
|
@@ -27121,13 +27346,13 @@ ${redactSecrets(result)}`;
|
|
|
27121
27346
|
annotations: WRITE_IDEMPOTENT,
|
|
27122
27347
|
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.",
|
|
27123
27348
|
inputSchema: {
|
|
27124
|
-
name:
|
|
27125
|
-
new_name:
|
|
27126
|
-
password:
|
|
27127
|
-
group:
|
|
27128
|
-
address:
|
|
27129
|
-
comment:
|
|
27130
|
-
disabled:
|
|
27349
|
+
name: z115.string(),
|
|
27350
|
+
new_name: z115.string().optional(),
|
|
27351
|
+
password: z115.string().optional(),
|
|
27352
|
+
group: z115.string().optional(),
|
|
27353
|
+
address: z115.string().optional(),
|
|
27354
|
+
comment: z115.string().optional(),
|
|
27355
|
+
disabled: z115.boolean().optional()
|
|
27131
27356
|
},
|
|
27132
27357
|
async handler(a, ctx) {
|
|
27133
27358
|
return runUpdateUser(a, ctx);
|
|
@@ -27138,7 +27363,7 @@ ${redactSecrets(result)}`;
|
|
|
27138
27363
|
title: "Remove Local User Account",
|
|
27139
27364
|
annotations: DESTRUCTIVE,
|
|
27140
27365
|
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`.",
|
|
27141
|
-
inputSchema: { name:
|
|
27366
|
+
inputSchema: { name: z115.string() },
|
|
27142
27367
|
async handler(a, ctx) {
|
|
27143
27368
|
ctx.info(`Removing user: name=${a.name}`);
|
|
27144
27369
|
if (a.name.toLowerCase() === "admin")
|
|
@@ -27157,7 +27382,7 @@ ${redactSecrets(result)}`;
|
|
|
27157
27382
|
title: "Disable Local User Account",
|
|
27158
27383
|
annotations: WRITE_IDEMPOTENT,
|
|
27159
27384
|
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`.",
|
|
27160
|
-
inputSchema: { name:
|
|
27385
|
+
inputSchema: { name: z115.string() },
|
|
27161
27386
|
async handler(a, ctx) {
|
|
27162
27387
|
return runUpdateUser({ name: a.name, disabled: true }, ctx);
|
|
27163
27388
|
}
|
|
@@ -27167,7 +27392,7 @@ ${redactSecrets(result)}`;
|
|
|
27167
27392
|
title: "Enable Local User Account",
|
|
27168
27393
|
annotations: WRITE_IDEMPOTENT,
|
|
27169
27394
|
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`.",
|
|
27170
|
-
inputSchema: { name:
|
|
27395
|
+
inputSchema: { name: z115.string() },
|
|
27171
27396
|
async handler(a, ctx) {
|
|
27172
27397
|
return runUpdateUser({ name: a.name, disabled: false }, ctx);
|
|
27173
27398
|
}
|
|
@@ -27178,10 +27403,10 @@ ${redactSecrets(result)}`;
|
|
|
27178
27403
|
annotations: WRITE,
|
|
27179
27404
|
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.",
|
|
27180
27405
|
inputSchema: {
|
|
27181
|
-
name:
|
|
27182
|
-
policy:
|
|
27183
|
-
skin:
|
|
27184
|
-
comment:
|
|
27406
|
+
name: z115.string(),
|
|
27407
|
+
policy: z115.array(z115.string()),
|
|
27408
|
+
skin: z115.string().optional(),
|
|
27409
|
+
comment: z115.string().optional()
|
|
27185
27410
|
},
|
|
27186
27411
|
async handler(a, ctx) {
|
|
27187
27412
|
ctx.info(`Adding user group: name=${a.name}`);
|
|
@@ -27218,8 +27443,8 @@ ${details}`;
|
|
|
27218
27443
|
annotations: READ,
|
|
27219
27444
|
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`.",
|
|
27220
27445
|
inputSchema: {
|
|
27221
|
-
name_filter:
|
|
27222
|
-
policy_filter:
|
|
27446
|
+
name_filter: z115.string().optional(),
|
|
27447
|
+
policy_filter: z115.string().optional()
|
|
27223
27448
|
},
|
|
27224
27449
|
async handler(a, ctx) {
|
|
27225
27450
|
ctx.info(`Listing user groups with filters: name=${a.name_filter}`);
|
|
@@ -27241,7 +27466,7 @@ ${result}`;
|
|
|
27241
27466
|
title: "Get User Group Details",
|
|
27242
27467
|
annotations: READ,
|
|
27243
27468
|
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`.",
|
|
27244
|
-
inputSchema: { name:
|
|
27469
|
+
inputSchema: { name: z115.string() },
|
|
27245
27470
|
async handler(a, ctx) {
|
|
27246
27471
|
ctx.info(`Getting user group details: name=${a.name}`);
|
|
27247
27472
|
const result = await executeMikrotikCommand(`/user group print detail where name="${a.name}"`, ctx);
|
|
@@ -27258,11 +27483,11 @@ ${result}`;
|
|
|
27258
27483
|
annotations: WRITE_IDEMPOTENT,
|
|
27259
27484
|
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.",
|
|
27260
27485
|
inputSchema: {
|
|
27261
|
-
name:
|
|
27262
|
-
new_name:
|
|
27263
|
-
policy:
|
|
27264
|
-
skin:
|
|
27265
|
-
comment:
|
|
27486
|
+
name: z115.string(),
|
|
27487
|
+
new_name: z115.string().optional(),
|
|
27488
|
+
policy: z115.array(z115.string()).optional(),
|
|
27489
|
+
skin: z115.string().optional(),
|
|
27490
|
+
comment: z115.string().optional()
|
|
27266
27491
|
},
|
|
27267
27492
|
async handler(a, ctx) {
|
|
27268
27493
|
ctx.info(`Updating user group: name=${a.name}`);
|
|
@@ -27295,7 +27520,7 @@ ${details}`;
|
|
|
27295
27520
|
title: "Remove User Group",
|
|
27296
27521
|
annotations: DESTRUCTIVE,
|
|
27297
27522
|
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`.",
|
|
27298
|
-
inputSchema: { name:
|
|
27523
|
+
inputSchema: { name: z115.string() },
|
|
27299
27524
|
async handler(a, ctx) {
|
|
27300
27525
|
ctx.info(`Removing user group: name=${a.name}`);
|
|
27301
27526
|
if (BUILTIN_GROUPS.includes(a.name))
|
|
@@ -27333,7 +27558,7 @@ ${result}`;
|
|
|
27333
27558
|
title: "Disconnect Active User Session",
|
|
27334
27559
|
annotations: DESTRUCTIVE,
|
|
27335
27560
|
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`.",
|
|
27336
|
-
inputSchema: { user_id:
|
|
27561
|
+
inputSchema: { user_id: z115.string() },
|
|
27337
27562
|
async handler(a, ctx) {
|
|
27338
27563
|
ctx.info(`Disconnecting user: user_id=${a.user_id}`);
|
|
27339
27564
|
const result = await executeMikrotikCommand(`/user active remove ${a.user_id}`, ctx);
|
|
@@ -27347,7 +27572,7 @@ ${result}`;
|
|
|
27347
27572
|
title: "Export User Configuration to File",
|
|
27348
27573
|
annotations: READ,
|
|
27349
27574
|
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.",
|
|
27350
|
-
inputSchema: { filename:
|
|
27575
|
+
inputSchema: { filename: z115.string().optional() },
|
|
27351
27576
|
async handler(a, ctx) {
|
|
27352
27577
|
ctx.info("Exporting user configuration");
|
|
27353
27578
|
const filename = a.filename || "user_config";
|
|
@@ -27363,8 +27588,8 @@ ${result}`;
|
|
|
27363
27588
|
annotations: WRITE,
|
|
27364
27589
|
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`.",
|
|
27365
27590
|
inputSchema: {
|
|
27366
|
-
username:
|
|
27367
|
-
key_file:
|
|
27591
|
+
username: z115.string(),
|
|
27592
|
+
key_file: z115.string()
|
|
27368
27593
|
},
|
|
27369
27594
|
async handler(a, ctx) {
|
|
27370
27595
|
ctx.info(`Setting SSH keys for user: ${a.username}`);
|
|
@@ -27381,7 +27606,7 @@ ${result}`;
|
|
|
27381
27606
|
title: "List User SSH Keys",
|
|
27382
27607
|
annotations: READ,
|
|
27383
27608
|
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`.",
|
|
27384
|
-
inputSchema: { username:
|
|
27609
|
+
inputSchema: { username: z115.string() },
|
|
27385
27610
|
async handler(a, ctx) {
|
|
27386
27611
|
ctx.info(`Listing SSH keys for user: ${a.username}`);
|
|
27387
27612
|
const result = await executeMikrotikCommand(`/user ssh-keys print where user="${a.username}"`, ctx);
|
|
@@ -27397,7 +27622,7 @@ ${result}`;
|
|
|
27397
27622
|
title: "Remove User SSH Key",
|
|
27398
27623
|
annotations: DESTRUCTIVE,
|
|
27399
27624
|
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`.",
|
|
27400
|
-
inputSchema: { key_id:
|
|
27625
|
+
inputSchema: { key_id: z115.string() },
|
|
27401
27626
|
async handler(a, ctx) {
|
|
27402
27627
|
ctx.info(`Removing SSH key: key_id=${a.key_id}`);
|
|
27403
27628
|
const result = await executeMikrotikCommand(`/user ssh-keys remove ${a.key_id}`, ctx);
|
|
@@ -27409,7 +27634,7 @@ ${result}`;
|
|
|
27409
27634
|
];
|
|
27410
27635
|
|
|
27411
27636
|
// src/tools/vlan-designer.ts
|
|
27412
|
-
import { z as
|
|
27637
|
+
import { z as z116 } from "zod";
|
|
27413
27638
|
function defaultRange2(subnet) {
|
|
27414
27639
|
const o = subnet.split("/")[0].split(".");
|
|
27415
27640
|
return `${o[0]}.${o[1]}.${o[2]}.10-${o[0]}.${o[1]}.${o[2]}.254`;
|
|
@@ -27421,18 +27646,18 @@ var vlanDesignerTools = [
|
|
|
27421
27646
|
annotations: DANGEROUS,
|
|
27422
27647
|
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.",
|
|
27423
27648
|
inputSchema: {
|
|
27424
|
-
vlan_id:
|
|
27425
|
-
name:
|
|
27426
|
-
subnet:
|
|
27427
|
-
gateway:
|
|
27428
|
-
bridge:
|
|
27429
|
-
tagged_ports:
|
|
27430
|
-
untagged_ports:
|
|
27431
|
-
dhcp:
|
|
27432
|
-
dhcp_range:
|
|
27433
|
-
internet:
|
|
27434
|
-
isolate_from:
|
|
27435
|
-
apply:
|
|
27649
|
+
vlan_id: z116.number().int().min(1).max(4094),
|
|
27650
|
+
name: z116.string().describe("Name for the VLAN interface, e.g. 'guest'"),
|
|
27651
|
+
subnet: z116.string().describe("CIDR for the segment, e.g. '192.168.30.0/24'"),
|
|
27652
|
+
gateway: z116.string().describe("Router's address in the segment, e.g. '192.168.30.1'"),
|
|
27653
|
+
bridge: z116.string().default("bridge").describe("Bridge to put the VLAN on"),
|
|
27654
|
+
tagged_ports: z116.string().optional().describe("Comma-separated trunk/tagged ports (+ the bridge)"),
|
|
27655
|
+
untagged_ports: z116.string().optional().describe("Comma-separated access/untagged ports"),
|
|
27656
|
+
dhcp: z116.boolean().default(true).describe("Create a DHCP server + pool for the segment"),
|
|
27657
|
+
dhcp_range: z116.string().optional().describe("Pool range; defaults to .10\u2013.254 of the subnet"),
|
|
27658
|
+
internet: z116.boolean().default(true).describe("Allow internet access via srcnat masquerade"),
|
|
27659
|
+
isolate_from: z116.array(z116.string()).optional().describe("Subnets this segment must NOT reach, e.g. ['192.168.1.0/24']"),
|
|
27660
|
+
apply: z116.boolean().default(false).describe("false = preview (default); true = build")
|
|
27436
27661
|
},
|
|
27437
27662
|
async handler(a, ctx) {
|
|
27438
27663
|
const prefix = a.subnet.split("/")[1] ?? "24";
|
|
@@ -27505,9 +27730,9 @@ Review partial segment (the VLAN may exist without DHCP/firewall).`;
|
|
|
27505
27730
|
];
|
|
27506
27731
|
|
|
27507
27732
|
// src/tools/vlan.ts
|
|
27508
|
-
import { z as
|
|
27509
|
-
var ArpMode2 =
|
|
27510
|
-
var LoopProtect =
|
|
27733
|
+
import { z as z117 } from "zod";
|
|
27734
|
+
var ArpMode2 = z117.enum(["enabled", "disabled", "proxy-arp", "reply-only"]);
|
|
27735
|
+
var LoopProtect = z117.enum(["default", "on", "off"]);
|
|
27511
27736
|
var vlanTools = [
|
|
27512
27737
|
defineTool({
|
|
27513
27738
|
name: "create_vlan_interface",
|
|
@@ -27515,18 +27740,18 @@ var vlanTools = [
|
|
|
27515
27740
|
annotations: WRITE,
|
|
27516
27741
|
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.",
|
|
27517
27742
|
inputSchema: {
|
|
27518
|
-
name:
|
|
27519
|
-
vlan_id:
|
|
27520
|
-
interface:
|
|
27521
|
-
comment:
|
|
27522
|
-
disabled:
|
|
27523
|
-
mtu:
|
|
27524
|
-
use_service_tag:
|
|
27743
|
+
name: z117.string().describe("Name for the new VLAN interface, e.g. 'vlan100'"),
|
|
27744
|
+
vlan_id: z117.number().int().min(1).max(4094).describe("802.1Q VLAN ID (1-4094)"),
|
|
27745
|
+
interface: z117.string().describe("Parent interface, e.g. 'ether1' or 'bridge'"),
|
|
27746
|
+
comment: z117.string().optional(),
|
|
27747
|
+
disabled: z117.boolean().default(false),
|
|
27748
|
+
mtu: z117.number().int().optional(),
|
|
27749
|
+
use_service_tag: z117.boolean().default(false).describe("Use 802.1ad service tag (QinQ)"),
|
|
27525
27750
|
arp: ArpMode2.default("enabled"),
|
|
27526
|
-
arp_timeout:
|
|
27751
|
+
arp_timeout: z117.string().optional(),
|
|
27527
27752
|
loop_protect: LoopProtect.optional().describe("Loop protection: default, on, off"),
|
|
27528
|
-
loop_protect_disable_time:
|
|
27529
|
-
loop_protect_send_interval:
|
|
27753
|
+
loop_protect_disable_time: z117.string().optional().describe("Time to disable interface on loop detection, e.g. '5m' (0 = forever)"),
|
|
27754
|
+
loop_protect_send_interval: z117.string().optional().describe("Interval between loop-protect probe packets, e.g. '5s'")
|
|
27530
27755
|
},
|
|
27531
27756
|
async handler(a, ctx) {
|
|
27532
27757
|
ctx.info(`Creating VLAN interface: name=${a.name}, vlan_id=${a.vlan_id}, interface=${a.interface}`);
|
|
@@ -27546,10 +27771,10 @@ ${details}` : "VLAN interface creation completed but unable to verify.";
|
|
|
27546
27771
|
annotations: READ,
|
|
27547
27772
|
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.",
|
|
27548
27773
|
inputSchema: {
|
|
27549
|
-
name_filter:
|
|
27550
|
-
vlan_id_filter:
|
|
27551
|
-
interface_filter:
|
|
27552
|
-
disabled_only:
|
|
27774
|
+
name_filter: z117.string().optional().describe("Partial name match"),
|
|
27775
|
+
vlan_id_filter: z117.number().int().optional(),
|
|
27776
|
+
interface_filter: z117.string().optional().describe("Exact parent interface name"),
|
|
27777
|
+
disabled_only: z117.boolean().default(false)
|
|
27553
27778
|
},
|
|
27554
27779
|
async handler(a, ctx) {
|
|
27555
27780
|
ctx.info("Listing VLAN interfaces");
|
|
@@ -27573,7 +27798,7 @@ ${result}`;
|
|
|
27573
27798
|
title: "Get VLAN Interface Details",
|
|
27574
27799
|
annotations: READ,
|
|
27575
27800
|
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`.",
|
|
27576
|
-
inputSchema: { name:
|
|
27801
|
+
inputSchema: { name: z117.string() },
|
|
27577
27802
|
async handler(a, ctx) {
|
|
27578
27803
|
ctx.info(`Getting VLAN interface details: name=${a.name}`);
|
|
27579
27804
|
const result = await executeMikrotikCommand(`/interface vlan print detail where name="${a.name}"`, ctx);
|
|
@@ -27588,19 +27813,19 @@ ${result}`;
|
|
|
27588
27813
|
annotations: WRITE_IDEMPOTENT,
|
|
27589
27814
|
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.",
|
|
27590
27815
|
inputSchema: {
|
|
27591
|
-
name:
|
|
27592
|
-
new_name:
|
|
27593
|
-
vlan_id:
|
|
27594
|
-
interface:
|
|
27595
|
-
comment:
|
|
27596
|
-
disabled:
|
|
27597
|
-
mtu:
|
|
27598
|
-
use_service_tag:
|
|
27816
|
+
name: z117.string().describe("Current name of the VLAN interface to update"),
|
|
27817
|
+
new_name: z117.string().optional(),
|
|
27818
|
+
vlan_id: z117.number().int().min(1).max(4094).optional(),
|
|
27819
|
+
interface: z117.string().optional(),
|
|
27820
|
+
comment: z117.string().optional(),
|
|
27821
|
+
disabled: z117.boolean().optional(),
|
|
27822
|
+
mtu: z117.number().int().optional(),
|
|
27823
|
+
use_service_tag: z117.boolean().optional(),
|
|
27599
27824
|
arp: ArpMode2.optional(),
|
|
27600
|
-
arp_timeout:
|
|
27825
|
+
arp_timeout: z117.string().optional(),
|
|
27601
27826
|
loop_protect: LoopProtect.optional().describe("Loop protection: default, on, off"),
|
|
27602
|
-
loop_protect_disable_time:
|
|
27603
|
-
loop_protect_send_interval:
|
|
27827
|
+
loop_protect_disable_time: z117.string().optional().describe("Time to disable interface on loop detection, e.g. '5m' (0 = forever)"),
|
|
27828
|
+
loop_protect_send_interval: z117.string().optional().describe("Interval between loop-protect probe packets, e.g. '5s'")
|
|
27604
27829
|
},
|
|
27605
27830
|
async handler(a, ctx) {
|
|
27606
27831
|
ctx.info(`Updating VLAN interface: name=${a.name}`);
|
|
@@ -27622,7 +27847,7 @@ ${details}`;
|
|
|
27622
27847
|
title: "Remove VLAN Interface",
|
|
27623
27848
|
annotations: DESTRUCTIVE,
|
|
27624
27849
|
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`.",
|
|
27625
|
-
inputSchema: { name:
|
|
27850
|
+
inputSchema: { name: z117.string() },
|
|
27626
27851
|
async handler(a, ctx) {
|
|
27627
27852
|
ctx.info(`Removing VLAN interface: name=${a.name}`);
|
|
27628
27853
|
const count = await executeMikrotikCommand(`/interface vlan print count-only where name="${a.name}"`, ctx);
|
|
@@ -27637,7 +27862,7 @@ ${details}`;
|
|
|
27637
27862
|
];
|
|
27638
27863
|
|
|
27639
27864
|
// src/tools/wireguard-mesh.ts
|
|
27640
|
-
import { z as
|
|
27865
|
+
import { z as z118 } from "zod";
|
|
27641
27866
|
function meshAddress(prefix, index) {
|
|
27642
27867
|
const [net, len = "24"] = prefix.split("/");
|
|
27643
27868
|
const octets = net.split(".");
|
|
@@ -27654,16 +27879,16 @@ var wireguardMeshTools = [
|
|
|
27654
27879
|
annotations: DANGEROUS,
|
|
27655
27880
|
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.",
|
|
27656
27881
|
inputSchema: {
|
|
27657
|
-
devices:
|
|
27658
|
-
address_prefix:
|
|
27659
|
-
interface:
|
|
27660
|
-
listen_port:
|
|
27661
|
-
topology:
|
|
27662
|
-
hub:
|
|
27663
|
-
endpoints:
|
|
27664
|
-
allowed_lans:
|
|
27665
|
-
persistent_keepalive:
|
|
27666
|
-
apply:
|
|
27882
|
+
devices: z118.array(z118.string()).min(2).describe("Configured device names to include in the mesh (2+)"),
|
|
27883
|
+
address_prefix: z118.string().default("10.20.0.0/24").describe("Mesh subnet; each device gets <prefix>.<index+1> on its WireGuard interface"),
|
|
27884
|
+
interface: z118.string().default("wg-mesh").describe("WireGuard interface name to create/use"),
|
|
27885
|
+
listen_port: z118.number().int().default(13231),
|
|
27886
|
+
topology: z118.enum(["full-mesh", "hub-spoke"]).default("full-mesh"),
|
|
27887
|
+
hub: z118.string().optional().describe("Hub device name (required when topology=hub-spoke)"),
|
|
27888
|
+
endpoints: z118.record(z118.string(), z118.string()).optional().describe('Per-device public endpoint host override, e.g. {"site-a":"a.example.com"}'),
|
|
27889
|
+
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"}'),
|
|
27890
|
+
persistent_keepalive: z118.string().default("25s"),
|
|
27891
|
+
apply: z118.boolean().default(false).describe("false = preview the plan (default); true = build")
|
|
27667
27892
|
},
|
|
27668
27893
|
async handler(a, ctx) {
|
|
27669
27894
|
const devices = a.devices;
|
|
@@ -27754,7 +27979,7 @@ Check handshakes per device with get_wireguard_peers / list_wireguard_peers.`;
|
|
|
27754
27979
|
|
|
27755
27980
|
// src/tools/vpn-onboard.ts
|
|
27756
27981
|
import { generateKeyPairSync } from "crypto";
|
|
27757
|
-
import { z as
|
|
27982
|
+
import { z as z119 } from "zod";
|
|
27758
27983
|
function generateWireGuardKeypair() {
|
|
27759
27984
|
const { privateKey, publicKey } = generateKeyPairSync("x25519");
|
|
27760
27985
|
const priv = privateKey.export({ type: "pkcs8", format: "der" });
|
|
@@ -27771,13 +27996,13 @@ var vpnOnboardTools = [
|
|
|
27771
27996
|
annotations: WRITE,
|
|
27772
27997
|
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.",
|
|
27773
27998
|
inputSchema: {
|
|
27774
|
-
interface:
|
|
27775
|
-
user:
|
|
27776
|
-
address:
|
|
27777
|
-
endpoint:
|
|
27778
|
-
dns:
|
|
27779
|
-
allowed_ips:
|
|
27780
|
-
keepalive:
|
|
27999
|
+
interface: z119.string().describe("Existing WireGuard SERVER interface, e.g. 'wg-server'"),
|
|
28000
|
+
user: z119.string().describe("User/device label, e.g. 'alice-laptop'"),
|
|
28001
|
+
address: z119.string().describe("Tunnel IP to assign the client, e.g. '10.20.0.50'"),
|
|
28002
|
+
endpoint: z119.string().describe("Server public endpoint host:port, e.g. 'vpn.example.com:13231'"),
|
|
28003
|
+
dns: z119.string().optional().describe("DNS for the client, e.g. '10.20.0.1'"),
|
|
28004
|
+
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"),
|
|
28005
|
+
keepalive: z119.string().default("25").describe("PersistentKeepalive seconds")
|
|
27781
28006
|
},
|
|
27782
28007
|
async handler(a, ctx) {
|
|
27783
28008
|
ctx.info(`Onboarding WireGuard user '${a.user}' on ${a.interface}`);
|
|
@@ -27815,7 +28040,7 @@ ${config}`;
|
|
|
27815
28040
|
title: "Revoke WireGuard Remote User",
|
|
27816
28041
|
annotations: DESTRUCTIVE,
|
|
27817
28042
|
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.",
|
|
27818
|
-
inputSchema: { user:
|
|
28043
|
+
inputSchema: { user: z119.string().describe("The user label used at onboarding") },
|
|
27819
28044
|
async handler(a, ctx) {
|
|
27820
28045
|
const count = await executeMikrotikCommand(`/interface wireguard peers print count-only where comment="vpn-user: ${a.user}"`, ctx);
|
|
27821
28046
|
if (count.trim() === "0")
|
|
@@ -27829,7 +28054,7 @@ ${config}`;
|
|
|
27829
28054
|
];
|
|
27830
28055
|
|
|
27831
28056
|
// src/tools/wireguard.ts
|
|
27832
|
-
import { z as
|
|
28057
|
+
import { z as z120 } from "zod";
|
|
27833
28058
|
var wireguardTools = [
|
|
27834
28059
|
defineTool({
|
|
27835
28060
|
name: "create_wireguard_interface",
|
|
@@ -27837,12 +28062,12 @@ var wireguardTools = [
|
|
|
27837
28062
|
annotations: WRITE,
|
|
27838
28063
|
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.",
|
|
27839
28064
|
inputSchema: {
|
|
27840
|
-
name:
|
|
27841
|
-
listen_port:
|
|
27842
|
-
private_key:
|
|
27843
|
-
mtu:
|
|
27844
|
-
comment:
|
|
27845
|
-
disabled:
|
|
28065
|
+
name: z120.string(),
|
|
28066
|
+
listen_port: z120.number().int().optional(),
|
|
28067
|
+
private_key: z120.string().optional(),
|
|
28068
|
+
mtu: z120.number().int().optional(),
|
|
28069
|
+
comment: z120.string().optional(),
|
|
28070
|
+
disabled: z120.boolean().default(false)
|
|
27846
28071
|
},
|
|
27847
28072
|
async handler(a, ctx) {
|
|
27848
28073
|
ctx.info(`Creating WireGuard interface: name=${a.name}`);
|
|
@@ -27862,9 +28087,9 @@ ${details}` : "WireGuard interface created successfully.";
|
|
|
27862
28087
|
annotations: READ,
|
|
27863
28088
|
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.",
|
|
27864
28089
|
inputSchema: {
|
|
27865
|
-
name_filter:
|
|
27866
|
-
disabled_only:
|
|
27867
|
-
running_only:
|
|
28090
|
+
name_filter: z120.string().optional(),
|
|
28091
|
+
disabled_only: z120.boolean().default(false),
|
|
28092
|
+
running_only: z120.boolean().default(false)
|
|
27868
28093
|
},
|
|
27869
28094
|
async handler(a, ctx) {
|
|
27870
28095
|
ctx.info("Listing WireGuard interfaces");
|
|
@@ -27886,7 +28111,7 @@ ${result}`;
|
|
|
27886
28111
|
title: "Get WireGuard Interface Details",
|
|
27887
28112
|
annotations: READ,
|
|
27888
28113
|
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.",
|
|
27889
|
-
inputSchema: { name:
|
|
28114
|
+
inputSchema: { name: z120.string() },
|
|
27890
28115
|
async handler(a, ctx) {
|
|
27891
28116
|
ctx.info(`Getting WireGuard interface details: name=${a.name}`);
|
|
27892
28117
|
const result = await executeMikrotikCommand(`/interface wireguard print detail where name="${a.name}"`, ctx);
|
|
@@ -27901,7 +28126,7 @@ ${result}`;
|
|
|
27901
28126
|
annotations: READ,
|
|
27902
28127
|
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.",
|
|
27903
28128
|
inputSchema: {
|
|
27904
|
-
interface_filter:
|
|
28129
|
+
interface_filter: z120.string().optional().describe("Limit to one interface name, e.g. 'wg-mesh'")
|
|
27905
28130
|
},
|
|
27906
28131
|
async handler(a, ctx) {
|
|
27907
28132
|
ctx.info("Reading WireGuard status (interfaces + peers)");
|
|
@@ -27926,13 +28151,13 @@ ${peerBlock}`;
|
|
|
27926
28151
|
annotations: WRITE_IDEMPOTENT,
|
|
27927
28152
|
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.",
|
|
27928
28153
|
inputSchema: {
|
|
27929
|
-
name:
|
|
27930
|
-
new_name:
|
|
27931
|
-
listen_port:
|
|
27932
|
-
private_key:
|
|
27933
|
-
mtu:
|
|
27934
|
-
comment:
|
|
27935
|
-
disabled:
|
|
28154
|
+
name: z120.string(),
|
|
28155
|
+
new_name: z120.string().optional(),
|
|
28156
|
+
listen_port: z120.number().int().optional(),
|
|
28157
|
+
private_key: z120.string().optional(),
|
|
28158
|
+
mtu: z120.number().int().optional(),
|
|
28159
|
+
comment: z120.string().optional(),
|
|
28160
|
+
disabled: z120.boolean().optional()
|
|
27936
28161
|
},
|
|
27937
28162
|
async handler(a, ctx) {
|
|
27938
28163
|
ctx.info(`Updating WireGuard interface: name=${a.name}`);
|
|
@@ -27955,7 +28180,7 @@ ${details}`;
|
|
|
27955
28180
|
title: "Remove WireGuard Interface",
|
|
27956
28181
|
annotations: DESTRUCTIVE,
|
|
27957
28182
|
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.",
|
|
27958
|
-
inputSchema: { name:
|
|
28183
|
+
inputSchema: { name: z120.string() },
|
|
27959
28184
|
async handler(a, ctx) {
|
|
27960
28185
|
ctx.info(`Removing WireGuard interface: name=${a.name}`);
|
|
27961
28186
|
const count = await executeMikrotikCommand(`/interface wireguard print count-only where name="${a.name}"`, ctx);
|
|
@@ -27972,7 +28197,7 @@ ${details}`;
|
|
|
27972
28197
|
title: "Enable WireGuard Interface",
|
|
27973
28198
|
annotations: WRITE_IDEMPOTENT,
|
|
27974
28199
|
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.",
|
|
27975
|
-
inputSchema: { name:
|
|
28200
|
+
inputSchema: { name: z120.string() },
|
|
27976
28201
|
async handler(a, ctx) {
|
|
27977
28202
|
ctx.info(`Enabling WireGuard interface: name=${a.name}`);
|
|
27978
28203
|
const result = await executeMikrotikCommand(`/interface wireguard enable [find name="${a.name}"]`, ctx);
|
|
@@ -27986,7 +28211,7 @@ ${details}`;
|
|
|
27986
28211
|
title: "Disable WireGuard Interface",
|
|
27987
28212
|
annotations: WRITE_IDEMPOTENT,
|
|
27988
28213
|
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.",
|
|
27989
|
-
inputSchema: { name:
|
|
28214
|
+
inputSchema: { name: z120.string() },
|
|
27990
28215
|
async handler(a, ctx) {
|
|
27991
28216
|
ctx.info(`Disabling WireGuard interface: name=${a.name}`);
|
|
27992
28217
|
const result = await executeMikrotikCommand(`/interface wireguard disable [find name="${a.name}"]`, ctx);
|
|
@@ -28006,23 +28231,23 @@ ${details}`;
|
|
|
28006
28231
|
` + ` endpoint_address: remote host IP or hostname e.g. "203.0.113.1" (omit for road-warrior clients that dial in)
|
|
28007
28232
|
` + ' persistent_keepalive: seconds as string e.g. "25"',
|
|
28008
28233
|
inputSchema: {
|
|
28009
|
-
interface:
|
|
28010
|
-
public_key:
|
|
28011
|
-
allowed_address:
|
|
28012
|
-
endpoint_address:
|
|
28013
|
-
endpoint_port:
|
|
28014
|
-
preshared_key:
|
|
28015
|
-
persistent_keepalive:
|
|
28016
|
-
name:
|
|
28017
|
-
private_key:
|
|
28018
|
-
responder:
|
|
28019
|
-
client_address:
|
|
28020
|
-
client_dns:
|
|
28021
|
-
client_endpoint:
|
|
28022
|
-
client_keepalive:
|
|
28023
|
-
client_listen_port:
|
|
28024
|
-
comment:
|
|
28025
|
-
disabled:
|
|
28234
|
+
interface: z120.string(),
|
|
28235
|
+
public_key: z120.string(),
|
|
28236
|
+
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"'),
|
|
28237
|
+
endpoint_address: z120.string().optional().describe('remote host IP or hostname e.g. "203.0.113.1"'),
|
|
28238
|
+
endpoint_port: z120.number().int().optional(),
|
|
28239
|
+
preshared_key: z120.string().optional(),
|
|
28240
|
+
persistent_keepalive: z120.string().optional().describe('seconds as string e.g. "25"'),
|
|
28241
|
+
name: z120.string().optional().describe("optional peer name label"),
|
|
28242
|
+
private_key: z120.string().optional().describe("peer's private key (lets the router generate this peer's client config)"),
|
|
28243
|
+
responder: z120.boolean().optional().describe("only respond to handshakes, never initiate (for road-warrior clients)"),
|
|
28244
|
+
client_address: z120.string().optional().describe("client tunnel address(es) for the generated client config"),
|
|
28245
|
+
client_dns: z120.string().optional().describe("DNS server(s) written into the generated client config"),
|
|
28246
|
+
client_endpoint: z120.string().optional().describe("server endpoint host[:port] written into the generated client config"),
|
|
28247
|
+
client_keepalive: z120.string().optional().describe('client persistent-keepalive for the generated config e.g. "25s"'),
|
|
28248
|
+
client_listen_port: z120.number().int().optional().describe("listen-port written into the generated client config"),
|
|
28249
|
+
comment: z120.string().optional(),
|
|
28250
|
+
disabled: z120.boolean().default(false)
|
|
28026
28251
|
},
|
|
28027
28252
|
async handler(a, ctx) {
|
|
28028
28253
|
ctx.info(`Adding WireGuard peer: interface=${a.interface}, public_key=${a.public_key.slice(0, 12)}...`);
|
|
@@ -28042,8 +28267,8 @@ ${details}` : "WireGuard peer added successfully.";
|
|
|
28042
28267
|
annotations: READ,
|
|
28043
28268
|
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.",
|
|
28044
28269
|
inputSchema: {
|
|
28045
|
-
interface_filter:
|
|
28046
|
-
disabled_only:
|
|
28270
|
+
interface_filter: z120.string().optional(),
|
|
28271
|
+
disabled_only: z120.boolean().default(false)
|
|
28047
28272
|
},
|
|
28048
28273
|
async handler(a, ctx) {
|
|
28049
28274
|
ctx.info("Listing WireGuard peers");
|
|
@@ -28067,7 +28292,7 @@ ${result}`;
|
|
|
28067
28292
|
` + `Notes:
|
|
28068
28293
|
` + ' peer_id: the .id from list_wireguard_peers, format "*N" or "N" e.g. "*2"',
|
|
28069
28294
|
inputSchema: {
|
|
28070
|
-
peer_id:
|
|
28295
|
+
peer_id: z120.string().describe('"*N" or "N" from list output e.g. "*2"')
|
|
28071
28296
|
},
|
|
28072
28297
|
async handler(a, ctx) {
|
|
28073
28298
|
ctx.info(`Getting WireGuard peer details: peer_id=${a.peer_id}`);
|
|
@@ -28089,22 +28314,22 @@ ${result}`;
|
|
|
28089
28314
|
` + ` persistent_keepalive: seconds as string e.g. "25"
|
|
28090
28315
|
` + ' Pass "" for endpoint_address or preshared_key to clear them.',
|
|
28091
28316
|
inputSchema: {
|
|
28092
|
-
peer_id:
|
|
28093
|
-
allowed_address:
|
|
28094
|
-
endpoint_address:
|
|
28095
|
-
endpoint_port:
|
|
28096
|
-
preshared_key:
|
|
28097
|
-
persistent_keepalive:
|
|
28098
|
-
name:
|
|
28099
|
-
private_key:
|
|
28100
|
-
responder:
|
|
28101
|
-
client_address:
|
|
28102
|
-
client_dns:
|
|
28103
|
-
client_endpoint:
|
|
28104
|
-
client_keepalive:
|
|
28105
|
-
client_listen_port:
|
|
28106
|
-
comment:
|
|
28107
|
-
disabled:
|
|
28317
|
+
peer_id: z120.string().describe('"*N" or "N" from list output e.g. "*2"'),
|
|
28318
|
+
allowed_address: z120.string().optional(),
|
|
28319
|
+
endpoint_address: z120.string().optional(),
|
|
28320
|
+
endpoint_port: z120.number().int().optional(),
|
|
28321
|
+
preshared_key: z120.string().optional(),
|
|
28322
|
+
persistent_keepalive: z120.string().optional(),
|
|
28323
|
+
name: z120.string().optional().describe("optional peer name label"),
|
|
28324
|
+
private_key: z120.string().optional().describe("peer's private key (lets the router generate this peer's client config)"),
|
|
28325
|
+
responder: z120.boolean().optional().describe("only respond to handshakes, never initiate"),
|
|
28326
|
+
client_address: z120.string().optional().describe("client tunnel address(es) for the generated client config"),
|
|
28327
|
+
client_dns: z120.string().optional().describe("DNS server(s) written into the generated client config"),
|
|
28328
|
+
client_endpoint: z120.string().optional().describe("server endpoint host[:port] written into the generated client config"),
|
|
28329
|
+
client_keepalive: z120.string().optional().describe('client persistent-keepalive for the generated config e.g. "25s"'),
|
|
28330
|
+
client_listen_port: z120.number().int().optional().describe("listen-port written into the generated client config"),
|
|
28331
|
+
comment: z120.string().optional(),
|
|
28332
|
+
disabled: z120.boolean().optional()
|
|
28108
28333
|
},
|
|
28109
28334
|
async handler(a, ctx) {
|
|
28110
28335
|
ctx.info(`Updating WireGuard peer: peer_id=${a.peer_id}`);
|
|
@@ -28130,7 +28355,7 @@ ${details}`;
|
|
|
28130
28355
|
` + `Notes:
|
|
28131
28356
|
` + ' peer_id: the .id from list_wireguard_peers, format "*N" or "N" e.g. "*2"',
|
|
28132
28357
|
inputSchema: {
|
|
28133
|
-
peer_id:
|
|
28358
|
+
peer_id: z120.string().describe('"*N" or "N" from list output e.g. "*2"')
|
|
28134
28359
|
},
|
|
28135
28360
|
async handler(a, ctx) {
|
|
28136
28361
|
ctx.info(`Removing WireGuard peer: peer_id=${a.peer_id}`);
|
|
@@ -28152,7 +28377,7 @@ ${details}`;
|
|
|
28152
28377
|
` + `Notes:
|
|
28153
28378
|
` + ' peer_id: the .id from list_wireguard_peers, format "*N" or "N" e.g. "*2"',
|
|
28154
28379
|
inputSchema: {
|
|
28155
|
-
peer_id:
|
|
28380
|
+
peer_id: z120.string().describe('"*N" or "N" from list output e.g. "*2"')
|
|
28156
28381
|
},
|
|
28157
28382
|
async handler(a, ctx) {
|
|
28158
28383
|
ctx.info(`Enabling WireGuard peer: peer_id=${a.peer_id}`);
|
|
@@ -28171,7 +28396,7 @@ ${details}`;
|
|
|
28171
28396
|
` + `Notes:
|
|
28172
28397
|
` + ' peer_id: the .id from list_wireguard_peers, format "*N" or "N" e.g. "*2"',
|
|
28173
28398
|
inputSchema: {
|
|
28174
|
-
peer_id:
|
|
28399
|
+
peer_id: z120.string().describe('"*N" or "N" from list output e.g. "*2"')
|
|
28175
28400
|
},
|
|
28176
28401
|
async handler(a, ctx) {
|
|
28177
28402
|
ctx.info(`Disabling WireGuard peer: peer_id=${a.peer_id}`);
|
|
@@ -28191,14 +28416,14 @@ ${details}`;
|
|
|
28191
28416
|
` + ` 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)
|
|
28192
28417
|
` + " persistent_keepalive: seconds integer, default 25",
|
|
28193
28418
|
inputSchema: {
|
|
28194
|
-
client_private_key:
|
|
28195
|
-
client_address:
|
|
28196
|
-
server_public_key:
|
|
28197
|
-
server_endpoint:
|
|
28198
|
-
server_port:
|
|
28199
|
-
allowed_ips:
|
|
28200
|
-
dns:
|
|
28201
|
-
persistent_keepalive:
|
|
28419
|
+
client_private_key: z120.string(),
|
|
28420
|
+
client_address: z120.string(),
|
|
28421
|
+
server_public_key: z120.string(),
|
|
28422
|
+
server_endpoint: z120.string(),
|
|
28423
|
+
server_port: z120.number().int().default(51820),
|
|
28424
|
+
allowed_ips: z120.string().default("0.0.0.0/0"),
|
|
28425
|
+
dns: z120.string().optional(),
|
|
28426
|
+
persistent_keepalive: z120.number().int().default(25)
|
|
28202
28427
|
},
|
|
28203
28428
|
async handler(a, ctx) {
|
|
28204
28429
|
ctx.info("Generating WireGuard client configuration");
|
|
@@ -28232,7 +28457,7 @@ ${details}`;
|
|
|
28232
28457
|
];
|
|
28233
28458
|
|
|
28234
28459
|
// src/tools/wireless.ts
|
|
28235
|
-
import { z as
|
|
28460
|
+
import { z as z121 } from "zod";
|
|
28236
28461
|
var V7_WIFI = ["/interface wifi", "/interface wifiwave2"];
|
|
28237
28462
|
function commandUnsupported2(result) {
|
|
28238
28463
|
const t = result.toLowerCase();
|
|
@@ -28263,12 +28488,12 @@ var wirelessTools = [
|
|
|
28263
28488
|
annotations: WRITE,
|
|
28264
28489
|
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`.",
|
|
28265
28490
|
inputSchema: {
|
|
28266
|
-
name:
|
|
28267
|
-
ssid:
|
|
28268
|
-
disabled:
|
|
28269
|
-
comment:
|
|
28270
|
-
radio_name:
|
|
28271
|
-
mode:
|
|
28491
|
+
name: z121.string(),
|
|
28492
|
+
ssid: z121.string().optional(),
|
|
28493
|
+
disabled: z121.boolean().default(false),
|
|
28494
|
+
comment: z121.string().optional(),
|
|
28495
|
+
radio_name: z121.string().optional().describe("Required for legacy wireless systems, e.g. 'wlan1'"),
|
|
28496
|
+
mode: z121.enum([
|
|
28272
28497
|
"ap-bridge",
|
|
28273
28498
|
"bridge",
|
|
28274
28499
|
"station",
|
|
@@ -28278,8 +28503,8 @@ var wirelessTools = [
|
|
|
28278
28503
|
"ap-bridge-wds",
|
|
28279
28504
|
"alignment-only"
|
|
28280
28505
|
]).optional(),
|
|
28281
|
-
frequency:
|
|
28282
|
-
band:
|
|
28506
|
+
frequency: z121.string().optional(),
|
|
28507
|
+
band: z121.enum([
|
|
28283
28508
|
"2ghz-b",
|
|
28284
28509
|
"2ghz-b/g",
|
|
28285
28510
|
"2ghz-b/g/n",
|
|
@@ -28291,24 +28516,24 @@ var wirelessTools = [
|
|
|
28291
28516
|
"5ghz-n",
|
|
28292
28517
|
"5ghz-ac"
|
|
28293
28518
|
]).optional(),
|
|
28294
|
-
channel_width:
|
|
28295
|
-
security_profile:
|
|
28296
|
-
mtu:
|
|
28297
|
-
arp:
|
|
28298
|
-
hide_ssid:
|
|
28299
|
-
wireless_protocol:
|
|
28300
|
-
scan_list:
|
|
28301
|
-
frequency_mode:
|
|
28302
|
-
country:
|
|
28303
|
-
antenna_gain:
|
|
28304
|
-
wds_mode:
|
|
28305
|
-
wds_default_bridge:
|
|
28306
|
-
default_authentication:
|
|
28307
|
-
default_forwarding:
|
|
28308
|
-
tx_power:
|
|
28309
|
-
tx_power_mode:
|
|
28310
|
-
distance:
|
|
28311
|
-
disconnect_timeout:
|
|
28519
|
+
channel_width: z121.enum(["20mhz", "40mhz", "80mhz", "160mhz", "20/40mhz-eC", "20/40mhz-Ce"]).optional(),
|
|
28520
|
+
security_profile: z121.string().optional(),
|
|
28521
|
+
mtu: z121.number().int().optional().describe("Interface MTU in bytes"),
|
|
28522
|
+
arp: z121.enum(["disabled", "enabled", "proxy-arp", "reply-only", "local-proxy-arp"]).optional().describe("ARP mode for the interface"),
|
|
28523
|
+
hide_ssid: z121.boolean().optional().describe("Legacy: do not broadcast the SSID in beacons (AP modes)"),
|
|
28524
|
+
wireless_protocol: z121.string().optional().describe("Legacy: wireless protocol, e.g. '802.11', 'nv2', 'nstreme'"),
|
|
28525
|
+
scan_list: z121.string().optional().describe("Legacy: frequencies/ranges to scan (e.g. 'default' or '5180-5320')"),
|
|
28526
|
+
frequency_mode: z121.enum(["manual-txpower", "regulatory-domain", "superchannel"]).optional().describe("Legacy: regulatory frequency mode"),
|
|
28527
|
+
country: z121.string().optional().describe("Legacy: regulatory country setting (e.g. 'united states')"),
|
|
28528
|
+
antenna_gain: z121.number().int().optional().describe("Legacy: antenna gain in dBi used for tx-power calculations"),
|
|
28529
|
+
wds_mode: z121.enum(["disabled", "dynamic", "dynamic-mesh", "static", "static-mesh"]).optional().describe("Legacy: WDS mode"),
|
|
28530
|
+
wds_default_bridge: z121.string().optional().describe("Legacy: bridge that dynamic WDS interfaces are added to"),
|
|
28531
|
+
default_authentication: z121.boolean().optional().describe("Legacy: allow clients not in the access-list to authenticate"),
|
|
28532
|
+
default_forwarding: z121.boolean().optional().describe("Legacy: allow client-to-client forwarding by default"),
|
|
28533
|
+
tx_power: z121.number().int().optional().describe("Legacy: manual transmit power in dBm"),
|
|
28534
|
+
tx_power_mode: z121.enum(["default", "card-rates", "all-rates-fixed", "manual-table"]).optional().describe("Legacy: how tx-power is determined"),
|
|
28535
|
+
distance: z121.string().optional().describe("Legacy: link distance ('dynamic', 'indoors', or a km value)"),
|
|
28536
|
+
disconnect_timeout: z121.string().optional().describe("Legacy: time before a non-responding client is disconnected")
|
|
28312
28537
|
},
|
|
28313
28538
|
async handler(a, ctx) {
|
|
28314
28539
|
ctx.info(`Creating wireless interface: name=${a.name}, ssid=${a.ssid}`);
|
|
@@ -28340,9 +28565,9 @@ ${details}`;
|
|
|
28340
28565
|
annotations: READ,
|
|
28341
28566
|
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.",
|
|
28342
28567
|
inputSchema: {
|
|
28343
|
-
name_filter:
|
|
28344
|
-
disabled_only:
|
|
28345
|
-
running_only:
|
|
28568
|
+
name_filter: z121.string().optional(),
|
|
28569
|
+
disabled_only: z121.boolean().default(false),
|
|
28570
|
+
running_only: z121.boolean().default(false)
|
|
28346
28571
|
},
|
|
28347
28572
|
async handler(a, ctx) {
|
|
28348
28573
|
ctx.info(`Listing wireless interfaces with filters: name=${a.name_filter}`);
|
|
@@ -28396,7 +28621,7 @@ NOTE: If you see wireless interfaces above, they might be using a different comm
|
|
|
28396
28621
|
title: "Get Wireless Interface Details",
|
|
28397
28622
|
annotations: READ,
|
|
28398
28623
|
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.",
|
|
28399
|
-
inputSchema: { name:
|
|
28624
|
+
inputSchema: { name: z121.string() },
|
|
28400
28625
|
async handler(a, ctx) {
|
|
28401
28626
|
ctx.info(`Getting wireless interface details: name=${a.name}`);
|
|
28402
28627
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
@@ -28415,7 +28640,7 @@ ${result}`;
|
|
|
28415
28640
|
title: "Remove Wireless Interface",
|
|
28416
28641
|
annotations: DESTRUCTIVE,
|
|
28417
28642
|
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.",
|
|
28418
|
-
inputSchema: { name:
|
|
28643
|
+
inputSchema: { name: z121.string() },
|
|
28419
28644
|
async handler(a, ctx) {
|
|
28420
28645
|
ctx.info(`Removing wireless interface: name=${a.name}`);
|
|
28421
28646
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
@@ -28435,7 +28660,7 @@ ${result}`;
|
|
|
28435
28660
|
title: "Enable Wireless Interface",
|
|
28436
28661
|
annotations: WRITE_IDEMPOTENT,
|
|
28437
28662
|
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.",
|
|
28438
|
-
inputSchema: { name:
|
|
28663
|
+
inputSchema: { name: z121.string() },
|
|
28439
28664
|
async handler(a, ctx) {
|
|
28440
28665
|
ctx.info(`Enabling wireless interface: ${a.name}`);
|
|
28441
28666
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
@@ -28452,7 +28677,7 @@ ${result}`;
|
|
|
28452
28677
|
title: "Disable Wireless Interface",
|
|
28453
28678
|
annotations: WRITE_IDEMPOTENT,
|
|
28454
28679
|
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.",
|
|
28455
|
-
inputSchema: { name:
|
|
28680
|
+
inputSchema: { name: z121.string() },
|
|
28456
28681
|
async handler(a, ctx) {
|
|
28457
28682
|
ctx.info(`Disabling wireless interface: ${a.name}`);
|
|
28458
28683
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
@@ -28470,8 +28695,8 @@ ${result}`;
|
|
|
28470
28695
|
annotations: READ,
|
|
28471
28696
|
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.",
|
|
28472
28697
|
inputSchema: {
|
|
28473
|
-
interface:
|
|
28474
|
-
duration:
|
|
28698
|
+
interface: z121.string(),
|
|
28699
|
+
duration: z121.number().int().default(5)
|
|
28475
28700
|
},
|
|
28476
28701
|
async handler(a, ctx) {
|
|
28477
28702
|
ctx.info(`Scanning wireless networks on interface: ${a.interface}`);
|
|
@@ -28493,7 +28718,7 @@ ${result}`;
|
|
|
28493
28718
|
annotations: READ,
|
|
28494
28719
|
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.",
|
|
28495
28720
|
inputSchema: {
|
|
28496
|
-
interface:
|
|
28721
|
+
interface: z121.string().optional()
|
|
28497
28722
|
},
|
|
28498
28723
|
async handler(a, ctx) {
|
|
28499
28724
|
ctx.info(`Getting wireless registration table for interface: ${a.interface}`);
|
|
@@ -28555,7 +28780,7 @@ For legacy systems:
|
|
|
28555
28780
|
title: "Create Wireless Security Profile (Legacy v6 Only \u2014 Not Implemented)",
|
|
28556
28781
|
annotations: WRITE,
|
|
28557
28782
|
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.",
|
|
28558
|
-
inputSchema: { name:
|
|
28783
|
+
inputSchema: { name: z121.string() },
|
|
28559
28784
|
async handler(_a, ctx) {
|
|
28560
28785
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
28561
28786
|
if (interfaceType && V7_WIFI.includes(interfaceType)) {
|
|
@@ -28582,7 +28807,7 @@ For legacy systems:
|
|
|
28582
28807
|
title: "Get Wireless Security Profile (Legacy v6 Only \u2014 Not Implemented)",
|
|
28583
28808
|
annotations: READ,
|
|
28584
28809
|
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.",
|
|
28585
|
-
inputSchema: { name:
|
|
28810
|
+
inputSchema: { name: z121.string() },
|
|
28586
28811
|
async handler(_a, ctx) {
|
|
28587
28812
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
28588
28813
|
if (interfaceType && V7_WIFI.includes(interfaceType)) {
|
|
@@ -28596,7 +28821,7 @@ For legacy systems:
|
|
|
28596
28821
|
title: "Remove Wireless Security Profile (Legacy v6 Only \u2014 Not Implemented)",
|
|
28597
28822
|
annotations: DESTRUCTIVE,
|
|
28598
28823
|
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.",
|
|
28599
|
-
inputSchema: { name:
|
|
28824
|
+
inputSchema: { name: z121.string() },
|
|
28600
28825
|
async handler(_a, ctx) {
|
|
28601
28826
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
28602
28827
|
if (interfaceType && V7_WIFI.includes(interfaceType)) {
|
|
@@ -28611,8 +28836,8 @@ For legacy systems:
|
|
|
28611
28836
|
annotations: WRITE,
|
|
28612
28837
|
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.",
|
|
28613
28838
|
inputSchema: {
|
|
28614
|
-
interface_name:
|
|
28615
|
-
security_profile:
|
|
28839
|
+
interface_name: z121.string(),
|
|
28840
|
+
security_profile: z121.string()
|
|
28616
28841
|
},
|
|
28617
28842
|
async handler(_a, ctx) {
|
|
28618
28843
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
@@ -28653,7 +28878,7 @@ For legacy systems:
|
|
|
28653
28878
|
title: "Remove Wireless Access List Entry (Legacy v6 Only \u2014 Not Implemented)",
|
|
28654
28879
|
annotations: DESTRUCTIVE,
|
|
28655
28880
|
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.",
|
|
28656
|
-
inputSchema: { entry_id:
|
|
28881
|
+
inputSchema: { entry_id: z121.string() },
|
|
28657
28882
|
async handler(_a, ctx) {
|
|
28658
28883
|
const interfaceType = await detectWirelessInterfaceType(ctx);
|
|
28659
28884
|
if (interfaceType && V7_WIFI.includes(interfaceType)) {
|
|
@@ -28668,31 +28893,31 @@ For legacy systems:
|
|
|
28668
28893
|
annotations: WRITE_IDEMPOTENT,
|
|
28669
28894
|
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.",
|
|
28670
28895
|
inputSchema: {
|
|
28671
|
-
name:
|
|
28672
|
-
new_name:
|
|
28673
|
-
ssid:
|
|
28674
|
-
disabled:
|
|
28675
|
-
comment:
|
|
28676
|
-
mtu:
|
|
28677
|
-
arp:
|
|
28678
|
-
hide_ssid:
|
|
28679
|
-
wireless_protocol:
|
|
28680
|
-
scan_list:
|
|
28681
|
-
frequency:
|
|
28682
|
-
band:
|
|
28683
|
-
channel_width:
|
|
28684
|
-
frequency_mode:
|
|
28685
|
-
country:
|
|
28686
|
-
antenna_gain:
|
|
28687
|
-
wds_mode:
|
|
28688
|
-
wds_default_bridge:
|
|
28689
|
-
default_authentication:
|
|
28690
|
-
default_forwarding:
|
|
28691
|
-
tx_power:
|
|
28692
|
-
tx_power_mode:
|
|
28693
|
-
distance:
|
|
28694
|
-
disconnect_timeout:
|
|
28695
|
-
security_profile:
|
|
28896
|
+
name: z121.string(),
|
|
28897
|
+
new_name: z121.string().optional(),
|
|
28898
|
+
ssid: z121.string().optional(),
|
|
28899
|
+
disabled: z121.boolean().optional(),
|
|
28900
|
+
comment: z121.string().optional(),
|
|
28901
|
+
mtu: z121.number().int().optional().describe("Interface MTU in bytes"),
|
|
28902
|
+
arp: z121.enum(["disabled", "enabled", "proxy-arp", "reply-only", "local-proxy-arp"]).optional().describe("ARP mode for the interface"),
|
|
28903
|
+
hide_ssid: z121.boolean().optional().describe("Legacy: do not broadcast the SSID in beacons (AP modes)"),
|
|
28904
|
+
wireless_protocol: z121.string().optional().describe("Legacy: wireless protocol, e.g. '802.11', 'nv2', 'nstreme'"),
|
|
28905
|
+
scan_list: z121.string().optional().describe("Legacy: frequencies/ranges to scan (e.g. 'default' or '5180-5320')"),
|
|
28906
|
+
frequency: z121.string().optional().describe("Legacy: operating frequency in MHz"),
|
|
28907
|
+
band: z121.string().optional().describe("Legacy: band, e.g. '2ghz-b/g/n' or '5ghz-a/n/ac'"),
|
|
28908
|
+
channel_width: z121.enum(["20mhz", "40mhz", "80mhz", "160mhz", "20/40mhz-eC", "20/40mhz-Ce"]).optional().describe("Legacy: channel width"),
|
|
28909
|
+
frequency_mode: z121.enum(["manual-txpower", "regulatory-domain", "superchannel"]).optional().describe("Legacy: regulatory frequency mode"),
|
|
28910
|
+
country: z121.string().optional().describe("Legacy: regulatory country setting (e.g. 'united states')"),
|
|
28911
|
+
antenna_gain: z121.number().int().optional().describe("Legacy: antenna gain in dBi used for tx-power calculations"),
|
|
28912
|
+
wds_mode: z121.enum(["disabled", "dynamic", "dynamic-mesh", "static", "static-mesh"]).optional().describe("Legacy: WDS mode"),
|
|
28913
|
+
wds_default_bridge: z121.string().optional().describe("Legacy: bridge that dynamic WDS interfaces are added to"),
|
|
28914
|
+
default_authentication: z121.boolean().optional().describe("Legacy: allow clients not in the access-list to authenticate"),
|
|
28915
|
+
default_forwarding: z121.boolean().optional().describe("Legacy: allow client-to-client forwarding by default"),
|
|
28916
|
+
tx_power: z121.number().int().optional().describe("Legacy: manual transmit power in dBm"),
|
|
28917
|
+
tx_power_mode: z121.enum(["default", "card-rates", "all-rates-fixed", "manual-table"]).optional().describe("Legacy: how tx-power is determined"),
|
|
28918
|
+
distance: z121.string().optional().describe("Legacy: link distance ('dynamic', 'indoors', or a km value)"),
|
|
28919
|
+
disconnect_timeout: z121.string().optional().describe("Legacy: time before a non-responding client is disconnected"),
|
|
28920
|
+
security_profile: z121.string().optional().describe("Legacy: name of the security profile to apply")
|
|
28696
28921
|
},
|
|
28697
28922
|
async handler(a, ctx) {
|
|
28698
28923
|
ctx.info(`Updating wireless interface: name=${a.name}`);
|
|
@@ -28721,7 +28946,7 @@ ${details}`;
|
|
|
28721
28946
|
annotations: READ,
|
|
28722
28947
|
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.",
|
|
28723
28948
|
inputSchema: {
|
|
28724
|
-
search:
|
|
28949
|
+
search: z121.string().optional().describe("Optional search string to filter countries by name or code.")
|
|
28725
28950
|
},
|
|
28726
28951
|
async handler(a, ctx) {
|
|
28727
28952
|
ctx.info("Listing Wi-Fi regulatory countries");
|
|
@@ -28748,7 +28973,7 @@ ${result}`;
|
|
|
28748
28973
|
];
|
|
28749
28974
|
|
|
28750
28975
|
// src/tools/wifi-optimizer.ts
|
|
28751
|
-
import { z as
|
|
28976
|
+
import { z as z122 } from "zod";
|
|
28752
28977
|
function pickBestFrequency(monitor) {
|
|
28753
28978
|
const cands = [];
|
|
28754
28979
|
for (const line of monitor.split(`
|
|
@@ -28769,9 +28994,9 @@ var wifiOptimizerTools = [
|
|
|
28769
28994
|
annotations: WRITE,
|
|
28770
28995
|
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.",
|
|
28771
28996
|
inputSchema: {
|
|
28772
|
-
interface:
|
|
28773
|
-
duration:
|
|
28774
|
-
apply:
|
|
28997
|
+
interface: z122.string().describe("Wireless interface, e.g. 'wlan1'"),
|
|
28998
|
+
duration: z122.string().default("5").describe("Survey duration in seconds"),
|
|
28999
|
+
apply: z122.boolean().default(false).describe("false = survey & recommend (default); true = set it")
|
|
28775
29000
|
},
|
|
28776
29001
|
async handler(a, ctx) {
|
|
28777
29002
|
ctx.info(`Wi-Fi survey on ${a.interface} for ${a.duration}s`);
|
|
@@ -28796,16 +29021,16 @@ ${monitor.trim() || "(empty)"}`;
|
|
|
28796
29021
|
];
|
|
28797
29022
|
|
|
28798
29023
|
// src/tools/memory.ts
|
|
28799
|
-
import { z as
|
|
28800
|
-
var EntityInput =
|
|
28801
|
-
name:
|
|
28802
|
-
entityType:
|
|
28803
|
-
observations:
|
|
29024
|
+
import { z as z123 } from "zod";
|
|
29025
|
+
var EntityInput = z123.object({
|
|
29026
|
+
name: z123.string().describe("Unique name of the entity"),
|
|
29027
|
+
entityType: z123.string().describe("Type/category of the entity (e.g. 'router', 'subnet', 'person')"),
|
|
29028
|
+
observations: z123.array(z123.string()).optional().describe("Initial observations (facts) to attach")
|
|
28804
29029
|
});
|
|
28805
|
-
var RelationInput =
|
|
28806
|
-
from:
|
|
28807
|
-
to:
|
|
28808
|
-
relationType:
|
|
29030
|
+
var RelationInput = z123.object({
|
|
29031
|
+
from: z123.string().describe("Source entity name"),
|
|
29032
|
+
to: z123.string().describe("Target entity name"),
|
|
29033
|
+
relationType: z123.string().describe("Relation type in active voice (e.g. 'manages', 'connects_to', 'depends_on')")
|
|
28809
29034
|
});
|
|
28810
29035
|
var memoryTools = [
|
|
28811
29036
|
defineTool({
|
|
@@ -28814,7 +29039,7 @@ var memoryTools = [
|
|
|
28814
29039
|
annotations: WRITE,
|
|
28815
29040
|
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.",
|
|
28816
29041
|
inputSchema: {
|
|
28817
|
-
entities:
|
|
29042
|
+
entities: z123.array(EntityInput).min(1).describe("Entities to create")
|
|
28818
29043
|
},
|
|
28819
29044
|
async handler(args) {
|
|
28820
29045
|
const store3 = await getMemoryStore();
|
|
@@ -28832,7 +29057,7 @@ ${created.map((e) => ` - ${e.name} (${e.entityType})`).join(`
|
|
|
28832
29057
|
annotations: WRITE,
|
|
28833
29058
|
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.",
|
|
28834
29059
|
inputSchema: {
|
|
28835
|
-
relations:
|
|
29060
|
+
relations: z123.array(RelationInput).min(1).describe("Relations to create")
|
|
28836
29061
|
},
|
|
28837
29062
|
async handler(args) {
|
|
28838
29063
|
const store3 = await getMemoryStore();
|
|
@@ -28850,9 +29075,9 @@ ${created.map((r) => ` - ${r.from} --[${r.relationType}]--> ${r.to}`).join(`
|
|
|
28850
29075
|
annotations: WRITE,
|
|
28851
29076
|
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.",
|
|
28852
29077
|
inputSchema: {
|
|
28853
|
-
observations:
|
|
28854
|
-
entityName:
|
|
28855
|
-
contents:
|
|
29078
|
+
observations: z123.array(z123.object({
|
|
29079
|
+
entityName: z123.string().describe("Name of the existing entity"),
|
|
29080
|
+
contents: z123.array(z123.string()).min(1).describe("Observations to add")
|
|
28856
29081
|
})).min(1)
|
|
28857
29082
|
},
|
|
28858
29083
|
async handler(args) {
|
|
@@ -28872,7 +29097,7 @@ ${lines.join(`
|
|
|
28872
29097
|
annotations: DESTRUCTIVE,
|
|
28873
29098
|
description: "Remove entities from the knowledge graph. This also deletes all their observations " + "and any relations where they appear as an endpoint (cascade delete).",
|
|
28874
29099
|
inputSchema: {
|
|
28875
|
-
entityNames:
|
|
29100
|
+
entityNames: z123.array(z123.string()).min(1).describe("Names of entities to delete")
|
|
28876
29101
|
},
|
|
28877
29102
|
async handler(args) {
|
|
28878
29103
|
const store3 = await getMemoryStore();
|
|
@@ -28886,9 +29111,9 @@ ${lines.join(`
|
|
|
28886
29111
|
annotations: DESTRUCTIVE,
|
|
28887
29112
|
description: "Remove specific observations from entities in the knowledge graph. The entity " + "itself is kept; only the named observation strings are removed.",
|
|
28888
29113
|
inputSchema: {
|
|
28889
|
-
deletions:
|
|
28890
|
-
entityName:
|
|
28891
|
-
observations:
|
|
29114
|
+
deletions: z123.array(z123.object({
|
|
29115
|
+
entityName: z123.string().describe("Entity to remove observations from"),
|
|
29116
|
+
observations: z123.array(z123.string()).min(1).describe("Exact observation strings to delete")
|
|
28892
29117
|
})).min(1)
|
|
28893
29118
|
},
|
|
28894
29119
|
async handler(args) {
|
|
@@ -28903,7 +29128,7 @@ ${lines.join(`
|
|
|
28903
29128
|
annotations: DESTRUCTIVE,
|
|
28904
29129
|
description: "Remove specific relations from the knowledge graph. Each relation is identified " + "by its (from, to, relationType) triple.",
|
|
28905
29130
|
inputSchema: {
|
|
28906
|
-
relations:
|
|
29131
|
+
relations: z123.array(RelationInput).min(1).describe("Relations to delete")
|
|
28907
29132
|
},
|
|
28908
29133
|
async handler(args) {
|
|
28909
29134
|
const store3 = await getMemoryStore();
|
|
@@ -28931,8 +29156,8 @@ ${lines.join(`
|
|
|
28931
29156
|
annotations: READ,
|
|
28932
29157
|
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.",
|
|
28933
29158
|
inputSchema: {
|
|
28934
|
-
query:
|
|
28935
|
-
limit:
|
|
29159
|
+
query: z123.string().describe("Search term \u2014 matched against entity names, types, and observation content"),
|
|
29160
|
+
limit: z123.number().int().positive().optional().describe("Max entities to return (default 50)")
|
|
28936
29161
|
},
|
|
28937
29162
|
async handler(args) {
|
|
28938
29163
|
const store3 = await getMemoryStore();
|
|
@@ -28948,7 +29173,7 @@ ${lines.join(`
|
|
|
28948
29173
|
annotations: READ,
|
|
28949
29174
|
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.",
|
|
28950
29175
|
inputSchema: {
|
|
28951
|
-
names:
|
|
29176
|
+
names: z123.array(z123.string()).min(1).describe("Exact entity names to retrieve")
|
|
28952
29177
|
},
|
|
28953
29178
|
async handler(args) {
|
|
28954
29179
|
const store3 = await getMemoryStore();
|
|
@@ -28969,6 +29194,13 @@ var moduleCatalog = [
|
|
|
28969
29194
|
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`).",
|
|
28970
29195
|
tools: toolGatewayTools
|
|
28971
29196
|
},
|
|
29197
|
+
{
|
|
29198
|
+
label: "Server Pulse",
|
|
29199
|
+
slug: "server-pulse",
|
|
29200
|
+
group: "Discovery & Meta",
|
|
29201
|
+
description: "Server self-awareness: running version, update availability, release notes, " + "upgrade path, and server vitals. No RouterOS device is contacted.",
|
|
29202
|
+
tools: serverPulseTools
|
|
29203
|
+
},
|
|
28972
29204
|
{
|
|
28973
29205
|
label: "RouterOS CLI",
|
|
28974
29206
|
slug: "raw-command",
|
|
@@ -29825,7 +30057,7 @@ var moduleCatalog = [
|
|
|
29825
30057
|
}
|
|
29826
30058
|
];
|
|
29827
30059
|
var allToolModules = moduleCatalog.map((m) => m.tools);
|
|
29828
|
-
var ALWAYS_ON_MODULES = new Set(["tool-gateway", "memory"]);
|
|
30060
|
+
var ALWAYS_ON_MODULES = new Set(["tool-gateway", "memory", "server-pulse"]);
|
|
29829
30061
|
function selectToolModules(filter = {}, catalog = moduleCatalog) {
|
|
29830
30062
|
const lc = (xs) => new Set((xs ?? []).map((s) => s.toLowerCase()));
|
|
29831
30063
|
const enabledModules = lc(filter.enabledModules);
|
|
@@ -29846,4 +30078,4 @@ function selectToolModules(filter = {}, catalog = moduleCatalog) {
|
|
|
29846
30078
|
}).map((m) => m.tools);
|
|
29847
30079
|
}
|
|
29848
30080
|
|
|
29849
|
-
export { __require, DEFAULT_SNAPSHOT_DB, DEFAULT_CONFIG_HISTORY_DIR, DeviceConfigSchema, ToolFilterSchema, MikrotikConfigSchema, getConfigSource, loadConfig, logger, setConfig, getConfig, listDevices, deviceLabels, resolveDeviceName, deviceDirectory, isMacTelnetDevice, createDeviceClient, describeTransport, isPoolEnabled, closeAll, poolStatus, getMemoryStore, closeMemoryStore, reopenMemoryStore, executeMikrotikCommand, createContext, Cmd, isEmpty, looksLikeError, commandUnsupported, parseKeyValues, parseRouterosDate, parseSize, parseSystemResource, parseRecords, parseLeadingNumber, REDACTED, redact, configureRecorder, getEventStore, subscribe, subscriberCount, registerTools, fetchDevices, sampleDeviceTraffic, sampleAllTraffic, setDeviceLimits, blockDevice, allowDevice, makeDeviceStatic, setDeviceIp, setDeviceLabel, removeDeviceLease, devicesView, PROMPTS_DIR,
|
|
30081
|
+
export { __require, DEFAULT_SNAPSHOT_DB, DEFAULT_CONFIG_HISTORY_DIR, DeviceConfigSchema, ToolFilterSchema, MikrotikConfigSchema, getConfigSource, loadConfig, logger, setConfig, getConfig, listDevices, deviceLabels, resolveDeviceName, deviceDirectory, isMacTelnetDevice, createDeviceClient, describeTransport, isPoolEnabled, closeAll, poolStatus, getMemoryStore, closeMemoryStore, reopenMemoryStore, executeMikrotikCommand, createContext, Cmd, isEmpty, looksLikeError, commandUnsupported, parseKeyValues, parseRouterosDate, parseSize, parseSystemResource, parseRecords, parseLeadingNumber, REDACTED, redact, configureRecorder, getEventStore, subscribe, subscriberCount, registerTools, fetchDevices, sampleDeviceTraffic, sampleAllTraffic, setDeviceLimits, blockDevice, allowDevice, makeDeviceStatic, setDeviceIp, setDeviceLabel, removeDeviceLease, devicesView, PROMPTS_DIR, UI_DIST_DIR, registerUiResources, backupDir, listBackups, readBackup, writeBackup, deleteBackup, renameBackup, createLocalBackup, restoreLocalBackup, isS3Configured, getS3Client, presignExpiresIn, s3Target, splitCommands, buildChangePlan, renderPlan, diffLines, normalizeExport, analyzeDrift, attributeChanges, openSnapshotStore, DEFAULT_TZSP_PORT, capture2 as capture, AAA_ENTITIES, listAaaEntity, addAaaEntity, updateAaaEntity, removeAaaEntity, toggleAaaEntity, getRadiusIncoming, setRadiusIncoming, resetRadiusCounters, getUmSettings, setUmSettings, VERSION, WEBSITE_URL, LOGO_URL, SERVER_TITLE, SERVER_DESCRIPTION, SERVER_NAME, PKG_META, loadFileCacheSync, fetchLatestRelease, checkForUpdate, updateSummaryLine, moduleCatalog, allToolModules, ALWAYS_ON_MODULES, selectToolModules };
|