@veertu/anka-mcp 0.1.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 +324 -0
- package/dist/anka.d.ts +41 -0
- package/dist/anka.js +65 -0
- package/dist/anka.js.map +1 -0
- package/dist/auth.d.ts +10 -0
- package/dist/auth.js +43 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +69 -0
- package/dist/config.js +98 -0
- package/dist/config.js.map +1 -0
- package/dist/controller.d.ts +73 -0
- package/dist/controller.js +125 -0
- package/dist/controller.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts +107 -0
- package/dist/log.js +254 -0
- package/dist/log.js.map +1 -0
- package/dist/security/host.d.ts +2 -0
- package/dist/security/host.js +9 -0
- package/dist/security/host.js.map +1 -0
- package/dist/security/rate-limit.d.ts +18 -0
- package/dist/security/rate-limit.js +71 -0
- package/dist/security/rate-limit.js.map +1 -0
- package/dist/security/sanitize.d.ts +6 -0
- package/dist/security/sanitize.js +33 -0
- package/dist/security/sanitize.js.map +1 -0
- package/dist/security/schemas.d.ts +9 -0
- package/dist/security/schemas.js +20 -0
- package/dist/security/schemas.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +13 -0
- package/dist/server.js.map +1 -0
- package/dist/ssh-key.d.ts +23 -0
- package/dist/ssh-key.js +73 -0
- package/dist/ssh-key.js.map +1 -0
- package/dist/tokens/cleanup.d.ts +10 -0
- package/dist/tokens/cleanup.js +28 -0
- package/dist/tokens/cleanup.js.map +1 -0
- package/dist/tokens/ownership.d.ts +6 -0
- package/dist/tokens/ownership.js +31 -0
- package/dist/tokens/ownership.js.map +1 -0
- package/dist/tokens/schema.d.ts +3 -0
- package/dist/tokens/schema.js +35 -0
- package/dist/tokens/schema.js.map +1 -0
- package/dist/tokens/store.d.ts +45 -0
- package/dist/tokens/store.js +145 -0
- package/dist/tokens/store.js.map +1 -0
- package/dist/tools/controller/get-vm.d.ts +3 -0
- package/dist/tools/controller/get-vm.js +34 -0
- package/dist/tools/controller/get-vm.js.map +1 -0
- package/dist/tools/controller/index.d.ts +3 -0
- package/dist/tools/controller/index.js +12 -0
- package/dist/tools/controller/index.js.map +1 -0
- package/dist/tools/controller/list-templates.d.ts +1 -0
- package/dist/tools/controller/list-templates.js +21 -0
- package/dist/tools/controller/list-templates.js.map +1 -0
- package/dist/tools/controller/request-vm.d.ts +8 -0
- package/dist/tools/controller/request-vm.js +101 -0
- package/dist/tools/controller/request-vm.js.map +1 -0
- package/dist/tools/controller/results.d.ts +5 -0
- package/dist/tools/controller/results.js +23 -0
- package/dist/tools/controller/results.js.map +1 -0
- package/dist/tools/controller/terminate-vm.d.ts +3 -0
- package/dist/tools/controller/terminate-vm.js +32 -0
- package/dist/tools/controller/terminate-vm.js.map +1 -0
- package/dist/tools/define-tool.d.ts +34 -0
- package/dist/tools/define-tool.js +51 -0
- package/dist/tools/define-tool.js.map +1 -0
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.js +20 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/local/delete-vm.d.ts +3 -0
- package/dist/tools/local/delete-vm.js +20 -0
- package/dist/tools/local/delete-vm.js.map +1 -0
- package/dist/tools/local/index.d.ts +3 -0
- package/dist/tools/local/index.js +14 -0
- package/dist/tools/local/index.js.map +1 -0
- package/dist/tools/local/list-templates.d.ts +1 -0
- package/dist/tools/local/list-templates.js +17 -0
- package/dist/tools/local/list-templates.js.map +1 -0
- package/dist/tools/local/show-vm.d.ts +3 -0
- package/dist/tools/local/show-vm.js +23 -0
- package/dist/tools/local/show-vm.js.map +1 -0
- package/dist/tools/local/ssh-access.d.ts +3 -0
- package/dist/tools/local/ssh-access.js +68 -0
- package/dist/tools/local/ssh-access.js.map +1 -0
- package/dist/tools/local/start-vm.d.ts +7 -0
- package/dist/tools/local/start-vm.js +52 -0
- package/dist/tools/local/start-vm.js.map +1 -0
- package/dist/tools/local/vms.d.ts +62 -0
- package/dist/tools/local/vms.js +91 -0
- package/dist/tools/local/vms.js.map +1 -0
- package/dist/transports/admin.d.ts +3 -0
- package/dist/transports/admin.js +74 -0
- package/dist/transports/admin.js.map +1 -0
- package/dist/transports/http.d.ts +14 -0
- package/dist/transports/http.js +283 -0
- package/dist/transports/http.js.map +1 -0
- package/package.json +46 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
function parseIntEnv(value, fallback) {
|
|
3
|
+
if (!value)
|
|
4
|
+
return fallback;
|
|
5
|
+
const parsed = Number.parseInt(value, 10);
|
|
6
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
7
|
+
}
|
|
8
|
+
function parsePositiveIntEnv(value, fallback) {
|
|
9
|
+
const parsed = parseIntEnv(value, fallback);
|
|
10
|
+
return parsed > 0 ? parsed : fallback;
|
|
11
|
+
}
|
|
12
|
+
function parseNonNegativeIntEnv(value, fallback) {
|
|
13
|
+
const parsed = parseIntEnv(value, fallback);
|
|
14
|
+
return parsed >= 0 ? parsed : fallback;
|
|
15
|
+
}
|
|
16
|
+
function parseBoolEnv(value) {
|
|
17
|
+
if (!value)
|
|
18
|
+
return false;
|
|
19
|
+
return ["1", "true", "yes", "on"].includes(value.trim().toLowerCase());
|
|
20
|
+
}
|
|
21
|
+
function parseListEnv(value) {
|
|
22
|
+
if (!value)
|
|
23
|
+
return [];
|
|
24
|
+
return value
|
|
25
|
+
.split(",")
|
|
26
|
+
.map((item) => item.trim())
|
|
27
|
+
.filter((item) => item.length > 0);
|
|
28
|
+
}
|
|
29
|
+
function stripTrailingSlash(value) {
|
|
30
|
+
return value.replace(/\/+$/, "");
|
|
31
|
+
}
|
|
32
|
+
/** Detect whether the local anka CLI is usable by invoking `<bin> --version`. */
|
|
33
|
+
function detectLocalAnka(bin) {
|
|
34
|
+
try {
|
|
35
|
+
execFileSync(bin, ["--version"], { stdio: "ignore", timeout: 5000 });
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve whether the local backend is enabled. `ANKA_LOCAL` may be
|
|
44
|
+
* `auto` (detect the binary), `on`, or `off`. When unset, `defaultMode`
|
|
45
|
+
* applies (`off` when a controller URL is configured, otherwise `auto`).
|
|
46
|
+
*/
|
|
47
|
+
function resolveLocalEnabled(value, bin, defaultMode = "auto") {
|
|
48
|
+
const mode = value?.trim().toLowerCase() || defaultMode;
|
|
49
|
+
if (mode === "on" || parseBoolEnv(mode))
|
|
50
|
+
return true;
|
|
51
|
+
if (mode === "off" || ["0", "false", "no"].includes(mode))
|
|
52
|
+
return false;
|
|
53
|
+
return detectLocalAnka(bin);
|
|
54
|
+
}
|
|
55
|
+
/** Build the runtime config from environment variables (read once at startup). */
|
|
56
|
+
export function loadConfig(env = process.env) {
|
|
57
|
+
const ankaBin = env.ANKA_BIN?.trim() || "anka";
|
|
58
|
+
const controllerUrl = stripTrailingSlash(env.ANKA_CONTROLLER_URL?.trim() || "");
|
|
59
|
+
const controllerEnabled = controllerUrl.length > 0;
|
|
60
|
+
const defaultLocalMode = controllerEnabled ? "off" : "auto";
|
|
61
|
+
return {
|
|
62
|
+
httpPort: parsePositiveIntEnv(env.MCP_HTTP_PORT, 9111),
|
|
63
|
+
httpHost: env.MCP_HTTP_HOST?.trim() || "127.0.0.1",
|
|
64
|
+
authToken: env.MCP_AUTH_TOKEN?.trim() || "",
|
|
65
|
+
adminToken: env.MCP_ADMIN_TOKEN?.trim() || "",
|
|
66
|
+
dbPath: env.MCP_DB_PATH?.trim() || "./anka-mcp.db",
|
|
67
|
+
revokeCleanupEnabled: !["0", "false", "no", "off"].includes(env.MCP_REVOKE_CLEANUP?.trim().toLowerCase() ?? ""),
|
|
68
|
+
allowNoAuth: parseBoolEnv(env.MCP_ALLOW_NO_AUTH),
|
|
69
|
+
allowedOrigins: parseListEnv(env.MCP_ALLOWED_ORIGINS),
|
|
70
|
+
logEnabled: !["0", "false", "no", "off"].includes(env.MCP_LOG?.trim().toLowerCase() ?? ""),
|
|
71
|
+
auditLogPath: env.MCP_AUDIT_LOG?.trim() || "",
|
|
72
|
+
maxBodyBytes: parsePositiveIntEnv(env.MCP_MAX_BODY_BYTES, 1_048_576),
|
|
73
|
+
rateLimitRpm: parseNonNegativeIntEnv(env.MCP_RATE_LIMIT_RPM, 120),
|
|
74
|
+
sessionIdleMs: parsePositiveIntEnv(env.MCP_SESSION_IDLE_MS, 3_600_000),
|
|
75
|
+
maxSessions: parsePositiveIntEnv(env.MCP_MAX_SESSIONS, 50),
|
|
76
|
+
maxResponseChars: parsePositiveIntEnv(env.MCP_MAX_RESPONSE_CHARS, 32_768),
|
|
77
|
+
localEnabled: resolveLocalEnabled(env.ANKA_LOCAL, ankaBin, defaultLocalMode),
|
|
78
|
+
ankaBin,
|
|
79
|
+
ankaTimeoutMs: parsePositiveIntEnv(env.ANKA_TIMEOUT_MS, 300_000),
|
|
80
|
+
localMaxVms: parseNonNegativeIntEnv(env.ANKA_LOCAL_MAX_VMS, 2),
|
|
81
|
+
localPollIntervalMs: parsePositiveIntEnv(env.ANKA_LOCAL_POLL_INTERVAL_MS, 2000),
|
|
82
|
+
localIpTimeoutMs: parsePositiveIntEnv(env.ANKA_LOCAL_IP_TIMEOUT_MS, 120_000),
|
|
83
|
+
controllerEnabled,
|
|
84
|
+
controllerUrl,
|
|
85
|
+
controllerAuth: env.ANKA_CONTROLLER_AUTH?.trim() || "",
|
|
86
|
+
controllerTlsInsecure: parseBoolEnv(env.ANKA_CONTROLLER_TLS_INSECURE),
|
|
87
|
+
controllerPollIntervalMs: parsePositiveIntEnv(env.ANKA_CONTROLLER_POLL_INTERVAL_MS, 3000),
|
|
88
|
+
controllerStartTimeoutMs: parsePositiveIntEnv(env.ANKA_CONTROLLER_START_TIMEOUT_MS, 180_000),
|
|
89
|
+
controllerSshProbeEnabled: !["0", "false", "no", "off"].includes(env.ANKA_CONTROLLER_SSH_PROBE?.trim().toLowerCase() ?? ""),
|
|
90
|
+
vmSshUser: env.ANKA_VM_SSH_USER?.trim() || "anka",
|
|
91
|
+
vmSshPassword: env.ANKA_VM_SSH_PASSWORD ?? "admin",
|
|
92
|
+
vmSshGuestPort: parsePositiveIntEnv(env.ANKA_VM_SSH_GUEST_PORT, 22),
|
|
93
|
+
serverName: "anka-mcp",
|
|
94
|
+
serverVersion: "0.1.0"
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export const config = loadConfig();
|
|
98
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA8ElD,SAAS,WAAW,CAAC,KAAyB,EAAE,QAAgB;IAC9D,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAC5B,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AACrD,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAyB,EAAE,QAAgB;IACtE,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC5C,OAAO,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AACxC,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAyB,EAAE,QAAgB;IACzE,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC5C,OAAO,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AACzC,CAAC;AAED,SAAS,YAAY,CAAC,KAAyB;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,YAAY,CAAC,KAAyB;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,iFAAiF;AACjF,SAAS,eAAe,CAAC,GAAW;IAClC,IAAI,CAAC;QACH,YAAY,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACrE,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,mBAAmB,CAC1B,KAAyB,EACzB,GAAW,EACX,cAA8B,MAAM;IAEpC,MAAM,IAAI,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,WAAW,CAAC;IACxD,IAAI,IAAI,KAAK,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACrD,IAAI,IAAI,KAAK,KAAK,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACxE,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC;IAC/C,MAAM,aAAa,GAAG,kBAAkB,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,MAAM,iBAAiB,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;IACnD,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAE5D,OAAO;QACL,QAAQ,EAAE,mBAAmB,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC;QACtD,QAAQ,EAAE,GAAG,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,WAAW;QAClD,SAAS,EAAE,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE;QAC3C,UAAU,EAAE,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,IAAI,EAAE;QAC7C,MAAM,EAAE,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,eAAe;QAClD,oBAAoB,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,QAAQ,CACzD,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,CACnD;QACD,WAAW,EAAE,YAAY,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAChD,cAAc,EAAE,YAAY,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACrD,UAAU,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC;QAC1F,YAAY,EAAE,GAAG,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE;QAC7C,YAAY,EAAE,mBAAmB,CAAC,GAAG,CAAC,kBAAkB,EAAE,SAAS,CAAC;QACpE,YAAY,EAAE,sBAAsB,CAAC,GAAG,CAAC,kBAAkB,EAAE,GAAG,CAAC;QACjE,aAAa,EAAE,mBAAmB,CAAC,GAAG,CAAC,mBAAmB,EAAE,SAAS,CAAC;QACtE,WAAW,EAAE,mBAAmB,CAAC,GAAG,CAAC,gBAAgB,EAAE,EAAE,CAAC;QAC1D,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC;QAEzE,YAAY,EAAE,mBAAmB,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,gBAAgB,CAAC;QAC5E,OAAO;QACP,aAAa,EAAE,mBAAmB,CAAC,GAAG,CAAC,eAAe,EAAE,OAAO,CAAC;QAChE,WAAW,EAAE,sBAAsB,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,CAAC;QAC9D,mBAAmB,EAAE,mBAAmB,CAAC,GAAG,CAAC,2BAA2B,EAAE,IAAI,CAAC;QAC/E,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC;QAE5E,iBAAiB;QACjB,aAAa;QACb,cAAc,EAAE,GAAG,CAAC,oBAAoB,EAAE,IAAI,EAAE,IAAI,EAAE;QACtD,qBAAqB,EAAE,YAAY,CAAC,GAAG,CAAC,4BAA4B,CAAC;QACrE,wBAAwB,EAAE,mBAAmB,CAAC,GAAG,CAAC,gCAAgC,EAAE,IAAI,CAAC;QACzF,wBAAwB,EAAE,mBAAmB,CAAC,GAAG,CAAC,gCAAgC,EAAE,OAAO,CAAC;QAC5F,yBAAyB,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,QAAQ,CAC9D,GAAG,CAAC,yBAAyB,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,CAC1D;QAED,SAAS,EAAE,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,MAAM;QACjD,aAAa,EAAE,GAAG,CAAC,oBAAoB,IAAI,OAAO;QAClD,cAAc,EAAE,mBAAmB,CAAC,GAAG,CAAC,sBAAsB,EAAE,EAAE,CAAC;QAEnE,UAAU,EAAE,UAAU;QACtB,aAAa,EAAE,OAAO;KACvB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export interface PortForwardingRule {
|
|
2
|
+
guest_port: number;
|
|
3
|
+
host_port?: number;
|
|
4
|
+
protocol?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
}
|
|
7
|
+
/** Subset of the `vminfo` object we rely on (other fields are passed through). */
|
|
8
|
+
export interface VmInfo {
|
|
9
|
+
uuid?: string;
|
|
10
|
+
name?: string;
|
|
11
|
+
status?: string;
|
|
12
|
+
host_ip?: string;
|
|
13
|
+
ip?: string;
|
|
14
|
+
vnc_port?: number;
|
|
15
|
+
port_forwarding?: PortForwardingRule[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
/** A controller VM instance as returned by GET /api/v1/vm?id=. */
|
|
19
|
+
export interface Instance {
|
|
20
|
+
instance_id?: string;
|
|
21
|
+
instance_state?: string;
|
|
22
|
+
vmid?: string;
|
|
23
|
+
tag?: string;
|
|
24
|
+
vminfo?: VmInfo;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
export interface RegistryTemplate {
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
arch?: string;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
}
|
|
33
|
+
export interface SshEndpoint {
|
|
34
|
+
host: string;
|
|
35
|
+
port: number;
|
|
36
|
+
username: string;
|
|
37
|
+
}
|
|
38
|
+
export interface StartVmRequest {
|
|
39
|
+
vmid: string;
|
|
40
|
+
tag?: string;
|
|
41
|
+
name?: string;
|
|
42
|
+
externalId?: string;
|
|
43
|
+
/** When true, attach an SSH port-forward rule even if the template lacks one. */
|
|
44
|
+
addSshPortForward?: boolean;
|
|
45
|
+
/** Base64-encoded startup script (controller `startup_script` field). */
|
|
46
|
+
startupScript?: string;
|
|
47
|
+
}
|
|
48
|
+
/** Raised when the controller responds with a non-OK status or a transport error. */
|
|
49
|
+
export declare class ControllerError extends Error {
|
|
50
|
+
}
|
|
51
|
+
export declare class ControllerClient {
|
|
52
|
+
private readonly baseUrl;
|
|
53
|
+
private readonly authHeader;
|
|
54
|
+
constructor(baseUrl?: string, authHeader?: string);
|
|
55
|
+
private request;
|
|
56
|
+
/** List registry templates so a caller can find the vmid/tag to start from. */
|
|
57
|
+
listTemplates(): Promise<RegistryTemplate[]>;
|
|
58
|
+
/** Start a single VM instance from a template; returns the new instance id. */
|
|
59
|
+
startVm(req: StartVmRequest): Promise<string>;
|
|
60
|
+
/** Fetch a single instance's full record. */
|
|
61
|
+
getVm(instanceId: string): Promise<Instance>;
|
|
62
|
+
/** Terminate a running instance. */
|
|
63
|
+
terminateVm(instanceId: string): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Pull SSH endpoint details out of a vminfo object: forwarded host port for the
|
|
67
|
+
* SSH guest port plus the configured username. Returns undefined when the VM is
|
|
68
|
+
* not yet reachable over SSH.
|
|
69
|
+
*/
|
|
70
|
+
export declare function extractSshEndpoint(vminfo: VmInfo | undefined): SshEndpoint | undefined;
|
|
71
|
+
/** True once the controller reports a started VM with a forwarded SSH port. */
|
|
72
|
+
export declare function isSshReady(instance: Instance): boolean;
|
|
73
|
+
export declare const controller: ControllerClient;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { config } from "./config.js";
|
|
2
|
+
import { logControllerRequest } from "./log.js";
|
|
3
|
+
/** Raised when the controller responds with a non-OK status or a transport error. */
|
|
4
|
+
export class ControllerError extends Error {
|
|
5
|
+
}
|
|
6
|
+
export class ControllerClient {
|
|
7
|
+
baseUrl;
|
|
8
|
+
authHeader;
|
|
9
|
+
constructor(baseUrl = config.controllerUrl, authHeader = config.controllerAuth) {
|
|
10
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
11
|
+
this.authHeader = authHeader;
|
|
12
|
+
// Global fetch (undici) has no per-request TLS toggle; opt out process-wide.
|
|
13
|
+
if (config.controllerTlsInsecure) {
|
|
14
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async request(method, path, body) {
|
|
18
|
+
const headers = { "Content-Type": "application/json" };
|
|
19
|
+
if (this.authHeader)
|
|
20
|
+
headers.Authorization = this.authHeader;
|
|
21
|
+
let response;
|
|
22
|
+
try {
|
|
23
|
+
response = await fetch(`${this.baseUrl}${path}`, {
|
|
24
|
+
method,
|
|
25
|
+
headers,
|
|
26
|
+
body: body === undefined ? undefined : JSON.stringify(body)
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const detail = String(error);
|
|
31
|
+
logControllerRequest(method, path, { ok: false, detail });
|
|
32
|
+
throw new ControllerError(`Failed to reach controller at ${this.baseUrl}: ${detail}`);
|
|
33
|
+
}
|
|
34
|
+
const text = await response.text();
|
|
35
|
+
let envelope;
|
|
36
|
+
if (text.trim()) {
|
|
37
|
+
try {
|
|
38
|
+
envelope = JSON.parse(text);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Fall through to the HTTP-status check below.
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const detail = envelope?.message || text || `HTTP ${response.status}`;
|
|
46
|
+
logControllerRequest(method, path, { ok: false, detail });
|
|
47
|
+
throw new ControllerError(`Controller request failed (${method} ${path}): ${detail}`);
|
|
48
|
+
}
|
|
49
|
+
if (envelope && envelope.status && envelope.status !== "OK") {
|
|
50
|
+
const detail = envelope.message || envelope.status;
|
|
51
|
+
logControllerRequest(method, path, { ok: false, detail });
|
|
52
|
+
throw new ControllerError(`Controller request failed (${method} ${path}): ${detail}`);
|
|
53
|
+
}
|
|
54
|
+
logControllerRequest(method, path, { ok: true });
|
|
55
|
+
return (envelope ? envelope.body : undefined);
|
|
56
|
+
}
|
|
57
|
+
/** List registry templates so a caller can find the vmid/tag to start from. */
|
|
58
|
+
async listTemplates() {
|
|
59
|
+
const body = await this.request("GET", "/api/v1/registry/vm");
|
|
60
|
+
return body ?? [];
|
|
61
|
+
}
|
|
62
|
+
/** Start a single VM instance from a template; returns the new instance id. */
|
|
63
|
+
async startVm(req) {
|
|
64
|
+
const payload = { vmid: req.vmid, count: 1 };
|
|
65
|
+
if (req.tag)
|
|
66
|
+
payload.tag = req.tag;
|
|
67
|
+
if (req.name)
|
|
68
|
+
payload.name = req.name;
|
|
69
|
+
if (req.externalId)
|
|
70
|
+
payload.external_id = req.externalId;
|
|
71
|
+
if (req.addSshPortForward) {
|
|
72
|
+
payload.port_forwarding_override = [
|
|
73
|
+
{ name: "ssh", guest_port: String(config.vmSshGuestPort) }
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
if (req.startupScript) {
|
|
77
|
+
payload.startup_script = req.startupScript;
|
|
78
|
+
// 1 = run immediately (before networking); installs the SSH key as early as possible.
|
|
79
|
+
payload.startup_script_condition = 1;
|
|
80
|
+
}
|
|
81
|
+
const body = await this.request("POST", "/api/v1/vm", payload);
|
|
82
|
+
const instanceId = body?.[0];
|
|
83
|
+
if (!instanceId) {
|
|
84
|
+
throw new ControllerError("Controller did not return an instance id for the started VM");
|
|
85
|
+
}
|
|
86
|
+
return instanceId;
|
|
87
|
+
}
|
|
88
|
+
/** Fetch a single instance's full record. */
|
|
89
|
+
async getVm(instanceId) {
|
|
90
|
+
const body = await this.request("GET", `/api/v1/vm?id=${encodeURIComponent(instanceId)}`);
|
|
91
|
+
if (!body) {
|
|
92
|
+
throw new ControllerError(`Instance ${instanceId} not found`);
|
|
93
|
+
}
|
|
94
|
+
return body;
|
|
95
|
+
}
|
|
96
|
+
/** Terminate a running instance. */
|
|
97
|
+
async terminateVm(instanceId) {
|
|
98
|
+
await this.request("DELETE", "/api/v1/vm", { id: instanceId });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Pull SSH endpoint details out of a vminfo object: forwarded host port for the
|
|
103
|
+
* SSH guest port plus the configured username. Returns undefined when the VM is
|
|
104
|
+
* not yet reachable over SSH.
|
|
105
|
+
*/
|
|
106
|
+
export function extractSshEndpoint(vminfo) {
|
|
107
|
+
if (!vminfo?.host_ip)
|
|
108
|
+
return undefined;
|
|
109
|
+
const rule = vminfo.port_forwarding?.find((entry) => entry.guest_port === config.vmSshGuestPort && entry.host_port);
|
|
110
|
+
if (!rule?.host_port)
|
|
111
|
+
return undefined;
|
|
112
|
+
return {
|
|
113
|
+
host: vminfo.host_ip,
|
|
114
|
+
port: rule.host_port,
|
|
115
|
+
username: config.vmSshUser
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** True once the controller reports a started VM with a forwarded SSH port. */
|
|
119
|
+
export function isSshReady(instance) {
|
|
120
|
+
return (instance.instance_state === "Started" &&
|
|
121
|
+
instance.vminfo?.status === "running" &&
|
|
122
|
+
extractSshEndpoint(instance.vminfo) !== undefined);
|
|
123
|
+
}
|
|
124
|
+
export const controller = new ControllerClient();
|
|
125
|
+
//# sourceMappingURL=controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/log.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export interface McpClientInfo {
|
|
3
|
+
name?: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface RequestContext {
|
|
7
|
+
/** Compact label for logs: IP plus optional user-agent. */
|
|
8
|
+
source: string;
|
|
9
|
+
ip: string;
|
|
10
|
+
userAgent?: string;
|
|
11
|
+
sessionId?: string;
|
|
12
|
+
mcpClientName?: string;
|
|
13
|
+
mcpClientVersion?: string;
|
|
14
|
+
credentialId?: string;
|
|
15
|
+
credentialLabel?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Log an auth failure (always written when logging is enabled). */
|
|
18
|
+
export declare function logAuthFailure(source: string, route: string, reason?: string): void;
|
|
19
|
+
/** Identifies who triggered a limit or security event in logs. */
|
|
20
|
+
export interface LimitActor {
|
|
21
|
+
source?: string;
|
|
22
|
+
ip?: string;
|
|
23
|
+
credentialId?: string;
|
|
24
|
+
credentialLabel?: string;
|
|
25
|
+
}
|
|
26
|
+
/** Build actor fields from an Express request (includes credential when auth ran). */
|
|
27
|
+
export declare function limitActorFromRequest(req: {
|
|
28
|
+
ip?: string;
|
|
29
|
+
socket: {
|
|
30
|
+
remoteAddress?: string | null;
|
|
31
|
+
};
|
|
32
|
+
headers: Record<string, string | string[] | undefined>;
|
|
33
|
+
mcpCredential?: {
|
|
34
|
+
credentialId: string;
|
|
35
|
+
credentialLabel?: string;
|
|
36
|
+
};
|
|
37
|
+
}): LimitActor;
|
|
38
|
+
/** Build actor fields from the current async request context. */
|
|
39
|
+
export declare function limitActorFromContext(): LimitActor;
|
|
40
|
+
/**
|
|
41
|
+
* Log that a configured limit was hit. Format:
|
|
42
|
+
* `LIMIT REACHED MCP_RATE_LIMIT_RPM=120 by source=… credential_id=… route=/mcp …`
|
|
43
|
+
*/
|
|
44
|
+
export declare function logLimitReached(opts: {
|
|
45
|
+
limit: string;
|
|
46
|
+
configured: string;
|
|
47
|
+
route?: string;
|
|
48
|
+
actor?: LimitActor;
|
|
49
|
+
detail?: string;
|
|
50
|
+
}): void;
|
|
51
|
+
/** Log MCP session lifecycle events. */
|
|
52
|
+
export declare function logSessionEvent(event: "created" | "closed", sessionId: string, actor?: LimitActor): void;
|
|
53
|
+
/** Log admin token lifecycle events (never logs plaintext secrets). */
|
|
54
|
+
export declare function logAdminEvent(event: "token created" | "token revoked", detail: {
|
|
55
|
+
id: string;
|
|
56
|
+
label?: string;
|
|
57
|
+
}): void;
|
|
58
|
+
/** Run `fn` with request-scoped logging context (client source). */
|
|
59
|
+
export declare function runWithRequestContext<T>(context: RequestContext, fn: () => T): T;
|
|
60
|
+
/** Run async `fn` with request-scoped logging context. */
|
|
61
|
+
export declare function runWithRequestContextAsync<T>(context: RequestContext, fn: () => Promise<T>): Promise<T>;
|
|
62
|
+
export declare function getRequestSource(): string;
|
|
63
|
+
export declare function getRequestContext(): RequestContext | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Build a controller `external_id` that identifies the MCP caller for admins.
|
|
66
|
+
* Always includes client/IP/session context; an optional caller `ref` is appended.
|
|
67
|
+
*/
|
|
68
|
+
export declare function buildControllerExternalId(callerExternalId?: string): string;
|
|
69
|
+
/** Build request-scoped context from an HTTP request and optional MCP client info. */
|
|
70
|
+
export declare function buildRequestContext(req: {
|
|
71
|
+
ip?: string;
|
|
72
|
+
socket: {
|
|
73
|
+
remoteAddress?: string | null;
|
|
74
|
+
};
|
|
75
|
+
headers: Record<string, string | string[] | undefined>;
|
|
76
|
+
mcpCredential?: {
|
|
77
|
+
credentialId: string;
|
|
78
|
+
credentialLabel?: string;
|
|
79
|
+
};
|
|
80
|
+
}, clientInfo?: McpClientInfo, sessionId?: string): RequestContext;
|
|
81
|
+
/** Extract MCP clientInfo from an initialize JSON-RPC body. */
|
|
82
|
+
export declare function mcpClientInfoFromBody(body: unknown): McpClientInfo | undefined;
|
|
83
|
+
/** Build a compact client label from an Express request. */
|
|
84
|
+
export declare function clientSourceFromRequest(req: {
|
|
85
|
+
ip?: string;
|
|
86
|
+
socket: {
|
|
87
|
+
remoteAddress?: string | null;
|
|
88
|
+
};
|
|
89
|
+
headers: Record<string, string | string[] | undefined>;
|
|
90
|
+
}): string;
|
|
91
|
+
/** Redact known secret fields before logging structured data. */
|
|
92
|
+
export declare function sanitizeForLog(value: unknown): unknown;
|
|
93
|
+
/** Extract JSON-RPC method name(s) from an MCP POST body. */
|
|
94
|
+
export declare function mcpMethodsFromBody(body: unknown): string[];
|
|
95
|
+
export declare function logMcpRequest(method: string, detail?: Record<string, unknown>): void;
|
|
96
|
+
export declare function logToolCall(name: string, args: unknown, result: CallToolResult): void;
|
|
97
|
+
export declare function logToolError(name: string, args: unknown, error: unknown): void;
|
|
98
|
+
export declare function logAnkaCommand(args: string[], outcome: {
|
|
99
|
+
ok: boolean;
|
|
100
|
+
message?: string;
|
|
101
|
+
}): void;
|
|
102
|
+
export declare function logControllerRequest(method: string, path: string, outcome: {
|
|
103
|
+
ok: boolean;
|
|
104
|
+
detail?: string;
|
|
105
|
+
}): void;
|
|
106
|
+
/** Log the tool names registered at startup (always written, like the listen banner). */
|
|
107
|
+
export declare function logStartupTools(toolNames: string[]): void;
|