@mgsoftwarebv/mg-dashboard-mcp 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +241 -39
- package/dist/index.js.map +1 -1
- package/package.json +46 -46
package/dist/index.js
CHANGED
|
@@ -434,6 +434,16 @@ function assertSafeCommand(command) {
|
|
|
434
434
|
}
|
|
435
435
|
}
|
|
436
436
|
}
|
|
437
|
+
var ALLOWED_LOG_PREFIXES = ["/var/log/", "/usr/local/lsws/logs/", "/var/www/"];
|
|
438
|
+
function assertAllowedLogPath(filePath) {
|
|
439
|
+
const safe = sanitizePath(filePath);
|
|
440
|
+
if (!safe.endsWith(".log")) {
|
|
441
|
+
throw new Error("Only .log files can be read with log-read");
|
|
442
|
+
}
|
|
443
|
+
if (!ALLOWED_LOG_PREFIXES.some((prefix) => safe.startsWith(prefix))) {
|
|
444
|
+
throw new Error(`Path not allowed. Must be under: ${ALLOWED_LOG_PREFIXES.join(", ")}`);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
437
447
|
async function discoverSiteDatabases(conn) {
|
|
438
448
|
const script = `
|
|
439
449
|
check_dir() {
|
|
@@ -492,22 +502,6 @@ done
|
|
|
492
502
|
}
|
|
493
503
|
return sites;
|
|
494
504
|
}
|
|
495
|
-
async function getSiteDbCredentials(conn, sitePath) {
|
|
496
|
-
const sites = await discoverSiteDatabases(conn);
|
|
497
|
-
const normalized = sitePath.replace(/\/$/, "");
|
|
498
|
-
const match = sites.find((s) => {
|
|
499
|
-
const sp = s.sitePath.replace(/\/$/, "");
|
|
500
|
-
return sp === normalized || sp === normalized + "/" || normalized.startsWith(sp);
|
|
501
|
-
});
|
|
502
|
-
if (!match) {
|
|
503
|
-
const available = sites.map((s) => ` ${s.sitePath} (${s.appType})`).join("\n");
|
|
504
|
-
throw new Error(`No database credentials found at ${sitePath}.
|
|
505
|
-
|
|
506
|
-
Available sites:
|
|
507
|
-
${available || " (none found)"}`);
|
|
508
|
-
}
|
|
509
|
-
return match;
|
|
510
|
-
}
|
|
511
505
|
function escapeMysqlShell(value) {
|
|
512
506
|
return value.replace(/'/g, "'\\''");
|
|
513
507
|
}
|
|
@@ -527,16 +521,61 @@ function assertSafeSql(query) {
|
|
|
527
521
|
}
|
|
528
522
|
}
|
|
529
523
|
}
|
|
530
|
-
|
|
531
|
-
const
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
524
|
+
function buildSiteMysqlCommand(sitePath, query) {
|
|
525
|
+
const safePath = escapeMysqlShell(sitePath.replace(/\/$/, ""));
|
|
526
|
+
const safeQuery = escapeMysqlShell(query);
|
|
527
|
+
return `
|
|
528
|
+
SITE='${safePath}'
|
|
529
|
+
DB_USER="" DB_PASS="" DB_NAME="" DB_HOST="localhost" DB_PORT="3306"
|
|
530
|
+
for root in "$SITE" "$SITE/html" "$SITE/public_html" "$SITE/public" "$SITE/httpdocs"; do
|
|
531
|
+
[ -d "$root" ] || continue
|
|
532
|
+
if [ -f "$root/wp-config.php" ]; then
|
|
533
|
+
DB_NAME=$(grep -oP "define\\s*\\(\\s*'DB_NAME'\\s*,\\s*'\\K[^']+" "$root/wp-config.php" 2>/dev/null)
|
|
534
|
+
DB_USER=$(grep -oP "define\\s*\\(\\s*'DB_USER'\\s*,\\s*'\\K[^']+" "$root/wp-config.php" 2>/dev/null)
|
|
535
|
+
DB_PASS=$(grep -oP "define\\s*\\(\\s*'DB_PASSWORD'\\s*,\\s*'\\K[^']+" "$root/wp-config.php" 2>/dev/null)
|
|
536
|
+
DB_HOST=$(grep -oP "define\\s*\\(\\s*'DB_HOST'\\s*,\\s*'\\K[^']+" "$root/wp-config.php" 2>/dev/null)
|
|
537
|
+
break
|
|
538
|
+
elif [ -f "$root/app/config/parameters.php" ]; then
|
|
539
|
+
DB_NAME=$(grep -oP "'database_name'\\s*=>\\s*'\\K[^']+" "$root/app/config/parameters.php" 2>/dev/null)
|
|
540
|
+
DB_USER=$(grep -oP "'database_user'\\s*=>\\s*'\\K[^']+" "$root/app/config/parameters.php" 2>/dev/null)
|
|
541
|
+
DB_PASS=$(grep -oP "'database_password'\\s*=>\\s*'\\K[^']+" "$root/app/config/parameters.php" 2>/dev/null)
|
|
542
|
+
DB_HOST=$(grep -oP "'database_host'\\s*=>\\s*'\\K[^']+" "$root/app/config/parameters.php" 2>/dev/null)
|
|
543
|
+
break
|
|
544
|
+
elif [ -f "$root/config/settings.inc.php" ]; then
|
|
545
|
+
DB_NAME=$(grep -oP "define\\s*\\(\\s*'_DB_NAME_'\\s*,\\s*'\\K[^']+" "$root/config/settings.inc.php" 2>/dev/null)
|
|
546
|
+
DB_USER=$(grep -oP "define\\s*\\(\\s*'_DB_USER_'\\s*,\\s*'\\K[^']+" "$root/config/settings.inc.php" 2>/dev/null)
|
|
547
|
+
DB_PASS=$(grep -oP "define\\s*\\(\\s*'_DB_PASSWD_'\\s*,\\s*'\\K[^']+" "$root/config/settings.inc.php" 2>/dev/null)
|
|
548
|
+
DB_HOST=$(grep -oP "define\\s*\\(\\s*'_DB_SERVER_'\\s*,\\s*'\\K[^']+" "$root/config/settings.inc.php" 2>/dev/null)
|
|
549
|
+
break
|
|
550
|
+
elif [ -f "$root/.env" ]; then
|
|
551
|
+
DB_CONN=$(grep -oP '^DB_CONNECTION=\\K.*' "$root/.env" 2>/dev/null)
|
|
552
|
+
if [ -n "$DB_CONN" ] && [ "$DB_CONN" != "sqlite" ]; then
|
|
553
|
+
DB_NAME=$(grep -oP '^DB_DATABASE=\\K.*' "$root/.env" 2>/dev/null)
|
|
554
|
+
DB_USER=$(grep -oP '^DB_USERNAME=\\K.*' "$root/.env" 2>/dev/null)
|
|
555
|
+
DB_PASS=$(grep -oP '^DB_PASSWORD=\\K.*' "$root/.env" 2>/dev/null)
|
|
556
|
+
DB_HOST=$(grep -oP '^DB_HOST=\\K.*' "$root/.env" 2>/dev/null)
|
|
557
|
+
DB_PORT=$(grep -oP '^DB_PORT=\\K.*' "$root/.env" 2>/dev/null)
|
|
558
|
+
break
|
|
559
|
+
fi
|
|
560
|
+
fi
|
|
561
|
+
done
|
|
562
|
+
[ -z "$DB_NAME" ] || [ -z "$DB_USER" ] && echo "ERROR: No database config found at $SITE" && exit 1
|
|
563
|
+
DB_HOST=\${DB_HOST:-localhost}
|
|
564
|
+
DB_PORT=\${DB_PORT:-3306}
|
|
565
|
+
mysql --user="$DB_USER" --password="$DB_PASS" --host="$DB_HOST" --port="$DB_PORT" -t -e '${safeQuery}' "$DB_NAME" 2>&1 | grep -v "\\[Warning\\].*password"
|
|
566
|
+
`.trim();
|
|
567
|
+
}
|
|
568
|
+
async function execSiteMysql(conn, sitePath, query) {
|
|
569
|
+
const cmd = buildSiteMysqlCommand(sitePath, query);
|
|
535
570
|
const result = await sshExec(conn, cmd);
|
|
536
|
-
|
|
537
|
-
|
|
571
|
+
const output = (result.stdout || "").trim();
|
|
572
|
+
if (output.startsWith("ERROR: No database config found")) {
|
|
573
|
+
throw new Error(output);
|
|
574
|
+
}
|
|
575
|
+
if (result.exitCode !== 0 && !output) {
|
|
576
|
+
throw new Error(result.stderr || "MySQL command failed");
|
|
538
577
|
}
|
|
539
|
-
return
|
|
578
|
+
return output;
|
|
540
579
|
}
|
|
541
580
|
var TOOLS = [
|
|
542
581
|
{
|
|
@@ -756,10 +795,46 @@ var TOOLS = [
|
|
|
756
795
|
},
|
|
757
796
|
required: ["appName", "environment", "content"]
|
|
758
797
|
}
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
name: "cache-purge",
|
|
801
|
+
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.",
|
|
802
|
+
inputSchema: {
|
|
803
|
+
type: "object",
|
|
804
|
+
properties: {
|
|
805
|
+
serverId: { type: "string", description: "UUID of the SSH server" }
|
|
806
|
+
},
|
|
807
|
+
required: ["serverId"]
|
|
808
|
+
}
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
name: "log-list",
|
|
812
|
+
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.",
|
|
813
|
+
inputSchema: {
|
|
814
|
+
type: "object",
|
|
815
|
+
properties: {
|
|
816
|
+
serverId: { type: "string", description: "UUID of the SSH server" }
|
|
817
|
+
},
|
|
818
|
+
required: ["serverId"]
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
{
|
|
822
|
+
name: "log-read",
|
|
823
|
+
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.",
|
|
824
|
+
inputSchema: {
|
|
825
|
+
type: "object",
|
|
826
|
+
properties: {
|
|
827
|
+
serverId: { type: "string", description: "UUID of the SSH server" },
|
|
828
|
+
path: { type: "string", description: "Absolute path to the log file (must end in .log)" },
|
|
829
|
+
lines: { type: "number", description: "Number of lines to read (default: 100, max: 500)" },
|
|
830
|
+
filter: { type: "string", description: "Optional grep pattern to filter lines before tailing" }
|
|
831
|
+
},
|
|
832
|
+
required: ["serverId", "path"]
|
|
833
|
+
}
|
|
759
834
|
}
|
|
760
835
|
];
|
|
761
836
|
var server = new Server(
|
|
762
|
-
{ name: "mg-dashboard-mcp", version: "1.
|
|
837
|
+
{ name: "mg-dashboard-mcp", version: "1.5.0" },
|
|
763
838
|
{ capabilities: { tools: {} } }
|
|
764
839
|
);
|
|
765
840
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
@@ -882,29 +957,25 @@ ${result.stderr}`);
|
|
|
882
957
|
}
|
|
883
958
|
case "db-tables": {
|
|
884
959
|
const conn = await getServerConnection(String(a.serverId));
|
|
885
|
-
const
|
|
886
|
-
const
|
|
887
|
-
const output = await execMysql(conn, creds, query, false);
|
|
960
|
+
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";
|
|
961
|
+
const output = await execSiteMysql(conn, String(a.sitePath), sql);
|
|
888
962
|
return { content: [{ type: "text", text: output || "No tables found" }] };
|
|
889
963
|
}
|
|
890
964
|
case "db-describe": {
|
|
891
|
-
const conn = await getServerConnection(String(a.serverId));
|
|
892
|
-
const creds = await getSiteDbCredentials(conn, String(a.sitePath));
|
|
893
965
|
const table = String(a.table).replace(/[^a-zA-Z0-9_]/g, "");
|
|
894
|
-
const
|
|
895
|
-
const
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
966
|
+
const conn = await getServerConnection(String(a.serverId));
|
|
967
|
+
const output = await execSiteMysql(
|
|
968
|
+
conn,
|
|
969
|
+
String(a.sitePath),
|
|
970
|
+
`DESCRIBE \`${table}\`; SHOW INDEX FROM \`${table}\``
|
|
971
|
+
);
|
|
972
|
+
return { content: [{ type: "text", text: output }] };
|
|
901
973
|
}
|
|
902
974
|
case "db-query": {
|
|
903
975
|
const query = String(a.query).trim();
|
|
904
976
|
assertSafeSql(query);
|
|
905
977
|
const conn = await getServerConnection(String(a.serverId));
|
|
906
|
-
const
|
|
907
|
-
const output = await execMysql(conn, creds, query);
|
|
978
|
+
const output = await execSiteMysql(conn, String(a.sitePath), query);
|
|
908
979
|
return { content: [{ type: "text", text: output || "Query executed successfully (no output)" }] };
|
|
909
980
|
}
|
|
910
981
|
// ----- Env Config -----
|
|
@@ -948,6 +1019,137 @@ ${indexes}` }] };
|
|
|
948
1019
|
if (error) throw new Error(error.message);
|
|
949
1020
|
return { content: [{ type: "text", text: `Stored env config: ${appName}/${environment}` }] };
|
|
950
1021
|
}
|
|
1022
|
+
// ----- Cache Purge -----
|
|
1023
|
+
case "cache-purge": {
|
|
1024
|
+
const conn = await getServerConnection(String(a.serverId));
|
|
1025
|
+
conn.timeout = 12e4;
|
|
1026
|
+
const script = `
|
|
1027
|
+
R=""
|
|
1028
|
+
# 1. OPcache \u2013 kill lsphp so it respawns with a fresh OPcache
|
|
1029
|
+
if pgrep -x lsphp >/dev/null 2>&1; then
|
|
1030
|
+
sudo killall lsphp 2>/dev/null && R="\${R}[OK] OPcache: killed lsphp processes\\n" || R="\${R}[FAIL] OPcache: could not kill lsphp\\n"
|
|
1031
|
+
else
|
|
1032
|
+
R="\${R}[SKIP] OPcache: no lsphp processes running\\n"
|
|
1033
|
+
fi
|
|
1034
|
+
# 2. LiteSpeed cache directories
|
|
1035
|
+
LS=0
|
|
1036
|
+
for cdir in /tmp/lshttpd/swap /usr/local/lsws/cachedata; do
|
|
1037
|
+
if [ -d "$cdir" ] && [ "$(ls -A "$cdir" 2>/dev/null)" ]; then
|
|
1038
|
+
sudo rm -rf "$cdir"/* 2>/dev/null && R="\${R}[OK] LS cache: cleared $cdir\\n" && LS=1 || R="\${R}[FAIL] LS cache: $cdir\\n"
|
|
1039
|
+
fi
|
|
1040
|
+
done
|
|
1041
|
+
[ "$LS" -eq 0 ] && R="\${R}[SKIP] LS cache: no cache dirs with content\\n"
|
|
1042
|
+
# 3. LiteSpeed graceful restart
|
|
1043
|
+
if [ -x /usr/local/lsws/bin/lswsctrl ]; then
|
|
1044
|
+
sudo /usr/local/lsws/bin/lswsctrl restart 2>/dev/null && R="\${R}[OK] LiteSpeed: graceful restart\\n" || R="\${R}[FAIL] LiteSpeed: restart failed\\n"
|
|
1045
|
+
elif systemctl is-active lsws >/dev/null 2>&1 || systemctl is-active lshttpd >/dev/null 2>&1; then
|
|
1046
|
+
sudo systemctl restart lsws 2>/dev/null || sudo systemctl restart lshttpd 2>/dev/null
|
|
1047
|
+
R="\${R}[OK] LiteSpeed: restarted via systemctl\\n"
|
|
1048
|
+
else
|
|
1049
|
+
R="\${R}[SKIP] LiteSpeed: not detected\\n"
|
|
1050
|
+
fi
|
|
1051
|
+
# 4. WordPress caches
|
|
1052
|
+
WP=0
|
|
1053
|
+
for dir in /var/www/*/; do
|
|
1054
|
+
[ -d "$dir" ] || continue
|
|
1055
|
+
for root in "$dir" "\${dir}html" "\${dir}public_html" "\${dir}public" "\${dir}httpdocs"; do
|
|
1056
|
+
[ -f "$root/wp-config.php" ] || continue
|
|
1057
|
+
WP=1; SITE=$(basename "$dir")
|
|
1058
|
+
if command -v wp >/dev/null 2>&1; then
|
|
1059
|
+
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"
|
|
1060
|
+
elif [ -d "$root/wp-content/cache" ]; then
|
|
1061
|
+
rm -rf "$root/wp-content/cache"/* 2>/dev/null && R="\${R}[OK] WP ($SITE): cleared wp-content/cache\\n"
|
|
1062
|
+
else
|
|
1063
|
+
R="\${R}[SKIP] WP ($SITE): no cache dir, no wp-cli\\n"
|
|
1064
|
+
fi
|
|
1065
|
+
break
|
|
1066
|
+
done
|
|
1067
|
+
done
|
|
1068
|
+
[ "$WP" -eq 0 ] && R="\${R}[SKIP] WordPress: no sites found\\n"
|
|
1069
|
+
# 5. PrestaShop caches
|
|
1070
|
+
PS=0
|
|
1071
|
+
for dir in /var/www/*/; do
|
|
1072
|
+
[ -d "$dir" ] || continue
|
|
1073
|
+
for root in "$dir" "\${dir}html" "\${dir}public_html" "\${dir}public" "\${dir}httpdocs"; do
|
|
1074
|
+
IS=0
|
|
1075
|
+
[ -f "$root/app/config/parameters.php" ] && IS=1
|
|
1076
|
+
[ -f "$root/config/settings.inc.php" ] && IS=1
|
|
1077
|
+
[ "$IS" -eq 0 ] && continue
|
|
1078
|
+
PS=1; SITE=$(basename "$dir"); C=""
|
|
1079
|
+
[ -d "$root/var/cache" ] && rm -rf "$root/var/cache"/* 2>/dev/null && C="\${C}var/cache "
|
|
1080
|
+
[ -d "$root/cache/smarty/compile" ] && rm -rf "$root/cache/smarty/compile"/* 2>/dev/null && C="\${C}smarty/compile "
|
|
1081
|
+
[ -d "$root/cache/smarty/cache" ] && rm -rf "$root/cache/smarty/cache"/* 2>/dev/null && C="\${C}smarty/cache "
|
|
1082
|
+
[ -n "$C" ] && R="\${R}[OK] PS ($SITE): cleared \${C}\\n" || R="\${R}[SKIP] PS ($SITE): no cache dirs\\n"
|
|
1083
|
+
break
|
|
1084
|
+
done
|
|
1085
|
+
done
|
|
1086
|
+
[ "$PS" -eq 0 ] && R="\${R}[SKIP] PrestaShop: no sites found\\n"
|
|
1087
|
+
# 6. Redis
|
|
1088
|
+
if command -v redis-cli >/dev/null 2>&1 && redis-cli ping >/dev/null 2>&1; then
|
|
1089
|
+
redis-cli FLUSHALL 2>/dev/null && R="\${R}[OK] Redis: FLUSHALL\\n" || R="\${R}[FAIL] Redis: FLUSHALL failed\\n"
|
|
1090
|
+
else
|
|
1091
|
+
R="\${R}[SKIP] Redis: not available\\n"
|
|
1092
|
+
fi
|
|
1093
|
+
# 7. Memcached
|
|
1094
|
+
if systemctl is-active memcached >/dev/null 2>&1; then
|
|
1095
|
+
if command -v memcflush >/dev/null 2>&1; then
|
|
1096
|
+
memcflush --servers=localhost 2>/dev/null && R="\${R}[OK] Memcached: flushed\\n" || R="\${R}[FAIL] Memcached: flush failed\\n"
|
|
1097
|
+
else
|
|
1098
|
+
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"
|
|
1099
|
+
fi
|
|
1100
|
+
else
|
|
1101
|
+
R="\${R}[SKIP] Memcached: not active\\n"
|
|
1102
|
+
fi
|
|
1103
|
+
echo -e "$R"
|
|
1104
|
+
`.trim();
|
|
1105
|
+
const result = await sshExec(conn, script);
|
|
1106
|
+
const output = (result.stdout || "").trim();
|
|
1107
|
+
return { content: [{ type: "text", text: output || "Cache purge completed (no output)" }] };
|
|
1108
|
+
}
|
|
1109
|
+
// ----- Log Reading -----
|
|
1110
|
+
case "log-list": {
|
|
1111
|
+
const conn = await getServerConnection(String(a.serverId));
|
|
1112
|
+
const script = `
|
|
1113
|
+
{
|
|
1114
|
+
[ -d /usr/local/lsws/logs ] && find /usr/local/lsws/logs -maxdepth 2 -name "*.log" -type f 2>/dev/null
|
|
1115
|
+
for f in /var/log/syslog /var/log/messages /var/log/auth.log /var/log/kern.log; do [ -f "$f" ] && echo "$f"; done
|
|
1116
|
+
find /var/log -maxdepth 2 \\( -name "php*.log" -o -name "lsphp*.log" \\) -type f 2>/dev/null
|
|
1117
|
+
[ -d /var/log/mg-monitoring ] && find /var/log/mg-monitoring -maxdepth 1 -name "*.log" -type f 2>/dev/null
|
|
1118
|
+
for dir in /var/www/*/; do
|
|
1119
|
+
[ -d "$dir" ] || continue
|
|
1120
|
+
for root in "$dir" "\${dir}html" "\${dir}public_html" "\${dir}public" "\${dir}httpdocs"; do
|
|
1121
|
+
[ -d "$root" ] || continue
|
|
1122
|
+
[ -f "$root/wp-content/debug.log" ] && echo "$root/wp-content/debug.log"
|
|
1123
|
+
[ -d "$root/var/logs" ] && find "$root/var/logs" -maxdepth 1 -name "*.log" -type f 2>/dev/null
|
|
1124
|
+
[ -d "$root/log" ] && find "$root/log" -maxdepth 1 -name "*.log" -type f 2>/dev/null
|
|
1125
|
+
[ -d "$root/storage/logs" ] && find "$root/storage/logs" -maxdepth 1 -name "*.log" -type f 2>/dev/null
|
|
1126
|
+
done
|
|
1127
|
+
done
|
|
1128
|
+
} | sort -u | while IFS= read -r f; do
|
|
1129
|
+
SZ=$(stat -c%s "$f" 2>/dev/null || echo 0)
|
|
1130
|
+
MOD=$(stat -c%y "$f" 2>/dev/null | cut -d. -f1)
|
|
1131
|
+
if [ "$SZ" -ge 1048576 ] 2>/dev/null; then HR="$(( SZ / 1048576 ))MB"
|
|
1132
|
+
elif [ "$SZ" -ge 1024 ] 2>/dev/null; then HR="$(( SZ / 1024 ))KB"
|
|
1133
|
+
else HR="\${SZ}B"; fi
|
|
1134
|
+
echo "$f $HR $MOD"
|
|
1135
|
+
done
|
|
1136
|
+
`.trim();
|
|
1137
|
+
const result = await sshExec(conn, script);
|
|
1138
|
+
return { content: [{ type: "text", text: result.stdout || "No log files found" }] };
|
|
1139
|
+
}
|
|
1140
|
+
case "log-read": {
|
|
1141
|
+
const logPath = sanitizePath(String(a.path));
|
|
1142
|
+
assertAllowedLogPath(logPath);
|
|
1143
|
+
const lineCount = Math.min(Math.max(Number(a.lines) || 100, 1), 500);
|
|
1144
|
+
const filter = a.filter ? String(a.filter).replace(/'/g, "'\\''") : "";
|
|
1145
|
+
const conn = await getServerConnection(String(a.serverId));
|
|
1146
|
+
const cmd = filter ? `grep '${filter}' '${logPath}' 2>/dev/null | tail -n ${lineCount}` : `tail -n ${lineCount} '${logPath}' 2>/dev/null`;
|
|
1147
|
+
const result = await sshExec(conn, cmd);
|
|
1148
|
+
if (result.exitCode !== 0 && !result.stdout) {
|
|
1149
|
+
throw new Error(result.stderr || `Failed to read log: ${logPath}`);
|
|
1150
|
+
}
|
|
1151
|
+
return { content: [{ type: "text", text: result.stdout || "(empty log file)" }] };
|
|
1152
|
+
}
|
|
951
1153
|
default:
|
|
952
1154
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }] };
|
|
953
1155
|
}
|
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\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { createClient } from '@supabase/supabase-js';\nimport { createHash, randomBytes, createCipheriv, createDecipheriv } from 'crypto';\nimport { Client as SshClient } from 'ssh2';\n\n// ---------------------------------------------------------------------------\n// CLI argument parsing\n// ---------------------------------------------------------------------------\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string): string | undefined {\n return args.find(a => a.startsWith(`--${name}=`))?.split('=').slice(1).join('=');\n}\n\nconst apiKey = getArg('api-key') || process.env.MG_DASHBOARD_API_KEY;\nconst supabaseUrl = getArg('supabase-url') || process.env.SUPABASE_URL;\nconst supabaseKey = getArg('supabase-key') || process.env.SUPABASE_SERVICE_ROLE_KEY;\nconst encryptionKey = getArg('encryption-key') || process.env.ENCRYPTION_KEY;\n\nif (!apiKey) {\n console.error('API key is required. Use --api-key=dk_xxx or set MG_DASHBOARD_API_KEY');\n process.exit(1);\n}\n\nif (!supabaseUrl || !supabaseKey) {\n console.error('Supabase credentials required. Use --supabase-url and --supabase-key or set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY');\n process.exit(1);\n}\n\nconst supabase = createClient(supabaseUrl, supabaseKey);\n\n// ---------------------------------------------------------------------------\n// Auth context\n// ---------------------------------------------------------------------------\n\ninterface AuthContext {\n userId: string;\n allowedServerIds: string[] | null;\n}\n\nlet authContext: AuthContext | null = null;\n\nasync function validateApiKey(key: string): Promise<AuthContext | null> {\n if (!key.startsWith('dk_') || key.length !== 67) {\n console.error('Invalid API key format (expected dk_ + 64 hex chars)');\n return null;\n }\n\n const keyHash = createHash('sha256').update(key).digest('hex');\n\n const { data, error } = await supabase\n .from('dashboard_mcp_api_key')\n .select('id, created_by, allowed_server_ids, is_active, expires_at')\n .eq('api_key_hash', keyHash)\n .eq('is_active', true)\n .single();\n\n if (error || !data) {\n console.error('API key not found or inactive');\n return null;\n }\n\n if (data.expires_at && new Date(data.expires_at) < new Date()) {\n console.error('API key has expired');\n return null;\n }\n\n await supabase\n .from('dashboard_mcp_api_key')\n .update({ last_used_at: new Date().toISOString() })\n .eq('id', data.id);\n\n console.error(`Authenticated as user ${data.created_by}`);\n\n return {\n userId: data.created_by,\n allowedServerIds: data.allowed_server_ids,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Server access helper\n// ---------------------------------------------------------------------------\n\nfunction assertServerAccess(serverId: string): void {\n if (!authContext) throw new Error('Not authenticated');\n if (authContext.allowedServerIds === null) return;\n if (!authContext.allowedServerIds.includes(serverId)) {\n throw new Error(`Access denied: you do not have permission for server ${serverId}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Encryption helpers (AES-256-GCM, compatible with dashboard encryption.ts)\n// ---------------------------------------------------------------------------\n\nconst ENC_ALGORITHM = 'aes-256-gcm';\nconst ENC_IV_LENGTH = 16;\nconst ENC_TAG_LENGTH = 16;\n\nfunction getEncryptionKey(): Buffer {\n if (!encryptionKey) throw new Error('ENCRYPTION_KEY is required for env operations');\n const buf = Buffer.from(encryptionKey, 'hex');\n if (buf.length !== 32) throw new Error('ENCRYPTION_KEY must be a 64-character hex string');\n return buf;\n}\n\nfunction encrypt(text: string): string {\n const key = getEncryptionKey();\n const iv = randomBytes(ENC_IV_LENGTH);\n const cipher = createCipheriv(ENC_ALGORITHM, new Uint8Array(key), new Uint8Array(iv));\n let encrypted = cipher.update(text, 'utf8', 'hex');\n encrypted += cipher.final('hex');\n const authTag = cipher.getAuthTag();\n return Buffer.concat([\n new Uint8Array(iv),\n new Uint8Array(authTag),\n new Uint8Array(Buffer.from(encrypted, 'hex')),\n ]).toString('base64');\n}\n\nfunction decrypt(payload: string): string {\n const key = getEncryptionKey();\n const buf = Buffer.from(payload, 'base64');\n const iv = buf.subarray(0, ENC_IV_LENGTH);\n const authTag = buf.subarray(ENC_IV_LENGTH, ENC_IV_LENGTH + ENC_TAG_LENGTH);\n const encrypted = buf.subarray(ENC_IV_LENGTH + ENC_TAG_LENGTH);\n const decipher = createDecipheriv(ENC_ALGORITHM, new Uint8Array(key), new Uint8Array(iv));\n decipher.setAuthTag(new Uint8Array(authTag));\n let decrypted = decipher.update(encrypted.toString('hex'), 'hex', 'utf8');\n decrypted += decipher.final('utf8');\n return decrypted;\n}\n\n// ---------------------------------------------------------------------------\n// SSH helpers\n// ---------------------------------------------------------------------------\n\ninterface SshConnectionOptions {\n hostname: string;\n port: number;\n username: string;\n password?: string;\n privateKey?: string;\n passphrase?: string;\n timeout?: number;\n}\n\ninterface SshResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\nasync function getServerConnection(serverId: string): Promise<SshConnectionOptions> {\n assertServerAccess(serverId);\n\n const { data, error } = await supabase\n .from('ssh_server')\n .select('hostname, port, username, password_encrypted, ssh_key_encrypted, ssh_key_passphrase_encrypted')\n .eq('id', serverId)\n .single();\n\n if (error || !data) throw new Error(`Server not found: ${serverId}`);\n if (!encryptionKey) throw new Error('ENCRYPTION_KEY required to decrypt server credentials');\n\n return {\n hostname: data.hostname,\n port: data.port || 22,\n username: data.username,\n password: data.password_encrypted ? decrypt(data.password_encrypted) : undefined,\n privateKey: data.ssh_key_encrypted ? decrypt(data.ssh_key_encrypted) : undefined,\n passphrase: data.ssh_key_passphrase_encrypted ? decrypt(data.ssh_key_passphrase_encrypted) : undefined,\n };\n}\n\nasync function sshExec(opts: SshConnectionOptions, command: string): Promise<SshResult> {\n return new Promise((resolve) => {\n const ssh = new SshClient();\n let stdout = '';\n let stderr = '';\n let done = false;\n const timeout = opts.timeout || 60_000;\n\n const timer = setTimeout(() => {\n if (!done) { done = true; ssh.end(); resolve({ stdout, stderr, exitCode: -1 }); }\n }, timeout);\n\n ssh.on('ready', () => {\n ssh.exec(command, (err, stream) => {\n if (err) {\n if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve({ stdout, stderr, exitCode: -1 }); }\n return;\n }\n stream.on('data', (d: Buffer) => { stdout += d.toString(); });\n stream.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });\n stream.on('close', (code: number | null) => {\n if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve({ stdout, stderr, exitCode: code ?? 0 }); }\n });\n });\n });\n\n ssh.on('error', (err) => {\n if (!done) { done = true; clearTimeout(timer); resolve({ stdout, stderr: err.message, exitCode: -1 }); }\n });\n\n ssh.connect({\n host: opts.hostname, port: opts.port, username: opts.username,\n password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase,\n readyTimeout: timeout,\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// SFTP helpers\n// ---------------------------------------------------------------------------\n\nfunction sanitizePath(path: string): string {\n let normalized = path.replace(/\\\\/g, '/').replace(/\\0/g, '');\n const parts = normalized.split('/');\n const resolved: string[] = [];\n for (const part of parts) {\n if (part === '..') { if (resolved.length > 0 && resolved[resolved.length - 1] !== '') resolved.pop(); }\n else if (part !== '.' && part !== '') resolved.push(part);\n }\n return '/' + resolved.join('/');\n}\n\nconst PROTECTED_PATHS = ['/etc/', '/boot/', '/usr/', '/bin/', '/sbin/', '/lib/', '/lib64/'];\n\nfunction assertWritablePath(path: string): void {\n const safe = sanitizePath(path);\n for (const p of PROTECTED_PATHS) {\n if (safe === p.slice(0, -1) || safe.startsWith(p)) {\n throw new Error(`Write access denied to protected path: ${safe}`);\n }\n }\n}\n\nasync function sftpReaddir(opts: SshConnectionOptions, dirPath: string): Promise<string> {\n const safe = sanitizePath(dirPath);\n return new Promise((resolve) => {\n const ssh = new SshClient();\n let done = false;\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 30_000);\n\n ssh.on('ready', () => {\n ssh.sftp((err, sftp) => {\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\n sftp.readdir(safe, (err, list) => {\n done = true; clearTimeout(timer);\n if (err) { ssh.end(); resolve(`Error: ${err.message}`); return; }\n const entries = list.map(item => {\n const mode = item.attrs.mode || 0;\n const isDir = (mode & 0o170000) === 0o040000;\n const size = item.attrs.size || 0;\n const mtime = item.attrs.mtime ? new Date(item.attrs.mtime * 1000).toISOString() : '';\n return `${isDir ? 'd' : '-'} ${String(size).padStart(10)} ${mtime} ${item.filename}`;\n });\n ssh.end();\n resolve(entries.join('\\n'));\n });\n });\n });\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 30_000 });\n });\n}\n\nasync function sftpRead(opts: SshConnectionOptions, filePath: string): Promise<string> {\n const safe = sanitizePath(filePath);\n return new Promise((resolve) => {\n const ssh = new SshClient();\n let done = false;\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 60_000);\n\n ssh.on('ready', () => {\n ssh.sftp((err, sftp) => {\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\n sftp.stat(safe, (err, stats) => {\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\n if ((stats.size || 0) > 1_048_576) {\n if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: file too large (${stats.size} bytes, max 1MB)`); }\n return;\n }\n const chunks: Buffer[] = [];\n const rs = sftp.createReadStream(safe);\n rs.on('data', (c: Buffer) => chunks.push(c));\n rs.on('end', () => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(Buffer.concat(chunks.map(c => new Uint8Array(c))).toString('utf-8')); } });\n rs.on('error', (e: Error) => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${e.message}`); } });\n });\n });\n });\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 60_000 });\n });\n}\n\nasync function sftpWrite(opts: SshConnectionOptions, filePath: string, content: string): Promise<string> {\n const safe = sanitizePath(filePath);\n assertWritablePath(safe);\n return new Promise((resolve) => {\n const ssh = new SshClient();\n let done = false;\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 60_000);\n\n ssh.on('ready', () => {\n ssh.sftp((err, sftp) => {\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\n const ws = sftp.createWriteStream(safe, { mode: 0o644 });\n ws.on('close', () => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Written ${content.length} bytes to ${safe}`); } });\n ws.on('error', (e: Error) => { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${e.message}`); } });\n ws.end(Buffer.from(content, 'utf-8'));\n });\n });\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 60_000 });\n });\n}\n\nasync function sftpDelete(opts: SshConnectionOptions, filePath: string): Promise<string> {\n const safe = sanitizePath(filePath);\n assertWritablePath(safe);\n return new Promise((resolve) => {\n const ssh = new SshClient();\n let done = false;\n const timer = setTimeout(() => { if (!done) { done = true; ssh.end(); resolve('Error: timeout'); } }, 30_000);\n\n ssh.on('ready', () => {\n ssh.sftp((err, sftp) => {\n if (err) { if (!done) { done = true; clearTimeout(timer); ssh.end(); resolve(`Error: ${err.message}`); } return; }\n sftp.unlink(safe, (err) => {\n if (err) {\n sftp.rmdir(safe, (err2) => {\n done = true; clearTimeout(timer); ssh.end();\n resolve(err2 ? `Error: ${err.message}` : `Deleted directory ${safe}`);\n });\n } else {\n done = true; clearTimeout(timer); ssh.end();\n resolve(`Deleted file ${safe}`);\n }\n });\n });\n });\n ssh.on('error', (e) => { if (!done) { done = true; clearTimeout(timer); resolve(`Error: ${e.message}`); } });\n ssh.connect({ host: opts.hostname, port: opts.port, username: opts.username, password: opts.password, privateKey: opts.privateKey, passphrase: opts.passphrase, readyTimeout: 30_000 });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Safety: dangerous command blocklist\n// ---------------------------------------------------------------------------\n\nconst BLOCKED_COMMANDS = [\n 'rm -rf /', 'rm -fr /', 'mkfs', 'dd if=', ':(){ :|:& };:',\n 'shutdown', 'halt', 'init 0', 'init 6',\n '> /dev/sda', 'mv /* /dev/null', 'chmod -R 000 /',\n];\n\nfunction assertSafeCommand(command: string): void {\n const lower = command.toLowerCase().trim();\n for (const blocked of BLOCKED_COMMANDS) {\n if (lower.includes(blocked)) {\n throw new Error(`Blocked dangerous command pattern: \"${blocked}\"`);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// MySQL / Database helpers\n// ---------------------------------------------------------------------------\n\ninterface DbCredentials {\n host: string;\n user: string;\n password: string;\n database: string;\n port: number;\n sitePath: string;\n appType: string;\n}\n\n/**\n * Discovers web applications under /var/www and extracts DB credentials\n * from their config files (WordPress, PrestaShop, Laravel, custom .env).\n */\nasync function discoverSiteDatabases(conn: SshConnectionOptions): Promise<DbCredentials[]> {\n const script = `\ncheck_dir() {\n local base=\"$1\" root=\"$2\"\n # WordPress\n if [ -f \"$root/wp-config.php\" ]; then\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)\"\n return\n fi\n # PrestaShop 1.7+\n if [ -f \"$root/app/config/parameters.php\" ]; then\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)\"\n return\n fi\n # PrestaShop 1.6\n if [ -f \"$root/config/settings.inc.php\" ]; then\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)\"\n return\n fi\n # Laravel / generic .env\n if [ -f \"$root/.env\" ]; then\n DB_CONN=$(grep -oP '^DB_CONNECTION=\\\\K.*' \"$root/.env\" 2>/dev/null)\n if [ -n \"$DB_CONN\" ] && [ \"$DB_CONN\" != \"sqlite\" ]; then\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)\"\n return\n fi\n fi\n}\nfor dir in /var/www/*/; do\n [ -d \"$dir\" ] || continue\n check_dir \"$dir\" \"$dir\"\n # Also check common subdirectories: html, public_html, public, httpdocs\n for sub in html public_html public httpdocs; do\n [ -d \"$dir$sub\" ] && check_dir \"$dir\" \"$dir$sub\"\n done\ndone\n`.trim();\n\n const result = await sshExec(conn, script);\n const sites: DbCredentials[] = [];\n\n for (const line of result.stdout.split('\\n')) {\n if (!line.trim()) continue;\n const parts = line.split('|');\n if (parts.length < 6) continue;\n\n const [type, sitePath, database, user, password, host, port] = parts;\n if (!database || !user || !type || !sitePath) continue;\n\n const appTypes: Record<string, string> = { WP: 'WordPress', PS: 'PrestaShop', ENV: 'Laravel/.env' };\n\n sites.push({\n appType: appTypes[type] || type,\n sitePath: sitePath.replace(/\\/$/, ''),\n database,\n user,\n password: password || '',\n host: host || 'localhost',\n port: parseInt(port || '3306', 10),\n });\n }\n\n return sites;\n}\n\n/**\n * Gets DB credentials for a specific site path on a server.\n */\nasync function getSiteDbCredentials(conn: SshConnectionOptions, sitePath: string): Promise<DbCredentials> {\n const sites = await discoverSiteDatabases(conn);\n const normalized = sitePath.replace(/\\/$/, '');\n const match = sites.find(s => {\n const sp = s.sitePath.replace(/\\/$/, '');\n return sp === normalized || sp === normalized + '/' || normalized.startsWith(sp);\n });\n if (!match) {\n const available = sites.map(s => ` ${s.sitePath} (${s.appType})`).join('\\n');\n throw new Error(`No database credentials found at ${sitePath}.\\n\\nAvailable sites:\\n${available || ' (none found)'}`);\n }\n return match;\n}\n\nfunction escapeMysqlShell(value: string): string {\n return value.replace(/'/g, \"'\\\\''\");\n}\n\nconst BLOCKED_SQL_PATTERNS = [\n /\\bDROP\\s+DATABASE\\b/i,\n /\\bDROP\\s+TABLE\\b/i,\n /\\bDROP\\s+INDEX\\b/i,\n /\\bTRUNCATE\\b/i,\n /\\bALTER\\s+TABLE\\s+\\w+\\s+DROP\\b/i,\n /\\bDELETE\\s+FROM\\s+\\w+\\s*$/i,\n];\n\nfunction assertSafeSql(query: string): void {\n const trimmed = query.trim();\n for (const pattern of BLOCKED_SQL_PATTERNS) {\n if (pattern.test(trimmed)) {\n throw new Error(`Blocked destructive SQL pattern: ${pattern.source}`);\n }\n }\n}\n\nasync function execMysql(\n conn: SshConnectionOptions,\n creds: DbCredentials,\n query: string,\n useDatabase = true,\n): Promise<string> {\n const dbArg = useDatabase ? ` '${escapeMysqlShell(creds.database)}'` : '';\n const hostArg = creds.host !== 'localhost' ? ` --host='${escapeMysqlShell(creds.host)}'` : '';\n const portArg = creds.port !== 3306 ? ` --port=${creds.port}` : '';\n const cmd = `mysql --user='${escapeMysqlShell(creds.user)}' --password='${escapeMysqlShell(creds.password)}'${hostArg}${portArg} -t -e '${escapeMysqlShell(query)}'${dbArg} 2>&1 | grep -v \"\\\\[Warning\\\\].*password\"`;\n const result = await sshExec(conn, cmd);\n if (result.exitCode !== 0) {\n throw new Error(result.stdout || result.stderr || 'MySQL command failed');\n }\n return result.stdout.trim();\n}\n\n// ---------------------------------------------------------------------------\n// Tool definitions\n// ---------------------------------------------------------------------------\n\nconst TOOLS = [\n {\n name: 'list-servers',\n description: 'List all SSH servers you have access to. Returns id, name, hostname, and tags for each server.',\n inputSchema: { type: 'object' as const, properties: {}, required: [] },\n },\n {\n name: 'server-status',\n description: 'Get server status including uptime, disk usage, memory, and load average.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n },\n required: ['serverId'],\n },\n },\n {\n name: 'ssh-execute',\n description: 'Execute a shell command on a remote server via SSH. Some dangerous commands are blocked for safety.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n command: { type: 'string', description: 'Shell command to execute' },\n timeout: { type: 'number', description: 'Timeout in milliseconds (default: 60000)' },\n },\n required: ['serverId', 'command'],\n },\n },\n {\n name: 'server-reboot',\n description: 'Reboot a remote server. This will cause downtime. The server will be unavailable until it restarts.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server to reboot' },\n },\n required: ['serverId'],\n },\n },\n {\n name: 'server-restart-service',\n description: 'Restart a systemd service on a remote server using systemctl restart.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n serviceName: { type: 'string', description: 'Name of the systemd service (e.g. nginx, docker, lsws)' },\n },\n required: ['serverId', 'serviceName'],\n },\n },\n {\n name: 'sftp-list',\n description: 'List files and directories at a given path on a remote server via SFTP.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n path: { type: 'string', description: 'Directory path to list (default: /)' },\n },\n required: ['serverId'],\n },\n },\n {\n name: 'sftp-read',\n description: 'Read the contents of a text file on a remote server via SFTP (max 1MB).',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n path: { type: 'string', description: 'File path to read' },\n },\n required: ['serverId', 'path'],\n },\n },\n {\n name: 'sftp-write',\n description: 'Write content to a file on a remote server via SFTP. Protected system paths are blocked.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n path: { type: 'string', description: 'File path to write' },\n content: { type: 'string', description: 'File content to write' },\n },\n required: ['serverId', 'path', 'content'],\n },\n },\n {\n name: 'sftp-delete',\n description: 'Delete a file or empty directory on a remote server via SFTP. Protected system paths are blocked.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n path: { type: 'string', description: 'File or directory path to delete' },\n },\n required: ['serverId', 'path'],\n },\n },\n {\n name: 'docker-list',\n description: 'List all Docker containers on a remote server (running and stopped).',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n },\n required: ['serverId'],\n },\n },\n {\n name: 'docker-action',\n description: 'Perform an action on a Docker container: start, stop, restart, or remove.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n containerName: { type: 'string', description: 'Container name or ID' },\n action: { type: 'string', enum: ['start', 'stop', 'restart', 'remove'], description: 'Action to perform' },\n },\n required: ['serverId', 'containerName', 'action'],\n },\n },\n {\n name: 'docker-logs',\n description: 'Get recent logs from a Docker container.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n containerName: { type: 'string', description: 'Container name or ID' },\n lines: { type: 'number', description: 'Number of log lines to retrieve (default: 100)' },\n },\n required: ['serverId', 'containerName'],\n },\n },\n {\n name: 'db-discover',\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.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n },\n required: ['serverId'],\n },\n },\n {\n name: 'db-tables',\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).',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n sitePath: { type: 'string', description: 'Site root path (e.g. /var/www/example.com)' },\n },\n required: ['serverId', 'sitePath'],\n },\n },\n {\n name: 'db-describe',\n description: 'Show the structure of a database table (columns, types, keys, defaults). Credentials are auto-discovered from site config files.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n sitePath: { type: 'string', description: 'Site root path (e.g. /var/www/example.com)' },\n table: { type: 'string', description: 'Table name' },\n },\n required: ['serverId', 'sitePath', 'table'],\n },\n },\n {\n name: 'db-query',\n description: 'Execute a SQL query on a site database. Credentials are auto-discovered from site config files. Destructive operations (DROP, TRUNCATE) are blocked.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n serverId: { type: 'string', description: 'UUID of the SSH server' },\n sitePath: { type: 'string', description: 'Site root path (e.g. /var/www/example.com)' },\n query: { type: 'string', description: 'SQL query to execute' },\n },\n required: ['serverId', 'sitePath', 'query'],\n },\n },\n {\n name: 'env-list',\n description: 'List all stored environment configurations (app name, environment, description).',\n inputSchema: { type: 'object' as const, properties: {}, required: [] },\n },\n {\n name: 'env-get',\n description: 'Retrieve the decrypted .env content for a specific app and environment.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n appName: { type: 'string', description: 'Application name (e.g. backoffice, api, web)' },\n environment: { type: 'string', description: 'Environment name (e.g. production, staging, development)' },\n },\n required: ['appName', 'environment'],\n },\n },\n {\n name: 'env-store',\n description: 'Store or update an encrypted .env configuration for an app and environment.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n appName: { type: 'string', description: 'Application name (e.g. backoffice, api, web)' },\n environment: { type: 'string', description: 'Environment name (e.g. production, staging, development)' },\n content: { type: 'string', description: 'The .env file content to store' },\n description: { type: 'string', description: 'Optional description' },\n },\n required: ['appName', 'environment', 'content'],\n },\n },\n];\n\n// ---------------------------------------------------------------------------\n// MCP Server\n// ---------------------------------------------------------------------------\n\nconst server = new Server(\n { name: 'mg-dashboard-mcp', version: '1.3.0' },\n { capabilities: { tools: {} } },\n);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n if (!authContext) {\n return { content: [{ type: 'text', text: 'Error: not authenticated' }] };\n }\n\n const { name, arguments: toolArgs } = request.params;\n const a = (toolArgs || {}) as Record<string, unknown>;\n\n try {\n switch (name) {\n // ----- Servers -----\n case 'list-servers': {\n let query = supabase\n .from('ssh_server')\n .select('id, name, hostname, port, username, tags, hosted_by, created_at')\n .order('name');\n\n if (authContext.allowedServerIds !== null) {\n query = query.in('id', authContext.allowedServerIds);\n }\n\n const { data, error } = await query;\n if (error) throw new Error(error.message);\n\n const lines = (data || []).map(s => {\n const tags = Array.isArray(s.tags) ? (s.tags as string[]).join(', ') : '';\n return `${s.id} ${s.name} ${s.hostname}:${s.port} ${s.username} [${tags}] ${s.hosted_by || ''}`;\n });\n\n return { content: [{ type: 'text', text: lines.length ? lines.join('\\n') : 'No servers found' }] };\n }\n\n case 'server-status': {\n const conn = await getServerConnection(String(a.serverId));\n const cmd = 'echo \"=== UPTIME ===\" && uptime && echo \"=== DISK ===\" && df -h --total && echo \"=== MEMORY ===\" && free -h && echo \"=== LOAD ===\" && cat /proc/loadavg';\n const result = await sshExec(conn, cmd);\n const output = result.exitCode === 0 ? result.stdout : `Exit ${result.exitCode}\\n${result.stdout}\\n${result.stderr}`;\n return { content: [{ type: 'text', text: output }] };\n }\n\n // ----- SSH -----\n case 'ssh-execute': {\n const command = String(a.command);\n assertSafeCommand(command);\n const conn = await getServerConnection(String(a.serverId));\n if (a.timeout) conn.timeout = Number(a.timeout);\n const result = await sshExec(conn, command);\n const output = [`Exit code: ${result.exitCode}`];\n if (result.stdout) output.push(`--- stdout ---\\n${result.stdout}`);\n if (result.stderr) output.push(`--- stderr ---\\n${result.stderr}`);\n return { content: [{ type: 'text', text: output.join('\\n') }] };\n }\n\n case 'server-reboot': {\n const conn = await getServerConnection(String(a.serverId));\n const result = await sshExec(conn, 'sudo reboot');\n return { content: [{ type: 'text', text: result.exitCode === 0 ? 'Reboot command sent. Server will be unavailable shortly.' : `Reboot failed: ${result.stderr}` }] };\n }\n\n case 'server-restart-service': {\n const service = String(a.serviceName).replace(/[^a-zA-Z0-9._@-]/g, '');\n const conn = await getServerConnection(String(a.serverId));\n const result = await sshExec(conn, `sudo systemctl restart ${service}`);\n if (result.exitCode === 0) {\n const status = await sshExec(conn, `sudo systemctl is-active ${service}`);\n return { content: [{ type: 'text', text: `Service \"${service}\" restarted. Status: ${status.stdout.trim()}` }] };\n }\n return { content: [{ type: 'text', text: `Failed to restart \"${service}\": ${result.stderr}` }] };\n }\n\n // ----- SFTP -----\n case 'sftp-list': {\n const conn = await getServerConnection(String(a.serverId));\n const listing = await sftpReaddir(conn, String(a.path || '/'));\n return { content: [{ type: 'text', text: listing }] };\n }\n\n case 'sftp-read': {\n const conn = await getServerConnection(String(a.serverId));\n const content = await sftpRead(conn, String(a.path));\n return { content: [{ type: 'text', text: content }] };\n }\n\n case 'sftp-write': {\n const conn = await getServerConnection(String(a.serverId));\n const result = await sftpWrite(conn, String(a.path), String(a.content));\n return { content: [{ type: 'text', text: result }] };\n }\n\n case 'sftp-delete': {\n const conn = await getServerConnection(String(a.serverId));\n const result = await sftpDelete(conn, String(a.path));\n return { content: [{ type: 'text', text: result }] };\n }\n\n // ----- Docker -----\n case 'docker-list': {\n const conn = await getServerConnection(String(a.serverId));\n const result = await sshExec(conn, 'docker ps -a --format \"table {{.Names}}\\t{{.Image}}\\t{{.Status}}\\t{{.Ports}}\"');\n return { content: [{ type: 'text', text: result.exitCode === 0 ? result.stdout : `Error: ${result.stderr}` }] };\n }\n\n case 'docker-action': {\n const container = String(a.containerName).replace(/[^a-zA-Z0-9._-]/g, '');\n const action = String(a.action);\n if (!['start', 'stop', 'restart', 'remove'].includes(action)) {\n throw new Error(`Invalid action: ${action}. Use start, stop, restart, or remove.`);\n }\n const conn = await getServerConnection(String(a.serverId));\n const dockerCmd = action === 'remove' ? `docker rm -f ${container}` : `docker ${action} ${container}`;\n const result = await sshExec(conn, dockerCmd);\n return { content: [{ type: 'text', text: result.exitCode === 0 ? `Container \"${container}\" ${action}ed successfully` : `Error: ${result.stderr}` }] };\n }\n\n case 'docker-logs': {\n const container = String(a.containerName).replace(/[^a-zA-Z0-9._-]/g, '');\n const lines = Number(a.lines) || 100;\n const conn = await getServerConnection(String(a.serverId));\n const result = await sshExec(conn, `docker logs --tail ${lines} ${container} 2>&1`);\n return { content: [{ type: 'text', text: result.exitCode === 0 ? result.stdout : `Error: ${result.stderr}` }] };\n }\n\n // ----- Database -----\n case 'db-discover': {\n const conn = await getServerConnection(String(a.serverId));\n const sites = await discoverSiteDatabases(conn);\n if (!sites.length) {\n return { content: [{ type: 'text', text: 'No web applications with database configs found in /var/www/' }] };\n }\n const lines = sites.map(s =>\n `${s.sitePath} [${s.appType}] db=${s.database} user=${s.user} host=${s.host}:${s.port}`\n );\n return { content: [{ type: 'text', text: lines.join('\\n') }] };\n }\n\n case 'db-tables': {\n const conn = await getServerConnection(String(a.serverId));\n const creds = await getSiteDbCredentials(conn, String(a.sitePath));\n const query = `SELECT TABLE_NAME, ENGINE, TABLE_ROWS, ROUND(DATA_LENGTH/1024/1024, 2) AS 'Size (MB)', TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA = '${escapeMysqlShell(creds.database)}' ORDER BY TABLE_NAME`;\n const output = await execMysql(conn, creds, query, false);\n return { content: [{ type: 'text', text: output || 'No tables found' }] };\n }\n\n case 'db-describe': {\n const conn = await getServerConnection(String(a.serverId));\n const creds = await getSiteDbCredentials(conn, String(a.sitePath));\n const table = String(a.table).replace(/[^a-zA-Z0-9_]/g, '');\n const structure = await execMysql(conn, creds, `DESCRIBE \\`${table}\\``);\n const indexes = await execMysql(conn, creds, `SHOW INDEX FROM \\`${table}\\``);\n return { content: [{ type: 'text', text: `=== Columns ===\\n${structure}\\n\\n=== Indexes ===\\n${indexes}` }] };\n }\n\n case 'db-query': {\n const query = String(a.query).trim();\n assertSafeSql(query);\n const conn = await getServerConnection(String(a.serverId));\n const creds = await getSiteDbCredentials(conn, String(a.sitePath));\n const output = await execMysql(conn, creds, query);\n return { content: [{ type: 'text', text: output || 'Query executed successfully (no output)' }] };\n }\n\n // ----- Env Config -----\n case 'env-list': {\n const { data, error } = await supabase\n .from('env_config')\n .select('id, app_name, environment, description, updated_at')\n .order('app_name')\n .order('environment');\n\n if (error) throw new Error(error.message);\n const lines = (data || []).map(e =>\n `${e.app_name}/${e.environment} ${e.description || ''} (updated: ${e.updated_at})`\n );\n return { content: [{ type: 'text', text: lines.length ? lines.join('\\n') : 'No environment configs stored' }] };\n }\n\n case 'env-get': {\n const { data, error } = await supabase\n .from('env_config')\n .select('env_data_encrypted')\n .eq('app_name', String(a.appName))\n .eq('environment', String(a.environment))\n .single();\n\n if (error || !data) throw new Error(`Env config not found: ${a.appName}/${a.environment}`);\n const decrypted = decrypt(data.env_data_encrypted);\n return { content: [{ type: 'text', text: decrypted }] };\n }\n\n case 'env-store': {\n const appName = String(a.appName);\n const environment = String(a.environment);\n const encrypted = encrypt(String(a.content));\n\n const { data: existing } = await supabase\n .from('env_config')\n .select('id')\n .eq('app_name', appName)\n .eq('environment', environment)\n .single();\n\n if (existing) {\n const { error } = await supabase\n .from('env_config')\n .update({\n env_data_encrypted: encrypted,\n description: a.description ? String(a.description) : undefined,\n updated_by: authContext.userId,\n updated_at: new Date().toISOString(),\n })\n .eq('id', existing.id);\n if (error) throw new Error(error.message);\n return { content: [{ type: 'text', text: `Updated env config: ${appName}/${environment}` }] };\n }\n\n const { error } = await supabase.from('env_config').insert({\n app_name: appName,\n environment,\n env_data_encrypted: encrypted,\n description: a.description ? String(a.description) : null,\n created_by: authContext.userId,\n updated_by: authContext.userId,\n });\n if (error) throw new Error(error.message);\n return { content: [{ type: 'text', text: `Stored env config: ${appName}/${environment}` }] };\n }\n\n default:\n return { content: [{ type: 'text', text: `Unknown tool: ${name}` }] };\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { content: [{ type: 'text', text: `Error: ${message}` }] };\n }\n});\n\n// ---------------------------------------------------------------------------\n// Main\n// ---------------------------------------------------------------------------\n\nasync function main() {\n console.error('Starting MG Dashboard MCP Server...');\n\n authContext = await validateApiKey(apiKey!);\n if (!authContext) {\n console.error('API key validation failed');\n process.exit(1);\n }\n\n console.error('API key validated. Starting stdio transport...');\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n console.error('MCP Server ready. Tools available: ' + TOOLS.map(t => t.name).join(', '));\n}\n\nmain().catch((err) => {\n console.error('Fatal error:', err);\n process.exit(1);\n});\n"]}
|
|
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\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// 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];\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.5.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 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,46 +1,46 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@mgsoftwarebv/mg-dashboard-mcp",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "MCP Server for MG Dashboard - SSH, SFTP, Docker, and environment config tools for Cursor",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"mg-dashboard-mcp": "dist/index.js"
|
|
9
|
-
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsup",
|
|
12
|
-
"dev": "tsup --watch",
|
|
13
|
-
"start": "node dist/index.js",
|
|
14
|
-
"typecheck": "tsc --noEmit"
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"mcp",
|
|
18
|
-
"dashboard",
|
|
19
|
-
"ssh",
|
|
20
|
-
"sftp",
|
|
21
|
-
"docker",
|
|
22
|
-
"cursor",
|
|
23
|
-
"mg-software"
|
|
24
|
-
],
|
|
25
|
-
"author": "MG Software B.V. <info@mgsoftware.nl> (https://www.mgsoftware.nl)",
|
|
26
|
-
"license": "MIT",
|
|
27
|
-
"homepage": "https://www.mgsoftware.nl",
|
|
28
|
-
"dependencies": {
|
|
29
|
-
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
30
|
-
"@supabase/supabase-js": "^2.50.0",
|
|
31
|
-
"ssh2": "^1.15.0"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"@types/node": "^20.0.0",
|
|
35
|
-
"@types/ssh2": "^1.15.0",
|
|
36
|
-
"tsup": "^8.0.0",
|
|
37
|
-
"typescript": "^5.0.0"
|
|
38
|
-
},
|
|
39
|
-
"files": [
|
|
40
|
-
"dist"
|
|
41
|
-
],
|
|
42
|
-
"publishConfig": {
|
|
43
|
-
"access": "public",
|
|
44
|
-
"registry": "https://registry.npmjs.org/"
|
|
45
|
-
}
|
|
46
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@mgsoftwarebv/mg-dashboard-mcp",
|
|
3
|
+
"version": "1.5.0",
|
|
4
|
+
"description": "MCP Server for MG Dashboard - SSH, SFTP, Docker, and environment config tools for Cursor",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mg-dashboard-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"dev": "tsup --watch",
|
|
13
|
+
"start": "node dist/index.js",
|
|
14
|
+
"typecheck": "tsc --noEmit"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mcp",
|
|
18
|
+
"dashboard",
|
|
19
|
+
"ssh",
|
|
20
|
+
"sftp",
|
|
21
|
+
"docker",
|
|
22
|
+
"cursor",
|
|
23
|
+
"mg-software"
|
|
24
|
+
],
|
|
25
|
+
"author": "MG Software B.V. <info@mgsoftware.nl> (https://www.mgsoftware.nl)",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"homepage": "https://www.mgsoftware.nl",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
30
|
+
"@supabase/supabase-js": "^2.50.0",
|
|
31
|
+
"ssh2": "^1.15.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^20.0.0",
|
|
35
|
+
"@types/ssh2": "^1.15.0",
|
|
36
|
+
"tsup": "^8.0.0",
|
|
37
|
+
"typescript": "^5.0.0"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist"
|
|
41
|
+
],
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public",
|
|
44
|
+
"registry": "https://registry.npmjs.org/"
|
|
45
|
+
}
|
|
46
|
+
}
|