labanalyze 0.1.2

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/index.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { main } from "./server.js";
3
+ main().catch((err) => {
4
+ process.stderr.write(`Fatal: ${err.stack ?? String(err)}\n`);
5
+ process.exit(1);
6
+ });
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAW,GAAa,CAAC,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/server.js ADDED
@@ -0,0 +1,41 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { ServerState } from "./state.js";
4
+ import { PowerShellHost } from "./connection/powershellHost.js";
5
+ import { ConnectionManager } from "./connection/connectionManager.js";
6
+ import { registerConnectionTools } from "./tools/connectionTools.js";
7
+ import { registerClusterTools } from "./tools/clusterTools.js";
8
+ import { registerLogTools } from "./tools/logTools.js";
9
+ import { registerCommandTools } from "./tools/commandTools.js";
10
+ export async function main() {
11
+ const state = new ServerState();
12
+ const host = new PowerShellHost({
13
+ logger: (msg) => process.stderr.write(`[pwsh] ${msg}\n`),
14
+ });
15
+ const mgr = new ConnectionManager(state, host);
16
+ const server = new McpServer({ name: "labanalyze", version: "0.1.0" }, { capabilities: { tools: {} } });
17
+ registerConnectionTools(server, mgr);
18
+ registerClusterTools(server, mgr);
19
+ registerLogTools(server, mgr);
20
+ registerCommandTools(server, mgr);
21
+ let shuttingDown = false;
22
+ const shutdown = async (signal) => {
23
+ if (shuttingDown)
24
+ return;
25
+ shuttingDown = true;
26
+ process.stderr.write(`Received ${signal}, shutting down...\n`);
27
+ try {
28
+ await mgr.dispose();
29
+ }
30
+ catch (err) {
31
+ process.stderr.write(`Error during shutdown: ${err.message}\n`);
32
+ }
33
+ process.exit(0);
34
+ };
35
+ process.on("SIGINT", () => void shutdown("SIGINT"));
36
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
37
+ const transport = new StdioServerTransport();
38
+ await server.connect(transport);
39
+ process.stderr.write("labanalyze MCP server listening on stdio\n");
40
+ }
41
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAEtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,IAAI;IACxB,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,cAAc,CAAC;QAC9B,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;KACzD,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,IAAI,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAE/C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,EACxC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IAEF,uBAAuB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACrC,oBAAoB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClC,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,oBAAoB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAElC,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACxC,IAAI,YAAY;YAAE,OAAO;QACzB,YAAY,GAAG,IAAI,CAAC;QACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,MAAM,sBAAsB,CAAC,CAAC;QAC/D,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA2B,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IAEtD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;AACrE,CAAC"}
package/dist/state.js ADDED
@@ -0,0 +1,69 @@
1
+ export class CaseInsensitiveMap {
2
+ _map = new Map();
3
+ get size() {
4
+ return this._map.size;
5
+ }
6
+ get(key) {
7
+ return this._map.get(key.toLowerCase());
8
+ }
9
+ set(key, value) {
10
+ this._map.set(key.toLowerCase(), value);
11
+ return this;
12
+ }
13
+ has(key) {
14
+ return this._map.has(key.toLowerCase());
15
+ }
16
+ clear() {
17
+ this._map.clear();
18
+ }
19
+ entries() {
20
+ return this._map.entries();
21
+ }
22
+ keys() {
23
+ return this._map.keys();
24
+ }
25
+ }
26
+ export class DvmConnectionInfo {
27
+ ip = "";
28
+ username = "Administrator";
29
+ password = "";
30
+ winRmPort = 5985;
31
+ useSsl = false;
32
+ get isConfigured() {
33
+ return this.ip !== "" && this.password !== "";
34
+ }
35
+ get winRmEndpoint() {
36
+ const scheme = this.useSsl ? "https" : "http";
37
+ return `${scheme}://${this.ip}:${this.winRmPort}/wsman`;
38
+ }
39
+ winRmEndpointForIp(ip) {
40
+ const scheme = this.useSsl ? "https" : "http";
41
+ return `${scheme}://${ip}:${this.winRmPort}/wsman`;
42
+ }
43
+ }
44
+ export class ServerState {
45
+ connectionInfo = new DvmConnectionInfo();
46
+ connected = false;
47
+ lastError = "";
48
+ domain = "";
49
+ clusterName = "";
50
+ clusterIp = "";
51
+ discoveredNodes = [];
52
+ nodeIpMap = new CaseInsensitiveMap();
53
+ seedNode = "";
54
+ get clusterQualifiedUsername() {
55
+ return this.domain ? `${this.domain}\\hcideploymentuser` : "hcideploymentuser";
56
+ }
57
+ reset() {
58
+ this.connected = false;
59
+ this.discoveredNodes = [];
60
+ this.nodeIpMap.clear();
61
+ this.seedNode = "";
62
+ this.clusterName = "";
63
+ this.clusterIp = "";
64
+ this.domain = "";
65
+ this.lastError = "";
66
+ this.connectionInfo = new DvmConnectionInfo();
67
+ }
68
+ }
69
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { formatError } from "../helpers/formatting.js";
2
+ export function requireConnected(mgr) {
3
+ return mgr.isConnected ? null : formatError("Not connected to a DVM. Call connect_to_dvm first.");
4
+ }
5
+ export function resolveNode(mgr, node) {
6
+ if (node)
7
+ return node;
8
+ return mgr.state.seedNode || "";
9
+ }
10
+ //# sourceMappingURL=_helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_helpers.js","sourceRoot":"","sources":["../../src/tools/_helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,UAAU,gBAAgB,CAAC,GAAuB;IACtD,OAAO,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,oDAAoD,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAuB,EAAE,IAAY;IAC/D,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;AAClC,CAAC"}
@@ -0,0 +1,113 @@
1
+ import { z } from "zod";
2
+ import { formatCommandResult, formatError } from "../helpers/formatting.js";
3
+ import { requireConnected, resolveNode } from "./_helpers.js";
4
+ export function registerClusterTools(server, mgr) {
5
+ server.registerTool("get_cluster_status", {
6
+ description: "Get overall cluster health — runs Get-Cluster and Get-ClusterNode.\n\n" +
7
+ "Args:\n node: Target cluster node name/IP. If empty, uses seed node.\n",
8
+ inputSchema: {
9
+ node: z.string().default("").describe("Target cluster node name/IP. If empty, uses seed node."),
10
+ },
11
+ }, async ({ node }) => {
12
+ const errMsg = requireConnected(mgr);
13
+ if (errMsg)
14
+ return { content: [{ type: "text", text: errMsg }] };
15
+ const target = resolveNode(mgr, node);
16
+ if (!target)
17
+ return { content: [{ type: "text", text: formatError("No node specified and no seed node discovered. Call list_cluster_nodes first.") }] };
18
+ const cmd = "$c = Get-Cluster -ErrorAction Stop; " +
19
+ "$nodes = Get-ClusterNode -ErrorAction Stop; " +
20
+ "Write-Output \"Cluster Name: $($c.Name)\"; " +
21
+ "Write-Output \"Cluster Domain: $($c.Domain)\"; " +
22
+ "Write-Output \"Cluster Quorum: $($c.QuorumResource)\"; " +
23
+ "Write-Output ''; " +
24
+ "Write-Output 'Cluster Nodes:'; " +
25
+ "$nodes | Format-Table Name, State, DrainStatus, DynamicWeight -AutoSize | Out-String";
26
+ const r = await mgr.runOnNode(target, cmd);
27
+ return { content: [{ type: "text", text: formatCommandResult("Cluster Status", r.stdout, r.stderr, r.exitCode) }] };
28
+ });
29
+ server.registerTool("get_cluster_resources", {
30
+ description: "List cluster resources and their current status.\n\n" +
31
+ "Args:\n node: Target cluster node name/IP. If empty, uses seed node.\n",
32
+ inputSchema: {
33
+ node: z.string().default("").describe("Target cluster node name/IP. If empty, uses seed node."),
34
+ },
35
+ }, async ({ node }) => {
36
+ const errMsg = requireConnected(mgr);
37
+ if (errMsg)
38
+ return { content: [{ type: "text", text: errMsg }] };
39
+ const target = resolveNode(mgr, node);
40
+ if (!target)
41
+ return { content: [{ type: "text", text: formatError("No node specified and no seed node discovered. Call list_cluster_nodes first.") }] };
42
+ const cmd = "Get-ClusterResource -ErrorAction Stop | Format-Table Name, ResourceType, State, OwnerNode -AutoSize | Out-String";
43
+ const r = await mgr.runOnNode(target, cmd);
44
+ return { content: [{ type: "text", text: formatCommandResult("Cluster Resources", r.stdout, r.stderr, r.exitCode) }] };
45
+ });
46
+ server.registerTool("get_cluster_network_info", {
47
+ description: "Get cluster network configuration — networks and interfaces.\n\n" +
48
+ "Args:\n node: Target cluster node name/IP. If empty, uses seed node.\n",
49
+ inputSchema: {
50
+ node: z.string().default("").describe("Target cluster node name/IP. If empty, uses seed node."),
51
+ },
52
+ }, async ({ node }) => {
53
+ const errMsg = requireConnected(mgr);
54
+ if (errMsg)
55
+ return { content: [{ type: "text", text: errMsg }] };
56
+ const target = resolveNode(mgr, node);
57
+ if (!target)
58
+ return { content: [{ type: "text", text: formatError("No node specified and no seed node discovered. Call list_cluster_nodes first.") }] };
59
+ const cmd = "Write-Output 'Cluster Networks:'; " +
60
+ "Get-ClusterNetwork -ErrorAction Stop | Format-Table Name, State, Role -AutoSize | Out-String; " +
61
+ "Write-Output ''; " +
62
+ "Write-Output 'Cluster Network Interfaces:'; " +
63
+ "Get-ClusterNetworkInterface -ErrorAction Stop | Format-Table Name, Network, Node, State -AutoSize | Out-String";
64
+ const r = await mgr.runOnNode(target, cmd);
65
+ return { content: [{ type: "text", text: formatCommandResult("Cluster Network Info", r.stdout, r.stderr, r.exitCode) }] };
66
+ });
67
+ server.registerTool("get_node_info", {
68
+ description: "Get detailed info about a specific cluster node — OS, uptime, hardware.\n\n" +
69
+ "Args:\n node: Target cluster node name/IP (required).\n",
70
+ inputSchema: {
71
+ node: z.string().describe("Target cluster node name/IP (required)"),
72
+ },
73
+ }, async ({ node }) => {
74
+ const errMsg = requireConnected(mgr);
75
+ if (errMsg)
76
+ return { content: [{ type: "text", text: errMsg }] };
77
+ const cmd = "$os = Get-CimInstance Win32_OperatingSystem; " +
78
+ "$cs = Get-CimInstance Win32_ComputerSystem; " +
79
+ "Write-Output \"Hostname: $($env:COMPUTERNAME)\"; " +
80
+ "Write-Output \"OS: $($os.Caption) $($os.Version)\"; " +
81
+ "Write-Output \"Last Boot: $($os.LastBootUpTime)\"; " +
82
+ "Write-Output \"Uptime: $((Get-Date) - $os.LastBootUpTime)\"; " +
83
+ "Write-Output \"Total Memory: $([math]::Round($cs.TotalPhysicalMemory / 1GB, 2)) GB\"; " +
84
+ "Write-Output \"Processors: $($cs.NumberOfProcessors) ($($cs.NumberOfLogicalProcessors) logical)\"; " +
85
+ "Write-Output \"Domain: $($cs.Domain)\"";
86
+ const r = await mgr.runOnNode(node, cmd);
87
+ return { content: [{ type: "text", text: formatCommandResult(`Node Info — ${node}`, r.stdout, r.stderr, r.exitCode) }] };
88
+ });
89
+ server.registerTool("get_storage_info", {
90
+ description: "Get storage pool and virtual disk status from the cluster.\n\n" +
91
+ "Args:\n node: Target cluster node name/IP. If empty, uses seed node.\n",
92
+ inputSchema: {
93
+ node: z.string().default("").describe("Target cluster node name/IP. If empty, uses seed node."),
94
+ },
95
+ }, async ({ node }) => {
96
+ const errMsg = requireConnected(mgr);
97
+ if (errMsg)
98
+ return { content: [{ type: "text", text: errMsg }] };
99
+ const target = resolveNode(mgr, node);
100
+ if (!target)
101
+ return { content: [{ type: "text", text: formatError("No node specified and no seed node discovered. Call list_cluster_nodes first.") }] };
102
+ const cmd = "Write-Output 'Storage Pools:'; " +
103
+ "Get-StoragePool -ErrorAction Stop | Where-Object IsPrimordial -eq $false | " +
104
+ "Format-Table FriendlyName, OperationalStatus, HealthStatus, Size -AutoSize | Out-String; " +
105
+ "Write-Output ''; " +
106
+ "Write-Output 'Virtual Disks:'; " +
107
+ "Get-VirtualDisk -ErrorAction Stop | " +
108
+ "Format-Table FriendlyName, OperationalStatus, HealthStatus, Size, ResiliencySettingName -AutoSize | Out-String";
109
+ const r = await mgr.runOnNode(target, cmd);
110
+ return { content: [{ type: "text", text: formatCommandResult("Storage Info", r.stdout, r.stderr, r.exitCode) }] };
111
+ });
112
+ }
113
+ //# sourceMappingURL=clusterTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clusterTools.js","sourceRoot":"","sources":["../../src/tools/clusterTools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ import { formatCommandResult } from "../helpers/formatting.js";
3
+ import { requireConnected } from "./_helpers.js";
4
+ export function registerCommandTools(server, mgr) {
5
+ server.registerTool("run_command_on_dvm", {
6
+ description: "Execute an arbitrary PowerShell command on the DVM.\n\n" +
7
+ "⚠️ This runs arbitrary code on the DVM — use with care in test/lab environments only.\n\n" +
8
+ "Args:\n command: PowerShell command or script block to execute.\n",
9
+ inputSchema: {
10
+ command: z.string().describe("PowerShell command or script block to execute"),
11
+ },
12
+ }, async ({ command }) => {
13
+ const errMsg = requireConnected(mgr);
14
+ if (errMsg)
15
+ return { content: [{ type: "text", text: errMsg }] };
16
+ const r = await mgr.runOnDvm(command);
17
+ return { content: [{ type: "text", text: formatCommandResult("Command on DVM", r.stdout, r.stderr, r.exitCode) }] };
18
+ });
19
+ server.registerTool("run_command_on_node", {
20
+ description: "Execute an arbitrary PowerShell command on a cluster node.\n\n" +
21
+ "⚠️ This runs arbitrary code on the cluster node — use with care in test/lab environments only.\n" +
22
+ "The command is executed via direct WinRM connection to the node.\n\n" +
23
+ "Args:\n" +
24
+ " node: Target cluster node name or IP address.\n" +
25
+ " command: PowerShell command or script block to execute.\n",
26
+ inputSchema: {
27
+ node: z.string().describe("Target cluster node name or IP address"),
28
+ command: z.string().describe("PowerShell command or script block to execute"),
29
+ },
30
+ }, async ({ node, command }) => {
31
+ const errMsg = requireConnected(mgr);
32
+ if (errMsg)
33
+ return { content: [{ type: "text", text: errMsg }] };
34
+ const r = await mgr.runOnNode(node, command);
35
+ return { content: [{ type: "text", text: formatCommandResult(`Command on ${node}`, r.stdout, r.stderr, r.exitCode) }] };
36
+ });
37
+ }
38
+ //# sourceMappingURL=commandTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commandTools.js","sourceRoot":"","sources":["../../src/tools/commandTools.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,GAAuB;IAC7E,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,WAAW,EACT,yDAAyD;YACzD,2FAA2F;YAC3F,sEAAsE;QACxE,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;SAC9E;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACpB,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACjE,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACtC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;IACtH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,WAAW,EACT,gEAAgE;YAChE,kGAAkG;YAClG,sEAAsE;YACtE,SAAS;YACT,qDAAqD;YACrD,+DAA+D;QACjE,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;YACnE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;SAC9E;KACF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1B,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACjE,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,cAAc,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1H,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,79 @@
1
+ import { z } from "zod";
2
+ import { DvmConnectionInfo } from "../state.js";
3
+ import { formatError, formatConnectionStatus, formatNodeList } from "../helpers/formatting.js";
4
+ export function registerConnectionTools(server, mgr) {
5
+ server.registerTool("connect_to_dvm", {
6
+ description: "Connect to a DVM (Deployment Virtual Machine) in the Azure Local test lab.\n\n" +
7
+ "This must be called before any other tool that accesses the DVM or cluster nodes.\n" +
8
+ "Credentials are held in memory only and never persisted.\n" +
9
+ "The DVM is always accessed as Administrator. Domain is auto-discovered.\n\n" +
10
+ "Args:\n" +
11
+ " ip: DVM IP address (e.g., \"10.0.0.5\")\n" +
12
+ " password: DVM password\n" +
13
+ " username: DVM username (default: \"Administrator\")\n" +
14
+ " winrm_port: WinRM port (default: 5985)\n" +
15
+ " use_ssl: Use HTTPS for WinRM (default: False)\n",
16
+ inputSchema: {
17
+ ip: z.string().describe("DVM IP address"),
18
+ password: z.string().describe("DVM password"),
19
+ username: z.string().default("Administrator").describe("DVM username (default: Administrator)"),
20
+ winrm_port: z.number().int().default(5985).describe("WinRM port"),
21
+ use_ssl: z.boolean().default(false).describe("Use HTTPS for WinRM"),
22
+ },
23
+ }, async ({ ip, password, username, winrm_port, use_ssl }) => {
24
+ const info = new DvmConnectionInfo();
25
+ info.ip = ip;
26
+ info.username = username;
27
+ info.password = password;
28
+ info.winRmPort = winrm_port;
29
+ info.useSsl = use_ssl;
30
+ const text = await mgr.connect(info);
31
+ return { content: [{ type: "text", text }] };
32
+ });
33
+ server.registerTool("disconnect_from_dvm", {
34
+ description: "Disconnect from the current DVM session.\n\n" +
35
+ "Clears all credentials from memory.\n",
36
+ inputSchema: {},
37
+ }, async () => {
38
+ let text;
39
+ if (!mgr.isConnected) {
40
+ text = formatError("Not currently connected to any DVM.");
41
+ }
42
+ else {
43
+ text = await mgr.disconnect();
44
+ }
45
+ return { content: [{ type: "text", text }] };
46
+ });
47
+ server.registerTool("get_connection_status", {
48
+ description: "Get the current DVM connection status.\n\n" +
49
+ "Shows whether connected, DVM IP, domain, cluster info, and discovered cluster nodes.\n",
50
+ inputSchema: {},
51
+ }, async () => {
52
+ const s = mgr.state;
53
+ const text = formatConnectionStatus(s.connected, s.connectionInfo.ip, s.domain, s.connectionInfo.username, s.discoveredNodes, s.clusterName, s.clusterIp, s.seedNode);
54
+ return { content: [{ type: "text", text }] };
55
+ });
56
+ server.registerTool("list_cluster_nodes", {
57
+ description: "Discover and list cluster nodes accessible from the DVM.\n\n" +
58
+ "Queries AD for the cluster object (name like *-cl or s-cluster) and its nodes.\n" +
59
+ "Nodes are sorted alphabetically; the first is the seed node (has deployment logs).\n" +
60
+ "Requires an active DVM connection.\n",
61
+ inputSchema: {},
62
+ }, async () => {
63
+ if (!mgr.isConnected) {
64
+ const text = formatError("Not connected to a DVM. Call connect_to_dvm first.");
65
+ return { content: [{ type: "text", text }] };
66
+ }
67
+ let text;
68
+ try {
69
+ await mgr.discoverNodes();
70
+ const s = mgr.state;
71
+ text = formatNodeList(s.discoveredNodes, s.nodeIpMap, s.seedNode, s.clusterName, s.clusterIp);
72
+ }
73
+ catch (err) {
74
+ text = formatError(`Failed to discover cluster nodes: ${err.message}`);
75
+ }
76
+ return { content: [{ type: "text", text }] };
77
+ });
78
+ }
79
+ //# sourceMappingURL=connectionTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectionTools.js","sourceRoot":"","sources":["../../src/tools/connectionTools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,131 @@
1
+ import { z } from "zod";
2
+ import { formatCommandResult, formatError } from "../helpers/formatting.js";
3
+ import { requireConnected, resolveNode } from "./_helpers.js";
4
+ export function registerLogTools(server, mgr) {
5
+ server.registerTool("get_event_logs", {
6
+ description: "Retrieve Windows Event Log entries from a cluster node.\n\n" +
7
+ "Args:\n" +
8
+ " node: Target cluster node name/IP. If empty, uses seed node.\n" +
9
+ " log_name: Event log name (default: \"System\"). Common: System, Application, Microsoft-Windows-FailoverClustering/Operational.\n" +
10
+ " level: Filter by level — 0=all, 1=Critical, 2=Error, 3=Warning, 4=Informational.\n" +
11
+ " max_events: Maximum events to retrieve (default: 50).\n" +
12
+ " hours: Look back this many hours (default: 24).\n",
13
+ inputSchema: {
14
+ node: z.string().default("").describe("Target cluster node name/IP. If empty, uses seed node."),
15
+ log_name: z.string().default("System").describe("Event log name"),
16
+ level: z.number().int().default(0).describe("Filter by level — 0=all, 1=Critical, 2=Error, 3=Warning, 4=Informational"),
17
+ max_events: z.number().int().default(50).describe("Maximum events to retrieve"),
18
+ hours: z.number().int().default(24).describe("Look back this many hours"),
19
+ },
20
+ }, async (args) => {
21
+ const errMsg = requireConnected(mgr);
22
+ if (errMsg)
23
+ return { content: [{ type: "text", text: errMsg }] };
24
+ const target = resolveNode(mgr, args.node);
25
+ if (!target)
26
+ return { content: [{ type: "text", text: formatError("No node specified and no seed node discovered. Call list_cluster_nodes first.") }] };
27
+ const levelFilter = args.level > 0 ? ` -and $_.Level -eq ${args.level}` : "";
28
+ const cmd = `$cutoff = (Get-Date).AddHours(-${args.hours}); ` +
29
+ `Get-WinEvent -LogName '${args.log_name}' -MaxEvents ${args.max_events * 5} -ErrorAction Stop | ` +
30
+ `Where-Object { $_.TimeCreated -ge $cutoff${levelFilter} } | ` +
31
+ `Select-Object -First ${args.max_events} | ` +
32
+ "Format-Table TimeCreated, LevelDisplayName, Id, Message -AutoSize -Wrap | Out-String";
33
+ const r = await mgr.runOnNode(target, cmd);
34
+ return { content: [{ type: "text", text: formatCommandResult(`Event Logs — ${args.log_name} on ${target}`, r.stdout, r.stderr, r.exitCode) }] };
35
+ });
36
+ server.registerTool("get_ece_logs", {
37
+ description: "Retrieve ECE (Environment Configuration Engine) deployment logs.\n\n" +
38
+ "Deployment logs are always located at C:\\CloudDeployment\\Logs on the seed node.\n\n" +
39
+ "Args:\n" +
40
+ " node: Target node name/IP. If empty, uses seed node (recommended).\n" +
41
+ " tail_lines: Number of lines from the end of the log to retrieve (default: 200).\n",
42
+ inputSchema: {
43
+ node: z.string().default("").describe("Target node name/IP. If empty, uses seed node."),
44
+ tail_lines: z.number().int().default(200).describe("Number of lines from the end of the log to retrieve"),
45
+ },
46
+ }, async (args) => {
47
+ const errMsg = requireConnected(mgr);
48
+ if (errMsg)
49
+ return { content: [{ type: "text", text: errMsg }] };
50
+ const target = resolveNode(mgr, args.node);
51
+ if (!target)
52
+ return { content: [{ type: "text", text: formatError("No node specified and no seed node discovered. Call list_cluster_nodes first.") }] };
53
+ const cmd = "$logDir = 'C:\\CloudDeployment\\Logs'; " +
54
+ "if (Test-Path $logDir) { " +
55
+ " $latestLog = Get-ChildItem $logDir -Filter 'CloudDeployment.*.log' | Sort-Object LastWriteTime -Descending | Select-Object -First 1; " +
56
+ " if ($latestLog) { " +
57
+ ' Write-Output "=== $($latestLog.FullName) ==="; ' +
58
+ ` Get-Content $latestLog.FullName -Tail ${args.tail_lines}; ` +
59
+ " } else { " +
60
+ " Write-Output 'No CloudDeployment log files found in C:\\CloudDeployment\\Logs.' " +
61
+ " } " +
62
+ "} else { " +
63
+ " Write-Output 'C:\\CloudDeployment\\Logs directory does not exist.' " +
64
+ "}";
65
+ const r = await mgr.runOnNode(target, cmd);
66
+ return { content: [{ type: "text", text: formatCommandResult(`ECE Logs — ${target}`, r.stdout, r.stderr, r.exitCode) }] };
67
+ });
68
+ server.registerTool("get_deployment_status", {
69
+ description: "Check Azure Local deployment status from the seed node.\n\n" +
70
+ "Looks for deployment progress via ECE action plan status on the seed node.\n",
71
+ inputSchema: {},
72
+ }, async () => {
73
+ const errMsg = requireConnected(mgr);
74
+ if (errMsg)
75
+ return { content: [{ type: "text", text: errMsg }] };
76
+ const target = mgr.state.seedNode || "";
77
+ if (!target)
78
+ return { content: [{ type: "text", text: formatError("No seed node discovered. Call list_cluster_nodes first.") }] };
79
+ const cmd = "try { " +
80
+ " Import-Module C:\\CloudDeployment\\ECEngine\\EnterpriseCloudEngine.psd1 -ErrorAction Stop; " +
81
+ " $plan = Get-ActionPlanInstance -ErrorAction Stop | Sort-Object StartTime -Descending | Select-Object -First 1; " +
82
+ " if ($plan) { " +
83
+ ' Write-Output "Plan ID: $($plan.PlanInstanceId)"; ' +
84
+ ' Write-Output "Status: $($plan.Status)"; ' +
85
+ ' Write-Output "Start: $($plan.StartTime)"; ' +
86
+ ' Write-Output "End: $($plan.EndTime)"; ' +
87
+ " Write-Output ''; " +
88
+ " Write-Output 'Step Summary:'; " +
89
+ " $plan | Get-ActionPlanInstanceSteps | Format-Table StepName, Status, StartTime, EndTime -AutoSize | Out-String " +
90
+ " } else { " +
91
+ " Write-Output 'No action plan instances found.' " +
92
+ " } " +
93
+ "} catch { " +
94
+ ' Write-Output "ECE module not available: $_" ' +
95
+ "}";
96
+ const r = await mgr.runOnNode(target, cmd);
97
+ return { content: [{ type: "text", text: formatCommandResult("Deployment Status", r.stdout, r.stderr, r.exitCode) }] };
98
+ });
99
+ server.registerTool("get_file_content", {
100
+ description: "Read a file from a cluster node or the DVM.\n\n" +
101
+ "Args:\n" +
102
+ " file_path: Full path to the file (e.g., \"C:\\CloudDeployment\\Logs\\ActionPlan.log\").\n" +
103
+ " node: Target node name/IP. If empty, uses seed node.\n" +
104
+ " tail_lines: If > 0, only return the last N lines.\n" +
105
+ " head_lines: If > 0, only return the first N lines.\n",
106
+ inputSchema: {
107
+ file_path: z.string().describe("Full path to the file"),
108
+ node: z.string().default("").describe("Target node name/IP. If empty, uses seed node."),
109
+ tail_lines: z.number().int().default(0).describe("If > 0, only return the last N lines"),
110
+ head_lines: z.number().int().default(0).describe("If > 0, only return the first N lines"),
111
+ },
112
+ }, async (args) => {
113
+ const errMsg = requireConnected(mgr);
114
+ if (errMsg)
115
+ return { content: [{ type: "text", text: errMsg }] };
116
+ const target = resolveNode(mgr, args.node);
117
+ if (!target)
118
+ return { content: [{ type: "text", text: formatError("No node specified and no seed node discovered. Call list_cluster_nodes first.") }] };
119
+ const escapedPath = args.file_path.replaceAll("'", "''");
120
+ let cmd;
121
+ if (args.tail_lines > 0)
122
+ cmd = `Get-Content '${escapedPath}' -Tail ${args.tail_lines} -ErrorAction Stop`;
123
+ else if (args.head_lines > 0)
124
+ cmd = `Get-Content '${escapedPath}' -TotalCount ${args.head_lines} -ErrorAction Stop`;
125
+ else
126
+ cmd = `Get-Content '${escapedPath}' -ErrorAction Stop`;
127
+ const r = await mgr.runOnNode(target, cmd);
128
+ return { content: [{ type: "text", text: formatCommandResult(`File — ${args.file_path} on ${target}`, r.stdout, r.stderr, r.exitCode) }] };
129
+ });
130
+ }
131
+ //# sourceMappingURL=logTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logTools.js","sourceRoot":"","sources":["../../src/tools/logTools.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "labanalyze",
3
+ "version": "0.1.2",
4
+ "description": "MCP server for Azure Local lab DVMs and cluster nodes (PowerShell remoting via long-lived pwsh child)",
5
+ "type": "module",
6
+ "bin": {
7
+ "labanalyze": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
17
+ "license": "MIT",
18
+ "author": "Fei Fang <kfang@microsoft.com>",
19
+ "homepage": "https://github.com/fangfei/mcpservers/tree/main/labanalyzemcp#readme",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/fangfei/mcpservers.git",
23
+ "directory": "labanalyzemcp"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/fangfei/mcpservers/issues"
27
+ },
28
+ "keywords": [
29
+ "mcp",
30
+ "model-context-protocol",
31
+ "azure-local",
32
+ "azure-stack-hci",
33
+ "dvm",
34
+ "powershell",
35
+ "winrm",
36
+ "psremoting"
37
+ ],
38
+ "scripts": {
39
+ "build": "tsc",
40
+ "test": "node --test --import tsx tests/connectionManager.test.ts tests/formatting.test.ts tests/powershellHost.test.ts tests/state.test.ts",
41
+ "prepublishOnly": "npm run build"
42
+ },
43
+ "dependencies": {
44
+ "@cfworker/json-schema": "^4.1.1",
45
+ "@modelcontextprotocol/sdk": "^1.29.0",
46
+ "zod": "^3.25.0"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^22.0.0",
50
+ "tsx": "^4.21.0",
51
+ "typescript": "^5.7.0"
52
+ }
53
+ }
54
+