@ebowwa/hetzner-mcp 1.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.
Files changed (227) hide show
  1. package/bun.lock +250 -0
  2. package/dist/index.d.ts +16 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +1928 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/hetzner/actions.d.ts +356 -0
  7. package/dist/lib/hetzner/actions.d.ts.map +1 -0
  8. package/dist/lib/hetzner/actions.js +804 -0
  9. package/dist/lib/hetzner/actions.js.map +1 -0
  10. package/dist/lib/hetzner/auth.d.ts +7 -0
  11. package/dist/lib/hetzner/auth.d.ts.map +1 -0
  12. package/dist/lib/hetzner/auth.js +35 -0
  13. package/dist/lib/hetzner/auth.js.map +1 -0
  14. package/dist/lib/hetzner/bootstrap/cloud-init.d.ts +79 -0
  15. package/dist/lib/hetzner/bootstrap/cloud-init.d.ts.map +1 -0
  16. package/dist/lib/hetzner/bootstrap/cloud-init.js +279 -0
  17. package/dist/lib/hetzner/bootstrap/cloud-init.js.map +1 -0
  18. package/dist/lib/hetzner/bootstrap/firewall.d.ts +119 -0
  19. package/dist/lib/hetzner/bootstrap/firewall.d.ts.map +1 -0
  20. package/dist/lib/hetzner/bootstrap/firewall.js +279 -0
  21. package/dist/lib/hetzner/bootstrap/firewall.js.map +1 -0
  22. package/dist/lib/hetzner/bootstrap/genesis.d.ts +83 -0
  23. package/dist/lib/hetzner/bootstrap/genesis.d.ts.map +1 -0
  24. package/dist/lib/hetzner/bootstrap/genesis.js +406 -0
  25. package/dist/lib/hetzner/bootstrap/genesis.js.map +1 -0
  26. package/dist/lib/hetzner/bootstrap/index.d.ts +30 -0
  27. package/dist/lib/hetzner/bootstrap/index.d.ts.map +1 -0
  28. package/dist/lib/hetzner/bootstrap/index.js +35 -0
  29. package/dist/lib/hetzner/bootstrap/index.js.map +1 -0
  30. package/dist/lib/hetzner/bootstrap/kernel-hardening.d.ts +70 -0
  31. package/dist/lib/hetzner/bootstrap/kernel-hardening.d.ts.map +1 -0
  32. package/dist/lib/hetzner/bootstrap/kernel-hardening.js +266 -0
  33. package/dist/lib/hetzner/bootstrap/kernel-hardening.js.map +1 -0
  34. package/dist/lib/hetzner/bootstrap/kernel-hardening.test.d.ts +7 -0
  35. package/dist/lib/hetzner/bootstrap/kernel-hardening.test.d.ts.map +1 -0
  36. package/dist/lib/hetzner/bootstrap/kernel-hardening.test.js +181 -0
  37. package/dist/lib/hetzner/bootstrap/kernel-hardening.test.js.map +1 -0
  38. package/dist/lib/hetzner/bootstrap/security-audit.d.ts +46 -0
  39. package/dist/lib/hetzner/bootstrap/security-audit.d.ts.map +1 -0
  40. package/dist/lib/hetzner/bootstrap/security-audit.js +118 -0
  41. package/dist/lib/hetzner/bootstrap/security-audit.js.map +1 -0
  42. package/dist/lib/hetzner/bootstrap/ssh-hardening.d.ts +68 -0
  43. package/dist/lib/hetzner/bootstrap/ssh-hardening.d.ts.map +1 -0
  44. package/dist/lib/hetzner/bootstrap/ssh-hardening.js +182 -0
  45. package/dist/lib/hetzner/bootstrap/ssh-hardening.js.map +1 -0
  46. package/dist/lib/hetzner/client.d.ts +63 -0
  47. package/dist/lib/hetzner/client.d.ts.map +1 -0
  48. package/dist/lib/hetzner/client.js +137 -0
  49. package/dist/lib/hetzner/client.js.map +1 -0
  50. package/dist/lib/hetzner/config.d.ts +5 -0
  51. package/dist/lib/hetzner/config.d.ts.map +1 -0
  52. package/dist/lib/hetzner/config.js +5 -0
  53. package/dist/lib/hetzner/config.js.map +1 -0
  54. package/dist/lib/hetzner/errors.d.ts +171 -0
  55. package/dist/lib/hetzner/errors.d.ts.map +1 -0
  56. package/dist/lib/hetzner/errors.js +270 -0
  57. package/dist/lib/hetzner/errors.js.map +1 -0
  58. package/dist/lib/hetzner/index.d.ts +21 -0
  59. package/dist/lib/hetzner/index.d.ts.map +1 -0
  60. package/dist/lib/hetzner/index.js +29 -0
  61. package/dist/lib/hetzner/index.js.map +1 -0
  62. package/dist/lib/hetzner/pricing.d.ts +207 -0
  63. package/dist/lib/hetzner/pricing.d.ts.map +1 -0
  64. package/dist/lib/hetzner/pricing.js +284 -0
  65. package/dist/lib/hetzner/pricing.js.map +1 -0
  66. package/dist/lib/hetzner/schemas.d.ts +1644 -0
  67. package/dist/lib/hetzner/schemas.d.ts.map +1 -0
  68. package/dist/lib/hetzner/schemas.js +660 -0
  69. package/dist/lib/hetzner/schemas.js.map +1 -0
  70. package/dist/lib/hetzner/server-status.d.ts +26 -0
  71. package/dist/lib/hetzner/server-status.d.ts.map +1 -0
  72. package/dist/lib/hetzner/server-status.js +64 -0
  73. package/dist/lib/hetzner/server-status.js.map +1 -0
  74. package/dist/lib/hetzner/servers.d.ts +165 -0
  75. package/dist/lib/hetzner/servers.d.ts.map +1 -0
  76. package/dist/lib/hetzner/servers.js +424 -0
  77. package/dist/lib/hetzner/servers.js.map +1 -0
  78. package/dist/lib/hetzner/ssh-keys.d.ts +36 -0
  79. package/dist/lib/hetzner/ssh-keys.d.ts.map +1 -0
  80. package/dist/lib/hetzner/ssh-keys.js +90 -0
  81. package/dist/lib/hetzner/ssh-keys.js.map +1 -0
  82. package/dist/lib/hetzner/ssh-setup.d.ts +48 -0
  83. package/dist/lib/hetzner/ssh-setup.d.ts.map +1 -0
  84. package/dist/lib/hetzner/ssh-setup.js +167 -0
  85. package/dist/lib/hetzner/ssh-setup.js.map +1 -0
  86. package/dist/lib/hetzner/types.d.ts +330 -0
  87. package/dist/lib/hetzner/types.d.ts.map +1 -0
  88. package/dist/lib/hetzner/types.js +96 -0
  89. package/dist/lib/hetzner/types.js.map +1 -0
  90. package/dist/lib/hetzner/volumes.d.ts +106 -0
  91. package/dist/lib/hetzner/volumes.d.ts.map +1 -0
  92. package/dist/lib/hetzner/volumes.js +172 -0
  93. package/dist/lib/hetzner/volumes.js.map +1 -0
  94. package/dist/lib/resources.d.ts +70 -0
  95. package/dist/lib/resources.d.ts.map +1 -0
  96. package/dist/lib/resources.js +115 -0
  97. package/dist/lib/resources.js.map +1 -0
  98. package/dist/lib/ssh/flags.d.ts +349 -0
  99. package/dist/lib/ssh/flags.d.ts.map +1 -0
  100. package/dist/lib/ssh/flags.js +322 -0
  101. package/dist/lib/ssh/flags.js.map +1 -0
  102. package/dist/lib/ssh/index.d.ts +5 -0
  103. package/dist/lib/ssh/index.d.ts.map +1 -0
  104. package/dist/lib/ssh/index.js +5 -0
  105. package/dist/lib/ssh/index.js.map +1 -0
  106. package/dist/lib/terminal/api.d.ts +8 -0
  107. package/dist/lib/terminal/api.d.ts.map +1 -0
  108. package/dist/lib/terminal/api.js +594 -0
  109. package/dist/lib/terminal/api.js.map +1 -0
  110. package/dist/lib/terminal/client.d.ts +15 -0
  111. package/dist/lib/terminal/client.d.ts.map +1 -0
  112. package/dist/lib/terminal/client.js +45 -0
  113. package/dist/lib/terminal/client.js.map +1 -0
  114. package/dist/lib/terminal/config.d.ts +86 -0
  115. package/dist/lib/terminal/config.d.ts.map +1 -0
  116. package/dist/lib/terminal/config.js +375 -0
  117. package/dist/lib/terminal/config.js.map +1 -0
  118. package/dist/lib/terminal/error.d.ts +8 -0
  119. package/dist/lib/terminal/error.d.ts.map +1 -0
  120. package/dist/lib/terminal/error.js +12 -0
  121. package/dist/lib/terminal/error.js.map +1 -0
  122. package/dist/lib/terminal/exec.d.ts +47 -0
  123. package/dist/lib/terminal/exec.d.ts.map +1 -0
  124. package/dist/lib/terminal/exec.js +107 -0
  125. package/dist/lib/terminal/exec.js.map +1 -0
  126. package/dist/lib/terminal/files.d.ts +124 -0
  127. package/dist/lib/terminal/files.d.ts.map +1 -0
  128. package/dist/lib/terminal/files.js +436 -0
  129. package/dist/lib/terminal/files.js.map +1 -0
  130. package/dist/lib/terminal/fingerprint.d.ts +67 -0
  131. package/dist/lib/terminal/fingerprint.d.ts.map +1 -0
  132. package/dist/lib/terminal/fingerprint.js +214 -0
  133. package/dist/lib/terminal/fingerprint.js.map +1 -0
  134. package/dist/lib/terminal/index.d.ts +14 -0
  135. package/dist/lib/terminal/index.d.ts.map +1 -0
  136. package/dist/lib/terminal/index.js +21 -0
  137. package/dist/lib/terminal/index.js.map +1 -0
  138. package/dist/lib/terminal/manager.d.ts +103 -0
  139. package/dist/lib/terminal/manager.d.ts.map +1 -0
  140. package/dist/lib/terminal/manager.js +237 -0
  141. package/dist/lib/terminal/manager.js.map +1 -0
  142. package/dist/lib/terminal/network-error-detector.d.ts +19 -0
  143. package/dist/lib/terminal/network-error-detector.d.ts.map +1 -0
  144. package/dist/lib/terminal/network-error-detector.js +98 -0
  145. package/dist/lib/terminal/network-error-detector.js.map +1 -0
  146. package/dist/lib/terminal/pool.d.ts +143 -0
  147. package/dist/lib/terminal/pool.d.ts.map +1 -0
  148. package/dist/lib/terminal/pool.js +554 -0
  149. package/dist/lib/terminal/pool.js.map +1 -0
  150. package/dist/lib/terminal/pty.d.ts +59 -0
  151. package/dist/lib/terminal/pty.d.ts.map +1 -0
  152. package/dist/lib/terminal/pty.js +224 -0
  153. package/dist/lib/terminal/pty.js.map +1 -0
  154. package/dist/lib/terminal/resources.d.ts +63 -0
  155. package/dist/lib/terminal/resources.d.ts.map +1 -0
  156. package/dist/lib/terminal/resources.js +62 -0
  157. package/dist/lib/terminal/resources.js.map +1 -0
  158. package/dist/lib/terminal/scp.d.ts +30 -0
  159. package/dist/lib/terminal/scp.d.ts.map +1 -0
  160. package/dist/lib/terminal/scp.js +74 -0
  161. package/dist/lib/terminal/scp.js.map +1 -0
  162. package/dist/lib/terminal/sessions.d.ts +101 -0
  163. package/dist/lib/terminal/sessions.d.ts.map +1 -0
  164. package/dist/lib/terminal/sessions.js +718 -0
  165. package/dist/lib/terminal/sessions.js.map +1 -0
  166. package/dist/lib/terminal/tmux-exec.d.ts +50 -0
  167. package/dist/lib/terminal/tmux-exec.d.ts.map +1 -0
  168. package/dist/lib/terminal/tmux-exec.js +79 -0
  169. package/dist/lib/terminal/tmux-exec.js.map +1 -0
  170. package/dist/lib/terminal/tmux-local.d.ts +273 -0
  171. package/dist/lib/terminal/tmux-local.d.ts.map +1 -0
  172. package/dist/lib/terminal/tmux-local.js +629 -0
  173. package/dist/lib/terminal/tmux-local.js.map +1 -0
  174. package/dist/lib/terminal/tmux-manager.d.ts +328 -0
  175. package/dist/lib/terminal/tmux-manager.d.ts.map +1 -0
  176. package/dist/lib/terminal/tmux-manager.js +667 -0
  177. package/dist/lib/terminal/tmux-manager.js.map +1 -0
  178. package/dist/lib/terminal/tmux.d.ts +213 -0
  179. package/dist/lib/terminal/tmux.d.ts.map +1 -0
  180. package/dist/lib/terminal/tmux.js +528 -0
  181. package/dist/lib/terminal/tmux.js.map +1 -0
  182. package/dist/lib/terminal/types.d.ts +18 -0
  183. package/dist/lib/terminal/types.d.ts.map +1 -0
  184. package/dist/lib/terminal/types.js +5 -0
  185. package/dist/lib/terminal/types.js.map +1 -0
  186. package/lmdb.db +0 -0
  187. package/lmdb.db-lock +0 -0
  188. package/package.json +48 -0
  189. package/src/index.js +2034 -0
  190. package/src/index.ts +2295 -0
  191. package/src/lib/hetzner/actions.ts +1056 -0
  192. package/src/lib/hetzner/auth.ts +37 -0
  193. package/src/lib/hetzner/bootstrap/cloud-init.ts +394 -0
  194. package/src/lib/hetzner/bootstrap/firewall.ts +342 -0
  195. package/src/lib/hetzner/bootstrap/genesis.ts +518 -0
  196. package/src/lib/hetzner/bootstrap/index.ts +71 -0
  197. package/src/lib/hetzner/bootstrap/kernel-hardening.test.ts +230 -0
  198. package/src/lib/hetzner/bootstrap/kernel-hardening.ts +272 -0
  199. package/src/lib/hetzner/bootstrap/security-audit.ts +124 -0
  200. package/src/lib/hetzner/bootstrap/ssh-hardening.ts +192 -0
  201. package/src/lib/hetzner/client.ts +177 -0
  202. package/src/lib/hetzner/config.ts +5 -0
  203. package/src/lib/hetzner/errors.ts +371 -0
  204. package/src/lib/hetzner/index.ts +56 -0
  205. package/src/lib/hetzner/pricing.ts +422 -0
  206. package/src/lib/hetzner/schemas.ts +765 -0
  207. package/src/lib/hetzner/server-status.ts +81 -0
  208. package/src/lib/hetzner/servers.ts +568 -0
  209. package/src/lib/hetzner/ssh-keys.ts +122 -0
  210. package/src/lib/hetzner/ssh-setup.ts +218 -0
  211. package/src/lib/hetzner/types.ts +419 -0
  212. package/src/lib/hetzner/volumes.ts +229 -0
  213. package/src/lib/resources.ts +156 -0
  214. package/src/lib/ssh/flags.ts +578 -0
  215. package/src/lib/ssh/index.ts +5 -0
  216. package/src/lib/terminal/client.ts +55 -0
  217. package/src/lib/terminal/config.ts +489 -0
  218. package/src/lib/terminal/error.ts +13 -0
  219. package/src/lib/terminal/exec.ts +128 -0
  220. package/src/lib/terminal/files.ts +636 -0
  221. package/src/lib/terminal/index.ts +71 -0
  222. package/src/lib/terminal/pool.ts +662 -0
  223. package/src/lib/terminal/scp.ts +109 -0
  224. package/src/lib/terminal/tmux-exec.ts +96 -0
  225. package/src/lib/terminal/tmux.ts +711 -0
  226. package/src/lib/terminal/types.ts +19 -0
  227. package/tsconfig.json +20 -0
