@usex/mikrotik-mcp 5.9.0 → 5.11.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/README.md +6 -0
- package/dist/cli.js +171 -16
- package/dist/index.js +1 -1
- package/dist/shared/{library-rkr0yp3t.js → library-drn9gmjm.js} +1 -1
- package/dist/shared/{library-dyeaqzj6.js → library-tm6yshkz.js} +171 -16
- package/dist/ui/aaa.html +5 -2
- package/dist/ui/connected-devices.html +5 -2
- package/dist/ui/dashboard.html +5 -2
- package/dist/ui/fabric.html +123 -0
- package/dist/ui/firewall-audit.html +9 -6
- package/dist/ui/firewall.html +6 -3
- package/dist/ui/interfaces.html +19 -16
- package/dist/ui/investigations.html +123 -0
- package/dist/ui/observability.html +3 -3
- package/dist/ui/operations.html +123 -0
- package/dist/ui/records.html +6 -3
- package/dist/ui/reports.html +123 -0
- package/dist/ui/round-trip.html +123 -0
- package/dist/ui/service-health.html +123 -0
- package/package.json +9 -9
- package/schemas/tool-catalog.json +1 -1
- /package/dist/shared/{cli-2a9bs005.js → cli-m947aqb2.js} +0 -0
package/README.md
CHANGED
|
@@ -46,6 +46,12 @@ Then just ask:
|
|
|
46
46
|
|
|
47
47
|
## Highlights
|
|
48
48
|
|
|
49
|
+
- **MCP App workspaces** — 13 host-themed views, with dedicated investigation,
|
|
50
|
+
round-trip, service-health, L2 fabric, operations and report workspaces alongside
|
|
51
|
+
the existing device, interface, firewall and record views. Responsive grids,
|
|
52
|
+
named path interfaces, expandable evidence and colored JSON keep results readable
|
|
53
|
+
inside compatible MCP clients. New report views never execute or replay tools.
|
|
54
|
+
[View guide](docs/mcp-app-workspaces.md)
|
|
49
55
|
- **Round-trip path lab** — model explicit forward/reverse static IPv4 paths across
|
|
50
56
|
fresh snapshots, with per-hop evidence and declared asymmetry. NAT or unsupported
|
|
51
57
|
state stops with UNKNOWN; modelled forwarding is not live connectivity.
|
package/dist/cli.js
CHANGED
|
@@ -16764,7 +16764,7 @@ function poolStatus() {
|
|
|
16764
16764
|
}
|
|
16765
16765
|
|
|
16766
16766
|
// src/ssh/safe-mode.ts
|
|
16767
|
-
var PROMPT_RE = /\[
|
|
16767
|
+
var PROMPT_RE = /\[[^\r\n\]]+@[^\r\n\]]+\][ \t]+(?:\/[^\r\n<>]*[ \t]*)?(?:<SAFE>(?:[ \t]*>)?|>)[ \t]*$/;
|
|
16768
16768
|
var ANSI_RE = /\x1B(?:\[[0-9;]*[mA-HJ-MSTfhilnprsu]|[()][0-9A-Za-z]|\[?\?\d+[hl])/g;
|
|
16769
16769
|
function stripAnsi(text) {
|
|
16770
16770
|
return text.replace(ANSI_RE, "");
|
|
@@ -16832,8 +16832,9 @@ class SafeModeManager {
|
|
|
16832
16832
|
this.cleanup();
|
|
16833
16833
|
return `Error: Timed out waiting for MikroTik shell prompt. Got: ${JSON.stringify(initial.slice(0, 300))}`;
|
|
16834
16834
|
}
|
|
16835
|
+
const activation = this.readUntilPrompt(1e4, (c) => isSafeModeActivated(c));
|
|
16835
16836
|
this.channel.write(CTRL_X);
|
|
16836
|
-
const response = (await
|
|
16837
|
+
const response = (await activation).text;
|
|
16837
16838
|
if (!isSafeModeActivated(response)) {
|
|
16838
16839
|
this.cleanup();
|
|
16839
16840
|
return `Error: Safe mode did not activate. Response: ${JSON.stringify(response.slice(0, 300))}`;
|
|
@@ -16850,11 +16851,12 @@ class SafeModeManager {
|
|
|
16850
16851
|
if (!this.active || !this.channel) {
|
|
16851
16852
|
throw new Error("Safe mode session is not active.");
|
|
16852
16853
|
}
|
|
16854
|
+
const response = this.readUntilPrompt();
|
|
16853
16855
|
this.channel.write(`${command}
|
|
16854
16856
|
`);
|
|
16855
|
-
const { text, timedOut } = await
|
|
16857
|
+
const { text, timedOut } = await response;
|
|
16856
16858
|
if (timedOut) {
|
|
16857
|
-
throw new Error(`Safe Mode
|
|
16859
|
+
throw new Error(`Safe Mode command did not return a recognized prompt before the timeout (command: ${command}). ` + "Execution may have occurred; do not retry the write blindly. Inspect the session " + "and roll back if its state cannot be verified.");
|
|
16858
16860
|
}
|
|
16859
16861
|
return this.extractOutput(text, command);
|
|
16860
16862
|
});
|
|
@@ -16961,12 +16963,17 @@ class SafeModeManager {
|
|
|
16961
16963
|
if (!this.channel)
|
|
16962
16964
|
return "unknown";
|
|
16963
16965
|
const token = "__MCP_SAFEMODE_PROBE__";
|
|
16966
|
+
const response = this.readUntilPrompt(8000, (cleaned) => {
|
|
16967
|
+
const lines = cleaned.replace(/\r/g, `
|
|
16968
|
+
`).split(`
|
|
16969
|
+
`);
|
|
16970
|
+
const i = lines.findIndex((line) => line.trim() === token);
|
|
16971
|
+
return i >= 0 && PROMPT_RE.test(lines.slice(i + 1).join(`
|
|
16972
|
+
`));
|
|
16973
|
+
});
|
|
16964
16974
|
this.channel.write(`:put "${token}"
|
|
16965
16975
|
`);
|
|
16966
|
-
const out = (await
|
|
16967
|
-
const i = cleaned.lastIndexOf(token);
|
|
16968
|
-
return i >= 0 && PROMPT_RE.test(cleaned.slice(i));
|
|
16969
|
-
})).text;
|
|
16976
|
+
const out = (await response).text;
|
|
16970
16977
|
return classifyPrompt(out);
|
|
16971
16978
|
}
|
|
16972
16979
|
extractOutput(raw, command) {
|
|
@@ -16984,6 +16991,11 @@ class SafeModeManager {
|
|
|
16984
16991
|
pastEcho = true;
|
|
16985
16992
|
continue;
|
|
16986
16993
|
}
|
|
16994
|
+
if (stripped.endsWith(command.trim())) {
|
|
16995
|
+
const prefix = stripped.slice(0, -command.trim().length).trimEnd();
|
|
16996
|
+
if (PROMPT_RE.test(prefix))
|
|
16997
|
+
continue;
|
|
16998
|
+
}
|
|
16987
16999
|
if (PROMPT_RE.test(stripped))
|
|
16988
17000
|
break;
|
|
16989
17001
|
result.push(line);
|
|
@@ -17656,12 +17668,117 @@ function indicatesFailure(text) {
|
|
|
17656
17668
|
return /^Failed\b/.test(firstLine) || /\(line \d+ column \d+\)/.test(text);
|
|
17657
17669
|
}
|
|
17658
17670
|
|
|
17671
|
+
// src/core/report-views.ts
|
|
17672
|
+
var REPORT_VIEW_TOOLS = {
|
|
17673
|
+
investigations: [
|
|
17674
|
+
"create_investigation",
|
|
17675
|
+
"get_investigation",
|
|
17676
|
+
"list_investigations",
|
|
17677
|
+
"inspect_flow_path",
|
|
17678
|
+
"list_client_flow_candidates"
|
|
17679
|
+
],
|
|
17680
|
+
"round-trip": ["trace_round_trip"],
|
|
17681
|
+
"service-health": [
|
|
17682
|
+
"create_service_contract",
|
|
17683
|
+
"list_service_contracts",
|
|
17684
|
+
"list_service_probe_targets",
|
|
17685
|
+
"run_service_contract",
|
|
17686
|
+
"service_contract_history",
|
|
17687
|
+
"audit_service_contracts"
|
|
17688
|
+
],
|
|
17689
|
+
fabric: ["map_l2_fabric", "locate_host_port"],
|
|
17690
|
+
operations: [
|
|
17691
|
+
"plan_changes",
|
|
17692
|
+
"apply_plan",
|
|
17693
|
+
"begin_transaction",
|
|
17694
|
+
"add_transaction_step",
|
|
17695
|
+
"verify_transaction",
|
|
17696
|
+
"commit_transaction",
|
|
17697
|
+
"abort_transaction",
|
|
17698
|
+
"plan_rollout",
|
|
17699
|
+
"rollout_status",
|
|
17700
|
+
"config_check_drift",
|
|
17701
|
+
"diff_config_snapshots",
|
|
17702
|
+
"get_access_scope",
|
|
17703
|
+
"safe_mode_status",
|
|
17704
|
+
"packet_capture_status"
|
|
17705
|
+
],
|
|
17706
|
+
reports: [
|
|
17707
|
+
"diagnose",
|
|
17708
|
+
"trace_path",
|
|
17709
|
+
"correlate_events",
|
|
17710
|
+
"suggest_fix",
|
|
17711
|
+
"run_compliance_audit",
|
|
17712
|
+
"audit_fleet",
|
|
17713
|
+
"audit_known_vulnerabilities",
|
|
17714
|
+
"audit_certificate_expiry",
|
|
17715
|
+
"audit_firewall_hardening",
|
|
17716
|
+
"audit_firewall_default_deny",
|
|
17717
|
+
"audit_address_list_enforcement",
|
|
17718
|
+
"audit_kernel_ip_hardening",
|
|
17719
|
+
"audit_ipv6_firewall_baseline",
|
|
17720
|
+
"audit_ssh_hardening",
|
|
17721
|
+
"audit_ip_service_exposure",
|
|
17722
|
+
"audit_connection_tracking_helpers",
|
|
17723
|
+
"audit_management_plane_exposure",
|
|
17724
|
+
"audit_account_hygiene",
|
|
17725
|
+
"audit_certificate_hygiene",
|
|
17726
|
+
"audit_network_segmentation",
|
|
17727
|
+
"audit_dns_resolver_exposure",
|
|
17728
|
+
"run_security_hardening_audit",
|
|
17729
|
+
"run_capsman_audit",
|
|
17730
|
+
"audit_capsman_coverage",
|
|
17731
|
+
"report_weak_signal_clients",
|
|
17732
|
+
"audit_capsman_load",
|
|
17733
|
+
"audit_capsman_ft",
|
|
17734
|
+
"audit_capsman_ha",
|
|
17735
|
+
"simulate_packet",
|
|
17736
|
+
"simulate_change",
|
|
17737
|
+
"simulate_suite",
|
|
17738
|
+
"explain_rule_reachability",
|
|
17739
|
+
"run_policy_check",
|
|
17740
|
+
"check_policy_snapshot",
|
|
17741
|
+
"explain_policy_finding",
|
|
17742
|
+
"explain_device",
|
|
17743
|
+
"explain_section",
|
|
17744
|
+
"diff_explanations",
|
|
17745
|
+
"flow_top_talkers",
|
|
17746
|
+
"analyze_flows",
|
|
17747
|
+
"forecast_link_saturation"
|
|
17748
|
+
]
|
|
17749
|
+
};
|
|
17750
|
+
var REPORT_VIEW_META = "mikrotik/reportView";
|
|
17751
|
+
var byTool = new Map(Object.entries(REPORT_VIEW_TOOLS).flatMap(([kind, names]) => names.map((name) => [name, kind])));
|
|
17752
|
+
function reportViewForTool(name) {
|
|
17753
|
+
return byTool.get(name);
|
|
17754
|
+
}
|
|
17755
|
+
function buildReportView(kind, tool, title, device, raw, structured) {
|
|
17756
|
+
let data = structured;
|
|
17757
|
+
if (data === undefined) {
|
|
17758
|
+
try {
|
|
17759
|
+
data = JSON.parse(raw);
|
|
17760
|
+
} catch {
|
|
17761
|
+
data = null;
|
|
17762
|
+
}
|
|
17763
|
+
}
|
|
17764
|
+
return {
|
|
17765
|
+
__mikrotikView: "report",
|
|
17766
|
+
kind,
|
|
17767
|
+
tool,
|
|
17768
|
+
title,
|
|
17769
|
+
device: device ?? "default",
|
|
17770
|
+
raw,
|
|
17771
|
+
data,
|
|
17772
|
+
generatedAt: new Date().toISOString()
|
|
17773
|
+
};
|
|
17774
|
+
}
|
|
17775
|
+
|
|
17659
17776
|
// src/core/ui-meta.ts
|
|
17660
17777
|
var UI_META_KEY = "ui";
|
|
17661
17778
|
var UI_RESOURCE_URI_LEGACY_KEY = "ui/resourceUri";
|
|
17662
17779
|
var OPENAI_OUTPUT_TEMPLATE_KEY = "openai/outputTemplate";
|
|
17663
17780
|
function uiViewUri(id) {
|
|
17664
|
-
return `ui://mikrotik/${id}.html`;
|
|
17781
|
+
return `ui://mikrotik/${id}.html?v=2`;
|
|
17665
17782
|
}
|
|
17666
17783
|
function toolUiMeta(ui) {
|
|
17667
17784
|
const meta = {
|
|
@@ -19418,6 +19535,9 @@ var UI_OUTPUT_SCHEMA = object({}).passthrough();
|
|
|
19418
19535
|
function effectiveUi(def) {
|
|
19419
19536
|
if (def.ui)
|
|
19420
19537
|
return { ui: def.ui, auto: false };
|
|
19538
|
+
const report = reportViewForTool(def.name);
|
|
19539
|
+
if (report)
|
|
19540
|
+
return { ui: { resourceUri: uiViewUri(report), visibility: ["model"] }, auto: true };
|
|
19421
19541
|
if (def.annotations.readOnlyHint === true && AUTO_RECORDS_VERB.test(def.name)) {
|
|
19422
19542
|
return { ui: { resourceUri: uiViewUri("records"), visibility: ["model", "app"] }, auto: true };
|
|
19423
19543
|
}
|
|
@@ -19597,10 +19717,9 @@ function defineTool(def) {
|
|
|
19597
19717
|
return { content: [{ type: "text", text: out.text }], isError: true };
|
|
19598
19718
|
}
|
|
19599
19719
|
if (auto && !out.structuredContent) {
|
|
19600
|
-
const
|
|
19601
|
-
|
|
19602
|
-
|
|
19603
|
-
}
|
|
19720
|
+
const report = reportViewForTool(def.name);
|
|
19721
|
+
const view = report ? buildReportView(report, def.name, def.title, deviceName, out.text) : buildRecordsView(def.name, def.title, out.text, new Date().toISOString());
|
|
19722
|
+
out.structuredContent = view;
|
|
19604
19723
|
}
|
|
19605
19724
|
const result = {
|
|
19606
19725
|
content: [{ type: "text", text: out.text }]
|
|
@@ -19609,6 +19728,12 @@ function defineTool(def) {
|
|
|
19609
19728
|
result.structuredContent = out.structuredContent;
|
|
19610
19729
|
hasStructured = true;
|
|
19611
19730
|
}
|
|
19731
|
+
const report = auto && reportViewForTool(def.name);
|
|
19732
|
+
if (report && out.structuredContent?.__mikrotikView !== "report") {
|
|
19733
|
+
result._meta = {
|
|
19734
|
+
[REPORT_VIEW_META]: buildReportView(report, def.name, def.title, deviceName, out.text, out.structuredContent)
|
|
19735
|
+
};
|
|
19736
|
+
}
|
|
19612
19737
|
if (deviceStamp)
|
|
19613
19738
|
result.content.push({ type: "text", text: deviceStamp });
|
|
19614
19739
|
return result;
|
|
@@ -19666,7 +19791,7 @@ function defineTool(def) {
|
|
|
19666
19791
|
inputSchema,
|
|
19667
19792
|
annotations: { ...def.annotations, title: def.title },
|
|
19668
19793
|
...ui ? { _meta: toolUiMeta(ui) } : {},
|
|
19669
|
-
...ui
|
|
19794
|
+
...ui ? { outputSchema: UI_OUTPUT_SCHEMA } : {}
|
|
19670
19795
|
}, callback);
|
|
19671
19796
|
}
|
|
19672
19797
|
};
|
|
@@ -24555,6 +24680,36 @@ var UI_VIEWS = [
|
|
|
24555
24680
|
id: "aaa",
|
|
24556
24681
|
name: "MikroTik RADIUS & User Manager",
|
|
24557
24682
|
description: "Full RADIUS client + built-in User Manager RADIUS server management: servers, users, " + "profiles, limitations, NAS clients, assignments, sessions and settings, with add/edit/remove."
|
|
24683
|
+
},
|
|
24684
|
+
{
|
|
24685
|
+
id: "investigations",
|
|
24686
|
+
name: "MikroTik Client Investigations",
|
|
24687
|
+
description: "Client attachment, router-scoped evidence, exported flow interfaces and unresolved visibility gaps."
|
|
24688
|
+
},
|
|
24689
|
+
{
|
|
24690
|
+
id: "round-trip",
|
|
24691
|
+
name: "MikroTik Round-trip Lab",
|
|
24692
|
+
description: "Forward and return snapshot paths with named interfaces, modelled boundaries and unknown hops. Not live packet proof."
|
|
24693
|
+
},
|
|
24694
|
+
{
|
|
24695
|
+
id: "service-health",
|
|
24696
|
+
name: "MikroTik Service Health",
|
|
24697
|
+
description: "Approved endpoint checks, contract definitions and historical PASS/FAIL/UNKNOWN evidence from the MCP host."
|
|
24698
|
+
},
|
|
24699
|
+
{
|
|
24700
|
+
id: "fabric",
|
|
24701
|
+
name: "MikroTik Layer-2 Fabric",
|
|
24702
|
+
description: "Bridge-port occupancy, attached clients and inferred access/uplink roles."
|
|
24703
|
+
},
|
|
24704
|
+
{
|
|
24705
|
+
id: "operations",
|
|
24706
|
+
name: "MikroTik Change Operations",
|
|
24707
|
+
description: "Read-only presentation of plans, transaction results, rollout progress, scope and drift. No apply/commit controls."
|
|
24708
|
+
},
|
|
24709
|
+
{
|
|
24710
|
+
id: "reports",
|
|
24711
|
+
name: "MikroTik Evidence Reports",
|
|
24712
|
+
description: "Readable diagnostic, compliance, security, simulation and traffic reports with searchable evidence and JSON export."
|
|
24558
24713
|
}
|
|
24559
24714
|
];
|
|
24560
24715
|
function placeholderHtml(view) {
|
|
@@ -30068,7 +30223,7 @@ var cache2 = null;
|
|
|
30068
30223
|
async function gateway() {
|
|
30069
30224
|
if (cache2)
|
|
30070
30225
|
return cache2;
|
|
30071
|
-
const { moduleCatalog } = await import("./shared/cli-
|
|
30226
|
+
const { moduleCatalog } = await import("./shared/cli-m947aqb2.js");
|
|
30072
30227
|
const forIndex = [];
|
|
30073
30228
|
const byName = new Map;
|
|
30074
30229
|
for (const mod of moduleCatalog) {
|
|
@@ -52294,7 +52449,7 @@ var riskByTool = null;
|
|
|
52294
52449
|
async function riskIndex() {
|
|
52295
52450
|
if (riskByTool)
|
|
52296
52451
|
return riskByTool;
|
|
52297
|
-
const { moduleCatalog } = await import("./shared/cli-
|
|
52452
|
+
const { moduleCatalog } = await import("./shared/cli-m947aqb2.js");
|
|
52298
52453
|
const index = new Map;
|
|
52299
52454
|
for (const mod of moduleCatalog) {
|
|
52300
52455
|
for (const tool of mod.tools)
|
package/dist/index.js
CHANGED
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
updateSummaryLine,
|
|
63
63
|
allToolModules2,
|
|
64
64
|
selectToolModules2
|
|
65
|
-
} from "./shared/library-
|
|
65
|
+
} from "./shared/library-tm6yshkz.js";
|
|
66
66
|
|
|
67
67
|
// node_modules/ajv/dist/compile/codegen/code.js
|
|
68
68
|
var require_code = __commonJS(function(exports) {
|
|
@@ -10181,7 +10181,7 @@ async function runPooled(command, deviceName, opts) {
|
|
|
10181
10181
|
}
|
|
10182
10182
|
|
|
10183
10183
|
// src/ssh/safe-mode.ts
|
|
10184
|
-
var PROMPT_RE = /\[
|
|
10184
|
+
var PROMPT_RE = /\[[^\r\n\]]+@[^\r\n\]]+\][ \t]+(?:\/[^\r\n<>]*[ \t]*)?(?:<SAFE>(?:[ \t]*>)?|>)[ \t]*$/;
|
|
10185
10185
|
var ANSI_RE = /\x1B(?:\[[0-9;]*[mA-HJ-MSTfhilnprsu]|[()][0-9A-Za-z]|\[?\?\d+[hl])/g;
|
|
10186
10186
|
function stripAnsi(text) {
|
|
10187
10187
|
return text.replace(ANSI_RE, "");
|
|
@@ -10249,8 +10249,9 @@ class SafeModeManager2 {
|
|
|
10249
10249
|
this.cleanup();
|
|
10250
10250
|
return `Error: Timed out waiting for MikroTik shell prompt. Got: ${JSON.stringify(initial.slice(0, 300))}`;
|
|
10251
10251
|
}
|
|
10252
|
+
const activation = this.readUntilPrompt(1e4, (c) => isSafeModeActivated(c));
|
|
10252
10253
|
this.channel.write(CTRL_X);
|
|
10253
|
-
const response = (await
|
|
10254
|
+
const response = (await activation).text;
|
|
10254
10255
|
if (!isSafeModeActivated(response)) {
|
|
10255
10256
|
this.cleanup();
|
|
10256
10257
|
return `Error: Safe mode did not activate. Response: ${JSON.stringify(response.slice(0, 300))}`;
|
|
@@ -10267,11 +10268,12 @@ class SafeModeManager2 {
|
|
|
10267
10268
|
if (!this.active || !this.channel) {
|
|
10268
10269
|
throw new Error("Safe mode session is not active.");
|
|
10269
10270
|
}
|
|
10271
|
+
const response = this.readUntilPrompt();
|
|
10270
10272
|
this.channel.write(`${command}
|
|
10271
10273
|
`);
|
|
10272
|
-
const { text, timedOut } = await
|
|
10274
|
+
const { text, timedOut } = await response;
|
|
10273
10275
|
if (timedOut) {
|
|
10274
|
-
throw new Error(`Safe Mode
|
|
10276
|
+
throw new Error(`Safe Mode command did not return a recognized prompt before the timeout (command: ${command}). ` + "Execution may have occurred; do not retry the write blindly. Inspect the session " + "and roll back if its state cannot be verified.");
|
|
10275
10277
|
}
|
|
10276
10278
|
return this.extractOutput(text, command);
|
|
10277
10279
|
});
|
|
@@ -10378,12 +10380,17 @@ class SafeModeManager2 {
|
|
|
10378
10380
|
if (!this.channel)
|
|
10379
10381
|
return "unknown";
|
|
10380
10382
|
const token = "__MCP_SAFEMODE_PROBE__";
|
|
10383
|
+
const response = this.readUntilPrompt(8000, (cleaned) => {
|
|
10384
|
+
const lines = cleaned.replace(/\r/g, `
|
|
10385
|
+
`).split(`
|
|
10386
|
+
`);
|
|
10387
|
+
const i = lines.findIndex((line) => line.trim() === token);
|
|
10388
|
+
return i >= 0 && PROMPT_RE.test(lines.slice(i + 1).join(`
|
|
10389
|
+
`));
|
|
10390
|
+
});
|
|
10381
10391
|
this.channel.write(`:put "${token}"
|
|
10382
10392
|
`);
|
|
10383
|
-
const out = (await
|
|
10384
|
-
const i = cleaned.lastIndexOf(token);
|
|
10385
|
-
return i >= 0 && PROMPT_RE.test(cleaned.slice(i));
|
|
10386
|
-
})).text;
|
|
10393
|
+
const out = (await response).text;
|
|
10387
10394
|
return classifyPrompt(out);
|
|
10388
10395
|
}
|
|
10389
10396
|
extractOutput(raw, command) {
|
|
@@ -10401,6 +10408,11 @@ class SafeModeManager2 {
|
|
|
10401
10408
|
pastEcho = true;
|
|
10402
10409
|
continue;
|
|
10403
10410
|
}
|
|
10411
|
+
if (stripped.endsWith(command.trim())) {
|
|
10412
|
+
const prefix = stripped.slice(0, -command.trim().length).trimEnd();
|
|
10413
|
+
if (PROMPT_RE.test(prefix))
|
|
10414
|
+
continue;
|
|
10415
|
+
}
|
|
10404
10416
|
if (PROMPT_RE.test(stripped))
|
|
10405
10417
|
break;
|
|
10406
10418
|
result.push(line);
|
|
@@ -11073,12 +11085,117 @@ function indicatesFailure(text) {
|
|
|
11073
11085
|
return /^Failed\b/.test(firstLine) || /\(line \d+ column \d+\)/.test(text);
|
|
11074
11086
|
}
|
|
11075
11087
|
|
|
11088
|
+
// src/core/report-views.ts
|
|
11089
|
+
var REPORT_VIEW_TOOLS = {
|
|
11090
|
+
investigations: [
|
|
11091
|
+
"create_investigation",
|
|
11092
|
+
"get_investigation",
|
|
11093
|
+
"list_investigations",
|
|
11094
|
+
"inspect_flow_path",
|
|
11095
|
+
"list_client_flow_candidates"
|
|
11096
|
+
],
|
|
11097
|
+
"round-trip": ["trace_round_trip"],
|
|
11098
|
+
"service-health": [
|
|
11099
|
+
"create_service_contract",
|
|
11100
|
+
"list_service_contracts",
|
|
11101
|
+
"list_service_probe_targets",
|
|
11102
|
+
"run_service_contract",
|
|
11103
|
+
"service_contract_history",
|
|
11104
|
+
"audit_service_contracts"
|
|
11105
|
+
],
|
|
11106
|
+
fabric: ["map_l2_fabric", "locate_host_port"],
|
|
11107
|
+
operations: [
|
|
11108
|
+
"plan_changes",
|
|
11109
|
+
"apply_plan",
|
|
11110
|
+
"begin_transaction",
|
|
11111
|
+
"add_transaction_step",
|
|
11112
|
+
"verify_transaction",
|
|
11113
|
+
"commit_transaction",
|
|
11114
|
+
"abort_transaction",
|
|
11115
|
+
"plan_rollout",
|
|
11116
|
+
"rollout_status",
|
|
11117
|
+
"config_check_drift",
|
|
11118
|
+
"diff_config_snapshots",
|
|
11119
|
+
"get_access_scope",
|
|
11120
|
+
"safe_mode_status",
|
|
11121
|
+
"packet_capture_status"
|
|
11122
|
+
],
|
|
11123
|
+
reports: [
|
|
11124
|
+
"diagnose",
|
|
11125
|
+
"trace_path",
|
|
11126
|
+
"correlate_events",
|
|
11127
|
+
"suggest_fix",
|
|
11128
|
+
"run_compliance_audit",
|
|
11129
|
+
"audit_fleet",
|
|
11130
|
+
"audit_known_vulnerabilities",
|
|
11131
|
+
"audit_certificate_expiry",
|
|
11132
|
+
"audit_firewall_hardening",
|
|
11133
|
+
"audit_firewall_default_deny",
|
|
11134
|
+
"audit_address_list_enforcement",
|
|
11135
|
+
"audit_kernel_ip_hardening",
|
|
11136
|
+
"audit_ipv6_firewall_baseline",
|
|
11137
|
+
"audit_ssh_hardening",
|
|
11138
|
+
"audit_ip_service_exposure",
|
|
11139
|
+
"audit_connection_tracking_helpers",
|
|
11140
|
+
"audit_management_plane_exposure",
|
|
11141
|
+
"audit_account_hygiene",
|
|
11142
|
+
"audit_certificate_hygiene",
|
|
11143
|
+
"audit_network_segmentation",
|
|
11144
|
+
"audit_dns_resolver_exposure",
|
|
11145
|
+
"run_security_hardening_audit",
|
|
11146
|
+
"run_capsman_audit",
|
|
11147
|
+
"audit_capsman_coverage",
|
|
11148
|
+
"report_weak_signal_clients",
|
|
11149
|
+
"audit_capsman_load",
|
|
11150
|
+
"audit_capsman_ft",
|
|
11151
|
+
"audit_capsman_ha",
|
|
11152
|
+
"simulate_packet",
|
|
11153
|
+
"simulate_change",
|
|
11154
|
+
"simulate_suite",
|
|
11155
|
+
"explain_rule_reachability",
|
|
11156
|
+
"run_policy_check",
|
|
11157
|
+
"check_policy_snapshot",
|
|
11158
|
+
"explain_policy_finding",
|
|
11159
|
+
"explain_device",
|
|
11160
|
+
"explain_section",
|
|
11161
|
+
"diff_explanations",
|
|
11162
|
+
"flow_top_talkers",
|
|
11163
|
+
"analyze_flows",
|
|
11164
|
+
"forecast_link_saturation"
|
|
11165
|
+
]
|
|
11166
|
+
};
|
|
11167
|
+
var REPORT_VIEW_META = "mikrotik/reportView";
|
|
11168
|
+
var byTool = new Map(Object.entries(REPORT_VIEW_TOOLS).flatMap(([kind, names]) => names.map((name) => [name, kind])));
|
|
11169
|
+
function reportViewForTool(name) {
|
|
11170
|
+
return byTool.get(name);
|
|
11171
|
+
}
|
|
11172
|
+
function buildReportView(kind, tool, title, device, raw, structured) {
|
|
11173
|
+
let data = structured;
|
|
11174
|
+
if (data === undefined) {
|
|
11175
|
+
try {
|
|
11176
|
+
data = JSON.parse(raw);
|
|
11177
|
+
} catch {
|
|
11178
|
+
data = null;
|
|
11179
|
+
}
|
|
11180
|
+
}
|
|
11181
|
+
return {
|
|
11182
|
+
__mikrotikView: "report",
|
|
11183
|
+
kind,
|
|
11184
|
+
tool,
|
|
11185
|
+
title,
|
|
11186
|
+
device: device ?? "default",
|
|
11187
|
+
raw,
|
|
11188
|
+
data,
|
|
11189
|
+
generatedAt: new Date().toISOString()
|
|
11190
|
+
};
|
|
11191
|
+
}
|
|
11192
|
+
|
|
11076
11193
|
// src/core/ui-meta.ts
|
|
11077
11194
|
var UI_META_KEY = "ui";
|
|
11078
11195
|
var UI_RESOURCE_URI_LEGACY_KEY = "ui/resourceUri";
|
|
11079
11196
|
var OPENAI_OUTPUT_TEMPLATE_KEY = "openai/outputTemplate";
|
|
11080
11197
|
function uiViewUri(id) {
|
|
11081
|
-
return `ui://mikrotik/${id}.html`;
|
|
11198
|
+
return `ui://mikrotik/${id}.html?v=2`;
|
|
11082
11199
|
}
|
|
11083
11200
|
function toolUiMeta(ui) {
|
|
11084
11201
|
const meta = {
|
|
@@ -12411,6 +12528,9 @@ var UI_OUTPUT_SCHEMA = object({}).passthrough();
|
|
|
12411
12528
|
function effectiveUi(def) {
|
|
12412
12529
|
if (def.ui)
|
|
12413
12530
|
return { ui: def.ui, auto: false };
|
|
12531
|
+
const report = reportViewForTool(def.name);
|
|
12532
|
+
if (report)
|
|
12533
|
+
return { ui: { resourceUri: uiViewUri(report), visibility: ["model"] }, auto: true };
|
|
12414
12534
|
if (def.annotations.readOnlyHint === true && AUTO_RECORDS_VERB.test(def.name)) {
|
|
12415
12535
|
return { ui: { resourceUri: uiViewUri("records"), visibility: ["model", "app"] }, auto: true };
|
|
12416
12536
|
}
|
|
@@ -12590,10 +12710,9 @@ function defineTool2(def) {
|
|
|
12590
12710
|
return { content: [{ type: "text", text: out.text }], isError: true };
|
|
12591
12711
|
}
|
|
12592
12712
|
if (auto && !out.structuredContent) {
|
|
12593
|
-
const
|
|
12594
|
-
|
|
12595
|
-
|
|
12596
|
-
}
|
|
12713
|
+
const report = reportViewForTool(def.name);
|
|
12714
|
+
const view = report ? buildReportView(report, def.name, def.title, deviceName, out.text) : buildRecordsView(def.name, def.title, out.text, new Date().toISOString());
|
|
12715
|
+
out.structuredContent = view;
|
|
12597
12716
|
}
|
|
12598
12717
|
const result = {
|
|
12599
12718
|
content: [{ type: "text", text: out.text }]
|
|
@@ -12602,6 +12721,12 @@ function defineTool2(def) {
|
|
|
12602
12721
|
result.structuredContent = out.structuredContent;
|
|
12603
12722
|
hasStructured = true;
|
|
12604
12723
|
}
|
|
12724
|
+
const report = auto && reportViewForTool(def.name);
|
|
12725
|
+
if (report && out.structuredContent?.__mikrotikView !== "report") {
|
|
12726
|
+
result._meta = {
|
|
12727
|
+
[REPORT_VIEW_META]: buildReportView(report, def.name, def.title, deviceName, out.text, out.structuredContent)
|
|
12728
|
+
};
|
|
12729
|
+
}
|
|
12605
12730
|
if (deviceStamp)
|
|
12606
12731
|
result.content.push({ type: "text", text: deviceStamp });
|
|
12607
12732
|
return result;
|
|
@@ -12659,7 +12784,7 @@ function defineTool2(def) {
|
|
|
12659
12784
|
inputSchema,
|
|
12660
12785
|
annotations: { ...def.annotations, title: def.title },
|
|
12661
12786
|
...ui ? { _meta: toolUiMeta(ui) } : {},
|
|
12662
|
-
...ui
|
|
12787
|
+
...ui ? { outputSchema: UI_OUTPUT_SCHEMA } : {}
|
|
12663
12788
|
}, callback);
|
|
12664
12789
|
}
|
|
12665
12790
|
};
|
|
@@ -17356,6 +17481,36 @@ var UI_VIEWS = [
|
|
|
17356
17481
|
id: "aaa",
|
|
17357
17482
|
name: "MikroTik RADIUS & User Manager",
|
|
17358
17483
|
description: "Full RADIUS client + built-in User Manager RADIUS server management: servers, users, " + "profiles, limitations, NAS clients, assignments, sessions and settings, with add/edit/remove."
|
|
17484
|
+
},
|
|
17485
|
+
{
|
|
17486
|
+
id: "investigations",
|
|
17487
|
+
name: "MikroTik Client Investigations",
|
|
17488
|
+
description: "Client attachment, router-scoped evidence, exported flow interfaces and unresolved visibility gaps."
|
|
17489
|
+
},
|
|
17490
|
+
{
|
|
17491
|
+
id: "round-trip",
|
|
17492
|
+
name: "MikroTik Round-trip Lab",
|
|
17493
|
+
description: "Forward and return snapshot paths with named interfaces, modelled boundaries and unknown hops. Not live packet proof."
|
|
17494
|
+
},
|
|
17495
|
+
{
|
|
17496
|
+
id: "service-health",
|
|
17497
|
+
name: "MikroTik Service Health",
|
|
17498
|
+
description: "Approved endpoint checks, contract definitions and historical PASS/FAIL/UNKNOWN evidence from the MCP host."
|
|
17499
|
+
},
|
|
17500
|
+
{
|
|
17501
|
+
id: "fabric",
|
|
17502
|
+
name: "MikroTik Layer-2 Fabric",
|
|
17503
|
+
description: "Bridge-port occupancy, attached clients and inferred access/uplink roles."
|
|
17504
|
+
},
|
|
17505
|
+
{
|
|
17506
|
+
id: "operations",
|
|
17507
|
+
name: "MikroTik Change Operations",
|
|
17508
|
+
description: "Read-only presentation of plans, transaction results, rollout progress, scope and drift. No apply/commit controls."
|
|
17509
|
+
},
|
|
17510
|
+
{
|
|
17511
|
+
id: "reports",
|
|
17512
|
+
name: "MikroTik Evidence Reports",
|
|
17513
|
+
description: "Readable diagnostic, compliance, security, simulation and traffic reports with searchable evidence and JSON export."
|
|
17359
17514
|
}
|
|
17360
17515
|
];
|
|
17361
17516
|
function placeholderHtml(view) {
|
|
@@ -22869,7 +23024,7 @@ var cache2 = null;
|
|
|
22869
23024
|
async function gateway() {
|
|
22870
23025
|
if (cache2)
|
|
22871
23026
|
return cache2;
|
|
22872
|
-
const { moduleCatalog } = await import("./library-
|
|
23027
|
+
const { moduleCatalog } = await import("./library-drn9gmjm.js");
|
|
22873
23028
|
const forIndex = [];
|
|
22874
23029
|
const byName = new Map;
|
|
22875
23030
|
for (const mod of moduleCatalog) {
|
|
@@ -44847,7 +45002,7 @@ var riskByTool = null;
|
|
|
44847
45002
|
async function riskIndex() {
|
|
44848
45003
|
if (riskByTool)
|
|
44849
45004
|
return riskByTool;
|
|
44850
|
-
const { moduleCatalog } = await import("./library-
|
|
45005
|
+
const { moduleCatalog } = await import("./library-drn9gmjm.js");
|
|
44851
45006
|
const index = new Map;
|
|
44852
45007
|
for (const mod of moduleCatalog) {
|
|
44853
45008
|
for (const tool of mod.tools)
|