@mgsoftwarebv/mg-dashboard-mcp 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -24,6 +24,71 @@ if (!supabaseUrl || !supabaseKey) {
24
24
  process.exit(1);
25
25
  }
26
26
  var supabase = createClient(supabaseUrl, supabaseKey);
27
+ var RateLimiter = class {
28
+ buckets = /* @__PURE__ */ new Map();
29
+ maxAttempts;
30
+ windowMs;
31
+ constructor(maxAttempts, windowMs) {
32
+ this.maxAttempts = maxAttempts;
33
+ this.windowMs = windowMs;
34
+ }
35
+ /**
36
+ * Check if an action is allowed for the given key.
37
+ * Increments the counter and returns whether the action should proceed.
38
+ */
39
+ check(key) {
40
+ const now = Date.now();
41
+ const entry = this.buckets.get(key);
42
+ if (!entry || now >= entry.resetAt) {
43
+ this.buckets.set(key, { count: 1, resetAt: now + this.windowMs });
44
+ return { allowed: true, remaining: this.maxAttempts - 1, retryAfterMs: 0 };
45
+ }
46
+ entry.count++;
47
+ if (entry.count > this.maxAttempts) {
48
+ return {
49
+ allowed: false,
50
+ remaining: 0,
51
+ retryAfterMs: entry.resetAt - now
52
+ };
53
+ }
54
+ return {
55
+ allowed: true,
56
+ remaining: this.maxAttempts - entry.count,
57
+ retryAfterMs: 0
58
+ };
59
+ }
60
+ /** Periodically remove expired entries to prevent unbounded growth. */
61
+ cleanup() {
62
+ const now = Date.now();
63
+ for (const [key, entry] of this.buckets) {
64
+ if (now >= entry.resetAt) this.buckets.delete(key);
65
+ }
66
+ }
67
+ };
68
+ var authRateLimiter = new RateLimiter(5, 15 * 60 * 1e3);
69
+ var toolCallRateLimiter = new RateLimiter(60, 60 * 1e3);
70
+ var destructiveActionRateLimiter = new RateLimiter(5, 60 * 1e3);
71
+ var DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
72
+ "ssh-execute",
73
+ "sftp-write",
74
+ "sftp-delete",
75
+ "server-reboot",
76
+ "server-restart-service",
77
+ "db-query",
78
+ "cron-add",
79
+ "cron-remove",
80
+ "cron-toggle",
81
+ "dns-create",
82
+ "dns-update",
83
+ "dns-delete",
84
+ "docker-action",
85
+ "env-store"
86
+ ]);
87
+ setInterval(() => {
88
+ authRateLimiter.cleanup();
89
+ toolCallRateLimiter.cleanup();
90
+ destructiveActionRateLimiter.cleanup();
91
+ }, 5 * 60 * 1e3).unref();
27
92
  var authContext = null;