package/src/index.js ADDED
@@ -0,0 +1,2034 @@
1
+ "use strict";
2
+ /**
3
+ * MCP - Model Context Protocol Server for Hetzner Infrastructure
4
+ * Exposes Hetzner VPS management, SSH sessions, tmux operations, and volume management as MCP tools
5
+ *
6
+ * This allows AI assistants (like Claude) to directly interact with
7
+ * Hetzner infrastructure for server management, SSH operations, and storage.
8
+ */
9
+ var __assign = (this && this.__assign) || function () {
10
+ __assign = Object.assign || function(t) {
11
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
12
+ s = arguments[i];
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
14
+ t[p] = s[p];
15
+ }
16
+ return t;
17
+ };
18
+ return __assign.apply(this, arguments);
19
+ };
20
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
21
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
22
+ return new (P || (P = Promise))(function (resolve, reject) {
23
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
24
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
25
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
26
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
27
+ });
28
+ };
29
+ var __generator = (this && this.__generator) || function (thisArg, body) {
30
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
31
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
32
+ function verb(n) { return function (v) { return step([n, v]); }; }
33
+ function step(op) {
34
+ if (f) throw new TypeError("Generator is already executing.");
35
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
36
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
37
+ if (y = 0, t) op = [op[0] & 2, t.value];
38
+ switch (op[0]) {
39
+ case 0: case 1: t = op; break;
40
+ case 4: _.label++; return { value: op[1], done: false };
41
+ case 5: _.label++; y = op[1]; op = [0]; continue;
42
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
43
+ default:
44
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
45
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
46
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
47
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
48
+ if (t[2]) _.ops.pop();
49
+ _.trys.pop(); continue;
50
+ }
51
+ op = body.call(thisArg, _);
52
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
53
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
54
+ }
55
+ };
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ var index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
58
+ var stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
59
+ var types_js_1 = require("@modelcontextprotocol/sdk/types.js");
60
+ var node_path_1 = require("node:path");
61
+ var node_os_1 = require("node:os");
62
+ // Import business logic from com.hetzner.codespaces workspace
63
+ var hetzner_1 = require("cheapspaces/workspace/src/lib/hetzner");
64
+ // Local tmux session state tracking (in-memory, per host)
65
+ // Tracks multiple named tmux sessions per host for different purposes
66
+ // Key format: "sessionName" (full session name)
67
+ // Value: { host, user, initialized, createdAt, windowName }
68
+ var localTmuxSessions = new Map();
69
+ // Get API token from CLI config
70
+ function getTokenFromCLI() {
71
+ return __awaiter(this, void 0, void 0, function () {
72
+ var configPath, configFile, config, match, e_1;
73
+ return __generator(this, function (_a) {
74
+ switch (_a.label) {
75
+ case 0:
76
+ _a.trys.push([0, 4, , 5]);
77
+ configPath = (0, node_path_1.join)((0, node_os_1.homedir)(), ".config", "hcloud", "cli.toml");
78
+ configFile = Bun.file(configPath);
79
+ return [4 /*yield*/, configFile.exists()];
80
+ case 1:
81
+ if (!_a.sent()) return [3 /*break*/, 3];
82
+ return [4 /*yield*/, configFile.text()];
83
+ case 2:
84
+ config = _a.sent();
85
+ match = config.match(/token\s*=\s*["']([^"']+)["']/);
86
+ if (match && match[1]) {
87
+ return [2 /*return*/, match[1]];
88
+ }
89
+ _a.label = 3;
90
+ case 3: return [3 /*break*/, 5];
91
+ case 4:
92
+ e_1 = _a.sent();
93
+ return [3 /*break*/, 5];
94
+ case 5: return [2 /*return*/, ""];
95
+ }
96
+ });
97
+ });
98
+ }
99
+ // Resolve API token: env var > CLI config
100
+ function resolveApiToken() {
101
+ return __awaiter(this, void 0, void 0, function () {
102
+ return __generator(this, function (_a) {
103
+ switch (_a.label) {
104
+ case 0:
105
+ if (process.env.HETZNER_API_TOKEN) {
106
+ return [2 /*return*/, process.env.HETZNER_API_TOKEN];
107
+ }
108
+ return [4 /*yield*/, getTokenFromCLI()];
109
+ case 1: return [2 /*return*/, _a.sent()];
110
+ }
111
+ });
112
+ });
113
+ }
114
+ // Initialize Hetzner client
115
+ var hetznerClient = null;
116
+ // Initialize asynchronously
117
+ function initializeClient() {
118
+ return __awaiter(this, void 0, void 0, function () {
119
+ var token;
120
+ return __generator(this, function (_a) {
121
+ switch (_a.label) {
122
+ case 0: return [4 /*yield*/, resolveApiToken()];
123
+ case 1:
124
+ token = _a.sent();
125
+ if (token) {
126
+ try {
127
+ hetznerClient = new hetzner_1.HetznerClient(token);
128
+ console.error("[hetzner-mcp] Authenticated via ".concat(process.env.HETZNER_API_TOKEN ? "HETZNER_API_TOKEN" : "Hetzner CLI config"));
129
+ }
130
+ catch (e) {
131
+ console.warn("[hetzner-mcp] Failed to initialize Hetzner client:", e);
132
+ }
133
+ }
134
+ else {
135
+ console.warn("[hetzner-mcp] Hetzner API token not configured - MCP running in limited mode");
136
+ }
137
+ return [2 /*return*/];
138
+ }
139
+ });
140
+ });
141
+ }
142
+ // Create MCP server
143
+ var server = new index_js_1.Server({
144
+ name: "hetzner-mcp",
145
+ version: "0.1.0",
146
+ }, {
147
+ capabilities: {
148
+ tools: {},
149
+ },
150
+ });
151
+ // List available tools
152
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, function () { return __awaiter(void 0, void 0, void 0, function () {
153
+ return __generator(this, function (_a) {
154
+ return [2 /*return*/, {
155
+ tools: [
156
+ // Environment Management
157
+ {
158
+ name: "list_environments",
159
+ description: "List all Hetzner VPS environments with their status, IPs, and metadata",
160
+ inputSchema: {
161
+ type: "object",
162
+ properties: {},
163
+ },
164
+ },
165
+ {
166
+ name: "get_environment",
167
+ description: "Get details of a specific environment by ID",
168
+ inputSchema: {
169
+ type: "object",
170
+ properties: {
171
+ id: {
172
+ type: "string",
173
+ description: "Environment ID (server ID)",
174
+ },
175
+ },
176
+ required: ["id"],
177
+ },
178
+ },
179
+ {
180
+ name: "create_environment",
181
+ description: "Create a new Hetzner VPS environment",
182
+ inputSchema: {
183
+ type: "object",
184
+ properties: {
185
+ name: {
186
+ type: "string",
187
+ description: "Server name",
188
+ },
189
+ serverType: {
190
+ type: "string",
191
+ description: "Server type (e.g., cax21, cpx21)",
192
+ default: "cax21",
193
+ },
194
+ location: {
195
+ type: "string",
196
+ description: "Datacenter location (e.g., nbg1, fsn1, hel1)",
197
+ },
198
+ sshKey: {
199
+ type: "string",
200
+ description: "SSH key name or public key to add to the server",
201
+ },
202
+ enablePassword: {
203
+ type: "boolean",
204
+ description: "Enable temporary password access via cloud-init (useful for initial setup)",
205
+ default: false,
206
+ },
207
+ userData: {
208
+ type: "string",
209
+ description: "Custom cloud-init user-data script (YAML format). Overrides enablePassword if both are set.",
210
+ },
211
+ },
212
+ required: ["name"],
213
+ },
214
+ },
215
+ {
216
+ name: "start_environment",
217
+ description: "Power on a stopped environment",
218
+ inputSchema: {
219
+ type: "object",
220
+ properties: {
221
+ id: {
222
+ type: "string",
223
+ description: "Environment ID",
224
+ },
225
+ },
226
+ required: ["id"],
227
+ },
228
+ },
229
+ {
230
+ name: "stop_environment",
231
+ description: "Power off an environment",
232
+ inputSchema: {
233
+ type: "object",
234
+ properties: {
235
+ id: {
236
+ type: "string",
237
+ description: "Environment ID",
238
+ },
239
+ },
240
+ required: ["id"],
241
+ },
242
+ },
243
+ {
244
+ name: "delete_environment",
245
+ description: "Delete an environment permanently",
246
+ inputSchema: {
247
+ type: "object",
248
+ properties: {
249
+ id: {
250
+ type: "string",
251
+ description: "Environment ID",
252
+ },
253
+ },
254
+ required: ["id"],
255
+ },
256
+ },
257
+ {
258
+ name: "get_resources",
259
+ description: "Get real-time CPU, memory, and disk usage for an environment",
260
+ inputSchema: {
261
+ type: "object",
262
+ properties: {
263
+ id: {
264
+ type: "string",
265
+ description: "Environment ID",
266
+ },
267
+ },
268
+ required: ["id"],
269
+ },
270
+ },
271
+ // SSH Operations
272
+ {
273
+ name: "ssh_test",
274
+ description: "Test SSH connectivity to an environment",
275
+ inputSchema: {
276
+ type: "object",
277
+ properties: {
278
+ host: {
279
+ type: "string",
280
+ description: "IP address or hostname",
281
+ },
282
+ user: {
283
+ type: "string",
284
+ description: "SSH user (default: root)",
285
+ default: "root",
286
+ },
287
+ keyPath: {
288
+ type: "string",
289
+ description: "Path to SSH private key (optional)",
290
+ },
291
+ password: {
292
+ type: "string",
293
+ description: "SSH password (optional, for password authentication)",
294
+ },
295
+ },
296
+ required: ["host"],
297
+ },
298
+ },
299
+ {
300
+ name: "create_ssh_key",
301
+ description: "Create a new SSH key in Hetzner for server access",
302
+ inputSchema: {
303
+ type: "object",
304
+ properties: {
305
+ name: {
306
+ type: "string",
307
+ description: "SSH key name",
308
+ },
309
+ publicKey: {
310
+ type: "string",
311
+ description: "SSH public key content",
312
+ },
313
+ },
314
+ required: ["name", "publicKey"],
315
+ },
316
+ },
317
+ {
318
+ name: "list_ssh_keys",
319
+ description: "List all SSH keys in Hetzner",
320
+ inputSchema: {
321
+ type: "object",
322
+ properties: {},
323
+ },
324
+ },
325
+ {
326
+ name: "exec_ssh",
327
+ description: "Execute a command via SSH on a server using a persistent local tmux session (preserves shell state: working directory, environment variables, aliases, etc.). The first call creates a local tmux session with an SSH connection; subsequent calls reuse the existing connection for faster execution.",
328
+ inputSchema: {
329
+ type: "object",
330
+ properties: {
331
+ host: {
332
+ type: "string",
333
+ description: "IP address or hostname",
334
+ },
335
+ command: {
336
+ type: "string",
337
+ description: "Command to execute",
338
+ },
339
+ user: {
340
+ type: "string",
341
+ description: "SSH user (default: root)",
342
+ default: "root",
343
+ },
344
+ keyPath: {
345
+ type: "string",
346
+ description: "Path to SSH private key (optional, tries SSH agent if not provided)",
347
+ },
348
+ password: {
349
+ type: "string",
350
+ description: "SSH password (optional, for password authentication - requires sshpass on local machine)",
351
+ },
352
+ sessionName: {
353
+ type: "string",
354
+ description: "Custom session name (e.g., 'dev', 'tests', 'monitoring'). If not provided, uses the default session for this host.",
355
+ },
356
+ paneIndex: {
357
+ type: "string",
358
+ description: "Pane index to send command to (default: '0'). Use '1', '2', etc. for additional panes created via split_pane.",
359
+ default: "0",
360
+ },
361
+ waitTime: {
362
+ type: "number",
363
+ description: "Time to wait after sending command (ms, default: 500)",
364
+ default: 500,
365
+ },
366
+ captureHistory: {
367
+ type: "boolean",
368
+ description: "Capture full pane history instead of just visible output (default: true)",
369
+ default: true,
370
+ },
371
+ },
372
+ required: ["host", "command"],
373
+ },
374
+ },
375
+ // tmux Operations
376
+ {
377
+ name: "list_tmux_sessions",
378
+ description: "List all local tmux sessions managed by MCP. Returns all sessions, MCP sessions (filtered), tracked sessions (with host/user info), and resource usage.",
379
+ inputSchema: {
380
+ type: "object",
381
+ properties: {},
382
+ },
383
+ },
384
+ {
385
+ name: "kill_tmux_session",
386
+ description: "Kill a local tmux session (closes the persistent SSH connection to the remote server)",
387
+ inputSchema: {
388
+ type: "object",
389
+ properties: {
390
+ host: {
391
+ type: "string",
392
+ description: "IP address or hostname (used to derive session name if sessionName not provided)",
393
+ },
394
+ sessionName: {
395
+ type: "string",
396
+ description: "Session name to kill (if not provided, kills the default session for this host)",
397
+ },
398
+ user: {
399
+ type: "string",
400
+ description: "SSH user (default: root)",
401
+ default: "root",
402
+ },
403
+ },
404
+ required: [],
405
+ },
406
+ },
407
+ {
408
+ name: "get_tmux_session_info",
409
+ description: "Get detailed information about a local tmux session (exists, window count, etc.)",
410
+ inputSchema: {
411
+ type: "object",
412
+ properties: {
413
+ host: {
414
+ type: "string",
415
+ description: "IP address or hostname (used to derive session name if sessionName not provided)",
416
+ },
417
+ sessionName: {
418
+ type: "string",
419
+ description: "Session name (if not provided, uses the default session for this host)",
420
+ },
421
+ user: {
422
+ type: "string",
423
+ description: "SSH user (default: root)",
424
+ default: "root",
425
+ },
426
+ },
427
+ required: [],
428
+ },
429
+ },
430
+ {
431
+ name: "attach_tmux_session",
432
+ description: "Get tmux command to attach to a local tmux session interactively (for use in your local terminal - gives you direct shell access to the remote server)",
433
+ inputSchema: {
434
+ type: "object",
435
+ properties: {
436
+ host: {
437
+ type: "string",
438
+ description: "IP address or hostname (used to derive session name if sessionName not provided)",
439
+ },
440
+ sessionName: {
441
+ type: "string",
442
+ description: "Session name (if not provided, uses the default session for this host)",
443
+ },
444
+ user: {
445
+ type: "string",
446
+ description: "SSH user (default: root)",
447
+ default: "root",
448
+ },
449
+ },
450
+ required: [],
451
+ },
452
+ },
453
+ {
454
+ name: "create_tmux_session",
455
+ description: "Create a new named tmux session with an SSH connection to a server. Allows creating multiple sessions per host for different purposes (e.g., 'dev', 'tests', 'monitoring').",
456
+ inputSchema: {
457
+ type: "object",
458
+ properties: {
459
+ host: {
460
+ type: "string",
461
+ description: "IP address or hostname",
462
+ },
463
+ sessionName: {
464
+ type: "string",
465
+ description: "Custom session name (e.g., 'dev', 'tests', 'monitoring'). If not provided, auto-generates based on host.",
466
+ },
467
+ user: {
468
+ type: "string",
469
+ description: "SSH user (default: root)",
470
+ default: "root",
471
+ },
472
+ keyPath: {
473
+ type: "string",
474
+ description: "Path to SSH private key (optional, tries SSH agent if not provided)",
475
+ },
476
+ password: {
477
+ type: "string",
478
+ description: "SSH password (optional, for password authentication)",
479
+ },
480
+ initialCommand: {
481
+ type: "string",
482
+ description: "Optional command to run after SSH connection",
483
+ },
484
+ windowName: {
485
+ type: "string",
486
+ description: "Window name (default: 'ssh')",
487
+ },
488
+ },
489
+ required: ["host"],
490
+ },
491
+ },
492
+ {
493
+ name: "split_pane",
494
+ description: "Split a pane horizontally or vertically in a local tmux session for parallel work",
495
+ inputSchema: {
496
+ type: "object",
497
+ properties: {
498
+ host: {
499
+ type: "string",
500
+ description: "IP address or hostname (used to derive session name if sessionName not provided)",
501
+ },
502
+ sessionName: {
503
+ type: "string",
504
+ description: "Session name (if not provided, uses the default session for this host)",
505
+ },
506
+ user: {
507
+ type: "string",
508
+ description: "SSH user (default: root)",
509
+ default: "root",
510
+ },
511
+ direction: {
512
+ type: "string",
513
+ description: "Split direction: 'v' for vertical (top/bottom), 'h' for horizontal (left/right)",
514
+ enum: ["v", "h"],
515
+ default: "v",
516
+ },
517
+ command: {
518
+ type: "string",
519
+ description: "Optional command to run in the new pane",
520
+ },
521
+ },
522
+ required: [],
523
+ },
524
+ },
525
+ {
526
+ name: "list_session_windows",
527
+ description: "List all windows in a local tmux session",
528
+ inputSchema: {
529
+ type: "object",
530
+ properties: {
531
+ host: {
532
+ type: "string",
533
+ description: "IP address or hostname (used to derive session name if sessionName not provided)",
534
+ },
535
+ sessionName: {
536
+ type: "string",
537
+ description: "Session name (if not provided, uses the default session for this host)",
538
+ },
539
+ user: {
540
+ type: "string",
541
+ description: "SSH user (default: root)",
542
+ default: "root",
543
+ },
544
+ },
545
+ required: [],
546
+ },
547
+ },
548
+ {
549
+ name: "list_window_panes",
550
+ description: "List all panes in a window of a local tmux session. Auto-detects the first window if windowIndex not provided.",
551
+ inputSchema: {
552
+ type: "object",
553
+ properties: {
554
+ host: {
555
+ type: "string",
556
+ description: "IP address or hostname (used to derive session name if sessionName not provided)",
557
+ },
558
+ sessionName: {
559
+ type: "string",
560
+ description: "Session name (if not provided, uses the default session for this host)",
561
+ },
562
+ user: {
563
+ type: "string",
564
+ description: "SSH user (default: root)",
565
+ default: "root",
566
+ },
567
+ windowIndex: {
568
+ type: "string",
569
+ description: "Window index (e.g., '1', '2') or name. If not provided, uses the first window in the session.",
570
+ },
571
+ },
572
+ required: [],
573
+ },
574
+ },
575
+ {
576
+ name: "switch_window",
577
+ description: "Switch to a specific window in a local tmux session",
578
+ inputSchema: {
579
+ type: "object",
580
+ properties: {
581
+ host: {
582
+ type: "string",
583
+ description: "IP address or hostname (used to derive session name if sessionName not provided)",
584
+ },
585
+ sessionName: {
586
+ type: "string",
587
+ description: "Session name (if not provided, uses the default session for this host)",
588
+ },
589
+ user: {
590
+ type: "string",
591
+ description: "SSH user (default: root)",
592
+ default: "root",
593
+ },
594
+ windowIndex: {
595
+ type: "string",
596
+ description: "Target window index",
597
+ },
598
+ },
599
+ required: ["windowIndex"],
600
+ },
601
+ },
602
+ {
603
+ name: "switch_pane",
604
+ description: "Switch to a specific pane in a local tmux session window",
605
+ inputSchema: {
606
+ type: "object",
607
+ properties: {
608
+ host: {
609
+ type: "string",
610
+ description: "IP address or hostname (used to derive session name if sessionName not provided)",
611
+ },
612
+ sessionName: {
613
+ type: "string",
614
+ description: "Session name (if not provided, uses the default session for this host)",
615
+ },
616
+ user: {
617
+ type: "string",
618
+ description: "SSH user (default: root)",
619
+ default: "root",
620
+ },
621
+ paneIndex: {
622
+ type: "string",
623
+ description: "Target pane index (e.g., '0', '1', '0.1' for window.pane)",
624
+ },
625
+ },
626
+ required: ["paneIndex"],
627
+ },
628
+ },
629
+ {
630
+ name: "rename_window",
631
+ description: "Rename a window in a local tmux session",
632
+ inputSchema: {
633
+ type: "object",
634
+ properties: {
635
+ host: {
636
+ type: "string",
637
+ description: "IP address or hostname (used to derive session name if sessionName not provided)",
638
+ },
639
+ sessionName: {
640
+ type: "string",
641
+ description: "Session name (if not provided, uses the default session for this host)",
642
+ },
643
+ user: {
644
+ type: "string",
645
+ description: "SSH user (default: root)",
646
+ default: "root",
647
+ },
648
+ windowIndex: {
649
+ type: "string",
650
+ description: "Window index (default: 'ssh')",
651
+ default: "ssh",
652
+ },
653
+ newName: {
654
+ type: "string",
655
+ description: "New window name",
656
+ },
657
+ },
658
+ required: ["newName"],
659
+ },
660
+ },
661
+ {
662
+ name: "kill_pane",
663
+ description: "Kill a specific pane in a local tmux session",
664
+ inputSchema: {
665
+ type: "object",
666
+ properties: {
667
+ host: {
668
+ type: "string",
669
+ description: "IP address or hostname (used to derive session name if sessionName not provided)",
670
+ },
671
+ sessionName: {
672
+ type: "string",
673
+ description: "Session name (if not provided, uses the default session for this host)",
674
+ },
675
+ user: {
676
+ type: "string",
677
+ description: "SSH user (default: root)",
678
+ default: "root",
679
+ },
680
+ paneIndex: {
681
+ type: "string",
682
+ description: "Pane index to kill",
683
+ },
684
+ },
685
+ required: ["paneIndex"],
686
+ },
687
+ },
688
+ // Volume Operations
689
+ {
690
+ name: "list_volumes",
691
+ description: "List all Hetzner volumes with their status, size, and server attachment",
692
+ inputSchema: {
693
+ type: "object",
694
+ properties: {
695
+ name: {
696
+ type: "string",
697
+ description: "Filter by volume name",
698
+ },
699
+ status: {
700
+ type: "string",
701
+ description: "Filter by status (creating, available, deleting)",
702
+ },
703
+ },
704
+ },
705
+ },
706
+ {
707
+ name: "get_volume",
708
+ description: "Get details of a specific volume by ID",
709
+ inputSchema: {
710
+ type: "object",
711
+ properties: {
712
+ id: {
713
+ type: "string",
714
+ description: "Volume ID",
715
+ },
716
+ },
717
+ required: ["id"],
718
+ },
719
+ },
720
+ {
721
+ name: "create_volume",
722
+ description: "Create a new Hetzner volume",
723
+ inputSchema: {
724
+ type: "object",
725
+ properties: {
726
+ name: {
727
+ type: "string",
728
+ description: "Volume name",
729
+ },
730
+ size: {
731
+ type: "number",
732
+ description: "Volume size in GB (10-10240)",
733
+ },
734
+ location: {
735
+ type: "string",
736
+ description: "Location name (e.g., nbg1, fsn1, hel1)",
737
+ },
738
+ serverId: {
739
+ type: "string",
740
+ description: "Server ID to attach volume to",
741
+ },
742
+ automount: {
743
+ type: "boolean",
744
+ description: "Automatically mount the volume (default: true)",
745
+ },
746
+ format: {
747
+ type: "string",
748
+ description: "File system format (ext4 or xfs)",
749
+ enum: ["ext4", "xfs"],
750
+ },
751
+ },
752
+ required: ["name", "size"],
753
+ },
754
+ },
755
+ {
756
+ name: "delete_volume",
757
+ description: "Delete a volume permanently",
758
+ inputSchema: {
759
+ type: "object",
760
+ properties: {
761
+ id: {
762
+ type: "string",
763
+ description: "Volume ID",
764
+ },
765
+ },
766
+ required: ["id"],
767
+ },
768
+ },
769
+ {
770
+ name: "attach_volume",
771
+ description: "Attach a volume to a server",
772
+ inputSchema: {
773
+ type: "object",
774
+ properties: {
775
+ volumeId: {
776
+ type: "string",
777
+ description: "Volume ID",
778
+ },
779
+ serverId: {
780
+ type: "string",
781
+ description: "Server ID",
782
+ },
783
+ automount: {
784
+ type: "boolean",
785
+ description: "Automatically mount the volume (default: true)",
786
+ },
787
+ },
788
+ required: ["volumeId", "serverId"],
789
+ },
790
+ },
791
+ {
792
+ name: "detach_volume",
793
+ description: "Detach a volume from a server",
794
+ inputSchema: {
795
+ type: "object",
796
+ properties: {
797
+ volumeId: {
798
+ type: "string",
799
+ description: "Volume ID",
800
+ },
801
+ },
802
+ required: ["volumeId"],
803
+ },
804
+ },
805
+ {
806
+ name: "resize_volume",
807
+ description: "Resize a volume (must be larger than current size)",
808
+ inputSchema: {
809
+ type: "object",
810
+ properties: {
811
+ volumeId: {
812
+ type: "string",
813
+ description: "Volume ID",
814
+ },
815
+ size: {
816
+ type: "number",
817
+ description: "New size in GB (must be larger than current)",
818
+ },
819
+ },
820
+ required: ["volumeId", "size"],
821
+ },
822
+ },
823
+ {
824
+ name: "calculate_volume_price",
825
+ description: "Calculate pricing for a volume based on size",
826
+ inputSchema: {
827
+ type: "object",
828
+ properties: {
829
+ size: {
830
+ type: "number",
831
+ description: "Volume size in GB",
832
+ },
833
+ },
834
+ required: ["size"],
835
+ },
836
+ },
837
+ // Metadata
838
+ {
839
+ name: "list_server_types",
840
+ description: "List all Hetzner server types with specs (cores, memory, disk, prices)",
841
+ inputSchema: {
842
+ type: "object",
843
+ properties: {},
844
+ },
845
+ },
846
+ {
847
+ name: "list_locations",
848
+ description: "List all Hetzner datacenter locations",
849
+ inputSchema: {
850
+ type: "object",
851
+ properties: {},
852
+ },
853
+ },
854
+ ],
855
+ }];
856
+ });
857
+ }); });
858
+ // Handle tool calls
859
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, function (request) { return __awaiter(void 0, void 0, void 0, function () {
860
+ var _a, name, args, _b, servers, environments, server_1, name_1, generateSeedBootstrap, userData, generatedPassword, cleanPassword, passwordSetup, seedLines, passwordLines, mergedLines, inRuncmd, runcmdIndex, _i, seedLines_1, line, _c, passwordLines_1, line, sshKeys, keyName, newKey, e_2, key, _d, _e, _f, _g, e_3, serverOptions, response, responseText, action, parseResources, execSSHParallel, getMetadata, server_2, metadata, keyPath, password, RESOURCE_COMMANDS, rawResults, resources, testSSHConnection, connected, sshKey, sshKeys, host, user, command, keyPath, password, waitTime_1, captureHistory, customSessionName, paneIndex, _h, generateLocalSessionName, isLocalTmuxInstalled, hasLocalSession, createLocalTmuxSSHSession, sendCommandToLocalSession, captureLocalPane, getLocalPaneHistory, tmuxInstalled, sessionName, sessionState, sessionExists, error_1, sent, output, _j, listLocalSessions, getLocalTmuxResourceUsage, sessions, mcpSessions, resources, trackedSessions, _k, _l, _m, name_2, state, _o, killLocalSession, generateLocalSessionName, host, user, sessionName, killed, _p, getDetailedLocalSessionInfo, generateLocalSessionName, host, user, sessionName, info, _q, generateLocalSessionName, hasLocalSession, host, user, customSessionName, sessionName, sessionExists, attachCmd, _r, generateLocalSessionName, isLocalTmuxInstalled, createLocalTmuxSSHSession, host, user, customSessionName, keyPath, password, initialCommand, windowName, tmuxInstalled, sessionName, result, effectiveWindowName, error_2, _s, generateLocalSessionName, splitLocalPane, host, user, customSessionName, direction, command, sessionName, sessionState, windowName, newPaneIndex, error_3, _t, generateLocalSessionName, listLocalSessionWindows, host, user, customSessionName, sessionName, windows, error_4, _u, generateLocalSessionName, listLocalWindowPanes, listLocalSessionWindows, host, user, customSessionName, windowIndex, sessionName, sessionState, windows, _v, panes, error_5, _w, generateLocalSessionName, switchLocalWindow, host, user, customSessionName, windowIndex, sessionName, switched, error_6, _x, generateLocalSessionName, switchLocalPane, host, user, customSessionName, paneIndex, sessionName, switched, error_7, _y, generateLocalSessionName, renameLocalWindow, host, user, customSessionName, windowIndex, newName, sessionName, renamed, sessionState, windows, error_8, _z, generateLocalSessionName, killLocalPane, host, user, customSessionName, paneIndex, sessionName, sessionState, windowName, killed, error_9, volumes, volume, name_3, size, result, action, action, action, action, VolumeOperations, price, serverTypes, locations, error_10;
861
+ var _0, _1;
862
+ var _2, _3, _4, _5, _6;
863
+ return __generator(this, function (_7) {
864
+ switch (_7.label) {
865
+ case 0:
866
+ _a = request.params, name = _a.name, args = _a.arguments;
867
+ _7.label = 1;
868
+ case 1:
869
+ _7.trys.push([1, 135, , 136]);
870
+ _b = name;
871
+ switch (_b) {
872
+ case "list_environments": return [3 /*break*/, 2];
873
+ case "get_environment": return [3 /*break*/, 4];
874
+ case "create_environment": return [3 /*break*/, 6];
875
+ case "start_environment": return [3 /*break*/, 20];
876
+ case "stop_environment": return [3 /*break*/, 22];
877
+ case "delete_environment": return [3 /*break*/, 24];
878
+ case "get_resources": return [3 /*break*/, 26];
879
+ case "ssh_test": return [3 /*break*/, 32];
880
+ case "create_ssh_key": return [3 /*break*/, 35];
881
+ case "list_ssh_keys": return [3 /*break*/, 37];
882
+ case "exec_ssh": return [3 /*break*/, 39];
883
+ case "list_tmux_sessions": return [3 /*break*/, 53];
884
+ case "kill_tmux_session": return [3 /*break*/, 57];
885
+ case "get_tmux_session_info": return [3 /*break*/, 60];
886
+ case "attach_tmux_session": return [3 /*break*/, 63];
887
+ case "create_tmux_session": return [3 /*break*/, 66];
888
+ case "split_pane": return [3 /*break*/, 72];
889
+ case "list_session_windows": return [3 /*break*/, 77];
890
+ case "list_window_panes": return [3 /*break*/, 82];
891
+ case "switch_window": return [3 /*break*/, 90];
892
+ case "switch_pane": return [3 /*break*/, 95];
893
+ case "rename_window": return [3 /*break*/, 100];
894
+ case "kill_pane": return [3 /*break*/, 108];
895
+ case "list_volumes": return [3 /*break*/, 113];
896
+ case "get_volume": return [3 /*break*/, 115];
897
+ case "create_volume": return [3 /*break*/, 117];
898
+ case "delete_volume": return [3 /*break*/, 119];
899
+ case "attach_volume": return [3 /*break*/, 121];
900
+ case "detach_volume": return [3 /*break*/, 123];
901
+ case "resize_volume": return [3 /*break*/, 125];
902
+ case "calculate_volume_price": return [3 /*break*/, 127];
903
+ case "list_server_types": return [3 /*break*/, 129];
904
+ case "list_locations": return [3 /*break*/, 131];
905
+ }
906
+ return [3 /*break*/, 133];
907
+ case 2:
908
+ if (!hetznerClient) {
909
+ return [2 /*return*/, {
910
+ content: [{
911
+ type: "text",
912
+ text: "Hetzner client not available. Please configure HETZNER_API_TOKEN.",
913
+ }],
914
+ }];
915
+ }
916
+ return [4 /*yield*/, hetznerClient.listServers()];
917
+ case 3:
918
+ servers = _7.sent();
919
+ environments = servers.map(function (server) {
920
+ var _a, _b;
921
+ return ({
922
+ id: server.id.toString(),
923
+ name: server.name,
924
+ status: server.status,
925
+ ipv4: ((_a = server.public_net.ipv4) === null || _a === void 0 ? void 0 : _a.ip) || null,
926
+ ipv6: ((_b = server.public_net.ipv6) === null || _b === void 0 ? void 0 : _b.ip) || null,
927
+ serverType: server.server_type.name,
928
+ location: server.datacenter.location.name,
929
+ created: server.created,
930
+ });
931
+ });
932
+ return [2 /*return*/, {
933
+ content: [{
934
+ type: "text",
935
+ text: JSON.stringify(environments, null, 2),
936
+ }],
937
+ }];
938
+ case 4:
939
+ if (!hetznerClient) {
940
+ return [2 /*return*/, {
941
+ content: [{
942
+ type: "text",
943
+ text: "Hetzner client not available.",
944
+ }],
945
+ }];
946
+ }
947
+ return [4 /*yield*/, hetznerClient.getServer(parseInt(args === null || args === void 0 ? void 0 : args.id))];
948
+ case 5:
949
+ server_1 = _7.sent();
950
+ return [2 /*return*/, {
951
+ content: [{
952
+ type: "text",
953
+ text: JSON.stringify(server_1, null, 2),
954
+ }],
955
+ }];
956
+ case 6:
957
+ if (!hetznerClient) {
958
+ return [2 /*return*/, {
959
+ content: [{
960
+ type: "text",
961
+ text: "Hetzner client not available.",
962
+ }],
963
+ }];
964
+ }
965
+ name_1 = args === null || args === void 0 ? void 0 : args.name;
966
+ if (!name_1 || typeof name_1 !== "string") {
967
+ return [2 /*return*/, {
968
+ content: [{
969
+ type: "text",
970
+ text: "Error: name is required and must be a string",
971
+ }],
972
+ isError: true,
973
+ }];
974
+ }
975
+ // Validate user-data format if provided
976
+ if ((args === null || args === void 0 ? void 0 : args.userData) && typeof args.userData === "string") {
977
+ if (!args.userData.trim().startsWith("#cloud-config")) {
978
+ return [2 /*return*/, {
979
+ content: [{
980
+ type: "text",
981
+ text: "Error: userData must start with '#cloud-config'",
982
+ }],
983
+ isError: true,
984
+ }];
985
+ }
986
+ }
987
+ return [4 /*yield*/, Promise.resolve().then(function () { return require("cheapspaces/workspace/src/lib/bootstrap/cloud-init"); })];
988
+ case 7:
989
+ generateSeedBootstrap = (_7.sent()).generateSeedBootstrap;
990
+ userData = generateSeedBootstrap();
991
+ generatedPassword = "";
992
+ // Override with custom userData if provided
993
+ if ((args === null || args === void 0 ? void 0 : args.userData) && typeof args.userData === "string") {
994
+ userData = args.userData;
995
+ }
996
+ // Override with password mode if requested
997
+ else if ((args === null || args === void 0 ? void 0 : args.enablePassword) === true) {
998
+ cleanPassword = Array.from({ length: 12 }, function () {
999
+ return 'abcdefghijklmnopqrstuvwxyz0123456789'[Math.floor(Math.random() * 36)];
1000
+ }).join('');
1001
+ generatedPassword = cleanPassword;
1002
+ passwordSetup = "#cloud-config\nruncmd:\n - sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config\n - sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config\n - systemctl restart ssh\n - sh -c 'echo root:".concat(cleanPassword, " | chpasswd'\n - sh -c 'echo ").concat(cleanPassword, " > /root/password.txt'\n - chmod 600 /root/password.txt\n");
1003
+ seedLines = userData.split('\n');
1004
+ passwordLines = passwordSetup.split('\n');
1005
+ mergedLines = [];
1006
+ inRuncmd = false;
1007
+ runcmdIndex = -1;
1008
+ // Add seed bootstrap content until we hit runcmd
1009
+ for (_i = 0, seedLines_1 = seedLines; _i < seedLines_1.length; _i++) {
1010
+ line = seedLines_1[_i];
1011
+ if (line.startsWith('runcmd:')) {
1012
+ inRuncmd = true;
1013
+ runcmdIndex = mergedLines.length;
1014
+ mergedLines.push(line);
1015
+ }
1016
+ else if (inRuncmd && line.startsWith(' -')) {
1017
+ mergedLines.push(line);
1018
+ }
1019
+ else if (!inRuncmd) {
1020
+ mergedLines.push(line);
1021
+ }
1022
+ else if (inRuncmd && !line.startsWith(' -')) {
1023
+ // End of runcmd section
1024
+ inRuncmd = false;
1025
+ }
1026
+ }
1027
+ // Append password runcmd commands
1028
+ for (_c = 0, passwordLines_1 = passwordLines; _c < passwordLines_1.length; _c++) {
1029
+ line = passwordLines_1[_c];
1030
+ if (line.startsWith('runcmd:'))
1031
+ continue; // Skip header
1032
+ if (line.trim() === '' || line.startsWith('#'))
1033
+ continue; // Skip empty and comments
1034
+ if (line.startsWith(' -')) {
1035
+ mergedLines.splice(runcmdIndex + 1, 0, line);
1036
+ runcmdIndex++;
1037
+ }
1038
+ }
1039
+ userData = mergedLines.join('\n');
1040
+ }
1041
+ sshKeys = [];
1042
+ if (!((args === null || args === void 0 ? void 0 : args.sshKey) && typeof args.sshKey === "string")) return [3 /*break*/, 18];
1043
+ if (!args.sshKey.includes(" ")) return [3 /*break*/, 12];
1044
+ _7.label = 8;
1045
+ case 8:
1046
+ _7.trys.push([8, 10, , 11]);
1047
+ keyName = "mcp-key-".concat(Date.now());
1048
+ return [4 /*yield*/, hetznerClient.ssh_keys.create({
1049
+ name: keyName,
1050
+ public_key: args.sshKey,
1051
+ })];
1052
+ case 9:
1053
+ newKey = _7.sent();
1054
+ sshKeys = [newKey.id];
1055
+ return [3 /*break*/, 11];
1056
+ case 10:
1057
+ e_2 = _7.sent();
1058
+ return [2 /*return*/, {
1059
+ content: [{
1060
+ type: "text",
1061
+ text: "Error creating SSH key: ".concat(String(e_2)),
1062
+ }],
1063
+ isError: true,
1064
+ }];
1065
+ case 11: return [3 /*break*/, 18];
1066
+ case 12:
1067
+ _7.trys.push([12, 17, , 18]);
1068
+ return [4 /*yield*/, hetznerClient.ssh_keys.findByName(args.sshKey)];
1069
+ case 13:
1070
+ key = _7.sent();
1071
+ if (!key) return [3 /*break*/, 14];
1072
+ sshKeys = [key.id];
1073
+ return [3 /*break*/, 16];
1074
+ case 14:
1075
+ _0 = {};
1076
+ _1 = {
1077
+ type: "text"
1078
+ };
1079
+ _e = (_d = "Error: SSH key '".concat(args.sshKey, "' not found. Available keys:\n")).concat;
1080
+ _g = (_f = JSON).stringify;
1081
+ return [4 /*yield*/, hetznerClient.ssh_keys.list()];
1082
+ case 15: return [2 /*return*/, (_0.content = [(_1.text = _e.apply(_d, [_g.apply(_f, [_7.sent(), null, 2])]),
1083
+ _1)],
1084
+ _0.isError = true,
1085
+ _0)];
1086
+ case 16: return [3 /*break*/, 18];
1087
+ case 17:
1088
+ e_3 = _7.sent();
1089
+ return [2 /*return*/, {
1090
+ content: [{
1091
+ type: "text",
1092
+ text: "Error looking up SSH key: ".concat(String(e_3)),
1093
+ }],
1094
+ isError: true,
1095
+ }];
1096
+ case 18:
1097
+ serverOptions = {
1098
+ name: name_1,
1099
+ server_type: typeof (args === null || args === void 0 ? void 0 : args.serverType) === "string" ? args.serverType : "cax21",
1100
+ ssh_keys: sshKeys,
1101
+ user_data: userData,
1102
+ };
1103
+ // Only add location if it's a valid string
1104
+ if ((args === null || args === void 0 ? void 0 : args.location) && typeof args.location === "string") {
1105
+ serverOptions.location = args.location;
1106
+ }
1107
+ return [4 /*yield*/, hetznerClient.createServer(serverOptions)];
1108
+ case 19:
1109
+ response = _7.sent();
1110
+ responseText = "";
1111
+ // CRITICAL: Put password FIRST and make it VERY prominent
1112
+ // The MCP tool layer seems to truncate responses after JSON, so password MUST come before
1113
+ if (generatedPassword) {
1114
+ responseText += "========================================\n";
1115
+ responseText += "\uD83D\uDD11 TEMPORARY ROOT PASSWORD: ".concat(generatedPassword, "\n");
1116
+ responseText += "========================================\n";
1117
+ responseText += "SAVE THIS NOW - It will NOT be shown again!\n\n";
1118
+ }
1119
+ responseText += "Environment created:\n".concat(JSON.stringify(response.server, null, 2));
1120
+ console.error("[MCP] Password generated for server ".concat(response.server.name, ": ").concat(generatedPassword));
1121
+ return [2 /*return*/, {
1122
+ content: [{
1123
+ type: "text",
1124
+ text: responseText,
1125
+ }],
1126
+ }];
1127
+ case 20:
1128
+ if (!hetznerClient) {
1129
+ return [2 /*return*/, {
1130
+ content: [{
1131
+ type: "text",
1132
+ text: "Hetzner client not available.",
1133
+ }],
1134
+ }];
1135
+ }
1136
+ return [4 /*yield*/, hetznerClient.powerOn(parseInt(args === null || args === void 0 ? void 0 : args.id))];
1137
+ case 21:
1138
+ action = _7.sent();
1139
+ return [2 /*return*/, {
1140
+ content: [{
1141
+ type: "text",
1142
+ text: "Start action initiated: ".concat(action.id),
1143
+ }],
1144
+ }];
1145
+ case 22:
1146
+ if (!hetznerClient) {
1147
+ return [2 /*return*/, {
1148
+ content: [{
1149
+ type: "text",
1150
+ text: "Hetzner client not available.",
1151
+ }],
1152
+ }];
1153
+ }
1154
+ return [4 /*yield*/, hetznerClient.powerOff(parseInt(args === null || args === void 0 ? void 0 : args.id))];
1155
+ case 23:
1156
+ _7.sent();
1157
+ return [2 /*return*/, {
1158
+ content: [{
1159
+ type: "text",
1160
+ text: "Environment stopped.",
1161
+ }],
1162
+ }];
1163
+ case 24:
1164
+ if (!hetznerClient) {
1165
+ return [2 /*return*/, {
1166
+ content: [{
1167
+ type: "text",
1168
+ text: "Hetzner client not available.",
1169
+ }],
1170
+ }];
1171
+ }
1172
+ return [4 /*yield*/, hetznerClient.deleteServer(parseInt(args === null || args === void 0 ? void 0 : args.id))];
1173
+ case 25:
1174
+ _7.sent();
1175
+ return [2 /*return*/, {
1176
+ content: [{
1177
+ type: "text",
1178
+ text: "Environment deleted.",
1179
+ }],
1180
+ }];
1181
+ case 26: return [4 /*yield*/, Promise.resolve().then(function () { return require("cheapspaces/workspace/src/lib/resources"); })];
1182
+ case 27:
1183
+ parseResources = (_7.sent()).parseResources;
1184
+ return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1185
+ case 28:
1186
+ execSSHParallel = (_7.sent()).execSSHParallel;
1187
+ return [4 /*yield*/, Promise.resolve().then(function () { return require("cheapspaces/workspace/src/lib/metadata"); })];
1188
+ case 29:
1189
+ getMetadata = (_7.sent()).getMetadata;
1190
+ if (!hetznerClient) {
1191
+ return [2 /*return*/, {
1192
+ content: [{
1193
+ type: "text",
1194
+ text: "Hetzner client not available.",
1195
+ }],
1196
+ }];
1197
+ }
1198
+ return [4 /*yield*/, hetznerClient.getServer(parseInt(args === null || args === void 0 ? void 0 : args.id))];
1199
+ case 30:
1200
+ server_2 = _7.sent();
1201
+ if (!((_2 = server_2 === null || server_2 === void 0 ? void 0 : server_2.public_net.ipv4) === null || _2 === void 0 ? void 0 : _2.ip)) {
1202
+ return [2 /*return*/, {
1203
+ content: [{
1204
+ type: "text",
1205
+ text: "Server not found or no IP address.",
1206
+ }],
1207
+ }];
1208
+ }
1209
+ metadata = getMetadata(server_2.id.toString());
1210
+ keyPath = metadata === null || metadata === void 0 ? void 0 : metadata.sshKeyPath;
1211
+ password = metadata === null || metadata === void 0 ? void 0 : metadata.sshPassword;
1212
+ RESOURCE_COMMANDS = {
1213
+ cpu: "top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1",
1214
+ memory: "free | grep Mem | awk '{printf \"%.1f\", ($3/$2) * 100.0}'",
1215
+ disk: "df -h / | tail -1 | awk '{print $5}' | sed 's/%//'",
1216
+ };
1217
+ return [4 /*yield*/, execSSHParallel(RESOURCE_COMMANDS, __assign(__assign({ host: server_2.public_net.ipv4.ip, user: "root", timeout: 5 }, (keyPath && { keyPath: keyPath })), (password && { password: password })))];
1218
+ case 31:
1219
+ rawResults = _7.sent();
1220
+ resources = parseResources(rawResults);
1221
+ return [2 /*return*/, {
1222
+ content: [{
1223
+ type: "text",
1224
+ text: JSON.stringify(resources, null, 2),
1225
+ }],
1226
+ }];
1227
+ case 32: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1228
+ case 33:
1229
+ testSSHConnection = (_7.sent()).testSSHConnection;
1230
+ return [4 /*yield*/, testSSHConnection({
1231
+ host: args === null || args === void 0 ? void 0 : args.host,
1232
+ user: (args === null || args === void 0 ? void 0 : args.user) || "root",
1233
+ port: 22,
1234
+ keyPath: args === null || args === void 0 ? void 0 : args.keyPath,
1235
+ password: args === null || args === void 0 ? void 0 : args.password,
1236
+ })];
1237
+ case 34:
1238
+ connected = _7.sent();
1239
+ return [2 /*return*/, {
1240
+ content: [{
1241
+ type: "text",
1242
+ text: connected ? "SSH connection successful." : "SSH connection failed.",
1243
+ }],
1244
+ }];
1245
+ case 35:
1246
+ if (!hetznerClient) {
1247
+ return [2 /*return*/, {
1248
+ content: [{
1249
+ type: "text",
1250
+ text: "Hetzner client not available.",
1251
+ }],
1252
+ }];
1253
+ }
1254
+ return [4 /*yield*/, hetznerClient.ssh_keys.create({
1255
+ name: args === null || args === void 0 ? void 0 : args.name,
1256
+ public_key: args === null || args === void 0 ? void 0 : args.publicKey,
1257
+ })];
1258
+ case 36:
1259
+ sshKey = _7.sent();
1260
+ return [2 /*return*/, {
1261
+ content: [{
1262
+ type: "text",
1263
+ text: "SSH key created:\n".concat(JSON.stringify(sshKey, null, 2)),
1264
+ }],
1265
+ }];
1266
+ case 37:
1267
+ if (!hetznerClient) {
1268
+ return [2 /*return*/, {
1269
+ content: [{
1270
+ type: "text",
1271
+ text: "Hetzner client not available.",
1272
+ }],
1273
+ }];
1274
+ }
1275
+ return [4 /*yield*/, hetznerClient.ssh_keys.list()];
1276
+ case 38:
1277
+ sshKeys = _7.sent();
1278
+ return [2 /*return*/, {
1279
+ content: [{
1280
+ type: "text",
1281
+ text: JSON.stringify(sshKeys, null, 2),
1282
+ }],
1283
+ }];
1284
+ case 39:
1285
+ host = args === null || args === void 0 ? void 0 : args.host;
1286
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1287
+ command = args === null || args === void 0 ? void 0 : args.command;
1288
+ keyPath = args === null || args === void 0 ? void 0 : args.keyPath;
1289
+ password = args === null || args === void 0 ? void 0 : args.password;
1290
+ waitTime_1 = (_3 = args === null || args === void 0 ? void 0 : args.waitTime) !== null && _3 !== void 0 ? _3 : 500;
1291
+ captureHistory = (_4 = args === null || args === void 0 ? void 0 : args.captureHistory) !== null && _4 !== void 0 ? _4 : true;
1292
+ customSessionName = args === null || args === void 0 ? void 0 : args.sessionName;
1293
+ paneIndex = (_5 = args === null || args === void 0 ? void 0 : args.paneIndex) !== null && _5 !== void 0 ? _5 : "0";
1294
+ return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1295
+ case 40:
1296
+ _h = _7.sent(), generateLocalSessionName = _h.generateLocalSessionName, isLocalTmuxInstalled = _h.isLocalTmuxInstalled, hasLocalSession = _h.hasLocalSession, createLocalTmuxSSHSession = _h.createLocalTmuxSSHSession, sendCommandToLocalSession = _h.sendCommandToLocalSession, captureLocalPane = _h.captureLocalPane, getLocalPaneHistory = _h.getLocalPaneHistory;
1297
+ return [4 /*yield*/, isLocalTmuxInstalled()];
1298
+ case 41:
1299
+ tmuxInstalled = _7.sent();
1300
+ if (!tmuxInstalled) {
1301
+ return [2 /*return*/, {
1302
+ content: [{
1303
+ type: "text",
1304
+ text: "Local tmux is not installed. Please install tmux on your local machine first.",
1305
+ }],
1306
+ isError: true,
1307
+ }];
1308
+ }
1309
+ sessionName = customSessionName || generateLocalSessionName(host, user);
1310
+ // Track session state
1311
+ if (!localTmuxSessions.has(sessionName)) {
1312
+ localTmuxSessions.set(sessionName, {
1313
+ host: host,
1314
+ user: user,
1315
+ initialized: false,
1316
+ createdAt: Date.now(),
1317
+ windowName: "ssh", // Default window name
1318
+ });
1319
+ }
1320
+ sessionState = localTmuxSessions.get(sessionName);
1321
+ return [4 /*yield*/, hasLocalSession(sessionName)];
1322
+ case 42:
1323
+ sessionExists = _7.sent();
1324
+ if (!(!sessionState.initialized || !sessionExists)) return [3 /*break*/, 46];
1325
+ _7.label = 43;
1326
+ case 43:
1327
+ _7.trys.push([43, 45, , 46]);
1328
+ return [4 /*yield*/, createLocalTmuxSSHSession(host, user, keyPath, password, { sessionName: sessionName })];
1329
+ case 44:
1330
+ _7.sent();
1331
+ sessionState.initialized = true;
1332
+ return [3 /*break*/, 46];
1333
+ case 45:
1334
+ error_1 = _7.sent();
1335
+ return [2 /*return*/, {
1336
+ content: [{
1337
+ type: "text",
1338
+ text: "Failed to create local tmux session '".concat(sessionName, "' for ").concat(user, "@").concat(host, ": ").concat(error_1 instanceof Error ? error_1.message : String(error_1)),
1339
+ }],
1340
+ isError: true,
1341
+ }];
1342
+ case 46: return [4 /*yield*/, sendCommandToLocalSession(sessionName, command, paneIndex, sessionState.windowName)];
1343
+ case 47:
1344
+ sent = _7.sent();
1345
+ if (!sent) {
1346
+ return [2 /*return*/, {
1347
+ content: [{
1348
+ type: "text",
1349
+ text: "Failed to send command to local tmux session",
1350
+ }],
1351
+ isError: true,
1352
+ }];
1353
+ }
1354
+ // Wait for command to execute
1355
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, waitTime_1); })];
1356
+ case 48:
1357
+ // Wait for command to execute
1358
+ _7.sent();
1359
+ output = void 0;
1360
+ if (!captureHistory) return [3 /*break*/, 50];
1361
+ return [4 /*yield*/, getLocalPaneHistory(sessionName, paneIndex, -1, sessionState.windowName)];
1362
+ case 49:
1363
+ output = _7.sent();
1364
+ return [3 /*break*/, 52];
1365
+ case 50: return [4 /*yield*/, captureLocalPane(sessionName, paneIndex, sessionState.windowName)];
1366
+ case 51:
1367
+ output = _7.sent();
1368
+ _7.label = 52;
1369
+ case 52: return [2 /*return*/, {
1370
+ content: [{
1371
+ type: "text",
1372
+ text: output || "Command executed (no output)",
1373
+ }],
1374
+ }];
1375
+ case 53: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1376
+ case 54:
1377
+ _j = _7.sent(), listLocalSessions = _j.listLocalSessions, getLocalTmuxResourceUsage = _j.getLocalTmuxResourceUsage;
1378
+ return [4 /*yield*/, listLocalSessions()];
1379
+ case 55:
1380
+ sessions = _7.sent();
1381
+ mcpSessions = sessions.filter(function (s) { return s.startsWith("mcp-ssh"); });
1382
+ return [4 /*yield*/, getLocalTmuxResourceUsage()];
1383
+ case 56:
1384
+ resources = _7.sent();
1385
+ trackedSessions = [];
1386
+ for (_k = 0, _l = localTmuxSessions.entries(); _k < _l.length; _k++) {
1387
+ _m = _l[_k], name_2 = _m[0], state = _m[1];
1388
+ if (sessions.includes(name_2)) {
1389
+ trackedSessions.push({
1390
+ sessionName: name_2,
1391
+ host: state.host,
1392
+ user: state.user,
1393
+ windowName: state.windowName,
1394
+ createdAt: state.createdAt,
1395
+ });
1396
+ }
1397
+ }
1398
+ return [2 /*return*/, {
1399
+ content: [{
1400
+ type: "text",
1401
+ text: JSON.stringify({
1402
+ allSessions: sessions,
1403
+ mcpSessions: mcpSessions,
1404
+ trackedSessions: trackedSessions,
1405
+ resources: resources,
1406
+ sessionType: "local",
1407
+ description: "Local tmux sessions with persistent SSH connections",
1408
+ }, null, 2),
1409
+ }],
1410
+ }];
1411
+ case 57: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1412
+ case 58:
1413
+ _o = _7.sent(), killLocalSession = _o.killLocalSession, generateLocalSessionName = _o.generateLocalSessionName;
1414
+ host = args === null || args === void 0 ? void 0 : args.host;
1415
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1416
+ sessionName = (args === null || args === void 0 ? void 0 : args.sessionName) || generateLocalSessionName(host, user);
1417
+ return [4 /*yield*/, killLocalSession(sessionName)];
1418
+ case 59:
1419
+ killed = _7.sent();
1420
+ // Clear from local state tracking (by session name directly)
1421
+ localTmuxSessions.delete(sessionName);
1422
+ return [2 /*return*/, {
1423
+ content: [{
1424
+ type: "text",
1425
+ text: killed
1426
+ ? "Local tmux session '".concat(sessionName, "' killed.")
1427
+ : "Failed to kill local tmux session '".concat(sessionName, "' or session not found."),
1428
+ }],
1429
+ }];
1430
+ case 60: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1431
+ case 61:
1432
+ _p = _7.sent(), getDetailedLocalSessionInfo = _p.getDetailedLocalSessionInfo, generateLocalSessionName = _p.generateLocalSessionName;
1433
+ host = args === null || args === void 0 ? void 0 : args.host;
1434
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1435
+ sessionName = (args === null || args === void 0 ? void 0 : args.sessionName) || generateLocalSessionName(host, user);
1436
+ return [4 /*yield*/, getDetailedLocalSessionInfo(sessionName)];
1437
+ case 62:
1438
+ info = _7.sent();
1439
+ return [2 /*return*/, {
1440
+ content: [{
1441
+ type: "text",
1442
+ text: JSON.stringify(__assign(__assign({}, info), { sessionType: "local", description: "Local tmux session with persistent SSH connection" }), null, 2),
1443
+ }],
1444
+ }];
1445
+ case 63: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1446
+ case 64:
1447
+ _q = _7.sent(), generateLocalSessionName = _q.generateLocalSessionName, hasLocalSession = _q.hasLocalSession;
1448
+ host = args === null || args === void 0 ? void 0 : args.host;
1449
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1450
+ customSessionName = args === null || args === void 0 ? void 0 : args.sessionName;
1451
+ sessionName = customSessionName || generateLocalSessionName(host, user);
1452
+ return [4 /*yield*/, hasLocalSession(sessionName)];
1453
+ case 65:
1454
+ sessionExists = _7.sent();
1455
+ attachCmd = "tmux attach-session -t \"".concat(sessionName, "\"");
1456
+ return [2 /*return*/, {
1457
+ content: [{
1458
+ type: "text",
1459
+ text: "To attach to the local tmux session '".concat(sessionName, "', run:\n\n").concat(attachCmd, "\n\n") +
1460
+ "Session exists: ".concat(sessionExists, "\n") +
1461
+ "Note: This is a local tmux session with a persistent SSH connection to ".concat(user, "@").concat(host, "."),
1462
+ }],
1463
+ }];
1464
+ case 66: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1465
+ case 67:
1466
+ _r = _7.sent(), generateLocalSessionName = _r.generateLocalSessionName, isLocalTmuxInstalled = _r.isLocalTmuxInstalled, createLocalTmuxSSHSession = _r.createLocalTmuxSSHSession;
1467
+ host = args === null || args === void 0 ? void 0 : args.host;
1468
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1469
+ customSessionName = args === null || args === void 0 ? void 0 : args.sessionName;
1470
+ keyPath = args === null || args === void 0 ? void 0 : args.keyPath;
1471
+ password = args === null || args === void 0 ? void 0 : args.password;
1472
+ initialCommand = args === null || args === void 0 ? void 0 : args.initialCommand;
1473
+ windowName = args === null || args === void 0 ? void 0 : args.windowName;
1474
+ return [4 /*yield*/, isLocalTmuxInstalled()];
1475
+ case 68:
1476
+ tmuxInstalled = _7.sent();
1477
+ if (!tmuxInstalled) {
1478
+ return [2 /*return*/, {
1479
+ content: [{
1480
+ type: "text",
1481
+ text: "Local tmux is not installed. Please install tmux on your local machine first.",
1482
+ }],
1483
+ isError: true,
1484
+ }];
1485
+ }
1486
+ sessionName = customSessionName || generateLocalSessionName(host, user);
1487
+ _7.label = 69;
1488
+ case 69:
1489
+ _7.trys.push([69, 71, , 72]);
1490
+ return [4 /*yield*/, createLocalTmuxSSHSession(host, user, keyPath, password, {
1491
+ sessionName: sessionName,
1492
+ initialCommand: initialCommand,
1493
+ windowName: windowName,
1494
+ })];
1495
+ case 70:
1496
+ result = _7.sent();
1497
+ effectiveWindowName = windowName || "ssh";
1498
+ localTmuxSessions.set(sessionName, {
1499
+ host: host,
1500
+ user: user,
1501
+ initialized: true,
1502
+ createdAt: Date.now(),
1503
+ windowName: effectiveWindowName,
1504
+ });
1505
+ return [2 /*return*/, {
1506
+ content: [{
1507
+ type: "text",
1508
+ text: result.newlyCreated
1509
+ ? "Created new tmux session '".concat(sessionName, "' for ").concat(user, "@").concat(host, ".\n\nTo attach: tmux attach-session -t \"").concat(sessionName, "\"")
1510
+ : "Tmux session '".concat(sessionName, "' already exists.\n\nTo attach: tmux attach-session -t \"").concat(sessionName, "\""),
1511
+ }],
1512
+ }];
1513
+ case 71:
1514
+ error_2 = _7.sent();
1515
+ return [2 /*return*/, {
1516
+ content: [{
1517
+ type: "text",
1518
+ text: "Failed to create tmux session: ".concat(error_2 instanceof Error ? error_2.message : String(error_2)),
1519
+ }],
1520
+ isError: true,
1521
+ }];
1522
+ case 72: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1523
+ case 73:
1524
+ _s = _7.sent(), generateLocalSessionName = _s.generateLocalSessionName, splitLocalPane = _s.splitLocalPane;
1525
+ host = args === null || args === void 0 ? void 0 : args.host;
1526
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1527
+ customSessionName = args === null || args === void 0 ? void 0 : args.sessionName;
1528
+ direction = (args === null || args === void 0 ? void 0 : args.direction) || "v";
1529
+ command = args === null || args === void 0 ? void 0 : args.command;
1530
+ sessionName = customSessionName || generateLocalSessionName(host, user);
1531
+ sessionState = localTmuxSessions.get(sessionName);
1532
+ windowName = sessionState === null || sessionState === void 0 ? void 0 : sessionState.windowName;
1533
+ _7.label = 74;
1534
+ case 74:
1535
+ _7.trys.push([74, 76, , 77]);
1536
+ return [4 /*yield*/, splitLocalPane(sessionName, direction, command, windowName)];
1537
+ case 75:
1538
+ newPaneIndex = _7.sent();
1539
+ return [2 /*return*/, {
1540
+ content: [{
1541
+ type: "text",
1542
+ text: newPaneIndex
1543
+ ? "Pane split ".concat(direction === "v" ? "vertically" : "horizontally", " in session '").concat(sessionName, "'.\n\nUse exec_ssh with paneIndex to send commands to specific panes.")
1544
+ : "Failed to split pane in session '".concat(sessionName, "'."),
1545
+ }],
1546
+ }];
1547
+ case 76:
1548
+ error_3 = _7.sent();
1549
+ return [2 /*return*/, {
1550
+ content: [{
1551
+ type: "text",
1552
+ text: "Failed to split pane: ".concat(error_3 instanceof Error ? error_3.message : String(error_3)),
1553
+ }],
1554
+ isError: true,
1555
+ }];
1556
+ case 77: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1557
+ case 78:
1558
+ _t = _7.sent(), generateLocalSessionName = _t.generateLocalSessionName, listLocalSessionWindows = _t.listLocalSessionWindows;
1559
+ host = args === null || args === void 0 ? void 0 : args.host;
1560
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1561
+ customSessionName = args === null || args === void 0 ? void 0 : args.sessionName;
1562
+ sessionName = customSessionName || generateLocalSessionName(host, user);
1563
+ _7.label = 79;
1564
+ case 79:
1565
+ _7.trys.push([79, 81, , 82]);
1566
+ return [4 /*yield*/, listLocalSessionWindows(sessionName)];
1567
+ case 80:
1568
+ windows = _7.sent();
1569
+ return [2 /*return*/, {
1570
+ content: [{
1571
+ type: "text",
1572
+ text: JSON.stringify({
1573
+ session: sessionName,
1574
+ windows: windows,
1575
+ count: windows.length,
1576
+ }, null, 2),
1577
+ }],
1578
+ }];
1579
+ case 81:
1580
+ error_4 = _7.sent();
1581
+ return [2 /*return*/, {
1582
+ content: [{
1583
+ type: "text",
1584
+ text: "Failed to list windows: ".concat(error_4 instanceof Error ? error_4.message : String(error_4)),
1585
+ }],
1586
+ isError: true,
1587
+ }];
1588
+ case 82: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1589
+ case 83:
1590
+ _u = _7.sent(), generateLocalSessionName = _u.generateLocalSessionName, listLocalWindowPanes = _u.listLocalWindowPanes, listLocalSessionWindows = _u.listLocalSessionWindows;
1591
+ host = args === null || args === void 0 ? void 0 : args.host;
1592
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1593
+ customSessionName = args === null || args === void 0 ? void 0 : args.sessionName;
1594
+ windowIndex = args === null || args === void 0 ? void 0 : args.windowIndex;
1595
+ sessionName = customSessionName || generateLocalSessionName(host, user);
1596
+ if (!!windowIndex) return [3 /*break*/, 87];
1597
+ sessionState = localTmuxSessions.get(sessionName);
1598
+ if (!(sessionState === null || sessionState === void 0 ? void 0 : sessionState.windowName)) return [3 /*break*/, 84];
1599
+ windowIndex = sessionState.windowName;
1600
+ return [3 /*break*/, 87];
1601
+ case 84:
1602
+ _7.trys.push([84, 86, , 87]);
1603
+ return [4 /*yield*/, listLocalSessionWindows(sessionName)];
1604
+ case 85:
1605
+ windows = _7.sent();
1606
+ if (windows.length > 0) {
1607
+ windowIndex = windows[0].index; // Use numeric index
1608
+ }
1609
+ return [3 /*break*/, 87];
1610
+ case 86:
1611
+ _v = _7.sent();
1612
+ windowIndex = "0"; // Fallback to 0
1613
+ return [3 /*break*/, 87];
1614
+ case 87:
1615
+ _7.trys.push([87, 89, , 90]);
1616
+ return [4 /*yield*/, listLocalWindowPanes(sessionName, windowIndex)];
1617
+ case 88:
1618
+ panes = _7.sent();
1619
+ return [2 /*return*/, {
1620
+ content: [{
1621
+ type: "text",
1622
+ text: JSON.stringify({
1623
+ session: sessionName,
1624
+ window: windowIndex,
1625
+ panes: panes,
1626
+ count: panes.length,
1627
+ }, null, 2),
1628
+ }],
1629
+ }];
1630
+ case 89:
1631
+ error_5 = _7.sent();
1632
+ return [2 /*return*/, {
1633
+ content: [{
1634
+ type: "text",
1635
+ text: "Failed to list panes: ".concat(error_5 instanceof Error ? error_5.message : String(error_5)),
1636
+ }],
1637
+ isError: true,
1638
+ }];
1639
+ case 90: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1640
+ case 91:
1641
+ _w = _7.sent(), generateLocalSessionName = _w.generateLocalSessionName, switchLocalWindow = _w.switchLocalWindow;
1642
+ host = args === null || args === void 0 ? void 0 : args.host;
1643
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1644
+ customSessionName = args === null || args === void 0 ? void 0 : args.sessionName;
1645
+ windowIndex = args === null || args === void 0 ? void 0 : args.windowIndex;
1646
+ sessionName = customSessionName || generateLocalSessionName(host, user);
1647
+ _7.label = 92;
1648
+ case 92:
1649
+ _7.trys.push([92, 94, , 95]);
1650
+ return [4 /*yield*/, switchLocalWindow(sessionName, windowIndex)];
1651
+ case 93:
1652
+ switched = _7.sent();
1653
+ return [2 /*return*/, {
1654
+ content: [{
1655
+ type: "text",
1656
+ text: switched
1657
+ ? "Switched to window ".concat(windowIndex, " in session '").concat(sessionName, "'.")
1658
+ : "Failed to switch to window ".concat(windowIndex, " in session '").concat(sessionName, "'."),
1659
+ }],
1660
+ }];
1661
+ case 94:
1662
+ error_6 = _7.sent();
1663
+ return [2 /*return*/, {
1664
+ content: [{
1665
+ type: "text",
1666
+ text: "Failed to switch window: ".concat(error_6 instanceof Error ? error_6.message : String(error_6)),
1667
+ }],
1668
+ isError: true,
1669
+ }];
1670
+ case 95: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1671
+ case 96:
1672
+ _x = _7.sent(), generateLocalSessionName = _x.generateLocalSessionName, switchLocalPane = _x.switchLocalPane;
1673
+ host = args === null || args === void 0 ? void 0 : args.host;
1674
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1675
+ customSessionName = args === null || args === void 0 ? void 0 : args.sessionName;
1676
+ paneIndex = args === null || args === void 0 ? void 0 : args.paneIndex;
1677
+ sessionName = customSessionName || generateLocalSessionName(host, user);
1678
+ _7.label = 97;
1679
+ case 97:
1680
+ _7.trys.push([97, 99, , 100]);
1681
+ return [4 /*yield*/, switchLocalPane(sessionName, paneIndex)];
1682
+ case 98:
1683
+ switched = _7.sent();
1684
+ return [2 /*return*/, {
1685
+ content: [{
1686
+ type: "text",
1687
+ text: switched
1688
+ ? "Switched to pane ".concat(paneIndex, " in session '").concat(sessionName, "'.")
1689
+ : "Failed to switch to pane ".concat(paneIndex, " in session '").concat(sessionName, "'."),
1690
+ }],
1691
+ }];
1692
+ case 99:
1693
+ error_7 = _7.sent();
1694
+ return [2 /*return*/, {
1695
+ content: [{
1696
+ type: "text",
1697
+ text: "Failed to switch pane: ".concat(error_7 instanceof Error ? error_7.message : String(error_7)),
1698
+ }],
1699
+ isError: true,
1700
+ }];
1701
+ case 100: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1702
+ case 101:
1703
+ _y = _7.sent(), generateLocalSessionName = _y.generateLocalSessionName, renameLocalWindow = _y.renameLocalWindow;
1704
+ host = args === null || args === void 0 ? void 0 : args.host;
1705
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1706
+ customSessionName = args === null || args === void 0 ? void 0 : args.sessionName;
1707
+ windowIndex = (args === null || args === void 0 ? void 0 : args.windowIndex) || "ssh";
1708
+ newName = args === null || args === void 0 ? void 0 : args.newName;
1709
+ sessionName = customSessionName || generateLocalSessionName(host, user);
1710
+ _7.label = 102;
1711
+ case 102:
1712
+ _7.trys.push([102, 107, , 108]);
1713
+ return [4 /*yield*/, renameLocalWindow(sessionName, windowIndex, newName)];
1714
+ case 103:
1715
+ renamed = _7.sent();
1716
+ if (!renamed) return [3 /*break*/, 106];
1717
+ sessionState = localTmuxSessions.get(sessionName);
1718
+ if (!sessionState) return [3 /*break*/, 106];
1719
+ return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1720
+ case 104: return [4 /*yield*/, (_7.sent()).listLocalSessionWindows(sessionName)];
1721
+ case 105:
1722
+ windows = _7.sent();
1723
+ if (windows.length > 0) {
1724
+ sessionState.windowName = newName;
1725
+ }
1726
+ _7.label = 106;
1727
+ case 106: return [2 /*return*/, {
1728
+ content: [{
1729
+ type: "text",
1730
+ text: renamed
1731
+ ? "Renamed window ".concat(windowIndex, " to '").concat(newName, "' in session '").concat(sessionName, "'.")
1732
+ : "Failed to rename window in session '".concat(sessionName, "'."),
1733
+ }],
1734
+ }];
1735
+ case 107:
1736
+ error_8 = _7.sent();
1737
+ return [2 /*return*/, {
1738
+ content: [{
1739
+ type: "text",
1740
+ text: "Failed to rename window: ".concat(error_8 instanceof Error ? error_8.message : String(error_8)),
1741
+ }],
1742
+ isError: true,
1743
+ }];
1744
+ case 108: return [4 /*yield*/, Promise.resolve().then(function () { return require("@codespaces/terminal"); })];
1745
+ case 109:
1746
+ _z = _7.sent(), generateLocalSessionName = _z.generateLocalSessionName, killLocalPane = _z.killLocalPane;
1747
+ host = args === null || args === void 0 ? void 0 : args.host;
1748
+ user = (args === null || args === void 0 ? void 0 : args.user) || "root";
1749
+ customSessionName = args === null || args === void 0 ? void 0 : args.sessionName;
1750
+ paneIndex = args === null || args === void 0 ? void 0 : args.paneIndex;
1751
+ sessionName = customSessionName || generateLocalSessionName(host, user);
1752
+ sessionState = localTmuxSessions.get(sessionName);
1753
+ windowName = sessionState === null || sessionState === void 0 ? void 0 : sessionState.windowName;
1754
+ _7.label = 110;
1755
+ case 110:
1756
+ _7.trys.push([110, 112, , 113]);
1757
+ return [4 /*yield*/, killLocalPane(sessionName, paneIndex, windowName)];
1758
+ case 111:
1759
+ killed = _7.sent();
1760
+ return [2 /*return*/, {
1761
+ content: [{
1762
+ type: "text",
1763
+ text: killed
1764
+ ? "Killed pane ".concat(paneIndex, " in session '").concat(sessionName, "'.")
1765
+ : "Failed to kill pane ".concat(paneIndex, " in session '").concat(sessionName, "'."),
1766
+ }],
1767
+ }];
1768
+ case 112:
1769
+ error_9 = _7.sent();
1770
+ return [2 /*return*/, {
1771
+ content: [{
1772
+ type: "text",
1773
+ text: "Failed to kill pane: ".concat(error_9 instanceof Error ? error_9.message : String(error_9)),
1774
+ }],
1775
+ isError: true,
1776
+ }];
1777
+ case 113:
1778
+ if (!hetznerClient) {
1779
+ return [2 /*return*/, {
1780
+ content: [{
1781
+ type: "text",
1782
+ text: "Hetzner client not available.",
1783
+ }],
1784
+ }];
1785
+ }
1786
+ return [4 /*yield*/, hetznerClient.volumes.list({
1787
+ name: args === null || args === void 0 ? void 0 : args.name,
1788
+ status: args === null || args === void 0 ? void 0 : args.status,
1789
+ })];
1790
+ case 114:
1791
+ volumes = _7.sent();
1792
+ return [2 /*return*/, {
1793
+ content: [{
1794
+ type: "text",
1795
+ text: JSON.stringify(volumes, null, 2),
1796
+ }],
1797
+ }];
1798
+ case 115:
1799
+ if (!hetznerClient) {
1800
+ return [2 /*return*/, {
1801
+ content: [{
1802
+ type: "text",
1803
+ text: "Hetzner client not available.",
1804
+ }],
1805
+ }];
1806
+ }
1807
+ return [4 /*yield*/, hetznerClient.volumes.get(parseInt(args === null || args === void 0 ? void 0 : args.id))];
1808
+ case 116:
1809
+ volume = _7.sent();
1810
+ return [2 /*return*/, {
1811
+ content: [{
1812
+ type: "text",
1813
+ text: JSON.stringify(volume, null, 2),
1814
+ }],
1815
+ }];
1816
+ case 117:
1817
+ if (!hetznerClient) {
1818
+ return [2 /*return*/, {
1819
+ content: [{
1820
+ type: "text",
1821
+ text: "Hetzner client not available.",
1822
+ }],
1823
+ }];
1824
+ }
1825
+ name_3 = args === null || args === void 0 ? void 0 : args.name;
1826
+ size = args === null || args === void 0 ? void 0 : args.size;
1827
+ if (!name_3 || typeof name_3 !== "string") {
1828
+ return [2 /*return*/, {
1829
+ content: [{
1830
+ type: "text",
1831
+ text: "Error: name is required and must be a string",
1832
+ }],
1833
+ isError: true,
1834
+ }];
1835
+ }
1836
+ if (!size || typeof size !== "number") {
1837
+ return [2 /*return*/, {
1838
+ content: [{
1839
+ type: "text",
1840
+ text: "Error: size is required and must be a number",
1841
+ }],
1842
+ isError: true,
1843
+ }];
1844
+ }
1845
+ if (size < 10 || size > 10240) {
1846
+ return [2 /*return*/, {
1847
+ content: [{
1848
+ type: "text",
1849
+ text: "Error: size must be between 10 and 10240 GB",
1850
+ }],
1851
+ isError: true,
1852
+ }];
1853
+ }
1854
+ return [4 /*yield*/, hetznerClient.volumes.create({
1855
+ name: name_3,
1856
+ size: size,
1857
+ location: args === null || args === void 0 ? void 0 : args.location,
1858
+ server: (args === null || args === void 0 ? void 0 : args.serverId) ? parseInt(args.serverId, 10) : undefined,
1859
+ automount: args === null || args === void 0 ? void 0 : args.automount,
1860
+ format: args === null || args === void 0 ? void 0 : args.format,
1861
+ })];
1862
+ case 118:
1863
+ result = _7.sent();
1864
+ return [2 /*return*/, {
1865
+ content: [{
1866
+ type: "text",
1867
+ text: "Volume created:\n".concat(JSON.stringify(result.volume, null, 2), "\n\nAction ID: ").concat(result.action.id),
1868
+ }],
1869
+ }];
1870
+ case 119:
1871
+ if (!hetznerClient) {
1872
+ return [2 /*return*/, {
1873
+ content: [{
1874
+ type: "text",
1875
+ text: "Hetzner client not available.",
1876
+ }],
1877
+ }];
1878
+ }
1879
+ return [4 /*yield*/, hetznerClient.volumes.delete(parseInt(args === null || args === void 0 ? void 0 : args.id))];
1880
+ case 120:
1881
+ action = _7.sent();
1882
+ return [2 /*return*/, {
1883
+ content: [{
1884
+ type: "text",
1885
+ text: "Volume deletion initiated. Action ID: ".concat(action.id),
1886
+ }],
1887
+ }];
1888
+ case 121:
1889
+ if (!hetznerClient) {
1890
+ return [2 /*return*/, {
1891
+ content: [{
1892
+ type: "text",
1893
+ text: "Hetzner client not available.",
1894
+ }],
1895
+ }];
1896
+ }
1897
+ return [4 /*yield*/, hetznerClient.volumes.attach(parseInt(args === null || args === void 0 ? void 0 : args.volumeId), parseInt(args === null || args === void 0 ? void 0 : args.serverId), (_6 = args === null || args === void 0 ? void 0 : args.automount) !== null && _6 !== void 0 ? _6 : true)];
1898
+ case 122:
1899
+ action = _7.sent();
1900
+ return [2 /*return*/, {
1901
+ content: [{
1902
+ type: "text",
1903
+ text: "Volume attachment initiated. Action ID: ".concat(action.id),
1904
+ }],
1905
+ }];
1906
+ case 123:
1907
+ if (!hetznerClient) {
1908
+ return [2 /*return*/, {
1909
+ content: [{
1910
+ type: "text",
1911
+ text: "Hetzner client not available.",
1912
+ }],
1913
+ }];
1914
+ }
1915
+ return [4 /*yield*/, hetznerClient.volumes.detach(parseInt(args === null || args === void 0 ? void 0 : args.volumeId))];
1916
+ case 124:
1917
+ action = _7.sent();
1918
+ return [2 /*return*/, {
1919
+ content: [{
1920
+ type: "text",
1921
+ text: "Volume detachment initiated. Action ID: ".concat(action.id),
1922
+ }],
1923
+ }];
1924
+ case 125:
1925
+ if (!hetznerClient) {
1926
+ return [2 /*return*/, {
1927
+ content: [{
1928
+ type: "text",
1929
+ text: "Hetzner client not available.",
1930
+ }],
1931
+ }];
1932
+ }
1933
+ return [4 /*yield*/, hetznerClient.volumes.resize(parseInt(args === null || args === void 0 ? void 0 : args.volumeId), args === null || args === void 0 ? void 0 : args.size)];
1934
+ case 126:
1935
+ action = _7.sent();
1936
+ return [2 /*return*/, {
1937
+ content: [{
1938
+ type: "text",
1939
+ text: "Volume resize initiated. Action ID: ".concat(action.id),
1940
+ }],
1941
+ }];
1942
+ case 127: return [4 /*yield*/, Promise.resolve().then(function () { return require("cheapspaces/workspace/src/lib/hetzner/volumes"); })];
1943
+ case 128:
1944
+ VolumeOperations = (_7.sent()).VolumeOperations;
1945
+ price = VolumeOperations.calculatePrice(args === null || args === void 0 ? void 0 : args.size);
1946
+ return [2 /*return*/, {
1947
+ content: [{
1948
+ type: "text",
1949
+ text: JSON.stringify(price, null, 2),
1950
+ }],
1951
+ }];
1952
+ case 129:
1953
+ if (!hetznerClient) {
1954
+ return [2 /*return*/, {
1955
+ content: [{
1956
+ type: "text",
1957
+ text: "Hetzner client not available.",
1958
+ }],
1959
+ }];
1960
+ }
1961
+ return [4 /*yield*/, hetznerClient.pricing.listServerTypes()];
1962
+ case 130:
1963
+ serverTypes = _7.sent();
1964
+ return [2 /*return*/, {
1965
+ content: [{
1966
+ type: "text",
1967
+ text: JSON.stringify(serverTypes, null, 2),
1968
+ }],
1969
+ }];
1970
+ case 131:
1971
+ if (!hetznerClient) {
1972
+ return [2 /*return*/, {
1973
+ content: [{
1974
+ type: "text",
1975
+ text: "Hetzner client not available.",
1976
+ }],
1977
+ }];
1978
+ }
1979
+ return [4 /*yield*/, hetznerClient.pricing.listLocations()];
1980
+ case 132:
1981
+ locations = _7.sent();
1982
+ return [2 /*return*/, {
1983
+ content: [{
1984
+ type: "text",
1985
+ text: JSON.stringify(locations, null, 2),
1986
+ }],
1987
+ }];
1988
+ case 133: return [2 /*return*/, {
1989
+ content: [{
1990
+ type: "text",
1991
+ text: "Unknown tool: ".concat(name),
1992
+ }],
1993
+ isError: true,
1994
+ }];
1995
+ case 134: return [3 /*break*/, 136];
1996
+ case 135:
1997
+ error_10 = _7.sent();
1998
+ return [2 /*return*/, {
1999
+ content: [{
2000
+ type: "text",
2001
+ text: "Error: ".concat(String(error_10)),
2002
+ }],
2003
+ isError: true,
2004
+ }];
2005
+ case 136: return [2 /*return*/];
2006
+ }
2007
+ });
2008
+ }); });
2009
+ // Start server
2010
+ function main() {
2011
+ return __awaiter(this, void 0, void 0, function () {
2012
+ var transport;
2013
+ return __generator(this, function (_a) {
2014
+ switch (_a.label) {
2015
+ case 0:
2016
+ // Initialize Hetzner client before starting server
2017
+ return [4 /*yield*/, initializeClient()];
2018
+ case 1:
2019
+ // Initialize Hetzner client before starting server
2020
+ _a.sent();
2021
+ transport = new stdio_js_1.StdioServerTransport();
2022
+ return [4 /*yield*/, server.connect(transport)];
2023
+ case 2:
2024
+ _a.sent();
2025
+ console.error("Hetzner MCP server running on stdio");
2026
+ return [2 /*return*/];
2027
+ }
2028
+ });
2029
+ });
2030
+ }
2031
+ main().catch(function (error) {
2032
+ console.error("Fatal error:", error);
2033
+ process.exit(1);
2034
+ });