@soyrageagency/proxmox-mcp 1.0.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/LICENSE +21 -0
- package/README.md +792 -0
- package/dist/assets.d.ts +18 -0
- package/dist/assets.js +53 -0
- package/dist/assets.js.map +1 -0
- package/dist/branding.d.ts +28 -0
- package/dist/branding.js +58 -0
- package/dist/branding.js.map +1 -0
- package/dist/config.d.ts +70 -0
- package/dist/config.js +119 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +23 -0
- package/dist/logger.js +65 -0
- package/dist/logger.js.map +1 -0
- package/dist/plugins.d.ts +32 -0
- package/dist/plugins.js +149 -0
- package/dist/plugins.js.map +1 -0
- package/dist/proxmox/client.d.ts +153 -0
- package/dist/proxmox/client.js +620 -0
- package/dist/proxmox/client.js.map +1 -0
- package/dist/resilience/backup-verifier.d.ts +28 -0
- package/dist/resilience/backup-verifier.js +222 -0
- package/dist/resilience/backup-verifier.js.map +1 -0
- package/dist/resilience/dr-drill.d.ts +17 -0
- package/dist/resilience/dr-drill.js +138 -0
- package/dist/resilience/dr-drill.js.map +1 -0
- package/dist/resilience/engine.d.ts +68 -0
- package/dist/resilience/engine.js +151 -0
- package/dist/resilience/engine.js.map +1 -0
- package/dist/resilience/patch-orchestrator.d.ts +31 -0
- package/dist/resilience/patch-orchestrator.js +188 -0
- package/dist/resilience/patch-orchestrator.js.map +1 -0
- package/dist/resilience/report.d.ts +33 -0
- package/dist/resilience/report.js +264 -0
- package/dist/resilience/report.js.map +1 -0
- package/dist/resilience/runbook.d.ts +42 -0
- package/dist/resilience/runbook.js +165 -0
- package/dist/resilience/runbook.js.map +1 -0
- package/dist/resilience/signing.d.ts +43 -0
- package/dist/resilience/signing.js +107 -0
- package/dist/resilience/signing.js.map +1 -0
- package/dist/resilience/types.d.ts +150 -0
- package/dist/resilience/types.js +14 -0
- package/dist/resilience/types.js.map +1 -0
- package/dist/resilience/util.d.ts +16 -0
- package/dist/resilience/util.js +32 -0
- package/dist/resilience/util.js.map +1 -0
- package/dist/tools/about.d.ts +14 -0
- package/dist/tools/about.js +54 -0
- package/dist/tools/about.js.map +1 -0
- package/dist/tools/backups.d.ts +15 -0
- package/dist/tools/backups.js +91 -0
- package/dist/tools/backups.js.map +1 -0
- package/dist/tools/cluster.d.ts +12 -0
- package/dist/tools/cluster.js +48 -0
- package/dist/tools/cluster.js.map +1 -0
- package/dist/tools/context.d.ts +30 -0
- package/dist/tools/context.js +12 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/guests.d.ts +15 -0
- package/dist/tools/guests.js +96 -0
- package/dist/tools/guests.js.map +1 -0
- package/dist/tools/lifecycle.d.ts +16 -0
- package/dist/tools/lifecycle.js +93 -0
- package/dist/tools/lifecycle.js.map +1 -0
- package/dist/tools/management.d.ts +17 -0
- package/dist/tools/management.js +135 -0
- package/dist/tools/management.js.map +1 -0
- package/dist/tools/nodes.d.ts +12 -0
- package/dist/tools/nodes.js +44 -0
- package/dist/tools/nodes.js.map +1 -0
- package/dist/tools/provisioning.d.ts +16 -0
- package/dist/tools/provisioning.js +122 -0
- package/dist/tools/provisioning.js.map +1 -0
- package/dist/tools/resilience.d.ts +21 -0
- package/dist/tools/resilience.js +116 -0
- package/dist/tools/resilience.js.map +1 -0
- package/dist/tools/snapshots.d.ts +17 -0
- package/dist/tools/snapshots.js +89 -0
- package/dist/tools/snapshots.js.map +1 -0
- package/dist/tools/storage.d.ts +11 -0
- package/dist/tools/storage.js +39 -0
- package/dist/tools/storage.js.map +1 -0
- package/dist/tools/tasks.d.ts +11 -0
- package/dist/tools/tasks.js +43 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/tui/ansi.d.ts +63 -0
- package/dist/tui/ansi.js +115 -0
- package/dist/tui/ansi.js.map +1 -0
- package/dist/tui/app.d.ts +109 -0
- package/dist/tui/app.js +904 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/box.d.ts +18 -0
- package/dist/tui/box.js +38 -0
- package/dist/tui/box.js.map +1 -0
- package/dist/tui/index.d.ts +20 -0
- package/dist/tui/index.js +65 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/update/channel.d.ts +69 -0
- package/dist/update/channel.js +165 -0
- package/dist/update/channel.js.map +1 -0
- package/dist/update/notice.d.ts +11 -0
- package/dist/update/notice.js +27 -0
- package/dist/update/notice.js.map +1 -0
- package/dist/utils/format.d.ts +21 -0
- package/dist/utils/format.js +63 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/result.d.ts +25 -0
- package/dist/utils/result.js +26 -0
- package/dist/utils/result.js.map +1 -0
- package/package.json +87 -0
- package/scripts/install.mjs +301 -0
package/dist/assets.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundled-asset access — works the same whether we're running from `dist/` on a
|
|
3
|
+
* machine with Node, or as a single-file standalone binary (Node SEA) with no
|
|
4
|
+
* Node installed at all.
|
|
5
|
+
*
|
|
6
|
+
* When packaged, the update channel (and any other embedded resource) is baked
|
|
7
|
+
* into the executable and read from the SEA blob; otherwise it's read from disk.
|
|
8
|
+
*
|
|
9
|
+
* Part of Proxmox MCP Server.
|
|
10
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
11
|
+
* MIT licensed (see LICENSE).
|
|
12
|
+
*/
|
|
13
|
+
/** True when running as an injected single-file executable. */
|
|
14
|
+
export declare function isPackaged(): boolean;
|
|
15
|
+
/** Read a bundled asset as a Buffer: from the SEA blob when packaged, else disk. */
|
|
16
|
+
export declare function readAssetBuffer(key: string, diskPath: string): Buffer;
|
|
17
|
+
/** Read a bundled asset as UTF-8 text. Returns null if it can't be read. */
|
|
18
|
+
export declare function readAssetText(key: string, diskPath: string): string | null;
|
package/dist/assets.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundled-asset access — works the same whether we're running from `dist/` on a
|
|
3
|
+
* machine with Node, or as a single-file standalone binary (Node SEA) with no
|
|
4
|
+
* Node installed at all.
|
|
5
|
+
*
|
|
6
|
+
* When packaged, the update channel (and any other embedded resource) is baked
|
|
7
|
+
* into the executable and read from the SEA blob; otherwise it's read from disk.
|
|
8
|
+
*
|
|
9
|
+
* Part of Proxmox MCP Server.
|
|
10
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
11
|
+
* MIT licensed (see LICENSE).
|
|
12
|
+
*/
|
|
13
|
+
import { readFileSync } from "node:fs";
|
|
14
|
+
import { createRequire } from "node:module";
|
|
15
|
+
let seaMod = null;
|
|
16
|
+
try {
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
seaMod = require("node:sea");
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
seaMod = null;
|
|
22
|
+
}
|
|
23
|
+
/** True when running as an injected single-file executable. */
|
|
24
|
+
export function isPackaged() {
|
|
25
|
+
try {
|
|
26
|
+
return Boolean(seaMod?.isSea());
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Read a bundled asset as a Buffer: from the SEA blob when packaged, else disk. */
|
|
33
|
+
export function readAssetBuffer(key, diskPath) {
|
|
34
|
+
if (seaMod && isPackaged()) {
|
|
35
|
+
try {
|
|
36
|
+
return Buffer.from(seaMod.getRawAsset(key));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* fall through to disk */
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return readFileSync(diskPath);
|
|
43
|
+
}
|
|
44
|
+
/** Read a bundled asset as UTF-8 text. Returns null if it can't be read. */
|
|
45
|
+
export function readAssetText(key, diskPath) {
|
|
46
|
+
try {
|
|
47
|
+
return readAssetBuffer(key, diskPath).toString("utf8");
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAI5C,IAAI,MAAM,GAAkB,IAAI,CAAC;AACjC,IAAI,CAAC;IACH,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,GAAG,OAAO,CAAC,UAAU,CAAW,CAAC;AACzC,CAAC;AAAC,MAAM,CAAC;IACP,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,QAAgB;IAC3D,IAAI,MAAM,IAAI,UAAU,EAAE,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,QAAgB;IACzD,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branding & identity.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for the project identity carried by the server: the
|
|
5
|
+
* startup banner, the MCP `instructions` payload and the `about` tool.
|
|
6
|
+
*
|
|
7
|
+
* Part of Proxmox MCP Server.
|
|
8
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
9
|
+
* MIT licensed (see LICENSE).
|
|
10
|
+
*/
|
|
11
|
+
/** Identity of the project's author. */
|
|
12
|
+
export declare const BRAND: Readonly<{
|
|
13
|
+
product: "Proxmox MCP Server";
|
|
14
|
+
author: "SoyRage Agency";
|
|
15
|
+
url: "https://soyrage.es/";
|
|
16
|
+
donate: "https://www.paypal.com/paypalme/soyrageagency";
|
|
17
|
+
tagline: "Chat with your Proxmox VE cluster — safely.";
|
|
18
|
+
version: "1.0.0";
|
|
19
|
+
}>;
|
|
20
|
+
/** ASCII welcome banner (ANSI Shadow style). */
|
|
21
|
+
export declare const ASCII_BANNER: string;
|
|
22
|
+
/** The full welcome block, banner + credits, used by the `about` tool. */
|
|
23
|
+
export declare function welcomeBlock(): string;
|
|
24
|
+
/**
|
|
25
|
+
* The MCP `instructions` payload — surfaced to the LLM by the client. Keep it
|
|
26
|
+
* strictly operational: what the server can do and how to use it safely.
|
|
27
|
+
*/
|
|
28
|
+
export declare function mcpInstructions(): string;
|
package/dist/branding.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branding & identity.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for the project identity carried by the server: the
|
|
5
|
+
* startup banner, the MCP `instructions` payload and the `about` tool.
|
|
6
|
+
*
|
|
7
|
+
* Part of Proxmox MCP Server.
|
|
8
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
9
|
+
* MIT licensed (see LICENSE).
|
|
10
|
+
*/
|
|
11
|
+
/** Identity of the project's author. */
|
|
12
|
+
export const BRAND = Object.freeze({
|
|
13
|
+
product: "Proxmox MCP Server",
|
|
14
|
+
author: "SoyRage Agency",
|
|
15
|
+
url: "https://soyrage.es/",
|
|
16
|
+
donate: "https://www.paypal.com/paypalme/soyrageagency",
|
|
17
|
+
tagline: "Chat with your Proxmox VE cluster — safely.",
|
|
18
|
+
version: "1.0.0",
|
|
19
|
+
});
|
|
20
|
+
/** ASCII welcome banner (ANSI Shadow style). */
|
|
21
|
+
export const ASCII_BANNER = String.raw `
|
|
22
|
+
███████╗ ██████╗ ██╗ ██╗██████╗ █████╗ ██████╗ ███████╗
|
|
23
|
+
██╔════╝██╔═══██╗╚██╗ ██╔╝██╔══██╗██╔══██╗██╔════╝ ██╔════╝
|
|
24
|
+
███████╗██║ ██║ ╚████╔╝ ██████╔╝███████║██║ ███╗█████╗
|
|
25
|
+
╚════██║██║ ██║ ╚██╔╝ ██╔══██╗██╔══██║██║ ██║██╔══╝
|
|
26
|
+
███████║╚██████╔╝ ██║ ██║ ██║██║ ██║╚██████╔╝███████╗
|
|
27
|
+
╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝
|
|
28
|
+
P R O X M O X M C P S E R V E R
|
|
29
|
+
~ Chat with your Proxmox VE cluster, safely ~
|
|
30
|
+
`;
|
|
31
|
+
/** The full welcome block, banner + credits, used by the `about` tool. */
|
|
32
|
+
export function welcomeBlock() {
|
|
33
|
+
return [
|
|
34
|
+
ASCII_BANNER,
|
|
35
|
+
` ${BRAND.product} v${BRAND.version}`,
|
|
36
|
+
` Crafted with care by ${BRAND.author} — ${BRAND.url}`,
|
|
37
|
+
" Free and open source under the MIT License.",
|
|
38
|
+
` Support the project: ${BRAND.donate}`,
|
|
39
|
+
"",
|
|
40
|
+
].join("\n");
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The MCP `instructions` payload — surfaced to the LLM by the client. Keep it
|
|
44
|
+
* strictly operational: what the server can do and how to use it safely.
|
|
45
|
+
*/
|
|
46
|
+
export function mcpInstructions() {
|
|
47
|
+
return [
|
|
48
|
+
`You are connected to "${BRAND.product}", an MCP server for Proxmox VE.`,
|
|
49
|
+
"",
|
|
50
|
+
"CAPABILITIES:",
|
|
51
|
+
"- You can list cluster nodes, QEMU VMs and LXC containers, read their status/config, view storage, tasks and cluster health, and (unless read-only) start/stop/shutdown/reboot guests and create/rollback/delete snapshots.",
|
|
52
|
+
"- A VM/CT is identified by its numeric VMID. Prefer read-only tools to understand state before any action, and confirm destructive actions (stop, rollback_snapshot, delete_snapshot) with the user first — `stop` pulls the virtual power cord, `shutdown` is graceful.",
|
|
53
|
+
"",
|
|
54
|
+
"ABOUT:",
|
|
55
|
+
'- Call the "about" tool if the user asks what this server is, who built it or which version is running.',
|
|
56
|
+
].join("\n");
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=branding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branding.js","sourceRoot":"","sources":["../src/branding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,wCAAwC;AACxC,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IACjC,OAAO,EAAE,oBAAoB;IAC7B,MAAM,EAAE,gBAAgB;IACxB,GAAG,EAAE,qBAAqB;IAC1B,MAAM,EAAE,+CAA+C;IACvD,OAAO,EAAE,6CAA6C;IACtD,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,gDAAgD;AAChD,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;CASrC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,UAAU,YAAY;IAC1B,OAAO;QACL,YAAY;QACZ,KAAK,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE;QACtC,0BAA0B,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,GAAG,EAAE;QACvD,+CAA+C;QAC/C,0BAA0B,KAAK,CAAC,MAAM,EAAE;QACxC,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,yBAAyB,KAAK,CAAC,OAAO,kCAAkC;QACxE,EAAE;QACF,eAAe;QACf,6NAA6N;QAC7N,0QAA0Q;QAC1Q,EAAE;QACF,QAAQ;QACR,yGAAyG;KAC1G,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime configuration.
|
|
3
|
+
*
|
|
4
|
+
* Layered so the server is fully customisable without code changes. Precedence,
|
|
5
|
+
* lowest to highest:
|
|
6
|
+
* 1. Built-in defaults.
|
|
7
|
+
* 2. An optional JSON config file (`proxmox-mcp.config.json`, or the path in
|
|
8
|
+
* `PROXMOX_MCP_CONFIG`).
|
|
9
|
+
* 3. A local `.env` file.
|
|
10
|
+
* 4. Real environment variables (what your MCP client passes).
|
|
11
|
+
*
|
|
12
|
+
* Part of Proxmox MCP Server.
|
|
13
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
14
|
+
* MIT licensed (see LICENSE).
|
|
15
|
+
*/
|
|
16
|
+
/** Supported diagnostic log levels, ordered by verbosity. */
|
|
17
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
18
|
+
/** Plugin enable/disable selection. */
|
|
19
|
+
export interface PluginSelection {
|
|
20
|
+
readonly enabled: readonly string[];
|
|
21
|
+
readonly disabled: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
/** Fully-resolved, immutable server configuration. */
|
|
24
|
+
export interface AppConfig {
|
|
25
|
+
/** Proxmox API base URL, e.g. https://host:8006 (no trailing slash). */
|
|
26
|
+
readonly host: string;
|
|
27
|
+
/** API token id "user@realm!tokenname" (preferred auth). */
|
|
28
|
+
readonly tokenId: string;
|
|
29
|
+
/** API token secret (UUID). */
|
|
30
|
+
readonly tokenSecret: string;
|
|
31
|
+
/** Username "user@realm" for ticket auth (fallback). */
|
|
32
|
+
readonly user: string;
|
|
33
|
+
/** Password for ticket auth (fallback). */
|
|
34
|
+
readonly password: string;
|
|
35
|
+
/** Whether to verify the node's TLS certificate. */
|
|
36
|
+
readonly verifyTls: boolean;
|
|
37
|
+
/** When true, all mutating tools are hidden. */
|
|
38
|
+
readonly readOnly: boolean;
|
|
39
|
+
/** When true, serve fabricated demo data instead of a real cluster. */
|
|
40
|
+
readonly demo: boolean;
|
|
41
|
+
/** Optional VMID/name allowlist (empty = allow all). */
|
|
42
|
+
readonly allowlist: readonly string[];
|
|
43
|
+
/** Diagnostic log level. */
|
|
44
|
+
readonly logLevel: LogLevel;
|
|
45
|
+
/** Modular plugin selection. */
|
|
46
|
+
readonly plugins: PluginSelection;
|
|
47
|
+
/** Optional OpenAI-compatible endpoint powering the TUI's AI copilot. */
|
|
48
|
+
readonly aiEndpoint: string;
|
|
49
|
+
/** API key for the AI endpoint (bearer). */
|
|
50
|
+
readonly aiKey: string;
|
|
51
|
+
/** Model name for the AI endpoint. */
|
|
52
|
+
readonly aiModel: string;
|
|
53
|
+
/** Resilience & compliance (backup verify, patching, DR drills). */
|
|
54
|
+
readonly resilience: ResilienceConfig;
|
|
55
|
+
}
|
|
56
|
+
/** Settings for the resilience & compliance capabilities. */
|
|
57
|
+
export interface ResilienceConfig {
|
|
58
|
+
/** Directory where signed evidence reports are written. */
|
|
59
|
+
readonly dir: string;
|
|
60
|
+
/** Path to the Ed25519 signing key (auto-generated on first use if absent). */
|
|
61
|
+
readonly signingKey: string;
|
|
62
|
+
/** First VMID of the ephemeral range used for backup-verification restores. */
|
|
63
|
+
readonly ephemeralVmidBase: number;
|
|
64
|
+
/** Isolated bridge ephemeral guests are fenced onto (no production traffic). */
|
|
65
|
+
readonly isolatedBridge: string;
|
|
66
|
+
/** Maintenance window for patching, e.g. "Sat 02:00-05:00" (empty = anytime). */
|
|
67
|
+
readonly maintenanceWindow: string;
|
|
68
|
+
}
|
|
69
|
+
/** Build the configuration object. Called once from the entry point. */
|
|
70
|
+
export declare function loadConfig(): AppConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime configuration.
|
|
3
|
+
*
|
|
4
|
+
* Layered so the server is fully customisable without code changes. Precedence,
|
|
5
|
+
* lowest to highest:
|
|
6
|
+
* 1. Built-in defaults.
|
|
7
|
+
* 2. An optional JSON config file (`proxmox-mcp.config.json`, or the path in
|
|
8
|
+
* `PROXMOX_MCP_CONFIG`).
|
|
9
|
+
* 3. A local `.env` file.
|
|
10
|
+
* 4. Real environment variables (what your MCP client passes).
|
|
11
|
+
*
|
|
12
|
+
* Part of Proxmox MCP Server.
|
|
13
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
14
|
+
* MIT licensed (see LICENSE).
|
|
15
|
+
*/
|
|
16
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
17
|
+
import { resolve } from "node:path";
|
|
18
|
+
/** Read and parse the JSON config file, if present. Never throws. */
|
|
19
|
+
function loadConfigFile() {
|
|
20
|
+
const path = resolve(process.cwd(), process.env.PROXMOX_MCP_CONFIG?.trim() || "proxmox-mcp.config.json");
|
|
21
|
+
if (!existsSync(path))
|
|
22
|
+
return {};
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
process.stderr.write(`[proxmox-mcp] Warning: could not parse config file at ${path}; ignoring it.\n`);
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Minimal, dependency-free `.env` loader. Real env always wins. */
|
|
32
|
+
function loadDotEnv() {
|
|
33
|
+
const path = resolve(process.cwd(), ".env");
|
|
34
|
+
if (!existsSync(path))
|
|
35
|
+
return;
|
|
36
|
+
for (const line of readFileSync(path, "utf8").split(/\r?\n/)) {
|
|
37
|
+
const trimmed = line.trim();
|
|
38
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
39
|
+
continue;
|
|
40
|
+
const eq = trimmed.indexOf("=");
|
|
41
|
+
if (eq === -1)
|
|
42
|
+
continue;
|
|
43
|
+
const key = trimmed.slice(0, eq).trim();
|
|
44
|
+
let value = trimmed.slice(eq + 1).trim();
|
|
45
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
46
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
47
|
+
value = value.slice(1, -1);
|
|
48
|
+
}
|
|
49
|
+
if (key && process.env[key] === undefined)
|
|
50
|
+
process.env[key] = value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function envFlag(name, fallback) {
|
|
54
|
+
const value = process.env[name];
|
|
55
|
+
if (value === undefined || value === "")
|
|
56
|
+
return fallback;
|
|
57
|
+
return /^(1|true|yes|on)$/i.test(value.trim());
|
|
58
|
+
}
|
|
59
|
+
function envStr(name, fallback) {
|
|
60
|
+
const value = process.env[name];
|
|
61
|
+
return value === undefined ? fallback : value.trim();
|
|
62
|
+
}
|
|
63
|
+
function envList(name, fallback) {
|
|
64
|
+
const value = process.env[name];
|
|
65
|
+
if (value === undefined)
|
|
66
|
+
return [...fallback];
|
|
67
|
+
return value
|
|
68
|
+
.split(",")
|
|
69
|
+
.map((item) => item.trim())
|
|
70
|
+
.filter(Boolean);
|
|
71
|
+
}
|
|
72
|
+
function envNum(name, fallback) {
|
|
73
|
+
const value = process.env[name];
|
|
74
|
+
if (value === undefined || value.trim() === "")
|
|
75
|
+
return fallback;
|
|
76
|
+
const n = Number(value);
|
|
77
|
+
return Number.isFinite(n) ? n : fallback;
|
|
78
|
+
}
|
|
79
|
+
/** Build the configuration object. Called once from the entry point. */
|
|
80
|
+
export function loadConfig() {
|
|
81
|
+
const file = loadConfigFile();
|
|
82
|
+
loadDotEnv();
|
|
83
|
+
const rawLevel = envStr("PROXMOX_MCP_LOG_LEVEL", file.logLevel ?? "info").toLowerCase();
|
|
84
|
+
const logLevel = ["debug", "info", "warn", "error"].includes(rawLevel)
|
|
85
|
+
? rawLevel
|
|
86
|
+
: "info";
|
|
87
|
+
// Normalise host: ensure scheme, strip trailing slash.
|
|
88
|
+
let host = envStr("PROXMOX_HOST", file.host ?? "");
|
|
89
|
+
if (host && !/^https?:\/\//i.test(host))
|
|
90
|
+
host = `https://${host}`;
|
|
91
|
+
host = host.replace(/\/+$/, "");
|
|
92
|
+
return Object.freeze({
|
|
93
|
+
host,
|
|
94
|
+
tokenId: envStr("PROXMOX_TOKEN_ID", file.tokenId ?? ""),
|
|
95
|
+
tokenSecret: envStr("PROXMOX_TOKEN_SECRET", file.tokenSecret ?? ""),
|
|
96
|
+
user: envStr("PROXMOX_USER", file.user ?? ""),
|
|
97
|
+
password: envStr("PROXMOX_PASSWORD", file.password ?? ""),
|
|
98
|
+
verifyTls: envFlag("PROXMOX_VERIFY_TLS", file.verifyTls ?? false),
|
|
99
|
+
readOnly: envFlag("PROXMOX_MCP_READONLY", file.readOnly ?? false),
|
|
100
|
+
demo: envFlag("PROXMOX_MCP_DEMO", file.demo ?? false),
|
|
101
|
+
allowlist: Object.freeze(envList("PROXMOX_MCP_ALLOWLIST", file.allowlist ?? [])),
|
|
102
|
+
logLevel,
|
|
103
|
+
plugins: Object.freeze({
|
|
104
|
+
enabled: Object.freeze(envList("PROXMOX_MCP_PLUGINS", file.plugins?.enabled ?? [])),
|
|
105
|
+
disabled: Object.freeze(envList("PROXMOX_MCP_DISABLED_PLUGINS", file.plugins?.disabled ?? [])),
|
|
106
|
+
}),
|
|
107
|
+
aiEndpoint: envStr("PROXMOX_MCP_AI_ENDPOINT", file.ai?.endpoint ?? ""),
|
|
108
|
+
aiKey: envStr("PROXMOX_MCP_AI_KEY", file.ai?.key ?? ""),
|
|
109
|
+
aiModel: envStr("PROXMOX_MCP_AI_MODEL", file.ai?.model ?? "gpt-4o-mini"),
|
|
110
|
+
resilience: Object.freeze({
|
|
111
|
+
dir: envStr("PROXMOX_MCP_RESILIENCE_DIR", file.resilience?.dir ?? "resilience-reports"),
|
|
112
|
+
signingKey: envStr("PROXMOX_MCP_SIGNING_KEY", file.resilience?.signingKey ?? ""),
|
|
113
|
+
ephemeralVmidBase: envNum("PROXMOX_MCP_EPHEMERAL_VMID_BASE", file.resilience?.ephemeralVmidBase ?? 90000),
|
|
114
|
+
isolatedBridge: envStr("PROXMOX_MCP_ISOLATED_BRIDGE", file.resilience?.isolatedBridge ?? "vmbr9"),
|
|
115
|
+
maintenanceWindow: envStr("PROXMOX_MCP_MAINT_WINDOW", file.resilience?.maintenanceWindow ?? ""),
|
|
116
|
+
}),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Proxmox MCP Server — entry point.
|
|
4
|
+
*
|
|
5
|
+
* Boots a Model Context Protocol server over stdio that lets any MCP-capable
|
|
6
|
+
* LLM (Claude Desktop, Cursor, Continue, …) manage a Proxmox VE cluster in
|
|
7
|
+
* natural language: list nodes, VMs and containers, read status, control the
|
|
8
|
+
* guest lifecycle and take snapshots — with read-only and allowlist safety.
|
|
9
|
+
*
|
|
10
|
+
* Part of Proxmox MCP Server.
|
|
11
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
12
|
+
* MIT licensed (see LICENSE).
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Proxmox MCP Server — entry point.
|
|
4
|
+
*
|
|
5
|
+
* Boots a Model Context Protocol server over stdio that lets any MCP-capable
|
|
6
|
+
* LLM (Claude Desktop, Cursor, Continue, …) manage a Proxmox VE cluster in
|
|
7
|
+
* natural language: list nodes, VMs and containers, read status, control the
|
|
8
|
+
* guest lifecycle and take snapshots — with read-only and allowlist safety.
|
|
9
|
+
*
|
|
10
|
+
* Part of Proxmox MCP Server.
|
|
11
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
12
|
+
* MIT licensed (see LICENSE).
|
|
13
|
+
*/
|
|
14
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
15
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
16
|
+
import { loadConfig } from "./config.js";
|
|
17
|
+
import { updateNoticeLine } from "./update/notice.js";
|
|
18
|
+
import { Logger } from "./logger.js";
|
|
19
|
+
import { ProxmoxClient } from "./proxmox/client.js";
|
|
20
|
+
import { BUILTIN_PLUGINS, selectPlugins } from "./plugins.js";
|
|
21
|
+
import { ASCII_BANNER, BRAND, mcpInstructions } from "./branding.js";
|
|
22
|
+
const SERVER_NAME = "proxmox-mcp-server";
|
|
23
|
+
const SERVER_VERSION = BRAND.version;
|
|
24
|
+
async function main() {
|
|
25
|
+
const config = loadConfig();
|
|
26
|
+
const logger = new Logger(config.logLevel);
|
|
27
|
+
// Welcome banner → stderr (stdout is the JSON-RPC stream).
|
|
28
|
+
process.stderr.write(`${ASCII_BANNER}\n`);
|
|
29
|
+
process.stderr.write(` ${BRAND.product} v${BRAND.version} — by ${BRAND.author} (${BRAND.url})\n\n`);
|
|
30
|
+
logger.info(`Starting ${SERVER_NAME} v${SERVER_VERSION}`);
|
|
31
|
+
logger.debug("Configuration", {
|
|
32
|
+
host: config.host || "(not configured)",
|
|
33
|
+
auth: config.tokenSecret ? "api-token" : config.password ? "ticket" : "(none)",
|
|
34
|
+
readOnly: config.readOnly,
|
|
35
|
+
allowlist: config.allowlist,
|
|
36
|
+
});
|
|
37
|
+
const proxmox = new ProxmoxClient(config, logger);
|
|
38
|
+
// Fail soft: probe the API but keep starting so tool calls return clean
|
|
39
|
+
// errors inside the chat client instead of a hard crash.
|
|
40
|
+
if (config.demo) {
|
|
41
|
+
logger.info("DEMO mode: serving fabricated cluster data (no real Proxmox needed).");
|
|
42
|
+
}
|
|
43
|
+
else if (config.host && (config.tokenSecret || config.password)) {
|
|
44
|
+
try {
|
|
45
|
+
await proxmox.ping();
|
|
46
|
+
logger.info(`Connected to Proxmox VE at ${config.host}.`);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
logger.error("Could not reach the Proxmox API. Check PROXMOX_HOST, credentials and TLS settings.", error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
logger.warn("Proxmox host/credentials not configured — set them, or try PROXMOX_MCP_DEMO=true.");
|
|
54
|
+
}
|
|
55
|
+
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION }, { instructions: mcpInstructions() });
|
|
56
|
+
// Resolve the modular plugin selection and register each enabled plugin.
|
|
57
|
+
const selected = selectPlugins(config, logger);
|
|
58
|
+
const enabledNames = new Set(selected.map((p) => p.name));
|
|
59
|
+
const pluginInfo = BUILTIN_PLUGINS.map((p) => ({
|
|
60
|
+
name: p.name,
|
|
61
|
+
title: p.title,
|
|
62
|
+
category: p.category,
|
|
63
|
+
mutating: p.mutating,
|
|
64
|
+
enabled: enabledNames.has(p.name),
|
|
65
|
+
}));
|
|
66
|
+
const context = { server, proxmox, config, logger, plugins: pluginInfo };
|
|
67
|
+
for (const plugin of selected)
|
|
68
|
+
plugin.register(context);
|
|
69
|
+
logger.info(config.readOnly
|
|
70
|
+
? "Tools registered in READ-ONLY mode."
|
|
71
|
+
: "Tools registered in full read/write mode.");
|
|
72
|
+
const transport = new StdioServerTransport();
|
|
73
|
+
await server.connect(transport);
|
|
74
|
+
logger.info("MCP server is ready and listening on stdio.");
|
|
75
|
+
// Non-blocking: note if a newer version is available (logs to stderr only).
|
|
76
|
+
void updateNoticeLine().then((line) => { if (line)
|
|
77
|
+
logger.info(line); }).catch(() => { });
|
|
78
|
+
const shutdown = (signal) => {
|
|
79
|
+
logger.info(`Received ${signal}, shutting down.`);
|
|
80
|
+
void server.close().finally(() => process.exit(0));
|
|
81
|
+
};
|
|
82
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
83
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
84
|
+
}
|
|
85
|
+
main().catch((error) => {
|
|
86
|
+
process.stderr.write(`Fatal: ${error instanceof Error ? error.stack : error}\n`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny structured logger.
|
|
3
|
+
*
|
|
4
|
+
* An MCP stdio server talks to its client over STDOUT, so every diagnostic
|
|
5
|
+
* line goes to STDERR only — anything else corrupts the JSON-RPC stream.
|
|
6
|
+
*
|
|
7
|
+
* Part of Proxmox MCP Server.
|
|
8
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
9
|
+
* MIT licensed (see LICENSE).
|
|
10
|
+
*/
|
|
11
|
+
import type { LogLevel } from "./config.js";
|
|
12
|
+
/** A namespaced logger that writes human-readable lines to stderr. */
|
|
13
|
+
export declare class Logger {
|
|
14
|
+
private readonly threshold;
|
|
15
|
+
private readonly scope;
|
|
16
|
+
constructor(threshold: LogLevel, scope?: string);
|
|
17
|
+
child(scope: string): Logger;
|
|
18
|
+
debug(message: string, meta?: unknown): void;
|
|
19
|
+
info(message: string, meta?: unknown): void;
|
|
20
|
+
warn(message: string, meta?: unknown): void;
|
|
21
|
+
error(message: string, meta?: unknown): void;
|
|
22
|
+
private write;
|
|
23
|
+
}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny structured logger.
|
|
3
|
+
*
|
|
4
|
+
* An MCP stdio server talks to its client over STDOUT, so every diagnostic
|
|
5
|
+
* line goes to STDERR only — anything else corrupts the JSON-RPC stream.
|
|
6
|
+
*
|
|
7
|
+
* Part of Proxmox MCP Server.
|
|
8
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
9
|
+
* MIT licensed (see LICENSE).
|
|
10
|
+
*/
|
|
11
|
+
const LEVEL_WEIGHT = {
|
|
12
|
+
debug: 10,
|
|
13
|
+
info: 20,
|
|
14
|
+
warn: 30,
|
|
15
|
+
error: 40,
|
|
16
|
+
};
|
|
17
|
+
/** A namespaced logger that writes human-readable lines to stderr. */
|
|
18
|
+
export class Logger {
|
|
19
|
+
threshold;
|
|
20
|
+
scope;
|
|
21
|
+
constructor(threshold, scope = "proxmox-mcp") {
|
|
22
|
+
this.threshold = threshold;
|
|
23
|
+
this.scope = scope;
|
|
24
|
+
}
|
|
25
|
+
child(scope) {
|
|
26
|
+
return new Logger(this.threshold, `${this.scope}:${scope}`);
|
|
27
|
+
}
|
|
28
|
+
debug(message, meta) {
|
|
29
|
+
this.write("debug", message, meta);
|
|
30
|
+
}
|
|
31
|
+
info(message, meta) {
|
|
32
|
+
this.write("info", message, meta);
|
|
33
|
+
}
|
|
34
|
+
warn(message, meta) {
|
|
35
|
+
this.write("warn", message, meta);
|
|
36
|
+
}
|
|
37
|
+
error(message, meta) {
|
|
38
|
+
this.write("error", message, meta);
|
|
39
|
+
}
|
|
40
|
+
write(level, message, meta) {
|
|
41
|
+
if (LEVEL_WEIGHT[level] < LEVEL_WEIGHT[this.threshold])
|
|
42
|
+
return;
|
|
43
|
+
const timestamp = new Date().toISOString();
|
|
44
|
+
const tag = level.toUpperCase().padEnd(5);
|
|
45
|
+
let line = `${timestamp} ${tag} [${this.scope}] ${message}`;
|
|
46
|
+
if (meta !== undefined) {
|
|
47
|
+
const rendered = meta instanceof Error
|
|
48
|
+
? meta.stack ?? meta.message
|
|
49
|
+
: typeof meta === "string"
|
|
50
|
+
? meta
|
|
51
|
+
: safeJson(meta);
|
|
52
|
+
line += ` ${rendered}`;
|
|
53
|
+
}
|
|
54
|
+
process.stderr.write(`${line}\n`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function safeJson(value) {
|
|
58
|
+
try {
|
|
59
|
+
return JSON.stringify(value);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return String(value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,YAAY,GAA6B;IAC7C,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;CACV,CAAC;AAEF,sEAAsE;AACtE,MAAM,OAAO,MAAM;IAEE;IACA;IAFnB,YACmB,SAAmB,EACnB,QAAQ,aAAa;QADrB,cAAS,GAAT,SAAS,CAAU;QACnB,UAAK,GAAL,KAAK,CAAgB;IACrC,CAAC;IAEJ,KAAK,CAAC,KAAa;QACjB,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAAc;QACnC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,CAAC,OAAe,EAAE,IAAc;QAClC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,IAAI,CAAC,OAAe,EAAE,IAAc;QAClC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,KAAK,CAAC,OAAe,EAAE,IAAc;QACnC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAEO,KAAK,CAAC,KAAe,EAAE,OAAe,EAAE,IAAc;QAC5D,IAAI,YAAY,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;YAAE,OAAO;QAC/D,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,IAAI,GAAG,GAAG,SAAS,IAAI,GAAG,KAAK,IAAI,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;QAC5D,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,QAAQ,GACZ,IAAI,YAAY,KAAK;gBACnB,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO;gBAC5B,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ;oBACxB,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,IAAI,IAAI,QAAQ,EAAE,CAAC;QACzB,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IACpC,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin registry & loader.
|
|
3
|
+
*
|
|
4
|
+
* The server is built as a set of independent *plugins*, each owning one
|
|
5
|
+
* capability group. Which plugins load is fully driven by configuration.
|
|
6
|
+
*
|
|
7
|
+
* The `about` plugin is NON-DISABLEABLE: it carries the SoyRage Agency identity
|
|
8
|
+
* and attribution, which the license requires to stay present.
|
|
9
|
+
*
|
|
10
|
+
* Part of Proxmox MCP Server.
|
|
11
|
+
* Crafted by SoyRage Agency — https://soyrage.es/
|
|
12
|
+
* MIT licensed (see LICENSE).
|
|
13
|
+
*/
|
|
14
|
+
import type { AppConfig } from "./config.js";
|
|
15
|
+
import type { Logger } from "./logger.js";
|
|
16
|
+
import type { ToolContext } from "./tools/context.js";
|
|
17
|
+
/** High-level grouping used for docs. */
|
|
18
|
+
export type PluginCategory = "identity" | "nodes" | "guests" | "storage" | "tasks" | "cluster" | "snapshots" | "lifecycle" | "management" | "backups" | "provisioning" | "resilience";
|
|
19
|
+
/** A self-contained capability group that can be toggled on or off. */
|
|
20
|
+
export interface ToolPlugin {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly title: string;
|
|
23
|
+
readonly description: string;
|
|
24
|
+
readonly category: PluginCategory;
|
|
25
|
+
readonly mutating: boolean;
|
|
26
|
+
readonly locked?: boolean;
|
|
27
|
+
readonly register: (ctx: ToolContext) => void;
|
|
28
|
+
}
|
|
29
|
+
/** The built-in plugin catalogue. */
|
|
30
|
+
export declare const BUILTIN_PLUGINS: readonly ToolPlugin[];
|
|
31
|
+
/** Resolve which plugins should load, applying the enable/disable selection. */
|
|
32
|
+
export declare function selectPlugins(config: AppConfig, logger: Logger, catalogue?: readonly ToolPlugin[]): ToolPlugin[];
|