28
93
  async function validateApiKey(key) {
29
94
  if (!key.startsWith("dk_") || key.length !== 67) {
@@ -31,13 +96,19 @@ async function validateApiKey(key) {
31
96
  return null;
32
97
  }
33
98
  const keyHash = createHash("sha256").update(key).digest("hex");
99
+ const rateCheck = authRateLimiter.check(keyHash);
100
+ if (!rateCheck.allowed) {
101
+ const retryMin = Math.ceil(rateCheck.retryAfterMs / 6e4);
102
+ console.error(`Rate limited: too many failed auth attempts. Retry in ${retryMin} minute(s).`);
103
+ return null;
104
+ }
34
105
  const { data, error } = await supabase.from("dashboard_mcp_api_key").select("id, created_by, allowed_server_ids, is_active, expires_at").eq("api_key_hash", keyHash).eq("is_active", true).single();
35
106
  if (error || !data) {
36
- console.error("API key not found or inactive");
107
+ console.error(`API key not found or inactive (${rateCheck.remaining} attempts remaining)`);
37
108
  return null;
38
109
  }
39
110
  if (data.expires_at && new Date(data.expires_at) < /* @__PURE__ */ new Date()) {
40
- console.error("API key has expired");
111
+ console.error(`API key has expired (${rateCheck.remaining} attempts remaining)`);
41
112
  return null;
42
113
  }
43
114
  await supabase.from("dashboard_mcp_api_key").update({ last_used_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", data.id);
@@ -54,6 +125,38 @@ function assertServerAccess(serverId) {
54
125
  throw new Error(`Access denied: you do not have permission for server ${serverId}`);
55
126
  }
56
127
  }
128
+ async function resolveReleaseProfileStageIds(profileName) {
129
+ const { data: profile, error } = await supabase.from("release_profile").select("id, name").ilike("name", profileName).maybeSingle();
130
+ if (error) throw new Error(`Failed to look up release profile: ${error.message}`);
131
+ if (!profile) {
132
+ const { data: all } = await supabase.from("release_profile").select("name").order("name");
133
+ const names = (all || []).map((p) => p.name).join(", ");
134
+ throw new Error(
135
+ `Release profile "${profileName}" not found. Available profiles: ${names || "(none)"}`
136
+ );
137
+ }
138
+ const { data: stages, error: stageErr } = await supabase.from("release_profile_stage").select("id").eq("release_profile_id", profile.id);
139
+ if (stageErr) throw new Error(`Failed to look up stages: ${stageErr.message}`);
140
+ if (!stages || stages.length === 0) {
141
+ throw new Error(`Release profile "${profile.name}" has no stages configured`);
142
+ }
143
+ return { stageIds: stages.map((s) => s.id), profileId: profile.id };
144
+ }
145
+ async function getProfileNamesForStageIds(stageIds) {
146
+ if (stageIds.length === 0) return {};
147
+ const { data: stages } = await supabase.from("release_profile_stage").select("id, release_profile_id").in("id", stageIds);
148
+ if (!stages || stages.length === 0) return {};
149
+ const profileIds = [...new Set(stages.map((s) => s.release_profile_id))];
150
+ const { data: profiles } = await supabase.from("release_profile").select("id, name").in("id", profileIds);
151
+ if (!profiles) return {};
152
+ const profileMap = {};
153
+ for (const p of profiles) profileMap[p.id] = p.name;
154
+ const result = {};
155
+ for (const s of stages) {
156
+ result[s.id] = profileMap[s.release_profile_id] || "unknown";
157
+ }
158
+ return result;
159
+ }
57
160
  var ENC_ALGORITHM = "aes-256-gcm";
58
161
  var ENC_IV_LENGTH = 16;
59
162
  var ENC_TAG_LENGTH = 16;
@@ -88,6 +191,120 @@ function decrypt(payload) {
88
191
  decrypted += decipher.final("utf8");
89
192
  return decrypted;
90
193
  }
194
+ var VERCEL_API = "https://api.vercel.com";
195
+ function parseEnvContent(content) {
196
+ const result = {};
197
+ for (const line of content.split("\n")) {
198
+ const trimmed = line.trim();
199
+ if (!trimmed || trimmed.startsWith("#")) continue;
200
+ const eqIdx = trimmed.indexOf("=");
201
+ if (eqIdx === -1) continue;
202
+ const key = trimmed.slice(0, eqIdx).trim();
203
+ let value = trimmed.slice(eqIdx + 1).trim();
204
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
205
+ value = value.slice(1, -1);
206
+ }
207
+ if (key) result[key] = value;
208
+ }
209
+ return result;
210
+ }
211
+ function stageToVercelTargets(stageType, customEnvId) {
212
+ if (stageType === "prod") return { target: ["production"] };
213
+ if (customEnvId) return { customEnvironmentIds: [customEnvId] };
214
+ return { target: ["preview"] };
215
+ }
216
+ async function syncEnvVarsToVercel(token, projectId, envVars) {
217
+ if (envVars.length === 0) return { created: 0, error: null };
218
+ const res = await fetch(
219
+ `${VERCEL_API}/v10/projects/${encodeURIComponent(projectId)}/env?upsert=true`,
220
+ {
221
+ method: "POST",
222
+ headers: {
223
+ Authorization: `Bearer ${token}`,
224
+ "Content-Type": "application/json"
225
+ },
226
+ body: JSON.stringify(envVars)
227
+ }
228
+ );
229
+ if (!res.ok) {
230
+ const body = await res.text().catch(() => "");
231
+ return { created: 0, error: `Vercel API ${res.status}: ${body}` };
232
+ }
233
+ const data = await res.json().catch(() => ({}));
234
+ return { created: data?.created?.length ?? envVars.length, error: null };
235
+ }
236
+ async function attemptVercelSync(appName, environment) {
237
+ try {
238
+ const { data: direct } = await supabase.from("env_config").select("release_profile_stage_id").eq("app_name", appName).not("release_profile_stage_id", "is", null).limit(1).single();
239
+ const stageId = direct?.release_profile_stage_id;
240
+ if (!stageId) return "Vercel sync skipped: no stage link found";
241
+ const { data: settings } = await supabase.from("app_setting").select("vercel_token_encrypted").maybeSingle();
242
+ if (!settings?.vercel_token_encrypted) return "Vercel sync skipped: no Vercel token configured";
243
+ let token;
244
+ try {
245
+ token = decrypt(settings.vercel_token_encrypted);
246
+ } catch {
247
+ return "Vercel sync failed: could not decrypt Vercel token";
248
+ }
249
+ const { data: stage } = await supabase.from("release_profile_stage").select("id, stage, stage_apps").eq("id", stageId).single();
250
+ if (!stage) return "Vercel sync skipped: stage not found";
251
+ const stageType = stage.stage;
252
+ const stageApps = stage.stage_apps || [];
253
+ const vercelApps = stageApps.filter(
254
+ (a) => a.deployMethod === "vercel" && a.enabled && a.vercelProjectId
255
+ );
256
+ if (vercelApps.length === 0) return "Vercel sync skipped: no Vercel apps in stage";
257
+ const { data: envConfigs } = await supabase.from("env_config").select("*").eq("release_profile_stage_id", stageId);
258
+ if (!envConfigs || envConfigs.length === 0) return "Vercel sync skipped: no env configs for stage";
259
+ const variantMap = {
260
+ dev: "development",
261
+ staging: "staging",
262
+ prod: "production"
263
+ };
264
+ const deployedVariant = variantMap[stageType] ?? stageType;
265
+ const syncResults = [];
266
+ for (const app of vercelApps) {
267
+ const name = app.path.replace("apps/", "");
268
+ const config = envConfigs.find(
269
+ (c) => c.app_name === name && c.variant === deployedVariant
270
+ );
271
+ if (!config) {
272
+ syncResults.push(`${app.label}: skipped (no config for variant "${deployedVariant}")`);
273
+ continue;
274
+ }
275
+ let envContent;
276
+ try {
277
+ envContent = decrypt(config.env_data_encrypted);
278
+ } catch {
279
+ syncResults.push(`${app.label}: decrypt failed`);
280
+ continue;
281
+ }
282
+ const pairs = parseEnvContent(envContent);
283
+ const keys = Object.keys(pairs);
284
+ if (keys.length === 0) {
285
+ syncResults.push(`${app.label}: empty config`);
286
+ continue;
287
+ }
288
+ const targeting = stageToVercelTargets(stageType, app.vercelCustomEnvId);
289
+ const envVars = keys.map((key) => ({
290
+ key,
291
+ value: pairs[key],
292
+ type: "encrypted",
293
+ ...targeting
294
+ }));
295
+ const { created, error } = await syncEnvVarsToVercel(token, app.vercelProjectId, envVars);
296
+ if (error) {
297
+ syncResults.push(`${app.label}: FAILED - ${error}`);
298
+ } else {
299
+ syncResults.push(`${app.label}: ${created} vars synced`);
300
+ }
301
+ }
302
+ return `Vercel sync: ${syncResults.join("; ")}`;
303
+ } catch (err) {
304
+ const msg = err instanceof Error ? err.message : String(err);
305
+ return `Vercel sync error: ${msg}`;
306
+ }
307
+ }
91
308
  async function getServerConnection(serverId) {
92
309
  assertServerAccess(serverId);
93
310
  const { data, error } = await supabase.from("ssh_server").select("hostname, port, username, password_encrypted, ssh_key_encrypted, ssh_key_passphrase_encrypted").eq("id", serverId).single();
@@ -794,8 +1011,13 @@ var TOOLS = [
794
1011
  },
795
1012
  {
796
1013
  name: "env-list",
797
- description: "List all stored environment configurations (app name, environment, description).",
798
- inputSchema: { type: "object", properties: {}, required: [] }
1014
+ description: "List all stored environment configurations with their release profile names.",
1015
+ inputSchema: {
1016
+ type: "object",
1017
+ properties: {
1018
+ releaseProfile: { type: "string", description: "Release profile name to filter by (usually matches the project folder name or git repo name, e.g. prefabaanbouw). Omit to list all." }
1019
+ }
1020
+ }
799
1021
  },
800
1022
  {
801
1023
  name: "env-get",
@@ -804,7 +1026,8 @@ var TOOLS = [
804
1026
  type: "object",
805
1027
  properties: {
806
1028
  appName: { type: "string", description: "Application name (e.g. backoffice, api, web)" },
807
- environment: { type: "string", description: "Environment name (e.g. production, staging, development)" }
1029
+ environment: { type: "string", description: "Environment name (e.g. production, staging, development, local)" },
1030
+ releaseProfile: { type: "string", description: "Release profile name (usually matches the project folder name or git repo name, e.g. prefabaanbouw). Required when multiple profiles exist. Use env-list to discover available profiles." }
808
1031
  },
809
1032
  required: ["appName", "environment"]
810
1033
  }
@@ -816,9 +1039,10 @@ var TOOLS = [
816
1039
  type: "object",
817
1040
  properties: {
818
1041
  appName: { type: "string", description: "Application name (e.g. backoffice, api, web)" },
819
- environment: { type: "string", description: "Environment name (e.g. production, staging, development)" },
1042
+ environment: { type: "string", description: "Environment name (e.g. production, staging, development, local)" },
820
1043
  content: { type: "string", description: "The .env file content to store" },
821
- description: { type: "string", description: "Optional description" }
1044
+ description: { type: "string", description: "Optional description" },
1045
+ releaseProfile: { type: "string", description: "Release profile name (usually matches the project folder name or git repo name, e.g. prefabaanbouw). Required when multiple profiles exist. Use env-list to discover available profiles." }
822
1046
  },
823
1047
  required: ["appName", "environment", "content"]
824
1048
  }
@@ -999,6 +1223,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
999
1223
  }
1000
1224
  const { name, arguments: toolArgs } = request.params;
1001
1225
  const a = toolArgs || {};
1226
+ const sessionKey = authContext.userId;
1227
+ const toolRate = toolCallRateLimiter.check(sessionKey);
1228
+ if (!toolRate.allowed) {
1229
+ const retrySec = Math.ceil(toolRate.retryAfterMs / 1e3);
1230
+ return {
1231
+ content: [{ type: "text", text: `Rate limited: too many tool calls. Retry in ${retrySec}s.` }]
1232
+ };
1233
+ }
1234
+ if (DESTRUCTIVE_TOOLS.has(name)) {
1235
+ const destructiveRate = destructiveActionRateLimiter.check(sessionKey);
1236
+ if (!destructiveRate.allowed) {
1237
+ const retrySec = Math.ceil(destructiveRate.retryAfterMs / 1e3);
1238
+ return {
1239
+ content: [{
1240
+ type: "text",
1241
+ text: `Rate limited: too many destructive actions (${name}). Retry in ${retrySec}s.`
1242
+ }]
1243
+ };
1244
+ }
1245
+ }
1002
1246
  try {
1003
1247
  switch (name) {
1004
1248
  // ----- Servers -----
@@ -1135,44 +1379,95 @@ ${result.stderr}`);
1135
1379
  }
1136
1380
  // ----- Env Config -----
1137
1381
  case "env-list": {
1138
- const { data, error } = await supabase.from("env_config").select("id, app_name, environment, description, updated_at").order("app_name").order("environment");
1382
+ let query = supabase.from("env_config").select("id, app_name, environment, description, updated_at, release_profile_stage_id").order("app_name").order("environment");
1383
+ if (a.releaseProfile) {
1384
+ const { stageIds: stageIds2 } = await resolveReleaseProfileStageIds(String(a.releaseProfile));
1385
+ query = query.in("release_profile_stage_id", stageIds2);
1386
+ }
1387
+ const { data, error } = await query;
1139
1388
  if (error) throw new Error(error.message);
1140
- const lines = (data || []).map(
1141
- (e) => `${e.app_name}/${e.environment} ${e.description || ""} (updated: ${e.updated_at})`
1142
- );
1389
+ const stageIds = (data || []).map((e) => e.release_profile_stage_id).filter(Boolean);
1390
+ const profileNames = await getProfileNamesForStageIds(stageIds);
1391
+ const lines = (data || []).map((e) => {
1392
+ const profile = e.release_profile_stage_id ? profileNames[e.release_profile_stage_id] || "unknown" : "unlinked";
1393
+ return `${e.app_name}/${e.environment} [${profile}] (updated: ${e.updated_at})`;
1394
+ });
1143
1395
  return { content: [{ type: "text", text: lines.length ? lines.join("\n") : "No environment configs stored" }] };
1144
1396
  }
1145
1397
  case "env-get": {
1146
- const { data, error } = await supabase.from("env_config").select("env_data_encrypted").eq("app_name", String(a.appName)).eq("environment", String(a.environment)).single();
1147
- if (error || !data) throw new Error(`Env config not found: ${a.appName}/${a.environment}`);
1148
- const decrypted = decrypt(data.env_data_encrypted);
1398
+ let query = supabase.from("env_config").select("env_data_encrypted, release_profile_stage_id").eq("app_name", String(a.appName)).eq("environment", String(a.environment));
1399
+ if (a.releaseProfile) {
1400
+ const { stageIds } = await resolveReleaseProfileStageIds(String(a.releaseProfile));
1401
+ query = query.in("release_profile_stage_id", stageIds);
1402
+ }
1403
+ const { data, error } = await query;
1404
+ if (error) throw new Error(`Env config query failed: ${error.message}`);
1405
+ if (!data || data.length === 0) {
1406
+ throw new Error(`Env config not found: ${a.appName}/${a.environment}${a.releaseProfile ? ` (profile: ${a.releaseProfile})` : ""}`);
1407
+ }
1408
+ if (data.length > 1) {
1409
+ const stageIds = data.map((r) => r.release_profile_stage_id).filter(Boolean);
1410
+ const profileNames = await getProfileNamesForStageIds(stageIds);
1411
+ const names = [...new Set(Object.values(profileNames))].join(", ");
1412
+ throw new Error(
1413
+ `Multiple env configs found for ${a.appName}/${a.environment} across profiles: ${names}. Pass releaseProfile parameter to select one (e.g. releaseProfile: "${Object.values(profileNames)[0] || "..."}")`
1414
+ );
1415
+ }
1416
+ const decrypted = decrypt(data[0].env_data_encrypted);
1149
1417
  return { content: [{ type: "text", text: decrypted }] };
1150
1418
  }
1151
1419
  case "env-store": {
1152
1420
  const appName = String(a.appName);
1153
1421
  const environment = String(a.environment);
1154
1422
  const encrypted = encrypt(String(a.content));
1155
- const { data: existing } = await supabase.from("env_config").select("id").eq("app_name", appName).eq("environment", environment).single();
1423
+ let resolvedStageIds = null;
1424
+ if (a.releaseProfile) {
1425
+ const { stageIds } = await resolveReleaseProfileStageIds(String(a.releaseProfile));
1426
+ resolvedStageIds = stageIds;
1427
+ }
1428
+ let existQuery = supabase.from("env_config").select("id, release_profile_stage_id").eq("app_name", appName).eq("environment", environment);
1429
+ if (resolvedStageIds) {
1430
+ existQuery = existQuery.in("release_profile_stage_id", resolvedStageIds);
1431
+ }
1432
+ const { data: existingRows, error: existErr } = await existQuery;
1433
+ if (existErr) throw new Error(`Lookup failed: ${existErr.message}`);
1434
+ if (existingRows && existingRows.length > 1 && !resolvedStageIds) {
1435
+ const stageIds = existingRows.map((r) => r.release_profile_stage_id).filter(Boolean);
1436
+ const profileNames = await getProfileNamesForStageIds(stageIds);
1437
+ const names = [...new Set(Object.values(profileNames))].join(", ");
1438
+ throw new Error(
1439
+ `Multiple env configs found for ${appName}/${environment} across profiles: ${names}. Pass releaseProfile parameter to select one.`
1440
+ );
1441
+ }
1442
+ const existing = existingRows?.[0] ?? null;
1443
+ let saveMsg;
1156
1444
  if (existing) {
1157
- const { error: error2 } = await supabase.from("env_config").update({
1445
+ const { error } = await supabase.from("env_config").update({
1158
1446
  env_data_encrypted: encrypted,
1159
1447
  description: a.description ? String(a.description) : void 0,
1160
1448
  updated_by: authContext.userId,
1161
1449
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
1162
1450
  }).eq("id", existing.id);
1163
- if (error2) throw new Error(error2.message);
1164
- return { content: [{ type: "text", text: `Updated env config: ${appName}/${environment}` }] };
1451
+ if (error) throw new Error(error.message);
1452
+ saveMsg = `Updated env config: ${appName}/${environment}`;
1453
+ } else {
1454
+ const insertData = {
1455
+ app_name: appName,
1456
+ environment,
1457
+ env_data_encrypted: encrypted,
1458
+ description: a.description ? String(a.description) : null,
1459
+ created_by: authContext.userId,
1460
+ updated_by: authContext.userId
1461
+ };
1462
+ if (resolvedStageIds?.[0]) {
1463
+ insertData.release_profile_stage_id = resolvedStageIds[0];
1464
+ }
1465
+ const { error } = await supabase.from("env_config").insert(insertData);
1466
+ if (error) throw new Error(error.message);
1467
+ saveMsg = `Stored env config: ${appName}/${environment}`;
1165
1468
  }
1166
- const { error } = await supabase.from("env_config").insert({
1167
- app_name: appName,
1168
- environment,
1169
- env_data_encrypted: encrypted,
1170
- description: a.description ? String(a.description) : null,
1171
- created_by: authContext.userId,
1172
- updated_by: authContext.userId
1173
- });
1174
- if (error) throw new Error(error.message);
1175
- return { content: [{ type: "text", text: `Stored env config: ${appName}/${environment}` }] };
1469
+ const vercelStatus = await attemptVercelSync(appName, environment);
1470
+ return { content: [{ type: "text", text: `${saveMsg}. ${vercelStatus}` }] };
1176
1471
  }
1177
1472
  // ----- Cache Purge -----
1178
1473
  case "cache-purge": {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["SshClient","err","err2","error"],"mappings":"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","file":"index.js","sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';\r\nimport { createClient } from '@supabase/supabase-js';\r\nimport { createHash, randomBytes, createCipheriv, createDecipheriv } from 'crypto';\r\nimport { Client as SshClient } from 'ssh2';\r\n\r\n// ---------------------------------------------------------------------------\r\n// CLI argument parsing\r\n// ---------------------------------------------------------------------------\r\n\r\nconst args = process.argv.slice(2);\r\n\r\nfunction getArg(name: string): string | undefined {\r\n return args.find(a => a.startsWith(`--${name}=`))?.split('=').slice(1).join('=');\r\n}\r\n\r\nconst apiKey = getArg('api-key') || process.env.MG_DASHBOARD_API_KEY;\r\nconst supabaseUrl = getArg('supabase-url') || process.env.SUPABASE_URL;\r\nconst supabaseKey = getArg('supabase-key') || process.env.SUPABASE_SERVICE_ROLE_KEY;\r\nconst encryptionKey = getArg('encryption-key') || process.env.ENCRYPTION_KEY;\r\nconst mijnhostApiKey = getArg('mijnhost-api-key') || process.env.MIJNHOST_API_KEY;\r\n\r\nif (!apiKey) {\r\n console.error('API key is required. Use --api-key=dk_xxx or set MG_DASHBOARD_API_KEY');\r\n process.exit(1);\r\n}\r\n\r\nif (!supabaseUrl || !supabaseKey) {\r\n console.error('Supabase credentials required. Use --supabase-url and --supabase-key or set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY');\r\n process.exit(1);\r\n}\r\n\r\nconst supabase = createClient(supabaseUrl, supabaseKey);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Auth context\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface AuthContext {\r\n userId: string;\r\n allowedServerIds: string[] | null;\r\n}\r\n\r\nlet authContext: AuthContext | null = null;\r\n\r\nasync function validateApiKey(key: string): Promise<AuthContext | null> {\r\n if (!key.startsWith('dk_') || key.length !== 67) {\r\n console.error('Invalid API key format (expected dk_ + 64 hex chars)');\r\n return null;\r\n }\r\n\r\n const keyHash = createHash('sha256').update(key).digest('hex');\r\n\r\n const { data, error } = await supabase\r\n .from('dashboard_mcp_api_key')\r\n .select('id, created_by, allowed_server_ids, is_active, expires_at')\r\n .eq('api_key_hash', keyHash)\r\n .eq('is_active', true)\r\n .single();\r\n\r\n if (error || !data) {\r\n console.error('API key not found or inactive');\r\n return null;\r\n }\r\n\r\n if (data.expires_at && new Date(data.expires_at) < new Date()) {\r\n console.error('API key has expired');\r\n return null;\r\n }\r\n\r\n await supabase\r\n .from('dashboard_mcp_api_key')\r\n .update({ last_used_at: new Date().toISOString() })\r\n .eq('id', data.id);\r\n\r\n console.error(`Authenticated as user ${data.created_by}`);\r\n\r\n return {\r\n userId: data.created_by,\r\n allowedServerIds: data.allowed_server_ids,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Server access helper\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction assertServerAccess(serverId: string): void {\r\n if (!authContext) throw new Error('Not authenticated');\r\n if (authContext.allowedServerIds === null) return;\r\n if (!authContext.allowedServerIds.includes(serverId)) {\r\n throw new Error(`Access denied: you do not have permission for server ${serverId}`);\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Encryption helpers (AES-256-GCM, compatible with dashboard encryption.ts)\r\n// ---------------------------------------------------------------------------\r\n\r\nconst ENC_ALGORITHM = 'aes-256-gcm';\r\nconst ENC_IV_LENGTH = 16;\r\nconst ENC_TAG_LENGTH = 16;\r\n\r\nfunction getEncryptionKey(): Buffer {\r\n if (!encryptionKey) throw new Error('ENCRYPTION_KEY is required for env operations');\r\n const buf = Buffer.from(encryptionKey, 'hex');\r\n if (buf.length !== 32) throw new Error('ENCRYPTION_KEY must be a 64-character hex string');\r\n return buf;\r\n}\r\n\r\nfunction encrypt(text: string): string {\r\n const key = getEncryptionKey();\r\n const iv = randomBytes(ENC_IV_LENGTH);\r\n const cipher = createCipheriv(ENC_ALGORITHM, new Uint8Array(key), new Uint8Array(iv));\r\n let encrypted = cipher.update(text, 'utf8', 'hex');\r\n encrypted += cipher.final('hex');\r\n const authTag = cipher.getAuthTag();\r\n return Buffer.concat([\r\n new Uint8Array(iv),\r\n new Uint8Array(authTag),\r\n new Uint8Array(Buffer.from(encrypted, 'hex')),\r\n ]).toString('base64');\r\n}\r\n\r\nfunction decrypt(payload: string): string {\r\n const key = getEncryptionKey();\r\n const buf = Buffer.from(payload, 'base64');\r\n const iv = buf.subarray(0, ENC_IV_LENGTH);\r\n const authTag = buf.subarray(ENC_IV_LENGTH, ENC_IV_LENGTH + ENC_TAG_LENGTH);\r\n const encrypted = buf.subarray(ENC_IV_LENGTH + ENC_TAG_LENGTH);\r\n const decipher = createDecipheriv(ENC_ALGORITHM, new Uint8Array(key), new Uint8Array(iv));\r\n decipher.setAuthTag(new Uint8Array(authTag));\r\n let decrypted = decipher.update(encrypted.toString('hex'), 'hex', 'utf8');\r\n decrypted += decipher.final('utf8');\r\n return decrypted;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// SSH helpers\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface SshConnectionOptions {\r\n hostname: string;\r\n port: number;\r\n username: string;\r\n password?: string;\r\n privateKey?: string;\r\n passphrase?: string;\r\n timeout?: number;\r\n}\r\n\r\ninterface SshResult {\r\n stdout: string;\r\n stderr: string;\r\n exitCode: number;\r\n}\r\n\r\nasync function getServerConnection(serverId: string): Promise<SshConnectionOptions> {\r\n assertServerAccess(serverId);\r\n\r\n const { data, error } = await supabase\r\n .from('ssh_server')\r\n .select('hostname, port, username, password_encrypted, ssh_key_encrypted, ssh_key_passphrase_encrypted')\r\n .eq('id', serverId)\r\n .single();\r\n\r\n if (error || !data) throw new Error(`Server not found: ${serverId}`);\r\n if (!encryptionKey) throw new Error('ENCRYPTION_KEY required to decrypt server credentials');\r\n\r\n return {\r\n hostname: data.hostname,\r\n port: data.port || 22,\r\n username: data.username,\r\n password: data.password_encrypted ? decrypt(data.password_encrypted) : undefined,\r\n privateKey: data.ssh_key_encrypted ? decrypt(data.ssh_key_encrypted) : undefined,\r\n passphrase: data.ssh_key_passphrase_encrypted ? decrypt(data.ssh_key_passphrase_encrypted) : undefined,\r\n };\r\n}\r\n\r\nasync function sshExec(opts: SshConnectionOptions, command: string): Promise<SshResult> {\r\n return new Promise((resolve) => {\r\n const ssh = new SshClient();\r\n let stdout = '';\r\n let stderr = '';\r\n let done = false;\r\n const timeout = opts.timeout || 60_000;\r\n\r\n const timer = setTimeout(() => {\r\n if (!done) { done = true; ssh.end(); resolve({ stdout, stderr, exitCode: -1 }); }\r\n }, timeout);\r\n\r\n ssh.on('ready', () => {\r\n ssh.exec(command, (err, stream) => {\r\n if (err) {\r\n if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve({ stdout, stderr, exitCode: -1 }); }\r\n return;\r\n }\r\n stream.on('data', (d: Buffer) => { stdout += d.toString(); });\r\n stream.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });\r\n stream.on('close', (code: number | null) => {\r\n if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve({ stdout, stderr, exitCode: code ?? 0 }); }\r\n });\r\n });\r\n });\r\n\r\n ssh.on('error', (err) => {\r\n if (!done) { done = true; clearTimeout(timer); resolve({ stdout, stderr: err.message, exitCode: -1 }); }\r\n });\r\n\r\n ssh.connect({\r\n host: opts.hostname, port: opts.port, username: opts.username,\r\n password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase,\r\n readyTimeout: timeout,\r\n });\r\n });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// SFTP helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction sanitizePath(path: string): string {\r\n let normalized = path.replace(/\\\\/g, '/').replace(/\\0/g, '');\r\n const parts = normalized.split('/');\r\n const resolved: string[] = [];\r\n for (const part of parts) {\r\n if (part === '..') { if (resolved.length > 0 && resolved[resolved.length - 1] !== '') resolved.pop(); }\r\n else if (part !== '.' && part !== '') resolved.push(part);\r\n }\r\n return '/' + resolved.join('/');\r\n}\r\n\r\nconst PROTECTED_PATHS = ['/etc/', '/boot/', '/usr/', '/bin/', '/sbin/', '/lib/', '/lib64/'];\r\n\r\nfunction assertWritablePath(path: string): void {\r\n const safe = sanitizePath(path);\r\n for (const p of PROTECTED_PATHS) {\r\n if (safe === p.slice(0, -1) || safe.startsWith(p)) {\r\n throw new Error(`Write access denied to protected path: ${safe}`);\r\n }\r\n }\r\n}\r\n\r\nasync function sftpReaddir(opts: SshConnectionOptions, dirPath: string): Promise<string> {\r\n const safe = sanitizePath(dirPath);\r\n return new Promise((resolve) => {\r\n const ssh = new SshClient();\r\n let done = false;\r\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 30_000);\r\n\r\n ssh.on('ready', () => {\r\n ssh.sftp((err, sftp) => {\r\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\r\n sftp.readdir(safe, (err, list) => {\r\n done = true; clearTimeout(timer);\r\n if (err) { ssh.end(); resolve(`Error: ${err.message}`); return; }\r\n const entries = list.map(item => {\r\n const mode = item.attrs.mode || 0;\r\n const isDir = (mode & 0o170000) === 0o040000;\r\n const size = item.attrs.size || 0;\r\n const mtime = item.attrs.mtime ? new Date(item.attrs.mtime * 1000).toISOString() : '';\r\n return `${isDir ? 'd' : '-'} ${String(size).padStart(10)} ${mtime} ${item.filename}`;\r\n });\r\n ssh.end();\r\n resolve(entries.join('\\n'));\r\n });\r\n });\r\n });\r\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\r\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 30_000 });\r\n });\r\n}\r\n\r\nasync function sftpRead(opts: SshConnectionOptions, filePath: string): Promise<string> {\r\n const safe = sanitizePath(filePath);\r\n return new Promise((resolve) => {\r\n const ssh = new SshClient();\r\n let done = false;\r\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 60_000);\r\n\r\n ssh.on('ready', () => {\r\n ssh.sftp((err, sftp) => {\r\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\r\n sftp.stat(safe, (err, stats) => {\r\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\r\n if ((stats.size || 0) > 1_048_576) {\r\n if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: file too large (${stats.size} bytes, max 1MB)`); }\r\n return;\r\n }\r\n const chunks: Buffer[] = [];\r\n const rs = sftp.createReadStream(safe);\r\n rs.on('data', (c: Buffer) => chunks.push(c));\r\n rs.on('end', () => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(Buffer.concat(chunks.map(c => new Uint8Array(c))).toString('utf-8')); } });\r\n rs.on('error', (e: Error) => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${e.message}`); } });\r\n });\r\n });\r\n });\r\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\r\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 60_000 });\r\n });\r\n}\r\n\r\nasync function sftpWrite(opts: SshConnectionOptions, filePath: string, content: string): Promise<string> {\r\n const safe = sanitizePath(filePath);\r\n assertWritablePath(safe);\r\n return new Promise((resolve) => {\r\n const ssh = new SshClient();\r\n let done = false;\r\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 60_000);\r\n\r\n ssh.on('ready', () => {\r\n ssh.sftp((err, sftp) => {\r\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\r\n const ws = sftp.createWriteStream(safe, { mode: 0o644 });\r\n ws.on('close', () => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Written ${content.length} bytes to ${safe}`); } });\r\n ws.on('error', (e: Error) => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${e.message}`); } });\r\n ws.end(Buffer.from(content, 'utf-8'));\r\n });\r\n });\r\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\r\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 60_000 });\r\n });\r\n}\r\n\r\nasync function sftpDelete(opts: SshConnectionOptions, filePath: string): Promise<string> {\r\n const safe = sanitizePath(filePath);\r\n assertWritablePath(safe);\r\n return new Promise((resolve) => {\r\n const ssh = new SshClient();\r\n let done = false;\r\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 30_000);\r\n\r\n ssh.on('ready', () => {\r\n ssh.sftp((err, sftp) => {\r\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\r\n sftp.unlink(safe, (err) => {\r\n if (err) {\r\n sftp.rmdir(safe, (err2) => {\r\n done = true; clearTimeout(timer); ssh.end();\r\n resolve(err2 ? `Error: ${err.message}` : `Deleted directory ${safe}`);\r\n });\r\n } else {\r\n done = true; clearTimeout(timer); ssh.end();\r\n resolve(`Deleted file ${safe}`);\r\n }\r\n });\r\n });\r\n });\r\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\r\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 30_000 });\r\n });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Safety: dangerous command blocklist\r\n// ---------------------------------------------------------------------------\r\n\r\nconst BLOCKED_COMMANDS = [\r\n 'rm -rf /', 'rm -fr /', 'mkfs', 'dd if=', ':(){ :|:& };:',\r\n 'shutdown', 'halt', 'init 0', 'init 6',\r\n '> /dev/sda', 'mv /* /dev/null', 'chmod -R 000 /',\r\n];\r\n\r\nfunction assertSafeCommand(command: string): void {\r\n const lower = command.toLowerCase().trim();\r\n for (const blocked of BLOCKED_COMMANDS) {\r\n if (lower.includes(blocked)) {\r\n throw new Error(`Blocked dangerous command pattern: \"${blocked}\"`);\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Log path validation\r\n// ---------------------------------------------------------------------------\r\n\r\nconst ALLOWED_LOG_PREFIXES = ['/var/log/', '/usr/local/lsws/logs/', '/var/www/'];\r\n\r\nfunction assertAllowedLogPath(filePath: string): void {\r\n const safe = sanitizePath(filePath);\r\n if (!safe.endsWith('.log')) {\r\n throw new Error('Only .log files can be read with log-read');\r\n }\r\n if (!ALLOWED_LOG_PREFIXES.some(prefix => safe.startsWith(prefix))) {\r\n throw new Error(`Path not allowed. Must be under: ${ALLOWED_LOG_PREFIXES.join(', ')}`);\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// MySQL / Database helpers\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface DbCredentials {\r\n host: string;\r\n user: string;\r\n password: string;\r\n database: string;\r\n port: number;\r\n sitePath: string;\r\n appType: string;\r\n}\r\n\r\n/**\r\n * Discovers web applications under /var/www and extracts DB credentials\r\n * from their config files (WordPress, PrestaShop, Laravel, custom .env).\r\n */\r\nasync function discoverSiteDatabases(conn: SshConnectionOptions): Promise<DbCredentials[]> {\r\n const script = `\r\ncheck_dir() {\r\n local base=\"$1\" root=\"$2\"\r\n # WordPress\r\n if [ -f \"$root/wp-config.php\" ]; then\r\n echo \"WP|$base|$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_NAME'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_USER'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_PASSWORD'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_HOST'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)\"\r\n return\r\n fi\r\n # PrestaShop 1.7+\r\n if [ -f \"$root/app/config/parameters.php\" ]; then\r\n echo \"PS|$base|$(grep -oP \"'database_name'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)|$(grep -oP \"'database_user'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)|$(grep -oP \"'database_password'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)|$(grep -oP \"'database_host'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)\"\r\n return\r\n fi\r\n # PrestaShop 1.6\r\n if [ -f \"$root/config/settings.inc.php\" ]; then\r\n echo \"PS|$base|$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_NAME_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_USER_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_PASSWD_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_SERVER_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)\"\r\n return\r\n fi\r\n # Laravel / generic .env\r\n if [ -f \"$root/.env\" ]; then\r\n DB_CONN=$(grep -oP '^DB_CONNECTION=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n if [ -n \"$DB_CONN\" ] && [ \"$DB_CONN\" != \"sqlite\" ]; then\r\n echo \"ENV|$base|$(grep -oP '^DB_DATABASE=\\\\K.*' \"$root/.env\" 2>/dev/null)|$(grep -oP '^DB_USERNAME=\\\\K.*' \"$root/.env\" 2>/dev/null)|$(grep -oP '^DB_PASSWORD=\\\\K.*' \"$root/.env\" 2>/dev/null)|$(grep -oP '^DB_HOST=\\\\K.*' \"$root/.env\" 2>/dev/null)|$(grep -oP '^DB_PORT=\\\\K.*' \"$root/.env\" 2>/dev/null)\"\r\n return\r\n fi\r\n fi\r\n}\r\nfor dir in /var/www/*/; do\r\n [ -d \"$dir\" ] || continue\r\n check_dir \"$dir\" \"$dir\"\r\n # Also check common subdirectories: html, public_html, public, httpdocs\r\n for sub in html public_html public httpdocs; do\r\n [ -d \"$dir$sub\" ] && check_dir \"$dir\" \"$dir$sub\"\r\n done\r\ndone\r\n`.trim();\r\n\r\n const result = await sshExec(conn, script);\r\n const sites: DbCredentials[] = [];\r\n\r\n for (const line of result.stdout.split('\\n')) {\r\n if (!line.trim()) continue;\r\n const parts = line.split('|');\r\n if (parts.length < 6) continue;\r\n\r\n const [type, sitePath, database, user, password, host, port] = parts;\r\n if (!database || !user || !type || !sitePath) continue;\r\n\r\n const appTypes: Record<string, string> = { WP: 'WordPress', PS: 'PrestaShop', ENV: 'Laravel/.env' };\r\n\r\n sites.push({\r\n appType: appTypes[type] || type,\r\n sitePath: sitePath.replace(/\\/$/, ''),\r\n database,\r\n user,\r\n password: password || '',\r\n host: host || 'localhost',\r\n port: parseInt(port || '3306', 10),\r\n });\r\n }\r\n\r\n return sites;\r\n}\r\n\r\nfunction escapeMysqlShell(value: string): string {\r\n return value.replace(/'/g, \"'\\\\''\");\r\n}\r\n\r\nconst BLOCKED_SQL_PATTERNS = [\r\n /\\bDROP\\s+DATABASE\\b/i,\r\n /\\bDROP\\s+TABLE\\b/i,\r\n /\\bDROP\\s+INDEX\\b/i,\r\n /\\bTRUNCATE\\b/i,\r\n /\\bALTER\\s+TABLE\\s+\\w+\\s+DROP\\b/i,\r\n /\\bDELETE\\s+FROM\\s+\\w+\\s*$/i,\r\n];\r\n\r\nfunction assertSafeSql(query: string): void {\r\n const trimmed = query.trim();\r\n for (const pattern of BLOCKED_SQL_PATTERNS) {\r\n if (pattern.test(trimmed)) {\r\n throw new Error(`Blocked destructive SQL pattern: ${pattern.source}`);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Builds a shell snippet that discovers DB credentials for a site path\r\n * and then executes a MySQL query, all in a single SSH session.\r\n */\r\nfunction buildSiteMysqlCommand(sitePath: string, query: string): string {\r\n const safePath = escapeMysqlShell(sitePath.replace(/\\/$/, ''));\r\n const safeQuery = escapeMysqlShell(query);\r\n\r\n return `\r\nSITE='${safePath}'\r\nDB_USER=\"\" DB_PASS=\"\" DB_NAME=\"\" DB_HOST=\"localhost\" DB_PORT=\"3306\"\r\nfor root in \"$SITE\" \"$SITE/html\" \"$SITE/public_html\" \"$SITE/public\" \"$SITE/httpdocs\"; do\r\n [ -d \"$root\" ] || continue\r\n if [ -f \"$root/wp-config.php\" ]; then\r\n DB_NAME=$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_NAME'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)\r\n DB_USER=$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_USER'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)\r\n DB_PASS=$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_PASSWORD'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)\r\n DB_HOST=$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_HOST'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)\r\n break\r\n elif [ -f \"$root/app/config/parameters.php\" ]; then\r\n DB_NAME=$(grep -oP \"'database_name'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)\r\n DB_USER=$(grep -oP \"'database_user'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)\r\n DB_PASS=$(grep -oP \"'database_password'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)\r\n DB_HOST=$(grep -oP \"'database_host'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)\r\n break\r\n elif [ -f \"$root/config/settings.inc.php\" ]; then\r\n DB_NAME=$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_NAME_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)\r\n DB_USER=$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_USER_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)\r\n DB_PASS=$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_PASSWD_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)\r\n DB_HOST=$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_SERVER_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)\r\n break\r\n elif [ -f \"$root/.env\" ]; then\r\n DB_CONN=$(grep -oP '^DB_CONNECTION=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n if [ -n \"$DB_CONN\" ] && [ \"$DB_CONN\" != \"sqlite\" ]; then\r\n DB_NAME=$(grep -oP '^DB_DATABASE=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n DB_USER=$(grep -oP '^DB_USERNAME=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n DB_PASS=$(grep -oP '^DB_PASSWORD=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n DB_HOST=$(grep -oP '^DB_HOST=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n DB_PORT=$(grep -oP '^DB_PORT=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n break\r\n fi\r\n fi\r\ndone\r\n[ -z \"$DB_NAME\" ] || [ -z \"$DB_USER\" ] && echo \"ERROR: No database config found at $SITE\" && exit 1\r\nDB_HOST=\\${DB_HOST:-localhost}\r\nDB_PORT=\\${DB_PORT:-3306}\r\nmysql --user=\"$DB_USER\" --password=\"$DB_PASS\" --host=\"$DB_HOST\" --port=\"$DB_PORT\" -t -e '${safeQuery}' \"$DB_NAME\" 2>&1 | grep -v \"\\\\[Warning\\\\].*password\"\r\n`.trim();\r\n}\r\n\r\n/**\r\n * Execute a MySQL query for a site in a single SSH session.\r\n * Discovers credentials and runs the query in one command.\r\n */\r\nasync function execSiteMysql(conn: SshConnectionOptions, sitePath: string, query: string): Promise<string> {\r\n const cmd = buildSiteMysqlCommand(sitePath, query);\r\n const result = await sshExec(conn, cmd);\r\n const output = (result.stdout || '').trim();\r\n if (output.startsWith('ERROR: No database config found')) {\r\n throw new Error(output);\r\n }\r\n if (result.exitCode !== 0 && !output) {\r\n throw new Error(result.stderr || 'MySQL command failed');\r\n }\r\n return output;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// mijn.host API helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nconst MIJNHOST_BASE_URL = 'https://mijn.host/api/v2';\r\n\r\ninterface MijnHostApiResponse<T = unknown> {\r\n status: number;\r\n status_description: string;\r\n data: T;\r\n}\r\n\r\nfunction requireMijnhostApiKey(): string {\r\n if (!mijnhostApiKey) {\r\n throw new Error('mijn.host API key not configured. Use --mijnhost-api-key=xxx or set MIJNHOST_API_KEY');\r\n }\r\n return mijnhostApiKey;\r\n}\r\n\r\nasync function mijnhostFetch<T>(path: string, options: RequestInit = {}): Promise<MijnHostApiResponse<T>> {\r\n const key = requireMijnhostApiKey();\r\n\r\n const res = await fetch(`${MIJNHOST_BASE_URL}${path}`, {\r\n ...options,\r\n headers: {\r\n 'API-Key': key,\r\n 'Accept': 'application/json',\r\n 'Content-Type': 'application/json',\r\n 'User-Agent': 'mg-dashboard-mcp/1.7.0',\r\n ...((options.headers as Record<string, string>) || {}),\r\n },\r\n });\r\n\r\n const json: unknown = await res.json();\r\n const body = json as MijnHostApiResponse<T>;\r\n\r\n if (!res.ok) {\r\n throw new Error(body?.status_description || `mijn.host API error: ${res.status}`);\r\n }\r\n\r\n return body;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Tool definitions\r\n// ---------------------------------------------------------------------------\r\n\r\nconst TOOLS = [\r\n {\r\n name: 'list-servers',\r\n description: 'List all SSH servers you have access to. Returns id, name, hostname, and tags for each server.',\r\n inputSchema: { type: 'object' as const, properties: {}, required: [] },\r\n },\r\n {\r\n name: 'server-status',\r\n description: 'Get server status including uptime, disk usage, memory, and load average.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'ssh-execute',\r\n description: 'Execute a shell command on a remote server via SSH. Some dangerous commands are blocked for safety.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n command: { type: 'string', description: 'Shell command to execute' },\r\n timeout: { type: 'number', description: 'Timeout in milliseconds (default: 60000)' },\r\n },\r\n required: ['serverId', 'command'],\r\n },\r\n },\r\n {\r\n name: 'server-reboot',\r\n description: 'Reboot a remote server. This will cause downtime. The server will be unavailable until it restarts.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server to reboot' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'server-restart-service',\r\n description: 'Restart a systemd service on a remote server using systemctl restart.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n serviceName: { type: 'string', description: 'Name of the systemd service (e.g. nginx, docker, lsws)' },\r\n },\r\n required: ['serverId', 'serviceName'],\r\n },\r\n },\r\n {\r\n name: 'sftp-list',\r\n description: 'List files and directories at a given path on a remote server via SFTP.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n path: { type: 'string', description: 'Directory path to list (default: /)' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'sftp-read',\r\n description: 'Read the contents of a text file on a remote server via SFTP (max 1MB).',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n path: { type: 'string', description: 'File path to read' },\r\n },\r\n required: ['serverId', 'path'],\r\n },\r\n },\r\n {\r\n name: 'sftp-write',\r\n description: 'Write content to a file on a remote server via SFTP. Protected system paths are blocked.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n path: { type: 'string', description: 'File path to write' },\r\n content: { type: 'string', description: 'File content to write' },\r\n },\r\n required: ['serverId', 'path', 'content'],\r\n },\r\n },\r\n {\r\n name: 'sftp-delete',\r\n description: 'Delete a file or empty directory on a remote server via SFTP. Protected system paths are blocked.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n path: { type: 'string', description: 'File or directory path to delete' },\r\n },\r\n required: ['serverId', 'path'],\r\n },\r\n },\r\n {\r\n name: 'docker-list',\r\n description: 'List all Docker containers on a remote server (running and stopped).',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'docker-action',\r\n description: 'Perform an action on a Docker container: start, stop, restart, or remove.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n containerName: { type: 'string', description: 'Container name or ID' },\r\n action: { type: 'string', enum: ['start', 'stop', 'restart', 'remove'], description: 'Action to perform' },\r\n },\r\n required: ['serverId', 'containerName', 'action'],\r\n },\r\n },\r\n {\r\n name: 'docker-logs',\r\n description: 'Get recent logs from a Docker container.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n containerName: { type: 'string', description: 'Container name or ID' },\r\n lines: { type: 'number', description: 'Number of log lines to retrieve (default: 100)' },\r\n },\r\n required: ['serverId', 'containerName'],\r\n },\r\n },\r\n {\r\n name: 'db-discover',\r\n description: 'Scan /var/www on a server for web applications (WordPress, PrestaShop, Laravel, .env) and list their database credentials. Use this first to find available sites before running other db-* tools.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'db-tables',\r\n description: 'List all tables in a site database with row counts and sizes. Credentials are auto-discovered from the site config files (wp-config.php, parameters.php, .env).',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n sitePath: { type: 'string', description: 'Site root path (e.g. /var/www/example.com)' },\r\n },\r\n required: ['serverId', 'sitePath'],\r\n },\r\n },\r\n {\r\n name: 'db-describe',\r\n description: 'Show the structure of a database table (columns, types, keys, defaults). Credentials are auto-discovered from site config files.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n sitePath: { type: 'string', description: 'Site root path (e.g. /var/www/example.com)' },\r\n table: { type: 'string', description: 'Table name' },\r\n },\r\n required: ['serverId', 'sitePath', 'table'],\r\n },\r\n },\r\n {\r\n name: 'db-query',\r\n description: 'Execute a SQL query on a site database. Credentials are auto-discovered from site config files. Destructive operations (DROP, TRUNCATE) are blocked.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n sitePath: { type: 'string', description: 'Site root path (e.g. /var/www/example.com)' },\r\n query: { type: 'string', description: 'SQL query to execute' },\r\n },\r\n required: ['serverId', 'sitePath', 'query'],\r\n },\r\n },\r\n {\r\n name: 'env-list',\r\n description: 'List all stored environment configurations (app name, environment, description).',\r\n inputSchema: { type: 'object' as const, properties: {}, required: [] },\r\n },\r\n {\r\n name: 'env-get',\r\n description: 'Retrieve the decrypted .env content for a specific app and environment.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n appName: { type: 'string', description: 'Application name (e.g. backoffice, api, web)' },\r\n environment: { type: 'string', description: 'Environment name (e.g. production, staging, development)' },\r\n },\r\n required: ['appName', 'environment'],\r\n },\r\n },\r\n {\r\n name: 'env-store',\r\n description: 'Store or update an encrypted .env configuration for an app and environment.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n appName: { type: 'string', description: 'Application name (e.g. backoffice, api, web)' },\r\n environment: { type: 'string', description: 'Environment name (e.g. production, staging, development)' },\r\n content: { type: 'string', description: 'The .env file content to store' },\r\n description: { type: 'string', description: 'Optional description' },\r\n },\r\n required: ['appName', 'environment', 'content'],\r\n },\r\n },\r\n {\r\n name: 'cache-purge',\r\n description: 'Purge ALL caches on a server in one operation: OPcache (kills lsphp), LiteSpeed cache, WordPress object cache (wp-cli or file-based), PrestaShop Smarty/app cache, Redis FLUSHALL, and Memcached flush. Returns a per-cache status report.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'log-list',\r\n description: 'Discover available log files on a server. Scans LiteSpeed logs, PHP error logs, syslog, and per-site application logs (WordPress debug.log, PrestaShop var/logs, Laravel storage/logs). Returns paths with file sizes and last modified dates.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'log-read',\r\n description: 'Read the last N lines from a specific log file on a server. Use log-list first to discover available files. Optionally filter lines with a grep pattern.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n path: { type: 'string', description: 'Absolute path to the log file (must end in .log)' },\r\n lines: { type: 'number', description: 'Number of lines to read (default: 100, max: 500)' },\r\n filter: { type: 'string', description: 'Optional grep pattern to filter lines before tailing' },\r\n },\r\n required: ['serverId', 'path'],\r\n },\r\n },\r\n // ----- Cron Jobs -----\r\n {\r\n name: 'cron-list',\r\n description: 'List all cron jobs on a server. Shows root crontab, system cron directories (/etc/cron.d/), and www-data crontab. Each entry shows the schedule, command, user, and source. Disabled (commented) entries are marked.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n user: { type: 'string', description: 'Specific user crontab to list (default: lists root + www-data + /etc/cron.d/)' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'cron-add',\r\n description: 'Add a new cron job to a user crontab. Provide a standard cron schedule expression and command. Examples: \"0 2 * * * /usr/bin/backup.sh\" (daily at 2am), \"*/5 * * * * curl http://example.com/cron.php\" (every 5 min).',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n schedule: { type: 'string', description: 'Cron schedule expression (e.g. \"0 2 * * *\" or \"@daily\")' },\r\n command: { type: 'string', description: 'Command to execute' },\r\n user: { type: 'string', description: 'User whose crontab to edit (default: root)' },\r\n comment: { type: 'string', description: 'Optional comment to add above the cron entry (for identification)' },\r\n },\r\n required: ['serverId', 'schedule', 'command'],\r\n },\r\n },\r\n {\r\n name: 'cron-remove',\r\n description: 'Remove a cron job from a user crontab by matching the command string (exact or partial match). Use cron-list first to see existing jobs.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n commandMatch: { type: 'string', description: 'Full or partial command string to match for removal' },\r\n user: { type: 'string', description: 'User whose crontab to edit (default: root)' },\r\n },\r\n required: ['serverId', 'commandMatch'],\r\n },\r\n },\r\n {\r\n name: 'cron-toggle',\r\n description: 'Enable or disable a cron job by commenting/uncommenting it. Matches by command string. Use cron-list to find the job first.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n commandMatch: { type: 'string', description: 'Full or partial command string to match' },\r\n enable: { type: 'boolean', description: 'true to enable (uncomment), false to disable (comment out)' },\r\n user: { type: 'string', description: 'User whose crontab to edit (default: root)' },\r\n },\r\n required: ['serverId', 'commandMatch', 'enable'],\r\n },\r\n },\r\n // ----- Domains (mijn.host) -----\r\n {\r\n name: 'domain-list',\r\n description: 'List all domains from the mijn.host account. Returns domain name, status, renewal date, and tags. Requires MIJNHOST_API_KEY.',\r\n inputSchema: { type: 'object' as const, properties: {}, required: [] },\r\n },\r\n {\r\n name: 'domain-get',\r\n description: 'Get detailed information about a specific domain: status, renewal date, lock state, managed DNS, DNSSEC, nameservers, contact handles, and messages.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n domain: { type: 'string', description: 'Domain name (e.g. example.com)' },\r\n },\r\n required: ['domain'],\r\n },\r\n },\r\n {\r\n name: 'dns-list',\r\n description: 'List all DNS records for a domain. Returns type (A, AAAA, CNAME, MX, TXT, etc.), name, value, and TTL for each record.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n domain: { type: 'string', description: 'Domain name (e.g. example.com)' },\r\n },\r\n required: ['domain'],\r\n },\r\n },\r\n {\r\n name: 'dns-create',\r\n description: 'Add a new DNS record to a domain. Uses PATCH to add without replacing existing records.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n domain: { type: 'string', description: 'Domain name (e.g. example.com)' },\r\n type: { type: 'string', description: 'Record type: A, AAAA, CNAME, MX, TXT, NS, SRV, CAA, or TLSA' },\r\n name: { type: 'string', description: 'Record name (e.g. @ or subdomain)' },\r\n value: { type: 'string', description: 'Record value (e.g. IP address, hostname)' },\r\n ttl: { type: 'number', description: 'TTL in seconds (min 60, default 3600)' },\r\n },\r\n required: ['domain', 'type', 'name', 'value'],\r\n },\r\n },\r\n {\r\n name: 'dns-update',\r\n description: 'Update an existing DNS record. Identifies the record by type+name+oldValue, then replaces it with new values via PATCH.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n domain: { type: 'string', description: 'Domain name (e.g. example.com)' },\r\n type: { type: 'string', description: 'Record type: A, AAAA, CNAME, MX, TXT, NS, SRV, CAA, or TLSA' },\r\n name: { type: 'string', description: 'Record name' },\r\n oldValue: { type: 'string', description: 'Current value of the record to update' },\r\n newValue: { type: 'string', description: 'New value for the record' },\r\n ttl: { type: 'number', description: 'New TTL in seconds (min 60)' },\r\n },\r\n required: ['domain', 'type', 'name', 'oldValue', 'newValue'],\r\n },\r\n },\r\n {\r\n name: 'dns-delete',\r\n description: 'Delete a DNS record by type, name, and value. Fetches all records, removes the matching one, then replaces the full set.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n domain: { type: 'string', description: 'Domain name (e.g. example.com)' },\r\n type: { type: 'string', description: 'Record type to delete' },\r\n name: { type: 'string', description: 'Record name to delete' },\r\n value: { type: 'string', description: 'Record value to delete (must match exactly)' },\r\n },\r\n required: ['domain', 'type', 'name', 'value'],\r\n },\r\n },\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// MCP Server\r\n// ---------------------------------------------------------------------------\r\n\r\nconst server = new Server(\r\n { name: 'mg-dashboard-mcp', version: '1.7.0' },\r\n { capabilities: { tools: {} } },\r\n);\r\n\r\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));\r\n\r\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\r\n if (!authContext) {\r\n return { content: [{ type: 'text', text: 'Error: not authenticated' }] };\r\n }\r\n\r\n const { name, arguments: toolArgs } = request.params;\r\n const a = (toolArgs || {}) as Record<string, unknown>;\r\n\r\n try {\r\n switch (name) {\r\n // ----- Servers -----\r\n case 'list-servers': {\r\n let query = supabase\r\n .from('ssh_server')\r\n .select('id, name, hostname, port, username, tags, hosted_by, created_at')\r\n .order('name');\r\n\r\n if (authContext.allowedServerIds !== null) {\r\n query = query.in('id', authContext.allowedServerIds);\r\n }\r\n\r\n const { data, error } = await query;\r\n if (error) throw new Error(error.message);\r\n\r\n const lines = (data || []).map(s => {\r\n const tags = Array.isArray(s.tags) ? (s.tags as string[]).join(', ') : '';\r\n return `${s.id} ${s.name} ${s.hostname}:${s.port} ${s.username} [${tags}] ${s.hosted_by || ''}`;\r\n });\r\n\r\n return { content: [{ type: 'text', text: lines.length ? lines.join('\\n') : 'No servers found' }] };\r\n }\r\n\r\n case 'server-status': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const cmd = 'echo \"=== UPTIME ===\" && uptime && echo \"=== DISK ===\" && df -h --total && echo \"=== MEMORY ===\" && free -h && echo \"=== LOAD ===\" && cat /proc/loadavg';\r\n const result = await sshExec(conn, cmd);\r\n const output = result.exitCode === 0 ? result.stdout : `Exit ${result.exitCode}\\n${result.stdout}\\n${result.stderr}`;\r\n return { content: [{ type: 'text', text: output }] };\r\n }\r\n\r\n // ----- SSH -----\r\n case 'ssh-execute': {\r\n const command = String(a.command);\r\n assertSafeCommand(command);\r\n const conn = await getServerConnection(String(a.serverId));\r\n if (a.timeout) conn.timeout = Number(a.timeout);\r\n const result = await sshExec(conn, command);\r\n const output = [`Exit code: ${result.exitCode}`];\r\n if (result.stdout) output.push(`--- stdout ---\\n${result.stdout}`);\r\n if (result.stderr) output.push(`--- stderr ---\\n${result.stderr}`);\r\n return { content: [{ type: 'text', text: output.join('\\n') }] };\r\n }\r\n\r\n case 'server-reboot': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sshExec(conn, 'sudo reboot');\r\n return { content: [{ type: 'text', text: result.exitCode === 0 ? 'Reboot command sent. Server will be unavailable shortly.' : `Reboot failed: ${result.stderr}` }] };\r\n }\r\n\r\n case 'server-restart-service': {\r\n const service = String(a.serviceName).replace(/[^a-zA-Z0-9._@-]/g, '');\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sshExec(conn, `sudo systemctl restart ${service}`);\r\n if (result.exitCode === 0) {\r\n const status = await sshExec(conn, `sudo systemctl is-active ${service}`);\r\n return { content: [{ type: 'text', text: `Service \"${service}\" restarted. Status: ${status.stdout.trim()}` }] };\r\n }\r\n return { content: [{ type: 'text', text: `Failed to restart \"${service}\": ${result.stderr}` }] };\r\n }\r\n\r\n // ----- SFTP -----\r\n case 'sftp-list': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const listing = await sftpReaddir(conn, String(a.path || '/'));\r\n return { content: [{ type: 'text', text: listing }] };\r\n }\r\n\r\n case 'sftp-read': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const content = await sftpRead(conn, String(a.path));\r\n return { content: [{ type: 'text', text: content }] };\r\n }\r\n\r\n case 'sftp-write': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sftpWrite(conn, String(a.path), String(a.content));\r\n return { content: [{ type: 'text', text: result }] };\r\n }\r\n\r\n case 'sftp-delete': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sftpDelete(conn, String(a.path));\r\n return { content: [{ type: 'text', text: result }] };\r\n }\r\n\r\n // ----- Docker -----\r\n case 'docker-list': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sshExec(conn, 'docker ps -a --format \"table {{.Names}}\\t{{.Image}}\\t{{.Status}}\\t{{.Ports}}\"');\r\n return { content: [{ type: 'text', text: result.exitCode === 0 ? result.stdout : `Error: ${result.stderr}` }] };\r\n }\r\n\r\n case 'docker-action': {\r\n const container = String(a.containerName).replace(/[^a-zA-Z0-9._-]/g, '');\r\n const action = String(a.action);\r\n if (!['start', 'stop', 'restart', 'remove'].includes(action)) {\r\n throw new Error(`Invalid action: ${action}. Use start, stop, restart, or remove.`);\r\n }\r\n const conn = await getServerConnection(String(a.serverId));\r\n const dockerCmd = action === 'remove' ? `docker rm -f ${container}` : `docker ${action} ${container}`;\r\n const result = await sshExec(conn, dockerCmd);\r\n return { content: [{ type: 'text', text: result.exitCode === 0 ? `Container \"${container}\" ${action}ed successfully` : `Error: ${result.stderr}` }] };\r\n }\r\n\r\n case 'docker-logs': {\r\n const container = String(a.containerName).replace(/[^a-zA-Z0-9._-]/g, '');\r\n const lines = Number(a.lines) || 100;\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sshExec(conn, `docker logs --tail ${lines} ${container} 2>&1`);\r\n return { content: [{ type: 'text', text: result.exitCode === 0 ? result.stdout : `Error: ${result.stderr}` }] };\r\n }\r\n\r\n // ----- Database -----\r\n case 'db-discover': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const sites = await discoverSiteDatabases(conn);\r\n if (!sites.length) {\r\n return { content: [{ type: 'text', text: 'No web applications with database configs found in /var/www/' }] };\r\n }\r\n const lines = sites.map(s =>\r\n `${s.sitePath} [${s.appType}] db=${s.database} user=${s.user} host=${s.host}:${s.port}`\r\n );\r\n return { content: [{ type: 'text', text: lines.join('\\n') }] };\r\n }\r\n\r\n case 'db-tables': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const sql = \"SELECT TABLE_NAME, ENGINE, TABLE_ROWS, ROUND(DATA_LENGTH/1024/1024, 2) AS `Size (MB)`, TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY TABLE_NAME\";\r\n const output = await execSiteMysql(conn, String(a.sitePath), sql);\r\n return { content: [{ type: 'text', text: output || 'No tables found' }] };\r\n }\r\n\r\n case 'db-describe': {\r\n const table = String(a.table).replace(/[^a-zA-Z0-9_]/g, '');\r\n const conn = await getServerConnection(String(a.serverId));\r\n const output = await execSiteMysql(conn, String(a.sitePath),\r\n `DESCRIBE \\`${table}\\`; SHOW INDEX FROM \\`${table}\\``);\r\n return { content: [{ type: 'text', text: output }] };\r\n }\r\n\r\n case 'db-query': {\r\n const query = String(a.query).trim();\r\n assertSafeSql(query);\r\n const conn = await getServerConnection(String(a.serverId));\r\n const output = await execSiteMysql(conn, String(a.sitePath), query);\r\n return { content: [{ type: 'text', text: output || 'Query executed successfully (no output)' }] };\r\n }\r\n\r\n // ----- Env Config -----\r\n case 'env-list': {\r\n const { data, error } = await supabase\r\n .from('env_config')\r\n .select('id, app_name, environment, description, updated_at')\r\n .order('app_name')\r\n .order('environment');\r\n\r\n if (error) throw new Error(error.message);\r\n const lines = (data || []).map(e =>\r\n `${e.app_name}/${e.environment} ${e.description || ''} (updated: ${e.updated_at})`\r\n );\r\n return { content: [{ type: 'text', text: lines.length ? lines.join('\\n') : 'No environment configs stored' }] };\r\n }\r\n\r\n case 'env-get': {\r\n const { data, error } = await supabase\r\n .from('env_config')\r\n .select('env_data_encrypted')\r\n .eq('app_name', String(a.appName))\r\n .eq('environment', String(a.environment))\r\n .single();\r\n\r\n if (error || !data) throw new Error(`Env config not found: ${a.appName}/${a.environment}`);\r\n const decrypted = decrypt(data.env_data_encrypted);\r\n return { content: [{ type: 'text', text: decrypted }] };\r\n }\r\n\r\n case 'env-store': {\r\n const appName = String(a.appName);\r\n const environment = String(a.environment);\r\n const encrypted = encrypt(String(a.content));\r\n\r\n const { data: existing } = await supabase\r\n .from('env_config')\r\n .select('id')\r\n .eq('app_name', appName)\r\n .eq('environment', environment)\r\n .single();\r\n\r\n if (existing) {\r\n const { error } = await supabase\r\n .from('env_config')\r\n .update({\r\n env_data_encrypted: encrypted,\r\n description: a.description ? String(a.description) : undefined,\r\n updated_by: authContext.userId,\r\n updated_at: new Date().toISOString(),\r\n })\r\n .eq('id', existing.id);\r\n if (error) throw new Error(error.message);\r\n return { content: [{ type: 'text', text: `Updated env config: ${appName}/${environment}` }] };\r\n }\r\n\r\n const { error } = await supabase.from('env_config').insert({\r\n app_name: appName,\r\n environment,\r\n env_data_encrypted: encrypted,\r\n description: a.description ? String(a.description) : null,\r\n created_by: authContext.userId,\r\n updated_by: authContext.userId,\r\n });\r\n if (error) throw new Error(error.message);\r\n return { content: [{ type: 'text', text: `Stored env config: ${appName}/${environment}` }] };\r\n }\r\n\r\n // ----- Cache Purge -----\r\n case 'cache-purge': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n conn.timeout = 120_000;\r\n const script = `\r\nR=\"\"\r\n# 1. OPcache – kill lsphp so it respawns with a fresh OPcache\r\nif pgrep -x lsphp >/dev/null 2>&1; then\r\n sudo killall lsphp 2>/dev/null && R=\"\\${R}[OK] OPcache: killed lsphp processes\\\\n\" || R=\"\\${R}[FAIL] OPcache: could not kill lsphp\\\\n\"\r\nelse\r\n R=\"\\${R}[SKIP] OPcache: no lsphp processes running\\\\n\"\r\nfi\r\n# 2. LiteSpeed cache directories\r\nLS=0\r\nfor cdir in /tmp/lshttpd/swap /usr/local/lsws/cachedata; do\r\n if [ -d \"\\$cdir\" ] && [ \"\\$(ls -A \"\\$cdir\" 2>/dev/null)\" ]; then\r\n sudo rm -rf \"\\$cdir\"/* 2>/dev/null && R=\"\\${R}[OK] LS cache: cleared \\$cdir\\\\n\" && LS=1 || R=\"\\${R}[FAIL] LS cache: \\$cdir\\\\n\"\r\n fi\r\ndone\r\n[ \"\\$LS\" -eq 0 ] && R=\"\\${R}[SKIP] LS cache: no cache dirs with content\\\\n\"\r\n# 3. LiteSpeed graceful restart\r\nif [ -x /usr/local/lsws/bin/lswsctrl ]; then\r\n sudo /usr/local/lsws/bin/lswsctrl restart 2>/dev/null && R=\"\\${R}[OK] LiteSpeed: graceful restart\\\\n\" || R=\"\\${R}[FAIL] LiteSpeed: restart failed\\\\n\"\r\nelif systemctl is-active lsws >/dev/null 2>&1 || systemctl is-active lshttpd >/dev/null 2>&1; then\r\n sudo systemctl restart lsws 2>/dev/null || sudo systemctl restart lshttpd 2>/dev/null\r\n R=\"\\${R}[OK] LiteSpeed: restarted via systemctl\\\\n\"\r\nelse\r\n R=\"\\${R}[SKIP] LiteSpeed: not detected\\\\n\"\r\nfi\r\n# 4. WordPress caches\r\nWP=0\r\nfor dir in /var/www/*/; do\r\n [ -d \"\\$dir\" ] || continue\r\n for root in \"\\$dir\" \"\\${dir}html\" \"\\${dir}public_html\" \"\\${dir}public\" \"\\${dir}httpdocs\"; do\r\n [ -f \"\\$root/wp-config.php\" ] || continue\r\n WP=1; SITE=\\$(basename \"\\$dir\")\r\n if command -v wp >/dev/null 2>&1; then\r\n wp cache flush --allow-root --path=\"\\$root\" 2>/dev/null && R=\"\\${R}[OK] WP (\\$SITE): wp cache flush\\\\n\" || R=\"\\${R}[FAIL] WP (\\$SITE): wp cache flush\\\\n\"\r\n elif [ -d \"\\$root/wp-content/cache\" ]; then\r\n rm -rf \"\\$root/wp-content/cache\"/* 2>/dev/null && R=\"\\${R}[OK] WP (\\$SITE): cleared wp-content/cache\\\\n\"\r\n else\r\n R=\"\\${R}[SKIP] WP (\\$SITE): no cache dir, no wp-cli\\\\n\"\r\n fi\r\n break\r\n done\r\ndone\r\n[ \"\\$WP\" -eq 0 ] && R=\"\\${R}[SKIP] WordPress: no sites found\\\\n\"\r\n# 5. PrestaShop caches\r\nPS=0\r\nfor dir in /var/www/*/; do\r\n [ -d \"\\$dir\" ] || continue\r\n for root in \"\\$dir\" \"\\${dir}html\" \"\\${dir}public_html\" \"\\${dir}public\" \"\\${dir}httpdocs\"; do\r\n IS=0\r\n [ -f \"\\$root/app/config/parameters.php\" ] && IS=1\r\n [ -f \"\\$root/config/settings.inc.php\" ] && IS=1\r\n [ \"\\$IS\" -eq 0 ] && continue\r\n PS=1; SITE=\\$(basename \"\\$dir\"); C=\"\"\r\n [ -d \"\\$root/var/cache\" ] && rm -rf \"\\$root/var/cache\"/* 2>/dev/null && C=\"\\${C}var/cache \"\r\n [ -d \"\\$root/cache/smarty/compile\" ] && rm -rf \"\\$root/cache/smarty/compile\"/* 2>/dev/null && C=\"\\${C}smarty/compile \"\r\n [ -d \"\\$root/cache/smarty/cache\" ] && rm -rf \"\\$root/cache/smarty/cache\"/* 2>/dev/null && C=\"\\${C}smarty/cache \"\r\n [ -n \"\\$C\" ] && R=\"\\${R}[OK] PS (\\$SITE): cleared \\${C}\\\\n\" || R=\"\\${R}[SKIP] PS (\\$SITE): no cache dirs\\\\n\"\r\n break\r\n done\r\ndone\r\n[ \"\\$PS\" -eq 0 ] && R=\"\\${R}[SKIP] PrestaShop: no sites found\\\\n\"\r\n# 6. Redis\r\nif command -v redis-cli >/dev/null 2>&1 && redis-cli ping >/dev/null 2>&1; then\r\n redis-cli FLUSHALL 2>/dev/null && R=\"\\${R}[OK] Redis: FLUSHALL\\\\n\" || R=\"\\${R}[FAIL] Redis: FLUSHALL failed\\\\n\"\r\nelse\r\n R=\"\\${R}[SKIP] Redis: not available\\\\n\"\r\nfi\r\n# 7. Memcached\r\nif systemctl is-active memcached >/dev/null 2>&1; then\r\n if command -v memcflush >/dev/null 2>&1; then\r\n memcflush --servers=localhost 2>/dev/null && R=\"\\${R}[OK] Memcached: flushed\\\\n\" || R=\"\\${R}[FAIL] Memcached: flush failed\\\\n\"\r\n else\r\n echo \"flush_all\" | nc -q1 localhost 11211 2>/dev/null && R=\"\\${R}[OK] Memcached: flushed via nc\\\\n\" || R=\"\\${R}[FAIL] Memcached: flush failed\\\\n\"\r\n fi\r\nelse\r\n R=\"\\${R}[SKIP] Memcached: not active\\\\n\"\r\nfi\r\necho -e \"\\$R\"\r\n`.trim();\r\n const result = await sshExec(conn, script);\r\n const output = (result.stdout || '').trim();\r\n return { content: [{ type: 'text', text: output || 'Cache purge completed (no output)' }] };\r\n }\r\n\r\n // ----- Log Reading -----\r\n case 'log-list': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const script = `\r\n{\r\n [ -d /usr/local/lsws/logs ] && find /usr/local/lsws/logs -maxdepth 2 -name \"*.log\" -type f 2>/dev/null\r\n for f in /var/log/syslog /var/log/messages /var/log/auth.log /var/log/kern.log; do [ -f \"\\$f\" ] && echo \"\\$f\"; done\r\n find /var/log -maxdepth 2 \\\\( -name \"php*.log\" -o -name \"lsphp*.log\" \\\\) -type f 2>/dev/null\r\n [ -d /var/log/mg-monitoring ] && find /var/log/mg-monitoring -maxdepth 1 -name \"*.log\" -type f 2>/dev/null\r\n for dir in /var/www/*/; do\r\n [ -d \"\\$dir\" ] || continue\r\n for root in \"\\$dir\" \"\\${dir}html\" \"\\${dir}public_html\" \"\\${dir}public\" \"\\${dir}httpdocs\"; do\r\n [ -d \"\\$root\" ] || continue\r\n [ -f \"\\$root/wp-content/debug.log\" ] && echo \"\\$root/wp-content/debug.log\"\r\n [ -d \"\\$root/var/logs\" ] && find \"\\$root/var/logs\" -maxdepth 1 -name \"*.log\" -type f 2>/dev/null\r\n [ -d \"\\$root/log\" ] && find \"\\$root/log\" -maxdepth 1 -name \"*.log\" -type f 2>/dev/null\r\n [ -d \"\\$root/storage/logs\" ] && find \"\\$root/storage/logs\" -maxdepth 1 -name \"*.log\" -type f 2>/dev/null\r\n done\r\n done\r\n} | sort -u | while IFS= read -r f; do\r\n SZ=\\$(stat -c%s \"\\$f\" 2>/dev/null || echo 0)\r\n MOD=\\$(stat -c%y \"\\$f\" 2>/dev/null | cut -d. -f1)\r\n if [ \"\\$SZ\" -ge 1048576 ] 2>/dev/null; then HR=\"\\$(( SZ / 1048576 ))MB\"\r\n elif [ \"\\$SZ\" -ge 1024 ] 2>/dev/null; then HR=\"\\$(( SZ / 1024 ))KB\"\r\n else HR=\"\\${SZ}B\"; fi\r\n echo \"\\$f \\$HR \\$MOD\"\r\ndone\r\n`.trim();\r\n const result = await sshExec(conn, script);\r\n return { content: [{ type: 'text', text: result.stdout || 'No log files found' }] };\r\n }\r\n\r\n case 'log-read': {\r\n const logPath = sanitizePath(String(a.path));\r\n assertAllowedLogPath(logPath);\r\n const lineCount = Math.min(Math.max(Number(a.lines) || 100, 1), 500);\r\n const filter = a.filter ? String(a.filter).replace(/'/g, \"'\\\\''\") : '';\r\n const conn = await getServerConnection(String(a.serverId));\r\n const cmd = filter\r\n ? `grep '${filter}' '${logPath}' 2>/dev/null | tail -n ${lineCount}`\r\n : `tail -n ${lineCount} '${logPath}' 2>/dev/null`;\r\n const result = await sshExec(conn, cmd);\r\n if (result.exitCode !== 0 && !result.stdout) {\r\n throw new Error(result.stderr || `Failed to read log: ${logPath}`);\r\n }\r\n return { content: [{ type: 'text', text: result.stdout || '(empty log file)' }] };\r\n }\r\n\r\n // ----- Cron Jobs -----\r\n case 'cron-list': {\r\n const conn = await getServerConnection(a.serverId as string);\r\n const user = a.user ? String(a.user) : null;\r\n\r\n const parts: string[] = [];\r\n\r\n if (user) {\r\n const result = await sshExec(conn, `crontab -l -u ${user} 2>/dev/null || echo '(no crontab for ${user})'`);\r\n parts.push(`## Crontab for ${user}\\n${result.stdout}`);\r\n } else {\r\n const rootCron = await sshExec(conn, `crontab -l 2>/dev/null || echo '(no crontab for root)'`);\r\n parts.push(`## Root crontab\\n${rootCron.stdout}`);\r\n\r\n const wwwCron = await sshExec(conn, `crontab -l -u www-data 2>/dev/null || echo '(no crontab for www-data)'`);\r\n parts.push(`## www-data crontab\\n${wwwCron.stdout}`);\r\n\r\n const cronD = await sshExec(conn, `for f in /etc/cron.d/*; do [ -f \"$f\" ] && echo \"--- $f ---\" && cat \"$f\" && echo; done 2>/dev/null || echo '(no files in /etc/cron.d/)'`);\r\n parts.push(`## /etc/cron.d/\\n${cronD.stdout}`);\r\n\r\n const summary = await sshExec(conn, [\r\n `echo \"## Scheduled directories\"`,\r\n `echo \"cron.hourly: $(ls /etc/cron.hourly/ 2>/dev/null | wc -l) scripts\"`,\r\n `echo \"cron.daily: $(ls /etc/cron.daily/ 2>/dev/null | wc -l) scripts\"`,\r\n `echo \"cron.weekly: $(ls /etc/cron.weekly/ 2>/dev/null | wc -l) scripts\"`,\r\n `echo \"cron.monthly: $(ls /etc/cron.monthly/ 2>/dev/null | wc -l) scripts\"`,\r\n ].join(' && '));\r\n parts.push(summary.stdout);\r\n }\r\n\r\n return { content: [{ type: 'text', text: parts.join('\\n\\n') }] };\r\n }\r\n\r\n case 'cron-add': {\r\n const conn = await getServerConnection(a.serverId as string);\r\n const user = a.user ? String(a.user) : 'root';\r\n const schedule = String(a.schedule).trim();\r\n const command = String(a.command).trim();\r\n const commentText = a.comment ? String(a.comment).trim() : '';\r\n\r\n if (!schedule || !command) {\r\n throw new Error('Both schedule and command are required');\r\n }\r\n\r\n const entry = commentText\r\n ? `# ${commentText}\\n${schedule} ${command}`\r\n : `${schedule} ${command}`;\r\n\r\n const result = await sshExec(conn, `(crontab -l -u ${user} 2>/dev/null; echo '${entry.replace(/'/g, \"'\\\\''\")}') | crontab -u ${user} -`);\r\n if (result.exitCode !== 0) {\r\n throw new Error(result.stderr || 'Failed to add cron job');\r\n }\r\n\r\n return { content: [{ type: 'text', text: `Cron job added for ${user}:\\n${schedule} ${command}` }] };\r\n }\r\n\r\n case 'cron-remove': {\r\n const conn = await getServerConnection(a.serverId as string);\r\n const user = a.user ? String(a.user) : 'root';\r\n const match = String(a.commandMatch).trim();\r\n\r\n if (!match) {\r\n throw new Error('commandMatch is required');\r\n }\r\n\r\n const current = await sshExec(conn, `crontab -l -u ${user} 2>/dev/null`);\r\n const lines = current.stdout.split('\\n');\r\n const before = lines.length;\r\n\r\n const filtered = lines.filter(line => {\r\n const trimmed = line.replace(/^#\\s*/, '');\r\n return !trimmed.includes(match);\r\n });\r\n const removed = before - filtered.length;\r\n\r\n if (removed === 0) {\r\n return { content: [{ type: 'text', text: `No cron entries found matching \"${match}\"` }] };\r\n }\r\n\r\n const escapedCrontab = filtered.join('\\n').replace(/'/g, \"'\\\\''\");\r\n const result = await sshExec(conn, `echo '${escapedCrontab}' | crontab -u ${user} -`);\r\n if (result.exitCode !== 0) {\r\n throw new Error(result.stderr || 'Failed to update crontab');\r\n }\r\n\r\n return { content: [{ type: 'text', text: `Removed ${removed} cron entry/entries matching \"${match}\" from ${user} crontab` }] };\r\n }\r\n\r\n case 'cron-toggle': {\r\n const conn = await getServerConnection(a.serverId as string);\r\n const user = a.user ? String(a.user) : 'root';\r\n const match = String(a.commandMatch).trim();\r\n const enable = Boolean(a.enable);\r\n\r\n if (!match) {\r\n throw new Error('commandMatch is required');\r\n }\r\n\r\n const current = await sshExec(conn, `crontab -l -u ${user} 2>/dev/null`);\r\n const lines = current.stdout.split('\\n');\r\n let toggled = 0;\r\n\r\n const updated = lines.map(line => {\r\n if (enable && line.startsWith('#') && line.replace(/^#\\s*/, '').includes(match)) {\r\n toggled++;\r\n return line.replace(/^#\\s*/, '');\r\n }\r\n if (!enable && !line.startsWith('#') && line.includes(match)) {\r\n toggled++;\r\n return `# ${line}`;\r\n }\r\n return line;\r\n });\r\n\r\n if (toggled === 0) {\r\n const state = enable ? 'disabled' : 'enabled';\r\n return { content: [{ type: 'text', text: `No ${state} cron entries found matching \"${match}\"` }] };\r\n }\r\n\r\n const escapedCrontab = updated.join('\\n').replace(/'/g, \"'\\\\''\");\r\n const result = await sshExec(conn, `echo '${escapedCrontab}' | crontab -u ${user} -`);\r\n if (result.exitCode !== 0) {\r\n throw new Error(result.stderr || 'Failed to update crontab');\r\n }\r\n\r\n const action = enable ? 'Enabled' : 'Disabled';\r\n return { content: [{ type: 'text', text: `${action} ${toggled} cron entry/entries matching \"${match}\" in ${user} crontab` }] };\r\n }\r\n\r\n // ----- Domains (mijn.host) -----\r\n case 'domain-list': {\r\n interface DomainListItem {\r\n id: number;\r\n domain: string;\r\n renewal_date: string;\r\n status: string;\r\n status_id: number;\r\n tags: string[];\r\n }\r\n\r\n const res = await mijnhostFetch<{ domains: DomainListItem[] }>('/domains');\r\n const domains = res.data.domains;\r\n\r\n if (!domains.length) {\r\n return { content: [{ type: 'text', text: 'No domains found' }] };\r\n }\r\n\r\n const lines = domains.map(d => {\r\n const tags = d.tags?.length ? ` [${d.tags.join(', ')}]` : '';\r\n return `${d.domain} status=${d.status} renewal=${d.renewal_date}${tags}`;\r\n });\r\n\r\n return { content: [{ type: 'text', text: `${domains.length} domain(s):\\n\\n${lines.join('\\n')}` }] };\r\n }\r\n\r\n case 'domain-get': {\r\n const domain = String(a.domain);\r\n if (!domain) throw new Error('domain is required');\r\n\r\n interface DomainDetail {\r\n domain: string;\r\n renewal_date: string;\r\n is_lockable: boolean;\r\n is_locked: boolean;\r\n dnssec_enabled: number;\r\n nameservers: string[];\r\n managed_dns: boolean;\r\n whitelabel_ns: boolean;\r\n handles: {\r\n owner: { type: string; name: string; handle_id: number };\r\n tech: { type: string; name: string; handle_id: number };\r\n admin: { type: string; name: string; handle_id: number };\r\n reseller: { type: string; name: string; handle_id: number };\r\n };\r\n status: string;\r\n messages: string[];\r\n }\r\n\r\n const res = await mijnhostFetch<DomainDetail>(`/domains/${encodeURIComponent(domain)}`);\r\n const d = res.data;\r\n\r\n const sections = [\r\n `=== ${d.domain} ===`,\r\n `Status: ${d.status}`,\r\n `Renewal: ${d.renewal_date}`,\r\n `Locked: ${d.is_locked ? 'Yes' : 'No'} (lockable: ${d.is_lockable ? 'Yes' : 'No'})`,\r\n `Managed DNS: ${d.managed_dns ? 'Yes' : 'No'}`,\r\n `DNSSEC: ${d.dnssec_enabled ? 'Enabled' : 'Disabled'}`,\r\n `Nameservers: ${d.nameservers.join(', ')}`,\r\n '',\r\n '--- Contact Handles ---',\r\n `Owner: ${d.handles?.owner?.name ?? '-'}`,\r\n `Admin: ${d.handles?.admin?.name ?? '-'}`,\r\n `Tech: ${d.handles?.tech?.name ?? '-'}`,\r\n `Reseller: ${d.handles?.reseller?.name ?? '-'}`,\r\n ];\r\n\r\n if (d.messages?.length) {\r\n sections.push('', '--- Messages ---', ...d.messages);\r\n }\r\n\r\n return { content: [{ type: 'text', text: sections.join('\\n') }] };\r\n }\r\n\r\n case 'dns-list': {\r\n const domain = String(a.domain);\r\n if (!domain) throw new Error('domain is required');\r\n\r\n interface DnsRecord { type: string; name: string; value: string; ttl: number; }\r\n\r\n const res = await mijnhostFetch<{ domain: string; records: DnsRecord[] }>(\r\n `/domains/${encodeURIComponent(domain)}/dns`\r\n );\r\n const records = res.data.records;\r\n\r\n if (!records.length) {\r\n return { content: [{ type: 'text', text: `No DNS records found for ${domain}` }] };\r\n }\r\n\r\n const header = 'TYPE NAME VALUE TTL';\r\n const sep = '-'.repeat(90);\r\n const lines = records.map(r =>\r\n `${r.type.padEnd(10)}${r.name.padEnd(31)}${r.value.substring(0, 40).padEnd(41)}${r.ttl}`\r\n );\r\n\r\n return { content: [{ type: 'text', text: `DNS records for ${domain} (${records.length}):\\n\\n${header}\\n${sep}\\n${lines.join('\\n')}` }] };\r\n }\r\n\r\n case 'dns-create': {\r\n const domain = String(a.domain);\r\n const type = String(a.type).toUpperCase();\r\n const dnsName = String(a.name);\r\n const value = String(a.value);\r\n const ttl = Number(a.ttl) || 3600;\r\n\r\n if (!domain || !type || !dnsName || !value) {\r\n throw new Error('domain, type, name, and value are required');\r\n }\r\n\r\n interface DnsRecordCreate { type: string; name: string; value: string; ttl: number; }\r\n\r\n const current = await mijnhostFetch<{ domain: string; records: DnsRecordCreate[] }>(\r\n `/domains/${encodeURIComponent(domain)}/dns`\r\n );\r\n\r\n const records = [...current.data.records, { type, name: dnsName, value, ttl }];\r\n\r\n await mijnhostFetch<void>(`/domains/${encodeURIComponent(domain)}/dns`, {\r\n method: 'PUT',\r\n body: JSON.stringify({ records }),\r\n });\r\n\r\n return { content: [{ type: 'text', text: `DNS record created: ${type} ${dnsName} → ${value} (TTL: ${ttl})` }] };\r\n }\r\n\r\n case 'dns-update': {\r\n const domain = String(a.domain);\r\n const type = String(a.type).toUpperCase();\r\n const dnsName = String(a.name);\r\n const oldValue = String(a.oldValue);\r\n const newValue = String(a.newValue);\r\n const ttl = Number(a.ttl) || undefined;\r\n\r\n if (!domain || !type || !dnsName || !oldValue || !newValue) {\r\n throw new Error('domain, type, name, oldValue, and newValue are required');\r\n }\r\n\r\n interface DnsRecord { type: string; name: string; value: string; ttl: number; }\r\n\r\n const current = await mijnhostFetch<{ domain: string; records: DnsRecord[] }>(\r\n `/domains/${encodeURIComponent(domain)}/dns`\r\n );\r\n\r\n const idx = current.data.records.findIndex(\r\n r => r.type === type && r.name === dnsName && r.value === oldValue\r\n );\r\n\r\n if (idx === -1) {\r\n throw new Error(`No matching DNS record found: ${type} ${dnsName} = ${oldValue}`);\r\n }\r\n\r\n const updated = [...current.data.records];\r\n const existingTtl = updated[idx]!.ttl;\r\n updated[idx] = {\r\n type,\r\n name: dnsName,\r\n value: newValue,\r\n ttl: ttl ?? existingTtl,\r\n };\r\n\r\n await mijnhostFetch<void>(`/domains/${encodeURIComponent(domain)}/dns`, {\r\n method: 'PUT',\r\n body: JSON.stringify({ records: updated }),\r\n });\r\n\r\n return { content: [{ type: 'text', text: `DNS record updated: ${type} ${dnsName} → ${newValue}${ttl ? ` (TTL: ${ttl})` : ''}` }] };\r\n }\r\n\r\n case 'dns-delete': {\r\n const domain = String(a.domain);\r\n const type = String(a.type).toUpperCase();\r\n const dnsName = String(a.name);\r\n const value = String(a.value);\r\n\r\n if (!domain || !type || !dnsName || !value) {\r\n throw new Error('domain, type, name, and value are required');\r\n }\r\n\r\n interface DnsRecord { type: string; name: string; value: string; ttl: number; }\r\n\r\n const current = await mijnhostFetch<{ domain: string; records: DnsRecord[] }>(\r\n `/domains/${encodeURIComponent(domain)}/dns`\r\n );\r\n\r\n const before = current.data.records.length;\r\n const remaining = current.data.records.filter(\r\n r => !(r.type === type && r.name === dnsName && r.value === value)\r\n );\r\n\r\n if (remaining.length === before) {\r\n throw new Error(`No matching DNS record found: ${type} ${dnsName} = ${value}`);\r\n }\r\n\r\n await mijnhostFetch<void>(`/domains/${encodeURIComponent(domain)}/dns`, {\r\n method: 'PUT',\r\n body: JSON.stringify({ records: remaining }),\r\n });\r\n\r\n return { content: [{ type: 'text', text: `DNS record deleted: ${type} ${dnsName} = ${value} (${remaining.length} records remaining)` }] };\r\n }\r\n\r\n default:\r\n return { content: [{ type: 'text', text: `Unknown tool: ${name}` }] };\r\n }\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n return { content: [{ type: 'text', text: `Error: ${message}` }] };\r\n }\r\n});\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function main() {\r\n console.error('Starting MG Dashboard MCP Server...');\r\n\r\n authContext = await validateApiKey(apiKey!);\r\n if (!authContext) {\r\n console.error('API key validation failed');\r\n process.exit(1);\r\n }\r\n\r\n console.error('API key validated. Starting stdio transport...');\r\n\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n\r\n console.error('MCP Server ready. Tools available: ' + TOOLS.map(t => t.name).join(', '));\r\n}\r\n\r\nmain().catch((err) => {\r\n console.error('Fatal error:', err);\r\n process.exit(1);\r\n});\r\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["SshClient","err","err2","stageIds"],"mappings":"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","file":"index.js","sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';\r\nimport { createClient } from '@supabase/supabase-js';\r\nimport { createHash, randomBytes, createCipheriv, createDecipheriv } from 'crypto';\r\nimport { Client as SshClient } from 'ssh2';\r\n\r\n// ---------------------------------------------------------------------------\r\n// CLI argument parsing\r\n// ---------------------------------------------------------------------------\r\n\r\nconst args = process.argv.slice(2);\r\n\r\nfunction getArg(name: string): string | undefined {\r\n return args.find(a => a.startsWith(`--${name}=`))?.split('=').slice(1).join('=');\r\n}\r\n\r\nconst apiKey = getArg('api-key') || process.env.MG_DASHBOARD_API_KEY;\r\nconst supabaseUrl = getArg('supabase-url') || process.env.SUPABASE_URL;\r\nconst supabaseKey = getArg('supabase-key') || process.env.SUPABASE_SERVICE_ROLE_KEY;\r\nconst encryptionKey = getArg('encryption-key') || process.env.ENCRYPTION_KEY;\r\nconst mijnhostApiKey = getArg('mijnhost-api-key') || process.env.MIJNHOST_API_KEY;\r\n\r\nif (!apiKey) {\r\n console.error('API key is required. Use --api-key=dk_xxx or set MG_DASHBOARD_API_KEY');\r\n process.exit(1);\r\n}\r\n\r\nif (!supabaseUrl || !supabaseKey) {\r\n console.error('Supabase credentials required. Use --supabase-url and --supabase-key or set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY');\r\n process.exit(1);\r\n}\r\n\r\nconst supabase = createClient(supabaseUrl, supabaseKey);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Rate limiting\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface RateLimitEntry {\r\n count: number;\r\n resetAt: number;\r\n}\r\n\r\nclass RateLimiter {\r\n private buckets = new Map<string, RateLimitEntry>();\r\n private readonly maxAttempts: number;\r\n private readonly windowMs: number;\r\n\r\n constructor(maxAttempts: number, windowMs: number) {\r\n this.maxAttempts = maxAttempts;\r\n this.windowMs = windowMs;\r\n }\r\n\r\n /**\r\n * Check if an action is allowed for the given key.\r\n * Increments the counter and returns whether the action should proceed.\r\n */\r\n check(key: string): { allowed: boolean; remaining: number; retryAfterMs: number } {\r\n const now = Date.now();\r\n const entry = this.buckets.get(key);\r\n\r\n if (!entry || now >= entry.resetAt) {\r\n this.buckets.set(key, { count: 1, resetAt: now + this.windowMs });\r\n return { allowed: true, remaining: this.maxAttempts - 1, retryAfterMs: 0 };\r\n }\r\n\r\n entry.count++;\r\n\r\n if (entry.count > this.maxAttempts) {\r\n return {\r\n allowed: false,\r\n remaining: 0,\r\n retryAfterMs: entry.resetAt - now,\r\n };\r\n }\r\n\r\n return {\r\n allowed: true,\r\n remaining: this.maxAttempts - entry.count,\r\n retryAfterMs: 0,\r\n };\r\n }\r\n\r\n /** Periodically remove expired entries to prevent unbounded growth. */\r\n cleanup(): void {\r\n const now = Date.now();\r\n for (const [key, entry] of this.buckets) {\r\n if (now >= entry.resetAt) this.buckets.delete(key);\r\n }\r\n }\r\n}\r\n\r\nconst authRateLimiter = new RateLimiter(5, 15 * 60 * 1000);\r\nconst toolCallRateLimiter = new RateLimiter(60, 60 * 1000);\r\nconst destructiveActionRateLimiter = new RateLimiter(5, 60 * 1000);\r\n\r\nconst DESTRUCTIVE_TOOLS = new Set([\r\n 'ssh-execute',\r\n 'sftp-write',\r\n 'sftp-delete',\r\n 'server-reboot',\r\n 'server-restart-service',\r\n 'db-query',\r\n 'cron-add',\r\n 'cron-remove',\r\n 'cron-toggle',\r\n 'dns-create',\r\n 'dns-update',\r\n 'dns-delete',\r\n 'docker-action',\r\n 'env-store',\r\n]);\r\n\r\n// Cleanup expired rate limit entries every 5 minutes\r\nsetInterval(() => {\r\n authRateLimiter.cleanup();\r\n toolCallRateLimiter.cleanup();\r\n destructiveActionRateLimiter.cleanup();\r\n}, 5 * 60 * 1000).unref();\r\n\r\n// ---------------------------------------------------------------------------\r\n// Auth context\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface AuthContext {\r\n userId: string;\r\n allowedServerIds: string[] | null;\r\n}\r\n\r\nlet authContext: AuthContext | null = null;\r\n\r\nasync function validateApiKey(key: string): Promise<AuthContext | null> {\r\n if (!key.startsWith('dk_') || key.length !== 67) {\r\n console.error('Invalid API key format (expected dk_ + 64 hex chars)');\r\n return null;\r\n }\r\n\r\n const keyHash = createHash('sha256').update(key).digest('hex');\r\n\r\n // Rate limit failed auth attempts per key hash\r\n const rateCheck = authRateLimiter.check(keyHash);\r\n if (!rateCheck.allowed) {\r\n const retryMin = Math.ceil(rateCheck.retryAfterMs / 60_000);\r\n console.error(`Rate limited: too many failed auth attempts. Retry in ${retryMin} minute(s).`);\r\n return null;\r\n }\r\n\r\n const { data, error } = await supabase\r\n .from('dashboard_mcp_api_key')\r\n .select('id, created_by, allowed_server_ids, is_active, expires_at')\r\n .eq('api_key_hash', keyHash)\r\n .eq('is_active', true)\r\n .single();\r\n\r\n if (error || !data) {\r\n console.error(`API key not found or inactive (${rateCheck.remaining} attempts remaining)`);\r\n return null;\r\n }\r\n\r\n if (data.expires_at && new Date(data.expires_at) < new Date()) {\r\n console.error(`API key has expired (${rateCheck.remaining} attempts remaining)`);\r\n return null;\r\n }\r\n\r\n await supabase\r\n .from('dashboard_mcp_api_key')\r\n .update({ last_used_at: new Date().toISOString() })\r\n .eq('id', data.id);\r\n\r\n console.error(`Authenticated as user ${data.created_by}`);\r\n\r\n return {\r\n userId: data.created_by,\r\n allowedServerIds: data.allowed_server_ids,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Server access helper\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction assertServerAccess(serverId: string): void {\r\n if (!authContext) throw new Error('Not authenticated');\r\n if (authContext.allowedServerIds === null) return;\r\n if (!authContext.allowedServerIds.includes(serverId)) {\r\n throw new Error(`Access denied: you do not have permission for server ${serverId}`);\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Release profile resolution helper\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Resolve a release profile name to its stage IDs.\r\n * Returns { stageIds, profileId } or throws with available profile names.\r\n */\r\nasync function resolveReleaseProfileStageIds(\r\n profileName: string,\r\n): Promise<{ stageIds: string[]; profileId: string }> {\r\n const { data: profile, error } = await supabase\r\n .from('release_profile')\r\n .select('id, name')\r\n .ilike('name', profileName)\r\n .maybeSingle();\r\n\r\n if (error) throw new Error(`Failed to look up release profile: ${error.message}`);\r\n\r\n if (!profile) {\r\n const { data: all } = await supabase\r\n .from('release_profile')\r\n .select('name')\r\n .order('name');\r\n const names = (all || []).map((p) => p.name).join(', ');\r\n throw new Error(\r\n `Release profile \"${profileName}\" not found. Available profiles: ${names || '(none)'}`,\r\n );\r\n }\r\n\r\n const { data: stages, error: stageErr } = await supabase\r\n .from('release_profile_stage')\r\n .select('id')\r\n .eq('release_profile_id', profile.id);\r\n\r\n if (stageErr) throw new Error(`Failed to look up stages: ${stageErr.message}`);\r\n if (!stages || stages.length === 0) {\r\n throw new Error(`Release profile \"${profile.name}\" has no stages configured`);\r\n }\r\n\r\n return { stageIds: stages.map((s) => s.id), profileId: profile.id };\r\n}\r\n\r\n/**\r\n * Look up release profile names for a set of stage IDs.\r\n * Returns a map of stageId -> profileName.\r\n */\r\nasync function getProfileNamesForStageIds(\r\n stageIds: string[],\r\n): Promise<Record<string, string>> {\r\n if (stageIds.length === 0) return {};\r\n\r\n const { data: stages } = await supabase\r\n .from('release_profile_stage')\r\n .select('id, release_profile_id')\r\n .in('id', stageIds);\r\n\r\n if (!stages || stages.length === 0) return {};\r\n\r\n const profileIds = [...new Set(stages.map((s) => s.release_profile_id))];\r\n const { data: profiles } = await supabase\r\n .from('release_profile')\r\n .select('id, name')\r\n .in('id', profileIds);\r\n\r\n if (!profiles) return {};\r\n\r\n const profileMap: Record<string, string> = {};\r\n for (const p of profiles) profileMap[p.id] = p.name;\r\n\r\n const result: Record<string, string> = {};\r\n for (const s of stages) {\r\n result[s.id] = profileMap[s.release_profile_id] || 'unknown';\r\n }\r\n return result;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Encryption helpers (AES-256-GCM, compatible with dashboard encryption.ts)\r\n// ---------------------------------------------------------------------------\r\n\r\nconst ENC_ALGORITHM = 'aes-256-gcm';\r\nconst ENC_IV_LENGTH = 16;\r\nconst ENC_TAG_LENGTH = 16;\r\n\r\nfunction getEncryptionKey(): Buffer {\r\n if (!encryptionKey) throw new Error('ENCRYPTION_KEY is required for env operations');\r\n const buf = Buffer.from(encryptionKey, 'hex');\r\n if (buf.length !== 32) throw new Error('ENCRYPTION_KEY must be a 64-character hex string');\r\n return buf;\r\n}\r\n\r\nfunction encrypt(text: string): string {\r\n const key = getEncryptionKey();\r\n const iv = randomBytes(ENC_IV_LENGTH);\r\n const cipher = createCipheriv(ENC_ALGORITHM, new Uint8Array(key), new Uint8Array(iv));\r\n let encrypted = cipher.update(text, 'utf8', 'hex');\r\n encrypted += cipher.final('hex');\r\n const authTag = cipher.getAuthTag();\r\n return Buffer.concat([\r\n new Uint8Array(iv),\r\n new Uint8Array(authTag),\r\n new Uint8Array(Buffer.from(encrypted, 'hex')),\r\n ]).toString('base64');\r\n}\r\n\r\nfunction decrypt(payload: string): string {\r\n const key = getEncryptionKey();\r\n const buf = Buffer.from(payload, 'base64');\r\n const iv = buf.subarray(0, ENC_IV_LENGTH);\r\n const authTag = buf.subarray(ENC_IV_LENGTH, ENC_IV_LENGTH + ENC_TAG_LENGTH);\r\n const encrypted = buf.subarray(ENC_IV_LENGTH + ENC_TAG_LENGTH);\r\n const decipher = createDecipheriv(ENC_ALGORITHM, new Uint8Array(key), new Uint8Array(iv));\r\n decipher.setAuthTag(new Uint8Array(authTag));\r\n let decrypted = decipher.update(encrypted.toString('hex'), 'hex', 'utf8');\r\n decrypted += decipher.final('utf8');\r\n return decrypted;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Vercel env sync helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nconst VERCEL_API = 'https://api.vercel.com';\r\n\r\n/**\r\n * Parse a .env content string into key-value pairs.\r\n * Lines starting with # and empty lines are skipped.\r\n */\r\nfunction parseEnvContent(content: string): Record<string, string> {\r\n const result: Record<string, string> = {};\r\n for (const line of content.split('\\n')) {\r\n const trimmed = line.trim();\r\n if (!trimmed || trimmed.startsWith('#')) continue;\r\n const eqIdx = trimmed.indexOf('=');\r\n if (eqIdx === -1) continue;\r\n const key = trimmed.slice(0, eqIdx).trim();\r\n let value = trimmed.slice(eqIdx + 1).trim();\r\n if (\r\n (value.startsWith('\"') && value.endsWith('\"')) ||\r\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\r\n ) {\r\n value = value.slice(1, -1);\r\n }\r\n if (key) result[key] = value;\r\n }\r\n return result;\r\n}\r\n\r\ninterface VercelEnvVar {\r\n key: string;\r\n value: string;\r\n type: 'encrypted';\r\n target?: ('production' | 'preview' | 'development')[];\r\n customEnvironmentIds?: string[];\r\n}\r\n\r\ninterface StageApp {\r\n path: string;\r\n label: string;\r\n deployMethod: string;\r\n enabled: boolean;\r\n vercelProjectId?: string | null;\r\n vercelCustomEnvId?: string | null;\r\n}\r\n\r\n/**\r\n * Map stage type to Vercel target environments or custom environment ID.\r\n */\r\nfunction stageToVercelTargets(\r\n stageType: 'dev' | 'staging' | 'prod',\r\n customEnvId?: string | null,\r\n): { target?: ('production' | 'preview' | 'development')[]; customEnvironmentIds?: string[] } {\r\n if (stageType === 'prod') return { target: ['production'] };\r\n if (customEnvId) return { customEnvironmentIds: [customEnvId] };\r\n return { target: ['preview'] };\r\n}\r\n\r\n/**\r\n * Push env vars to a Vercel project using upsert.\r\n */\r\nasync function syncEnvVarsToVercel(\r\n token: string,\r\n projectId: string,\r\n envVars: VercelEnvVar[],\r\n): Promise<{ created: number; error: string | null }> {\r\n if (envVars.length === 0) return { created: 0, error: null };\r\n\r\n const res = await fetch(\r\n `${VERCEL_API}/v10/projects/${encodeURIComponent(projectId)}/env?upsert=true`,\r\n {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(envVars),\r\n },\r\n );\r\n\r\n if (!res.ok) {\r\n const body = await res.text().catch(() => '');\r\n return { created: 0, error: `Vercel API ${res.status}: ${body}` };\r\n }\r\n\r\n const data = await res.json().catch(() => ({}));\r\n return { created: (data as any)?.created?.length ?? envVars.length, error: null };\r\n}\r\n\r\n/**\r\n * After an env_config upsert, attempt to sync env vars to Vercel for the\r\n * linked stage. Resolves the stage via `release_profile_stage_id` on the\r\n * record or by looking up siblings with the same `app_name`.\r\n *\r\n * Returns a status string for inclusion in the MCP response.\r\n */\r\nasync function attemptVercelSync(appName: string, environment: string): Promise<string> {\r\n try {\r\n // 1. Find the stage linked to this app_name\r\n const { data: direct } = await supabase\r\n .from('env_config')\r\n .select('release_profile_stage_id')\r\n .eq('app_name', appName)\r\n .not('release_profile_stage_id', 'is', null)\r\n .limit(1)\r\n .single();\r\n\r\n const stageId = direct?.release_profile_stage_id;\r\n if (!stageId) return 'Vercel sync skipped: no stage link found';\r\n\r\n // 2. Get Vercel token\r\n const { data: settings } = await supabase\r\n .from('app_setting')\r\n .select('vercel_token_encrypted')\r\n .maybeSingle();\r\n\r\n if (!settings?.vercel_token_encrypted) return 'Vercel sync skipped: no Vercel token configured';\r\n\r\n let token: string;\r\n try {\r\n token = decrypt(settings.vercel_token_encrypted);\r\n } catch {\r\n return 'Vercel sync failed: could not decrypt Vercel token';\r\n }\r\n\r\n // 3. Fetch stage + stage_apps\r\n const { data: stage } = await supabase\r\n .from('release_profile_stage')\r\n .select('id, stage, stage_apps')\r\n .eq('id', stageId)\r\n .single();\r\n\r\n if (!stage) return 'Vercel sync skipped: stage not found';\r\n\r\n const stageType = stage.stage as 'dev' | 'staging' | 'prod';\r\n const stageApps: StageApp[] = (stage.stage_apps as StageApp[]) || [];\r\n const vercelApps = stageApps.filter(\r\n (a) => a.deployMethod === 'vercel' && a.enabled && a.vercelProjectId,\r\n );\r\n\r\n if (vercelApps.length === 0) return 'Vercel sync skipped: no Vercel apps in stage';\r\n\r\n // 4. Fetch all env_configs for the stage\r\n const { data: envConfigs } = await supabase\r\n .from('env_config')\r\n .select('*')\r\n .eq('release_profile_stage_id', stageId);\r\n\r\n if (!envConfigs || envConfigs.length === 0) return 'Vercel sync skipped: no env configs for stage';\r\n\r\n const variantMap: Record<string, string> = {\r\n dev: 'development',\r\n staging: 'staging',\r\n prod: 'production',\r\n };\r\n const deployedVariant = variantMap[stageType] ?? stageType;\r\n\r\n // 5. Sync each Vercel app\r\n const syncResults: string[] = [];\r\n for (const app of vercelApps) {\r\n const name = app.path.replace('apps/', '');\r\n const config = envConfigs.find(\r\n (c: any) => c.app_name === name && c.variant === deployedVariant,\r\n );\r\n\r\n if (!config) {\r\n syncResults.push(`${app.label}: skipped (no config for variant \"${deployedVariant}\")`);\r\n continue;\r\n }\r\n\r\n let envContent: string;\r\n try {\r\n envContent = decrypt((config as any).env_data_encrypted);\r\n } catch {\r\n syncResults.push(`${app.label}: decrypt failed`);\r\n continue;\r\n }\r\n\r\n const pairs = parseEnvContent(envContent);\r\n const keys = Object.keys(pairs);\r\n if (keys.length === 0) {\r\n syncResults.push(`${app.label}: empty config`);\r\n continue;\r\n }\r\n\r\n const targeting = stageToVercelTargets(stageType, app.vercelCustomEnvId);\r\n const envVars: VercelEnvVar[] = keys.map((key) => ({\r\n key,\r\n value: pairs[key]!,\r\n type: 'encrypted' as const,\r\n ...targeting,\r\n }));\r\n\r\n const { created, error } = await syncEnvVarsToVercel(token, app.vercelProjectId!, envVars);\r\n if (error) {\r\n syncResults.push(`${app.label}: FAILED - ${error}`);\r\n } else {\r\n syncResults.push(`${app.label}: ${created} vars synced`);\r\n }\r\n }\r\n\r\n return `Vercel sync: ${syncResults.join('; ')}`;\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return `Vercel sync error: ${msg}`;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// SSH helpers\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface SshConnectionOptions {\r\n hostname: string;\r\n port: number;\r\n username: string;\r\n password?: string;\r\n privateKey?: string;\r\n passphrase?: string;\r\n timeout?: number;\r\n}\r\n\r\ninterface SshResult {\r\n stdout: string;\r\n stderr: string;\r\n exitCode: number;\r\n}\r\n\r\nasync function getServerConnection(serverId: string): Promise<SshConnectionOptions> {\r\n assertServerAccess(serverId);\r\n\r\n const { data, error } = await supabase\r\n .from('ssh_server')\r\n .select('hostname, port, username, password_encrypted, ssh_key_encrypted, ssh_key_passphrase_encrypted')\r\n .eq('id', serverId)\r\n .single();\r\n\r\n if (error || !data) throw new Error(`Server not found: ${serverId}`);\r\n if (!encryptionKey) throw new Error('ENCRYPTION_KEY required to decrypt server credentials');\r\n\r\n return {\r\n hostname: data.hostname,\r\n port: data.port || 22,\r\n username: data.username,\r\n password: data.password_encrypted ? decrypt(data.password_encrypted) : undefined,\r\n privateKey: data.ssh_key_encrypted ? decrypt(data.ssh_key_encrypted) : undefined,\r\n passphrase: data.ssh_key_passphrase_encrypted ? decrypt(data.ssh_key_passphrase_encrypted) : undefined,\r\n };\r\n}\r\n\r\nasync function sshExec(opts: SshConnectionOptions, command: string): Promise<SshResult> {\r\n return new Promise((resolve) => {\r\n const ssh = new SshClient();\r\n let stdout = '';\r\n let stderr = '';\r\n let done = false;\r\n const timeout = opts.timeout || 60_000;\r\n\r\n const timer = setTimeout(() => {\r\n if (!done) { done = true; ssh.end(); resolve({ stdout, stderr, exitCode: -1 }); }\r\n }, timeout);\r\n\r\n ssh.on('ready', () => {\r\n ssh.exec(command, (err, stream) => {\r\n if (err) {\r\n if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve({ stdout, stderr, exitCode: -1 }); }\r\n return;\r\n }\r\n stream.on('data', (d: Buffer) => { stdout += d.toString(); });\r\n stream.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });\r\n stream.on('close', (code: number | null) => {\r\n if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve({ stdout, stderr, exitCode: code ?? 0 }); }\r\n });\r\n });\r\n });\r\n\r\n ssh.on('error', (err) => {\r\n if (!done) { done = true; clearTimeout(timer); resolve({ stdout, stderr: err.message, exitCode: -1 }); }\r\n });\r\n\r\n ssh.connect({\r\n host: opts.hostname, port: opts.port, username: opts.username,\r\n password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase,\r\n readyTimeout: timeout,\r\n });\r\n });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// SFTP helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction sanitizePath(path: string): string {\r\n let normalized = path.replace(/\\\\/g, '/').replace(/\\0/g, '');\r\n const parts = normalized.split('/');\r\n const resolved: string[] = [];\r\n for (const part of parts) {\r\n if (part === '..') { if (resolved.length > 0 && resolved[resolved.length - 1] !== '') resolved.pop(); }\r\n else if (part !== '.' && part !== '') resolved.push(part);\r\n }\r\n return '/' + resolved.join('/');\r\n}\r\n\r\nconst PROTECTED_PATHS = ['/etc/', '/boot/', '/usr/', '/bin/', '/sbin/', '/lib/', '/lib64/'];\r\n\r\nfunction assertWritablePath(path: string): void {\r\n const safe = sanitizePath(path);\r\n for (const p of PROTECTED_PATHS) {\r\n if (safe === p.slice(0, -1) || safe.startsWith(p)) {\r\n throw new Error(`Write access denied to protected path: ${safe}`);\r\n }\r\n }\r\n}\r\n\r\nasync function sftpReaddir(opts: SshConnectionOptions, dirPath: string): Promise<string> {\r\n const safe = sanitizePath(dirPath);\r\n return new Promise((resolve) => {\r\n const ssh = new SshClient();\r\n let done = false;\r\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 30_000);\r\n\r\n ssh.on('ready', () => {\r\n ssh.sftp((err, sftp) => {\r\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\r\n sftp.readdir(safe, (err, list) => {\r\n done = true; clearTimeout(timer);\r\n if (err) { ssh.end(); resolve(`Error: ${err.message}`); return; }\r\n const entries = list.map(item => {\r\n const mode = item.attrs.mode || 0;\r\n const isDir = (mode & 0o170000) === 0o040000;\r\n const size = item.attrs.size || 0;\r\n const mtime = item.attrs.mtime ? new Date(item.attrs.mtime * 1000).toISOString() : '';\r\n return `${isDir ? 'd' : '-'} ${String(size).padStart(10)} ${mtime} ${item.filename}`;\r\n });\r\n ssh.end();\r\n resolve(entries.join('\\n'));\r\n });\r\n });\r\n });\r\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\r\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 30_000 });\r\n });\r\n}\r\n\r\nasync function sftpRead(opts: SshConnectionOptions, filePath: string): Promise<string> {\r\n const safe = sanitizePath(filePath);\r\n return new Promise((resolve) => {\r\n const ssh = new SshClient();\r\n let done = false;\r\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 60_000);\r\n\r\n ssh.on('ready', () => {\r\n ssh.sftp((err, sftp) => {\r\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\r\n sftp.stat(safe, (err, stats) => {\r\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\r\n if ((stats.size || 0) > 1_048_576) {\r\n if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: file too large (${stats.size} bytes, max 1MB)`); }\r\n return;\r\n }\r\n const chunks: Buffer[] = [];\r\n const rs = sftp.createReadStream(safe);\r\n rs.on('data', (c: Buffer) => chunks.push(c));\r\n rs.on('end', () => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(Buffer.concat(chunks.map(c => new Uint8Array(c))).toString('utf-8')); } });\r\n rs.on('error', (e: Error) => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${e.message}`); } });\r\n });\r\n });\r\n });\r\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\r\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 60_000 });\r\n });\r\n}\r\n\r\nasync function sftpWrite(opts: SshConnectionOptions, filePath: string, content: string): Promise<string> {\r\n const safe = sanitizePath(filePath);\r\n assertWritablePath(safe);\r\n return new Promise((resolve) => {\r\n const ssh = new SshClient();\r\n let done = false;\r\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 60_000);\r\n\r\n ssh.on('ready', () => {\r\n ssh.sftp((err, sftp) => {\r\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\r\n const ws = sftp.createWriteStream(safe, { mode: 0o644 });\r\n ws.on('close', () => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Written ${content.length} bytes to ${safe}`); } });\r\n ws.on('error', (e: Error) => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${e.message}`); } });\r\n ws.end(Buffer.from(content, 'utf-8'));\r\n });\r\n });\r\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\r\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 60_000 });\r\n });\r\n}\r\n\r\nasync function sftpDelete(opts: SshConnectionOptions, filePath: string): Promise<string> {\r\n const safe = sanitizePath(filePath);\r\n assertWritablePath(safe);\r\n return new Promise((resolve) => {\r\n const ssh = new SshClient();\r\n let done = false;\r\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 30_000);\r\n\r\n ssh.on('ready', () => {\r\n ssh.sftp((err, sftp) => {\r\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\r\n sftp.unlink(safe, (err) => {\r\n if (err) {\r\n sftp.rmdir(safe, (err2) => {\r\n done = true; clearTimeout(timer); ssh.end();\r\n resolve(err2 ? `Error: ${err.message}` : `Deleted directory ${safe}`);\r\n });\r\n } else {\r\n done = true; clearTimeout(timer); ssh.end();\r\n resolve(`Deleted file ${safe}`);\r\n }\r\n });\r\n });\r\n });\r\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\r\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 30_000 });\r\n });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Safety: dangerous command blocklist\r\n// ---------------------------------------------------------------------------\r\n\r\nconst BLOCKED_COMMANDS = [\r\n 'rm -rf /', 'rm -fr /', 'mkfs', 'dd if=', ':(){ :|:& };:',\r\n 'shutdown', 'halt', 'init 0', 'init 6',\r\n '> /dev/sda', 'mv /* /dev/null', 'chmod -R 000 /',\r\n];\r\n\r\nfunction assertSafeCommand(command: string): void {\r\n const lower = command.toLowerCase().trim();\r\n for (const blocked of BLOCKED_COMMANDS) {\r\n if (lower.includes(blocked)) {\r\n throw new Error(`Blocked dangerous command pattern: \"${blocked}\"`);\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Log path validation\r\n// ---------------------------------------------------------------------------\r\n\r\nconst ALLOWED_LOG_PREFIXES = ['/var/log/', '/usr/local/lsws/logs/', '/var/www/'];\r\n\r\nfunction assertAllowedLogPath(filePath: string): void {\r\n const safe = sanitizePath(filePath);\r\n if (!safe.endsWith('.log')) {\r\n throw new Error('Only .log files can be read with log-read');\r\n }\r\n if (!ALLOWED_LOG_PREFIXES.some(prefix => safe.startsWith(prefix))) {\r\n throw new Error(`Path not allowed. Must be under: ${ALLOWED_LOG_PREFIXES.join(', ')}`);\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// MySQL / Database helpers\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface DbCredentials {\r\n host: string;\r\n user: string;\r\n password: string;\r\n database: string;\r\n port: number;\r\n sitePath: string;\r\n appType: string;\r\n}\r\n\r\n/**\r\n * Discovers web applications under /var/www and extracts DB credentials\r\n * from their config files (WordPress, PrestaShop, Laravel, custom .env).\r\n */\r\nasync function discoverSiteDatabases(conn: SshConnectionOptions): Promise<DbCredentials[]> {\r\n const script = `\r\ncheck_dir() {\r\n local base=\"$1\" root=\"$2\"\r\n # WordPress\r\n if [ -f \"$root/wp-config.php\" ]; then\r\n echo \"WP|$base|$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_NAME'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_USER'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_PASSWORD'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_HOST'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)\"\r\n return\r\n fi\r\n # PrestaShop 1.7+\r\n if [ -f \"$root/app/config/parameters.php\" ]; then\r\n echo \"PS|$base|$(grep -oP \"'database_name'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)|$(grep -oP \"'database_user'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)|$(grep -oP \"'database_password'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)|$(grep -oP \"'database_host'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)\"\r\n return\r\n fi\r\n # PrestaShop 1.6\r\n if [ -f \"$root/config/settings.inc.php\" ]; then\r\n echo \"PS|$base|$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_NAME_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_USER_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_PASSWD_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)|$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_SERVER_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)\"\r\n return\r\n fi\r\n # Laravel / generic .env\r\n if [ -f \"$root/.env\" ]; then\r\n DB_CONN=$(grep -oP '^DB_CONNECTION=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n if [ -n \"$DB_CONN\" ] && [ \"$DB_CONN\" != \"sqlite\" ]; then\r\n echo \"ENV|$base|$(grep -oP '^DB_DATABASE=\\\\K.*' \"$root/.env\" 2>/dev/null)|$(grep -oP '^DB_USERNAME=\\\\K.*' \"$root/.env\" 2>/dev/null)|$(grep -oP '^DB_PASSWORD=\\\\K.*' \"$root/.env\" 2>/dev/null)|$(grep -oP '^DB_HOST=\\\\K.*' \"$root/.env\" 2>/dev/null)|$(grep -oP '^DB_PORT=\\\\K.*' \"$root/.env\" 2>/dev/null)\"\r\n return\r\n fi\r\n fi\r\n}\r\nfor dir in /var/www/*/; do\r\n [ -d \"$dir\" ] || continue\r\n check_dir \"$dir\" \"$dir\"\r\n # Also check common subdirectories: html, public_html, public, httpdocs\r\n for sub in html public_html public httpdocs; do\r\n [ -d \"$dir$sub\" ] && check_dir \"$dir\" \"$dir$sub\"\r\n done\r\ndone\r\n`.trim();\r\n\r\n const result = await sshExec(conn, script);\r\n const sites: DbCredentials[] = [];\r\n\r\n for (const line of result.stdout.split('\\n')) {\r\n if (!line.trim()) continue;\r\n const parts = line.split('|');\r\n if (parts.length < 6) continue;\r\n\r\n const [type, sitePath, database, user, password, host, port] = parts;\r\n if (!database || !user || !type || !sitePath) continue;\r\n\r\n const appTypes: Record<string, string> = { WP: 'WordPress', PS: 'PrestaShop', ENV: 'Laravel/.env' };\r\n\r\n sites.push({\r\n appType: appTypes[type] || type,\r\n sitePath: sitePath.replace(/\\/$/, ''),\r\n database,\r\n user,\r\n password: password || '',\r\n host: host || 'localhost',\r\n port: parseInt(port || '3306', 10),\r\n });\r\n }\r\n\r\n return sites;\r\n}\r\n\r\nfunction escapeMysqlShell(value: string): string {\r\n return value.replace(/'/g, \"'\\\\''\");\r\n}\r\n\r\nconst BLOCKED_SQL_PATTERNS = [\r\n /\\bDROP\\s+DATABASE\\b/i,\r\n /\\bDROP\\s+TABLE\\b/i,\r\n /\\bDROP\\s+INDEX\\b/i,\r\n /\\bTRUNCATE\\b/i,\r\n /\\bALTER\\s+TABLE\\s+\\w+\\s+DROP\\b/i,\r\n /\\bDELETE\\s+FROM\\s+\\w+\\s*$/i,\r\n];\r\n\r\nfunction assertSafeSql(query: string): void {\r\n const trimmed = query.trim();\r\n for (const pattern of BLOCKED_SQL_PATTERNS) {\r\n if (pattern.test(trimmed)) {\r\n throw new Error(`Blocked destructive SQL pattern: ${pattern.source}`);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Builds a shell snippet that discovers DB credentials for a site path\r\n * and then executes a MySQL query, all in a single SSH session.\r\n */\r\nfunction buildSiteMysqlCommand(sitePath: string, query: string): string {\r\n const safePath = escapeMysqlShell(sitePath.replace(/\\/$/, ''));\r\n const safeQuery = escapeMysqlShell(query);\r\n\r\n return `\r\nSITE='${safePath}'\r\nDB_USER=\"\" DB_PASS=\"\" DB_NAME=\"\" DB_HOST=\"localhost\" DB_PORT=\"3306\"\r\nfor root in \"$SITE\" \"$SITE/html\" \"$SITE/public_html\" \"$SITE/public\" \"$SITE/httpdocs\"; do\r\n [ -d \"$root\" ] || continue\r\n if [ -f \"$root/wp-config.php\" ]; then\r\n DB_NAME=$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_NAME'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)\r\n DB_USER=$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_USER'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)\r\n DB_PASS=$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_PASSWORD'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)\r\n DB_HOST=$(grep -oP \"define\\\\s*\\\\(\\\\s*'DB_HOST'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/wp-config.php\" 2>/dev/null)\r\n break\r\n elif [ -f \"$root/app/config/parameters.php\" ]; then\r\n DB_NAME=$(grep -oP \"'database_name'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)\r\n DB_USER=$(grep -oP \"'database_user'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)\r\n DB_PASS=$(grep -oP \"'database_password'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)\r\n DB_HOST=$(grep -oP \"'database_host'\\\\s*=>\\\\s*'\\\\K[^']+\" \"$root/app/config/parameters.php\" 2>/dev/null)\r\n break\r\n elif [ -f \"$root/config/settings.inc.php\" ]; then\r\n DB_NAME=$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_NAME_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)\r\n DB_USER=$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_USER_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)\r\n DB_PASS=$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_PASSWD_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)\r\n DB_HOST=$(grep -oP \"define\\\\s*\\\\(\\\\s*'_DB_SERVER_'\\\\s*,\\\\s*'\\\\K[^']+\" \"$root/config/settings.inc.php\" 2>/dev/null)\r\n break\r\n elif [ -f \"$root/.env\" ]; then\r\n DB_CONN=$(grep -oP '^DB_CONNECTION=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n if [ -n \"$DB_CONN\" ] && [ \"$DB_CONN\" != \"sqlite\" ]; then\r\n DB_NAME=$(grep -oP '^DB_DATABASE=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n DB_USER=$(grep -oP '^DB_USERNAME=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n DB_PASS=$(grep -oP '^DB_PASSWORD=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n DB_HOST=$(grep -oP '^DB_HOST=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n DB_PORT=$(grep -oP '^DB_PORT=\\\\K.*' \"$root/.env\" 2>/dev/null)\r\n break\r\n fi\r\n fi\r\ndone\r\n[ -z \"$DB_NAME\" ] || [ -z \"$DB_USER\" ] && echo \"ERROR: No database config found at $SITE\" && exit 1\r\nDB_HOST=\\${DB_HOST:-localhost}\r\nDB_PORT=\\${DB_PORT:-3306}\r\nmysql --user=\"$DB_USER\" --password=\"$DB_PASS\" --host=\"$DB_HOST\" --port=\"$DB_PORT\" -t -e '${safeQuery}' \"$DB_NAME\" 2>&1 | grep -v \"\\\\[Warning\\\\].*password\"\r\n`.trim();\r\n}\r\n\r\n/**\r\n * Execute a MySQL query for a site in a single SSH session.\r\n * Discovers credentials and runs the query in one command.\r\n */\r\nasync function execSiteMysql(conn: SshConnectionOptions, sitePath: string, query: string): Promise<string> {\r\n const cmd = buildSiteMysqlCommand(sitePath, query);\r\n const result = await sshExec(conn, cmd);\r\n const output = (result.stdout || '').trim();\r\n if (output.startsWith('ERROR: No database config found')) {\r\n throw new Error(output);\r\n }\r\n if (result.exitCode !== 0 && !output) {\r\n throw new Error(result.stderr || 'MySQL command failed');\r\n }\r\n return output;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// mijn.host API helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nconst MIJNHOST_BASE_URL = 'https://mijn.host/api/v2';\r\n\r\ninterface MijnHostApiResponse<T = unknown> {\r\n status: number;\r\n status_description: string;\r\n data: T;\r\n}\r\n\r\nfunction requireMijnhostApiKey(): string {\r\n if (!mijnhostApiKey) {\r\n throw new Error('mijn.host API key not configured. Use --mijnhost-api-key=xxx or set MIJNHOST_API_KEY');\r\n }\r\n return mijnhostApiKey;\r\n}\r\n\r\nasync function mijnhostFetch<T>(path: string, options: RequestInit = {}): Promise<MijnHostApiResponse<T>> {\r\n const key = requireMijnhostApiKey();\r\n\r\n const res = await fetch(`${MIJNHOST_BASE_URL}${path}`, {\r\n ...options,\r\n headers: {\r\n 'API-Key': key,\r\n 'Accept': 'application/json',\r\n 'Content-Type': 'application/json',\r\n 'User-Agent': 'mg-dashboard-mcp/1.7.0',\r\n ...((options.headers as Record<string, string>) || {}),\r\n },\r\n });\r\n\r\n const json: unknown = await res.json();\r\n const body = json as MijnHostApiResponse<T>;\r\n\r\n if (!res.ok) {\r\n throw new Error(body?.status_description || `mijn.host API error: ${res.status}`);\r\n }\r\n\r\n return body;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Tool definitions\r\n// ---------------------------------------------------------------------------\r\n\r\nconst TOOLS = [\r\n {\r\n name: 'list-servers',\r\n description: 'List all SSH servers you have access to. Returns id, name, hostname, and tags for each server.',\r\n inputSchema: { type: 'object' as const, properties: {}, required: [] },\r\n },\r\n {\r\n name: 'server-status',\r\n description: 'Get server status including uptime, disk usage, memory, and load average.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'ssh-execute',\r\n description: 'Execute a shell command on a remote server via SSH. Some dangerous commands are blocked for safety.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n command: { type: 'string', description: 'Shell command to execute' },\r\n timeout: { type: 'number', description: 'Timeout in milliseconds (default: 60000)' },\r\n },\r\n required: ['serverId', 'command'],\r\n },\r\n },\r\n {\r\n name: 'server-reboot',\r\n description: 'Reboot a remote server. This will cause downtime. The server will be unavailable until it restarts.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server to reboot' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'server-restart-service',\r\n description: 'Restart a systemd service on a remote server using systemctl restart.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n serviceName: { type: 'string', description: 'Name of the systemd service (e.g. nginx, docker, lsws)' },\r\n },\r\n required: ['serverId', 'serviceName'],\r\n },\r\n },\r\n {\r\n name: 'sftp-list',\r\n description: 'List files and directories at a given path on a remote server via SFTP.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n path: { type: 'string', description: 'Directory path to list (default: /)' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'sftp-read',\r\n description: 'Read the contents of a text file on a remote server via SFTP (max 1MB).',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n path: { type: 'string', description: 'File path to read' },\r\n },\r\n required: ['serverId', 'path'],\r\n },\r\n },\r\n {\r\n name: 'sftp-write',\r\n description: 'Write content to a file on a remote server via SFTP. Protected system paths are blocked.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n path: { type: 'string', description: 'File path to write' },\r\n content: { type: 'string', description: 'File content to write' },\r\n },\r\n required: ['serverId', 'path', 'content'],\r\n },\r\n },\r\n {\r\n name: 'sftp-delete',\r\n description: 'Delete a file or empty directory on a remote server via SFTP. Protected system paths are blocked.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n path: { type: 'string', description: 'File or directory path to delete' },\r\n },\r\n required: ['serverId', 'path'],\r\n },\r\n },\r\n {\r\n name: 'docker-list',\r\n description: 'List all Docker containers on a remote server (running and stopped).',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'docker-action',\r\n description: 'Perform an action on a Docker container: start, stop, restart, or remove.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n containerName: { type: 'string', description: 'Container name or ID' },\r\n action: { type: 'string', enum: ['start', 'stop', 'restart', 'remove'], description: 'Action to perform' },\r\n },\r\n required: ['serverId', 'containerName', 'action'],\r\n },\r\n },\r\n {\r\n name: 'docker-logs',\r\n description: 'Get recent logs from a Docker container.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n containerName: { type: 'string', description: 'Container name or ID' },\r\n lines: { type: 'number', description: 'Number of log lines to retrieve (default: 100)' },\r\n },\r\n required: ['serverId', 'containerName'],\r\n },\r\n },\r\n {\r\n name: 'db-discover',\r\n description: 'Scan /var/www on a server for web applications (WordPress, PrestaShop, Laravel, .env) and list their database credentials. Use this first to find available sites before running other db-* tools.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'db-tables',\r\n description: 'List all tables in a site database with row counts and sizes. Credentials are auto-discovered from the site config files (wp-config.php, parameters.php, .env).',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n sitePath: { type: 'string', description: 'Site root path (e.g. /var/www/example.com)' },\r\n },\r\n required: ['serverId', 'sitePath'],\r\n },\r\n },\r\n {\r\n name: 'db-describe',\r\n description: 'Show the structure of a database table (columns, types, keys, defaults). Credentials are auto-discovered from site config files.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n sitePath: { type: 'string', description: 'Site root path (e.g. /var/www/example.com)' },\r\n table: { type: 'string', description: 'Table name' },\r\n },\r\n required: ['serverId', 'sitePath', 'table'],\r\n },\r\n },\r\n {\r\n name: 'db-query',\r\n description: 'Execute a SQL query on a site database. Credentials are auto-discovered from site config files. Destructive operations (DROP, TRUNCATE) are blocked.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n sitePath: { type: 'string', description: 'Site root path (e.g. /var/www/example.com)' },\r\n query: { type: 'string', description: 'SQL query to execute' },\r\n },\r\n required: ['serverId', 'sitePath', 'query'],\r\n },\r\n },\r\n {\r\n name: 'env-list',\r\n description: 'List all stored environment configurations with their release profile names.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n releaseProfile: { type: 'string', description: 'Release profile name to filter by (usually matches the project folder name or git repo name, e.g. prefabaanbouw). Omit to list all.' },\r\n },\r\n },\r\n },\r\n {\r\n name: 'env-get',\r\n description: 'Retrieve the decrypted .env content for a specific app and environment.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n appName: { type: 'string', description: 'Application name (e.g. backoffice, api, web)' },\r\n environment: { type: 'string', description: 'Environment name (e.g. production, staging, development, local)' },\r\n releaseProfile: { type: 'string', description: 'Release profile name (usually matches the project folder name or git repo name, e.g. prefabaanbouw). Required when multiple profiles exist. Use env-list to discover available profiles.' },\r\n },\r\n required: ['appName', 'environment'],\r\n },\r\n },\r\n {\r\n name: 'env-store',\r\n description: 'Store or update an encrypted .env configuration for an app and environment.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n appName: { type: 'string', description: 'Application name (e.g. backoffice, api, web)' },\r\n environment: { type: 'string', description: 'Environment name (e.g. production, staging, development, local)' },\r\n content: { type: 'string', description: 'The .env file content to store' },\r\n description: { type: 'string', description: 'Optional description' },\r\n releaseProfile: { type: 'string', description: 'Release profile name (usually matches the project folder name or git repo name, e.g. prefabaanbouw). Required when multiple profiles exist. Use env-list to discover available profiles.' },\r\n },\r\n required: ['appName', 'environment', 'content'],\r\n },\r\n },\r\n {\r\n name: 'cache-purge',\r\n description: 'Purge ALL caches on a server in one operation: OPcache (kills lsphp), LiteSpeed cache, WordPress object cache (wp-cli or file-based), PrestaShop Smarty/app cache, Redis FLUSHALL, and Memcached flush. Returns a per-cache status report.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'log-list',\r\n description: 'Discover available log files on a server. Scans LiteSpeed logs, PHP error logs, syslog, and per-site application logs (WordPress debug.log, PrestaShop var/logs, Laravel storage/logs). Returns paths with file sizes and last modified dates.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'log-read',\r\n description: 'Read the last N lines from a specific log file on a server. Use log-list first to discover available files. Optionally filter lines with a grep pattern.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n path: { type: 'string', description: 'Absolute path to the log file (must end in .log)' },\r\n lines: { type: 'number', description: 'Number of lines to read (default: 100, max: 500)' },\r\n filter: { type: 'string', description: 'Optional grep pattern to filter lines before tailing' },\r\n },\r\n required: ['serverId', 'path'],\r\n },\r\n },\r\n // ----- Cron Jobs -----\r\n {\r\n name: 'cron-list',\r\n description: 'List all cron jobs on a server. Shows root crontab, system cron directories (/etc/cron.d/), and www-data crontab. Each entry shows the schedule, command, user, and source. Disabled (commented) entries are marked.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n user: { type: 'string', description: 'Specific user crontab to list (default: lists root + www-data + /etc/cron.d/)' },\r\n },\r\n required: ['serverId'],\r\n },\r\n },\r\n {\r\n name: 'cron-add',\r\n description: 'Add a new cron job to a user crontab. Provide a standard cron schedule expression and command. Examples: \"0 2 * * * /usr/bin/backup.sh\" (daily at 2am), \"*/5 * * * * curl http://example.com/cron.php\" (every 5 min).',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n schedule: { type: 'string', description: 'Cron schedule expression (e.g. \"0 2 * * *\" or \"@daily\")' },\r\n command: { type: 'string', description: 'Command to execute' },\r\n user: { type: 'string', description: 'User whose crontab to edit (default: root)' },\r\n comment: { type: 'string', description: 'Optional comment to add above the cron entry (for identification)' },\r\n },\r\n required: ['serverId', 'schedule', 'command'],\r\n },\r\n },\r\n {\r\n name: 'cron-remove',\r\n description: 'Remove a cron job from a user crontab by matching the command string (exact or partial match). Use cron-list first to see existing jobs.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n commandMatch: { type: 'string', description: 'Full or partial command string to match for removal' },\r\n user: { type: 'string', description: 'User whose crontab to edit (default: root)' },\r\n },\r\n required: ['serverId', 'commandMatch'],\r\n },\r\n },\r\n {\r\n name: 'cron-toggle',\r\n description: 'Enable or disable a cron job by commenting/uncommenting it. Matches by command string. Use cron-list to find the job first.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n serverId: { type: 'string', description: 'UUID of the SSH server' },\r\n commandMatch: { type: 'string', description: 'Full or partial command string to match' },\r\n enable: { type: 'boolean', description: 'true to enable (uncomment), false to disable (comment out)' },\r\n user: { type: 'string', description: 'User whose crontab to edit (default: root)' },\r\n },\r\n required: ['serverId', 'commandMatch', 'enable'],\r\n },\r\n },\r\n // ----- Domains (mijn.host) -----\r\n {\r\n name: 'domain-list',\r\n description: 'List all domains from the mijn.host account. Returns domain name, status, renewal date, and tags. Requires MIJNHOST_API_KEY.',\r\n inputSchema: { type: 'object' as const, properties: {}, required: [] },\r\n },\r\n {\r\n name: 'domain-get',\r\n description: 'Get detailed information about a specific domain: status, renewal date, lock state, managed DNS, DNSSEC, nameservers, contact handles, and messages.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n domain: { type: 'string', description: 'Domain name (e.g. example.com)' },\r\n },\r\n required: ['domain'],\r\n },\r\n },\r\n {\r\n name: 'dns-list',\r\n description: 'List all DNS records for a domain. Returns type (A, AAAA, CNAME, MX, TXT, etc.), name, value, and TTL for each record.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n domain: { type: 'string', description: 'Domain name (e.g. example.com)' },\r\n },\r\n required: ['domain'],\r\n },\r\n },\r\n {\r\n name: 'dns-create',\r\n description: 'Add a new DNS record to a domain. Uses PATCH to add without replacing existing records.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n domain: { type: 'string', description: 'Domain name (e.g. example.com)' },\r\n type: { type: 'string', description: 'Record type: A, AAAA, CNAME, MX, TXT, NS, SRV, CAA, or TLSA' },\r\n name: { type: 'string', description: 'Record name (e.g. @ or subdomain)' },\r\n value: { type: 'string', description: 'Record value (e.g. IP address, hostname)' },\r\n ttl: { type: 'number', description: 'TTL in seconds (min 60, default 3600)' },\r\n },\r\n required: ['domain', 'type', 'name', 'value'],\r\n },\r\n },\r\n {\r\n name: 'dns-update',\r\n description: 'Update an existing DNS record. Identifies the record by type+name+oldValue, then replaces it with new values via PATCH.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n domain: { type: 'string', description: 'Domain name (e.g. example.com)' },\r\n type: { type: 'string', description: 'Record type: A, AAAA, CNAME, MX, TXT, NS, SRV, CAA, or TLSA' },\r\n name: { type: 'string', description: 'Record name' },\r\n oldValue: { type: 'string', description: 'Current value of the record to update' },\r\n newValue: { type: 'string', description: 'New value for the record' },\r\n ttl: { type: 'number', description: 'New TTL in seconds (min 60)' },\r\n },\r\n required: ['domain', 'type', 'name', 'oldValue', 'newValue'],\r\n },\r\n },\r\n {\r\n name: 'dns-delete',\r\n description: 'Delete a DNS record by type, name, and value. Fetches all records, removes the matching one, then replaces the full set.',\r\n inputSchema: {\r\n type: 'object' as const,\r\n properties: {\r\n domain: { type: 'string', description: 'Domain name (e.g. example.com)' },\r\n type: { type: 'string', description: 'Record type to delete' },\r\n name: { type: 'string', description: 'Record name to delete' },\r\n value: { type: 'string', description: 'Record value to delete (must match exactly)' },\r\n },\r\n required: ['domain', 'type', 'name', 'value'],\r\n },\r\n },\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// MCP Server\r\n// ---------------------------------------------------------------------------\r\n\r\nconst server = new Server(\r\n { name: 'mg-dashboard-mcp', version: '1.7.0' },\r\n { capabilities: { tools: {} } },\r\n);\r\n\r\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));\r\n\r\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\r\n if (!authContext) {\r\n return { content: [{ type: 'text', text: 'Error: not authenticated' }] };\r\n }\r\n\r\n const { name, arguments: toolArgs } = request.params;\r\n const a = (toolArgs || {}) as Record<string, unknown>;\r\n\r\n // General tool call rate limiting (60/min per session)\r\n const sessionKey = authContext.userId;\r\n const toolRate = toolCallRateLimiter.check(sessionKey);\r\n if (!toolRate.allowed) {\r\n const retrySec = Math.ceil(toolRate.retryAfterMs / 1000);\r\n return {\r\n content: [{ type: 'text', text: `Rate limited: too many tool calls. Retry in ${retrySec}s.` }],\r\n };\r\n }\r\n\r\n // Stricter rate limiting for destructive actions (5/min)\r\n if (DESTRUCTIVE_TOOLS.has(name)) {\r\n const destructiveRate = destructiveActionRateLimiter.check(sessionKey);\r\n if (!destructiveRate.allowed) {\r\n const retrySec = Math.ceil(destructiveRate.retryAfterMs / 1000);\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Rate limited: too many destructive actions (${name}). Retry in ${retrySec}s.`,\r\n }],\r\n };\r\n }\r\n }\r\n\r\n try {\r\n switch (name) {\r\n // ----- Servers -----\r\n case 'list-servers': {\r\n let query = supabase\r\n .from('ssh_server')\r\n .select('id, name, hostname, port, username, tags, hosted_by, created_at')\r\n .order('name');\r\n\r\n if (authContext.allowedServerIds !== null) {\r\n query = query.in('id', authContext.allowedServerIds);\r\n }\r\n\r\n const { data, error } = await query;\r\n if (error) throw new Error(error.message);\r\n\r\n const lines = (data || []).map(s => {\r\n const tags = Array.isArray(s.tags) ? (s.tags as string[]).join(', ') : '';\r\n return `${s.id} ${s.name} ${s.hostname}:${s.port} ${s.username} [${tags}] ${s.hosted_by || ''}`;\r\n });\r\n\r\n return { content: [{ type: 'text', text: lines.length ? lines.join('\\n') : 'No servers found' }] };\r\n }\r\n\r\n case 'server-status': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const cmd = 'echo \"=== UPTIME ===\" && uptime && echo \"=== DISK ===\" && df -h --total && echo \"=== MEMORY ===\" && free -h && echo \"=== LOAD ===\" && cat /proc/loadavg';\r\n const result = await sshExec(conn, cmd);\r\n const output = result.exitCode === 0 ? result.stdout : `Exit ${result.exitCode}\\n${result.stdout}\\n${result.stderr}`;\r\n return { content: [{ type: 'text', text: output }] };\r\n }\r\n\r\n // ----- SSH -----\r\n case 'ssh-execute': {\r\n const command = String(a.command);\r\n assertSafeCommand(command);\r\n const conn = await getServerConnection(String(a.serverId));\r\n if (a.timeout) conn.timeout = Number(a.timeout);\r\n const result = await sshExec(conn, command);\r\n const output = [`Exit code: ${result.exitCode}`];\r\n if (result.stdout) output.push(`--- stdout ---\\n${result.stdout}`);\r\n if (result.stderr) output.push(`--- stderr ---\\n${result.stderr}`);\r\n return { content: [{ type: 'text', text: output.join('\\n') }] };\r\n }\r\n\r\n case 'server-reboot': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sshExec(conn, 'sudo reboot');\r\n return { content: [{ type: 'text', text: result.exitCode === 0 ? 'Reboot command sent. Server will be unavailable shortly.' : `Reboot failed: ${result.stderr}` }] };\r\n }\r\n\r\n case 'server-restart-service': {\r\n const service = String(a.serviceName).replace(/[^a-zA-Z0-9._@-]/g, '');\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sshExec(conn, `sudo systemctl restart ${service}`);\r\n if (result.exitCode === 0) {\r\n const status = await sshExec(conn, `sudo systemctl is-active ${service}`);\r\n return { content: [{ type: 'text', text: `Service \"${service}\" restarted. Status: ${status.stdout.trim()}` }] };\r\n }\r\n return { content: [{ type: 'text', text: `Failed to restart \"${service}\": ${result.stderr}` }] };\r\n }\r\n\r\n // ----- SFTP -----\r\n case 'sftp-list': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const listing = await sftpReaddir(conn, String(a.path || '/'));\r\n return { content: [{ type: 'text', text: listing }] };\r\n }\r\n\r\n case 'sftp-read': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const content = await sftpRead(conn, String(a.path));\r\n return { content: [{ type: 'text', text: content }] };\r\n }\r\n\r\n case 'sftp-write': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sftpWrite(conn, String(a.path), String(a.content));\r\n return { content: [{ type: 'text', text: result }] };\r\n }\r\n\r\n case 'sftp-delete': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sftpDelete(conn, String(a.path));\r\n return { content: [{ type: 'text', text: result }] };\r\n }\r\n\r\n // ----- Docker -----\r\n case 'docker-list': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sshExec(conn, 'docker ps -a --format \"table {{.Names}}\\t{{.Image}}\\t{{.Status}}\\t{{.Ports}}\"');\r\n return { content: [{ type: 'text', text: result.exitCode === 0 ? result.stdout : `Error: ${result.stderr}` }] };\r\n }\r\n\r\n case 'docker-action': {\r\n const container = String(a.containerName).replace(/[^a-zA-Z0-9._-]/g, '');\r\n const action = String(a.action);\r\n if (!['start', 'stop', 'restart', 'remove'].includes(action)) {\r\n throw new Error(`Invalid action: ${action}. Use start, stop, restart, or remove.`);\r\n }\r\n const conn = await getServerConnection(String(a.serverId));\r\n const dockerCmd = action === 'remove' ? `docker rm -f ${container}` : `docker ${action} ${container}`;\r\n const result = await sshExec(conn, dockerCmd);\r\n return { content: [{ type: 'text', text: result.exitCode === 0 ? `Container \"${container}\" ${action}ed successfully` : `Error: ${result.stderr}` }] };\r\n }\r\n\r\n case 'docker-logs': {\r\n const container = String(a.containerName).replace(/[^a-zA-Z0-9._-]/g, '');\r\n const lines = Number(a.lines) || 100;\r\n const conn = await getServerConnection(String(a.serverId));\r\n const result = await sshExec(conn, `docker logs --tail ${lines} ${container} 2>&1`);\r\n return { content: [{ type: 'text', text: result.exitCode === 0 ? result.stdout : `Error: ${result.stderr}` }] };\r\n }\r\n\r\n // ----- Database -----\r\n case 'db-discover': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const sites = await discoverSiteDatabases(conn);\r\n if (!sites.length) {\r\n return { content: [{ type: 'text', text: 'No web applications with database configs found in /var/www/' }] };\r\n }\r\n const lines = sites.map(s =>\r\n `${s.sitePath} [${s.appType}] db=${s.database} user=${s.user} host=${s.host}:${s.port}`\r\n );\r\n return { content: [{ type: 'text', text: lines.join('\\n') }] };\r\n }\r\n\r\n case 'db-tables': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const sql = \"SELECT TABLE_NAME, ENGINE, TABLE_ROWS, ROUND(DATA_LENGTH/1024/1024, 2) AS `Size (MB)`, TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY TABLE_NAME\";\r\n const output = await execSiteMysql(conn, String(a.sitePath), sql);\r\n return { content: [{ type: 'text', text: output || 'No tables found' }] };\r\n }\r\n\r\n case 'db-describe': {\r\n const table = String(a.table).replace(/[^a-zA-Z0-9_]/g, '');\r\n const conn = await getServerConnection(String(a.serverId));\r\n const output = await execSiteMysql(conn, String(a.sitePath),\r\n `DESCRIBE \\`${table}\\`; SHOW INDEX FROM \\`${table}\\``);\r\n return { content: [{ type: 'text', text: output }] };\r\n }\r\n\r\n case 'db-query': {\r\n const query = String(a.query).trim();\r\n assertSafeSql(query);\r\n const conn = await getServerConnection(String(a.serverId));\r\n const output = await execSiteMysql(conn, String(a.sitePath), query);\r\n return { content: [{ type: 'text', text: output || 'Query executed successfully (no output)' }] };\r\n }\r\n\r\n // ----- Env Config -----\r\n case 'env-list': {\r\n let query = supabase\r\n .from('env_config')\r\n .select('id, app_name, environment, description, updated_at, release_profile_stage_id')\r\n .order('app_name')\r\n .order('environment');\r\n\r\n if (a.releaseProfile) {\r\n const { stageIds } = await resolveReleaseProfileStageIds(String(a.releaseProfile));\r\n query = query.in('release_profile_stage_id', stageIds);\r\n }\r\n\r\n const { data, error } = await query;\r\n if (error) throw new Error(error.message);\r\n\r\n const stageIds = (data || [])\r\n .map((e) => e.release_profile_stage_id)\r\n .filter(Boolean) as string[];\r\n const profileNames = await getProfileNamesForStageIds(stageIds);\r\n\r\n const lines = (data || []).map((e) => {\r\n const profile = e.release_profile_stage_id\r\n ? profileNames[e.release_profile_stage_id] || 'unknown'\r\n : 'unlinked';\r\n return `${e.app_name}/${e.environment} [${profile}] (updated: ${e.updated_at})`;\r\n });\r\n return { content: [{ type: 'text', text: lines.length ? lines.join('\\n') : 'No environment configs stored' }] };\r\n }\r\n\r\n case 'env-get': {\r\n let query = supabase\r\n .from('env_config')\r\n .select('env_data_encrypted, release_profile_stage_id')\r\n .eq('app_name', String(a.appName))\r\n .eq('environment', String(a.environment));\r\n\r\n if (a.releaseProfile) {\r\n const { stageIds } = await resolveReleaseProfileStageIds(String(a.releaseProfile));\r\n query = query.in('release_profile_stage_id', stageIds);\r\n }\r\n\r\n const { data, error } = await query;\r\n\r\n if (error) throw new Error(`Env config query failed: ${error.message}`);\r\n if (!data || data.length === 0) {\r\n throw new Error(`Env config not found: ${a.appName}/${a.environment}${a.releaseProfile ? ` (profile: ${a.releaseProfile})` : ''}`);\r\n }\r\n if (data.length > 1) {\r\n const stageIds = data\r\n .map((r) => r.release_profile_stage_id)\r\n .filter(Boolean) as string[];\r\n const profileNames = await getProfileNamesForStageIds(stageIds);\r\n const names = [...new Set(Object.values(profileNames))].join(', ');\r\n throw new Error(\r\n `Multiple env configs found for ${a.appName}/${a.environment} across profiles: ${names}. ` +\r\n `Pass releaseProfile parameter to select one (e.g. releaseProfile: \"${Object.values(profileNames)[0] || '...'}\")`,\r\n );\r\n }\r\n\r\n const decrypted = decrypt(data[0]!.env_data_encrypted);\r\n return { content: [{ type: 'text', text: decrypted }] };\r\n }\r\n\r\n case 'env-store': {\r\n const appName = String(a.appName);\r\n const environment = String(a.environment);\r\n const encrypted = encrypt(String(a.content));\r\n\r\n let resolvedStageIds: string[] | null = null;\r\n if (a.releaseProfile) {\r\n const { stageIds } = await resolveReleaseProfileStageIds(String(a.releaseProfile));\r\n resolvedStageIds = stageIds;\r\n }\r\n\r\n let existQuery = supabase\r\n .from('env_config')\r\n .select('id, release_profile_stage_id')\r\n .eq('app_name', appName)\r\n .eq('environment', environment);\r\n\r\n if (resolvedStageIds) {\r\n existQuery = existQuery.in('release_profile_stage_id', resolvedStageIds);\r\n }\r\n\r\n const { data: existingRows, error: existErr } = await existQuery;\r\n if (existErr) throw new Error(`Lookup failed: ${existErr.message}`);\r\n\r\n if (existingRows && existingRows.length > 1 && !resolvedStageIds) {\r\n const stageIds = existingRows\r\n .map((r) => r.release_profile_stage_id)\r\n .filter(Boolean) as string[];\r\n const profileNames = await getProfileNamesForStageIds(stageIds);\r\n const names = [...new Set(Object.values(profileNames))].join(', ');\r\n throw new Error(\r\n `Multiple env configs found for ${appName}/${environment} across profiles: ${names}. ` +\r\n `Pass releaseProfile parameter to select one.`,\r\n );\r\n }\r\n\r\n const existing = existingRows?.[0] ?? null;\r\n let saveMsg: string;\r\n if (existing) {\r\n const { error } = await supabase\r\n .from('env_config')\r\n .update({\r\n env_data_encrypted: encrypted,\r\n description: a.description ? String(a.description) : undefined,\r\n updated_by: authContext!.userId,\r\n updated_at: new Date().toISOString(),\r\n })\r\n .eq('id', existing.id);\r\n if (error) throw new Error(error.message);\r\n saveMsg = `Updated env config: ${appName}/${environment}`;\r\n } else {\r\n const insertData: Record<string, unknown> = {\r\n app_name: appName,\r\n environment,\r\n env_data_encrypted: encrypted,\r\n description: a.description ? String(a.description) : null,\r\n created_by: authContext!.userId,\r\n updated_by: authContext!.userId,\r\n };\r\n if (resolvedStageIds?.[0]) {\r\n insertData.release_profile_stage_id = resolvedStageIds[0];\r\n }\r\n const { error } = await supabase.from('env_config').insert(insertData);\r\n if (error) throw new Error(error.message);\r\n saveMsg = `Stored env config: ${appName}/${environment}`;\r\n }\r\n\r\n const vercelStatus = await attemptVercelSync(appName, environment);\r\n return { content: [{ type: 'text', text: `${saveMsg}. ${vercelStatus}` }] };\r\n }\r\n\r\n // ----- Cache Purge -----\r\n case 'cache-purge': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n conn.timeout = 120_000;\r\n const script = `\r\nR=\"\"\r\n# 1. OPcache – kill lsphp so it respawns with a fresh OPcache\r\nif pgrep -x lsphp >/dev/null 2>&1; then\r\n sudo killall lsphp 2>/dev/null && R=\"\\${R}[OK] OPcache: killed lsphp processes\\\\n\" || R=\"\\${R}[FAIL] OPcache: could not kill lsphp\\\\n\"\r\nelse\r\n R=\"\\${R}[SKIP] OPcache: no lsphp processes running\\\\n\"\r\nfi\r\n# 2. LiteSpeed cache directories\r\nLS=0\r\nfor cdir in /tmp/lshttpd/swap /usr/local/lsws/cachedata; do\r\n if [ -d \"\\$cdir\" ] && [ \"\\$(ls -A \"\\$cdir\" 2>/dev/null)\" ]; then\r\n sudo rm -rf \"\\$cdir\"/* 2>/dev/null && R=\"\\${R}[OK] LS cache: cleared \\$cdir\\\\n\" && LS=1 || R=\"\\${R}[FAIL] LS cache: \\$cdir\\\\n\"\r\n fi\r\ndone\r\n[ \"\\$LS\" -eq 0 ] && R=\"\\${R}[SKIP] LS cache: no cache dirs with content\\\\n\"\r\n# 3. LiteSpeed graceful restart\r\nif [ -x /usr/local/lsws/bin/lswsctrl ]; then\r\n sudo /usr/local/lsws/bin/lswsctrl restart 2>/dev/null && R=\"\\${R}[OK] LiteSpeed: graceful restart\\\\n\" || R=\"\\${R}[FAIL] LiteSpeed: restart failed\\\\n\"\r\nelif systemctl is-active lsws >/dev/null 2>&1 || systemctl is-active lshttpd >/dev/null 2>&1; then\r\n sudo systemctl restart lsws 2>/dev/null || sudo systemctl restart lshttpd 2>/dev/null\r\n R=\"\\${R}[OK] LiteSpeed: restarted via systemctl\\\\n\"\r\nelse\r\n R=\"\\${R}[SKIP] LiteSpeed: not detected\\\\n\"\r\nfi\r\n# 4. WordPress caches\r\nWP=0\r\nfor dir in /var/www/*/; do\r\n [ -d \"\\$dir\" ] || continue\r\n for root in \"\\$dir\" \"\\${dir}html\" \"\\${dir}public_html\" \"\\${dir}public\" \"\\${dir}httpdocs\"; do\r\n [ -f \"\\$root/wp-config.php\" ] || continue\r\n WP=1; SITE=\\$(basename \"\\$dir\")\r\n if command -v wp >/dev/null 2>&1; then\r\n wp cache flush --allow-root --path=\"\\$root\" 2>/dev/null && R=\"\\${R}[OK] WP (\\$SITE): wp cache flush\\\\n\" || R=\"\\${R}[FAIL] WP (\\$SITE): wp cache flush\\\\n\"\r\n elif [ -d \"\\$root/wp-content/cache\" ]; then\r\n rm -rf \"\\$root/wp-content/cache\"/* 2>/dev/null && R=\"\\${R}[OK] WP (\\$SITE): cleared wp-content/cache\\\\n\"\r\n else\r\n R=\"\\${R}[SKIP] WP (\\$SITE): no cache dir, no wp-cli\\\\n\"\r\n fi\r\n break\r\n done\r\ndone\r\n[ \"\\$WP\" -eq 0 ] && R=\"\\${R}[SKIP] WordPress: no sites found\\\\n\"\r\n# 5. PrestaShop caches\r\nPS=0\r\nfor dir in /var/www/*/; do\r\n [ -d \"\\$dir\" ] || continue\r\n for root in \"\\$dir\" \"\\${dir}html\" \"\\${dir}public_html\" \"\\${dir}public\" \"\\${dir}httpdocs\"; do\r\n IS=0\r\n [ -f \"\\$root/app/config/parameters.php\" ] && IS=1\r\n [ -f \"\\$root/config/settings.inc.php\" ] && IS=1\r\n [ \"\\$IS\" -eq 0 ] && continue\r\n PS=1; SITE=\\$(basename \"\\$dir\"); C=\"\"\r\n [ -d \"\\$root/var/cache\" ] && rm -rf \"\\$root/var/cache\"/* 2>/dev/null && C=\"\\${C}var/cache \"\r\n [ -d \"\\$root/cache/smarty/compile\" ] && rm -rf \"\\$root/cache/smarty/compile\"/* 2>/dev/null && C=\"\\${C}smarty/compile \"\r\n [ -d \"\\$root/cache/smarty/cache\" ] && rm -rf \"\\$root/cache/smarty/cache\"/* 2>/dev/null && C=\"\\${C}smarty/cache \"\r\n [ -n \"\\$C\" ] && R=\"\\${R}[OK] PS (\\$SITE): cleared \\${C}\\\\n\" || R=\"\\${R}[SKIP] PS (\\$SITE): no cache dirs\\\\n\"\r\n break\r\n done\r\ndone\r\n[ \"\\$PS\" -eq 0 ] && R=\"\\${R}[SKIP] PrestaShop: no sites found\\\\n\"\r\n# 6. Redis\r\nif command -v redis-cli >/dev/null 2>&1 && redis-cli ping >/dev/null 2>&1; then\r\n redis-cli FLUSHALL 2>/dev/null && R=\"\\${R}[OK] Redis: FLUSHALL\\\\n\" || R=\"\\${R}[FAIL] Redis: FLUSHALL failed\\\\n\"\r\nelse\r\n R=\"\\${R}[SKIP] Redis: not available\\\\n\"\r\nfi\r\n# 7. Memcached\r\nif systemctl is-active memcached >/dev/null 2>&1; then\r\n if command -v memcflush >/dev/null 2>&1; then\r\n memcflush --servers=localhost 2>/dev/null && R=\"\\${R}[OK] Memcached: flushed\\\\n\" || R=\"\\${R}[FAIL] Memcached: flush failed\\\\n\"\r\n else\r\n echo \"flush_all\" | nc -q1 localhost 11211 2>/dev/null && R=\"\\${R}[OK] Memcached: flushed via nc\\\\n\" || R=\"\\${R}[FAIL] Memcached: flush failed\\\\n\"\r\n fi\r\nelse\r\n R=\"\\${R}[SKIP] Memcached: not active\\\\n\"\r\nfi\r\necho -e \"\\$R\"\r\n`.trim();\r\n const result = await sshExec(conn, script);\r\n const output = (result.stdout || '').trim();\r\n return { content: [{ type: 'text', text: output || 'Cache purge completed (no output)' }] };\r\n }\r\n\r\n // ----- Log Reading -----\r\n case 'log-list': {\r\n const conn = await getServerConnection(String(a.serverId));\r\n const script = `\r\n{\r\n [ -d /usr/local/lsws/logs ] && find /usr/local/lsws/logs -maxdepth 2 -name \"*.log\" -type f 2>/dev/null\r\n for f in /var/log/syslog /var/log/messages /var/log/auth.log /var/log/kern.log; do [ -f \"\\$f\" ] && echo \"\\$f\"; done\r\n find /var/log -maxdepth 2 \\\\( -name \"php*.log\" -o -name \"lsphp*.log\" \\\\) -type f 2>/dev/null\r\n [ -d /var/log/mg-monitoring ] && find /var/log/mg-monitoring -maxdepth 1 -name \"*.log\" -type f 2>/dev/null\r\n for dir in /var/www/*/; do\r\n [ -d \"\\$dir\" ] || continue\r\n for root in \"\\$dir\" \"\\${dir}html\" \"\\${dir}public_html\" \"\\${dir}public\" \"\\${dir}httpdocs\"; do\r\n [ -d \"\\$root\" ] || continue\r\n [ -f \"\\$root/wp-content/debug.log\" ] && echo \"\\$root/wp-content/debug.log\"\r\n [ -d \"\\$root/var/logs\" ] && find \"\\$root/var/logs\" -maxdepth 1 -name \"*.log\" -type f 2>/dev/null\r\n [ -d \"\\$root/log\" ] && find \"\\$root/log\" -maxdepth 1 -name \"*.log\" -type f 2>/dev/null\r\n [ -d \"\\$root/storage/logs\" ] && find \"\\$root/storage/logs\" -maxdepth 1 -name \"*.log\" -type f 2>/dev/null\r\n done\r\n done\r\n} | sort -u | while IFS= read -r f; do\r\n SZ=\\$(stat -c%s \"\\$f\" 2>/dev/null || echo 0)\r\n MOD=\\$(stat -c%y \"\\$f\" 2>/dev/null | cut -d. -f1)\r\n if [ \"\\$SZ\" -ge 1048576 ] 2>/dev/null; then HR=\"\\$(( SZ / 1048576 ))MB\"\r\n elif [ \"\\$SZ\" -ge 1024 ] 2>/dev/null; then HR=\"\\$(( SZ / 1024 ))KB\"\r\n else HR=\"\\${SZ}B\"; fi\r\n echo \"\\$f \\$HR \\$MOD\"\r\ndone\r\n`.trim();\r\n const result = await sshExec(conn, script);\r\n return { content: [{ type: 'text', text: result.stdout || 'No log files found' }] };\r\n }\r\n\r\n case 'log-read': {\r\n const logPath = sanitizePath(String(a.path));\r\n assertAllowedLogPath(logPath);\r\n const lineCount = Math.min(Math.max(Number(a.lines) || 100, 1), 500);\r\n const filter = a.filter ? String(a.filter).replace(/'/g, \"'\\\\''\") : '';\r\n const conn = await getServerConnection(String(a.serverId));\r\n const cmd = filter\r\n ? `grep '${filter}' '${logPath}' 2>/dev/null | tail -n ${lineCount}`\r\n : `tail -n ${lineCount} '${logPath}' 2>/dev/null`;\r\n const result = await sshExec(conn, cmd);\r\n if (result.exitCode !== 0 && !result.stdout) {\r\n throw new Error(result.stderr || `Failed to read log: ${logPath}`);\r\n }\r\n return { content: [{ type: 'text', text: result.stdout || '(empty log file)' }] };\r\n }\r\n\r\n // ----- Cron Jobs -----\r\n case 'cron-list': {\r\n const conn = await getServerConnection(a.serverId as string);\r\n const user = a.user ? String(a.user) : null;\r\n\r\n const parts: string[] = [];\r\n\r\n if (user) {\r\n const result = await sshExec(conn, `crontab -l -u ${user} 2>/dev/null || echo '(no crontab for ${user})'`);\r\n parts.push(`## Crontab for ${user}\\n${result.stdout}`);\r\n } else {\r\n const rootCron = await sshExec(conn, `crontab -l 2>/dev/null || echo '(no crontab for root)'`);\r\n parts.push(`## Root crontab\\n${rootCron.stdout}`);\r\n\r\n const wwwCron = await sshExec(conn, `crontab -l -u www-data 2>/dev/null || echo '(no crontab for www-data)'`);\r\n parts.push(`## www-data crontab\\n${wwwCron.stdout}`);\r\n\r\n const cronD = await sshExec(conn, `for f in /etc/cron.d/*; do [ -f \"$f\" ] && echo \"--- $f ---\" && cat \"$f\" && echo; done 2>/dev/null || echo '(no files in /etc/cron.d/)'`);\r\n parts.push(`## /etc/cron.d/\\n${cronD.stdout}`);\r\n\r\n const summary = await sshExec(conn, [\r\n `echo \"## Scheduled directories\"`,\r\n `echo \"cron.hourly: $(ls /etc/cron.hourly/ 2>/dev/null | wc -l) scripts\"`,\r\n `echo \"cron.daily: $(ls /etc/cron.daily/ 2>/dev/null | wc -l) scripts\"`,\r\n `echo \"cron.weekly: $(ls /etc/cron.weekly/ 2>/dev/null | wc -l) scripts\"`,\r\n `echo \"cron.monthly: $(ls /etc/cron.monthly/ 2>/dev/null | wc -l) scripts\"`,\r\n ].join(' && '));\r\n parts.push(summary.stdout);\r\n }\r\n\r\n return { content: [{ type: 'text', text: parts.join('\\n\\n') }] };\r\n }\r\n\r\n case 'cron-add': {\r\n const conn = await getServerConnection(a.serverId as string);\r\n const user = a.user ? String(a.user) : 'root';\r\n const schedule = String(a.schedule).trim();\r\n const command = String(a.command).trim();\r\n const commentText = a.comment ? String(a.comment).trim() : '';\r\n\r\n if (!schedule || !command) {\r\n throw new Error('Both schedule and command are required');\r\n }\r\n\r\n const entry = commentText\r\n ? `# ${commentText}\\n${schedule} ${command}`\r\n : `${schedule} ${command}`;\r\n\r\n const result = await sshExec(conn, `(crontab -l -u ${user} 2>/dev/null; echo '${entry.replace(/'/g, \"'\\\\''\")}') | crontab -u ${user} -`);\r\n if (result.exitCode !== 0) {\r\n throw new Error(result.stderr || 'Failed to add cron job');\r\n }\r\n\r\n return { content: [{ type: 'text', text: `Cron job added for ${user}:\\n${schedule} ${command}` }] };\r\n }\r\n\r\n case 'cron-remove': {\r\n const conn = await getServerConnection(a.serverId as string);\r\n const user = a.user ? String(a.user) : 'root';\r\n const match = String(a.commandMatch).trim();\r\n\r\n if (!match) {\r\n throw new Error('commandMatch is required');\r\n }\r\n\r\n const current = await sshExec(conn, `crontab -l -u ${user} 2>/dev/null`);\r\n const lines = current.stdout.split('\\n');\r\n const before = lines.length;\r\n\r\n const filtered = lines.filter(line => {\r\n const trimmed = line.replace(/^#\\s*/, '');\r\n return !trimmed.includes(match);\r\n });\r\n const removed = before - filtered.length;\r\n\r\n if (removed === 0) {\r\n return { content: [{ type: 'text', text: `No cron entries found matching \"${match}\"` }] };\r\n }\r\n\r\n const escapedCrontab = filtered.join('\\n').replace(/'/g, \"'\\\\''\");\r\n const result = await sshExec(conn, `echo '${escapedCrontab}' | crontab -u ${user} -`);\r\n if (result.exitCode !== 0) {\r\n throw new Error(result.stderr || 'Failed to update crontab');\r\n }\r\n\r\n return { content: [{ type: 'text', text: `Removed ${removed} cron entry/entries matching \"${match}\" from ${user} crontab` }] };\r\n }\r\n\r\n case 'cron-toggle': {\r\n const conn = await getServerConnection(a.serverId as string);\r\n const user = a.user ? String(a.user) : 'root';\r\n const match = String(a.commandMatch).trim();\r\n const enable = Boolean(a.enable);\r\n\r\n if (!match) {\r\n throw new Error('commandMatch is required');\r\n }\r\n\r\n const current = await sshExec(conn, `crontab -l -u ${user} 2>/dev/null`);\r\n const lines = current.stdout.split('\\n');\r\n let toggled = 0;\r\n\r\n const updated = lines.map(line => {\r\n if (enable && line.startsWith('#') && line.replace(/^#\\s*/, '').includes(match)) {\r\n toggled++;\r\n return line.replace(/^#\\s*/, '');\r\n }\r\n if (!enable && !line.startsWith('#') && line.includes(match)) {\r\n toggled++;\r\n return `# ${line}`;\r\n }\r\n return line;\r\n });\r\n\r\n if (toggled === 0) {\r\n const state = enable ? 'disabled' : 'enabled';\r\n return { content: [{ type: 'text', text: `No ${state} cron entries found matching \"${match}\"` }] };\r\n }\r\n\r\n const escapedCrontab = updated.join('\\n').replace(/'/g, \"'\\\\''\");\r\n const result = await sshExec(conn, `echo '${escapedCrontab}' | crontab -u ${user} -`);\r\n if (result.exitCode !== 0) {\r\n throw new Error(result.stderr || 'Failed to update crontab');\r\n }\r\n\r\n const action = enable ? 'Enabled' : 'Disabled';\r\n return { content: [{ type: 'text', text: `${action} ${toggled} cron entry/entries matching \"${match}\" in ${user} crontab` }] };\r\n }\r\n\r\n // ----- Domains (mijn.host) -----\r\n case 'domain-list': {\r\n interface DomainListItem {\r\n id: number;\r\n domain: string;\r\n renewal_date: string;\r\n status: string;\r\n status_id: number;\r\n tags: string[];\r\n }\r\n\r\n const res = await mijnhostFetch<{ domains: DomainListItem[] }>('/domains');\r\n const domains = res.data.domains;\r\n\r\n if (!domains.length) {\r\n return { content: [{ type: 'text', text: 'No domains found' }] };\r\n }\r\n\r\n const lines = domains.map(d => {\r\n const tags = d.tags?.length ? ` [${d.tags.join(', ')}]` : '';\r\n return `${d.domain} status=${d.status} renewal=${d.renewal_date}${tags}`;\r\n });\r\n\r\n return { content: [{ type: 'text', text: `${domains.length} domain(s):\\n\\n${lines.join('\\n')}` }] };\r\n }\r\n\r\n case 'domain-get': {\r\n const domain = String(a.domain);\r\n if (!domain) throw new Error('domain is required');\r\n\r\n interface DomainDetail {\r\n domain: string;\r\n renewal_date: string;\r\n is_lockable: boolean;\r\n is_locked: boolean;\r\n dnssec_enabled: number;\r\n nameservers: string[];\r\n managed_dns: boolean;\r\n whitelabel_ns: boolean;\r\n handles: {\r\n owner: { type: string; name: string; handle_id: number };\r\n tech: { type: string; name: string; handle_id: number };\r\n admin: { type: string; name: string; handle_id: number };\r\n reseller: { type: string; name: string; handle_id: number };\r\n };\r\n status: string;\r\n messages: string[];\r\n }\r\n\r\n const res = await mijnhostFetch<DomainDetail>(`/domains/${encodeURIComponent(domain)}`);\r\n const d = res.data;\r\n\r\n const sections = [\r\n `=== ${d.domain} ===`,\r\n `Status: ${d.status}`,\r\n `Renewal: ${d.renewal_date}`,\r\n `Locked: ${d.is_locked ? 'Yes' : 'No'} (lockable: ${d.is_lockable ? 'Yes' : 'No'})`,\r\n `Managed DNS: ${d.managed_dns ? 'Yes' : 'No'}`,\r\n `DNSSEC: ${d.dnssec_enabled ? 'Enabled' : 'Disabled'}`,\r\n `Nameservers: ${d.nameservers.join(', ')}`,\r\n '',\r\n '--- Contact Handles ---',\r\n `Owner: ${d.handles?.owner?.name ?? '-'}`,\r\n `Admin: ${d.handles?.admin?.name ?? '-'}`,\r\n `Tech: ${d.handles?.tech?.name ?? '-'}`,\r\n `Reseller: ${d.handles?.reseller?.name ?? '-'}`,\r\n ];\r\n\r\n if (d.messages?.length) {\r\n sections.push('', '--- Messages ---', ...d.messages);\r\n }\r\n\r\n return { content: [{ type: 'text', text: sections.join('\\n') }] };\r\n }\r\n\r\n case 'dns-list': {\r\n const domain = String(a.domain);\r\n if (!domain) throw new Error('domain is required');\r\n\r\n interface DnsRecord { type: string; name: string; value: string; ttl: number; }\r\n\r\n const res = await mijnhostFetch<{ domain: string; records: DnsRecord[] }>(\r\n `/domains/${encodeURIComponent(domain)}/dns`\r\n );\r\n const records = res.data.records;\r\n\r\n if (!records.length) {\r\n return { content: [{ type: 'text', text: `No DNS records found for ${domain}` }] };\r\n }\r\n\r\n const header = 'TYPE NAME VALUE TTL';\r\n const sep = '-'.repeat(90);\r\n const lines = records.map(r =>\r\n `${r.type.padEnd(10)}${r.name.padEnd(31)}${r.value.substring(0, 40).padEnd(41)}${r.ttl}`\r\n );\r\n\r\n return { content: [{ type: 'text', text: `DNS records for ${domain} (${records.length}):\\n\\n${header}\\n${sep}\\n${lines.join('\\n')}` }] };\r\n }\r\n\r\n case 'dns-create': {\r\n const domain = String(a.domain);\r\n const type = String(a.type).toUpperCase();\r\n const dnsName = String(a.name);\r\n const value = String(a.value);\r\n const ttl = Number(a.ttl) || 3600;\r\n\r\n if (!domain || !type || !dnsName || !value) {\r\n throw new Error('domain, type, name, and value are required');\r\n }\r\n\r\n interface DnsRecordCreate { type: string; name: string; value: string; ttl: number; }\r\n\r\n const current = await mijnhostFetch<{ domain: string; records: DnsRecordCreate[] }>(\r\n `/domains/${encodeURIComponent(domain)}/dns`\r\n );\r\n\r\n const records = [...current.data.records, { type, name: dnsName, value, ttl }];\r\n\r\n await mijnhostFetch<void>(`/domains/${encodeURIComponent(domain)}/dns`, {\r\n method: 'PUT',\r\n body: JSON.stringify({ records }),\r\n });\r\n\r\n return { content: [{ type: 'text', text: `DNS record created: ${type} ${dnsName} → ${value} (TTL: ${ttl})` }] };\r\n }\r\n\r\n case 'dns-update': {\r\n const domain = String(a.domain);\r\n const type = String(a.type).toUpperCase();\r\n const dnsName = String(a.name);\r\n const oldValue = String(a.oldValue);\r\n const newValue = String(a.newValue);\r\n const ttl = Number(a.ttl) || undefined;\r\n\r\n if (!domain || !type || !dnsName || !oldValue || !newValue) {\r\n throw new Error('domain, type, name, oldValue, and newValue are required');\r\n }\r\n\r\n interface DnsRecord { type: string; name: string; value: string; ttl: number; }\r\n\r\n const current = await mijnhostFetch<{ domain: string; records: DnsRecord[] }>(\r\n `/domains/${encodeURIComponent(domain)}/dns`\r\n );\r\n\r\n const idx = current.data.records.findIndex(\r\n r => r.type === type && r.name === dnsName && r.value === oldValue\r\n );\r\n\r\n if (idx === -1) {\r\n throw new Error(`No matching DNS record found: ${type} ${dnsName} = ${oldValue}`);\r\n }\r\n\r\n const updated = [...current.data.records];\r\n const existingTtl = updated[idx]!.ttl;\r\n updated[idx] = {\r\n type,\r\n name: dnsName,\r\n value: newValue,\r\n ttl: ttl ?? existingTtl,\r\n };\r\n\r\n await mijnhostFetch<void>(`/domains/${encodeURIComponent(domain)}/dns`, {\r\n method: 'PUT',\r\n body: JSON.stringify({ records: updated }),\r\n });\r\n\r\n return { content: [{ type: 'text', text: `DNS record updated: ${type} ${dnsName} → ${newValue}${ttl ? ` (TTL: ${ttl})` : ''}` }] };\r\n }\r\n\r\n case 'dns-delete': {\r\n const domain = String(a.domain);\r\n const type = String(a.type).toUpperCase();\r\n const dnsName = String(a.name);\r\n const value = String(a.value);\r\n\r\n if (!domain || !type || !dnsName || !value) {\r\n throw new Error('domain, type, name, and value are required');\r\n }\r\n\r\n interface DnsRecord { type: string; name: string; value: string; ttl: number; }\r\n\r\n const current = await mijnhostFetch<{ domain: string; records: DnsRecord[] }>(\r\n `/domains/${encodeURIComponent(domain)}/dns`\r\n );\r\n\r\n const before = current.data.records.length;\r\n const remaining = current.data.records.filter(\r\n r => !(r.type === type && r.name === dnsName && r.value === value)\r\n );\r\n\r\n if (remaining.length === before) {\r\n throw new Error(`No matching DNS record found: ${type} ${dnsName} = ${value}`);\r\n }\r\n\r\n await mijnhostFetch<void>(`/domains/${encodeURIComponent(domain)}/dns`, {\r\n method: 'PUT',\r\n body: JSON.stringify({ records: remaining }),\r\n });\r\n\r\n return { content: [{ type: 'text', text: `DNS record deleted: ${type} ${dnsName} = ${value} (${remaining.length} records remaining)` }] };\r\n }\r\n\r\n default:\r\n return { content: [{ type: 'text', text: `Unknown tool: ${name}` }] };\r\n }\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n return { content: [{ type: 'text', text: `Error: ${message}` }] };\r\n }\r\n});\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function main() {\r\n console.error('Starting MG Dashboard MCP Server...');\r\n\r\n authContext = await validateApiKey(apiKey!);\r\n if (!authContext) {\r\n console.error('API key validation failed');\r\n process.exit(1);\r\n }\r\n\r\n console.error('API key validated. Starting stdio transport...');\r\n\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n\r\n console.error('MCP Server ready. Tools available: ' + TOOLS.map(t => t.name).join(', '));\r\n}\r\n\r\nmain().catch((err) => {\r\n console.error('Fatal error:', err);\r\n process.exit(1);\r\n});\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mgsoftwarebv/mg-dashboard-mcp",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "MCP Server for MG Dashboard - SSH, SFTP, Docker, domains, DNS, and environment config tools for Cursor",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",