@aaarc/handfree-ssh-mcp 1.0.3 → 1.0.4
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.
|
@@ -148,6 +148,12 @@ function buildYamlServerConfig(name, serverConfig, options = {}) {
|
|
|
148
148
|
if (serverConfig.blacklist !== undefined) {
|
|
149
149
|
merged.commandBlacklist = serverConfig.blacklist ?? undefined;
|
|
150
150
|
}
|
|
151
|
+
if (serverConfig.disableBuiltinGuards !== undefined) {
|
|
152
|
+
merged.disableBuiltinGuards = serverConfig.disableBuiltinGuards === true;
|
|
153
|
+
}
|
|
154
|
+
if (serverConfig.disableBuiltinBlacklist !== undefined) {
|
|
155
|
+
merged.disableBuiltinBlacklist = serverConfig.disableBuiltinBlacklist === true;
|
|
156
|
+
}
|
|
151
157
|
if (serverConfig.safeDirectory !== undefined) {
|
|
152
158
|
merged.safeDirectory = serverConfig.safeDirectory ?? undefined;
|
|
153
159
|
}
|
|
@@ -175,6 +181,8 @@ function mergeConfigMaps(sshConfigs, yamlConfigs) {
|
|
|
175
181
|
commandMode: yamlConfig.commandMode ?? merged[name]?.commandMode,
|
|
176
182
|
commandWhitelist: yamlConfig.commandWhitelist ?? merged[name]?.commandWhitelist,
|
|
177
183
|
commandBlacklist: yamlConfig.commandBlacklist ?? merged[name]?.commandBlacklist,
|
|
184
|
+
disableBuiltinGuards: yamlConfig.disableBuiltinGuards ?? merged[name]?.disableBuiltinGuards,
|
|
185
|
+
disableBuiltinBlacklist: yamlConfig.disableBuiltinBlacklist ?? merged[name]?.disableBuiltinBlacklist,
|
|
178
186
|
safeDirectory: yamlConfig.safeDirectory ?? merged[name]?.safeDirectory,
|
|
179
187
|
};
|
|
180
188
|
}
|
package/build/config/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const SERVER_CONFIG = {
|
|
2
2
|
name: "ssh-mcp-server",
|
|
3
|
-
version: "1.0.
|
|
3
|
+
version: "1.0.4",
|
|
4
4
|
};
|
|
5
5
|
export const SERVER_INSTRUCTIONS = `This server provides SSH access to servers loaded from OpenSSH config (~/.ssh/config by default) and optional YAML config/policy overlays.
|
|
6
6
|
|
|
@@ -29,23 +29,10 @@ export const BUILT_IN_COMMAND_BLACKLIST = [
|
|
|
29
29
|
{ regex: /\bRemove-Item\b(?=.*\s-Recurse(?:\s|$))(?=.*\s-Force(?:\s|$))/i, reason: "recursive force Remove-Item" },
|
|
30
30
|
{ regex: /^\s*(?:del|erase|rd)\b(?=.*(?:\/s\b|\s-Recurse(?:\s|$)))(?=.*(?:\/q\b|\s-Force(?:\s|$)))/i, reason: "recursive quiet Windows delete" },
|
|
31
31
|
{ regex: /^\s*(?:sudo\s+)?rmdir\s+(?:\/|\*|~|\$HOME|%USERPROFILE%|[A-Za-z]:\\)(?:\s|$)/i, reason: "dangerous rmdir target" },
|
|
32
|
-
{ regex: /^\s*(?:sudo\s+)?dd\b.*\bof=/i, reason: "dd with of= (can overwrite devices/files)" },
|
|
33
|
-
{ regex: /^\s*(?:sudo\s+)?mkfs(?:\.\S+)?\b/i, reason: "filesystem formatting command" },
|
|
34
|
-
{ regex: /^\s*(?:sudo\s+)?(?:diskpart|format)(?:\s|$)/i, reason: "disk formatting command" },
|
|
35
|
-
{ regex: /\b(?:Format-Volume|Clear-Disk|Remove-Partition)\b/i, reason: "Windows disk destructive command" },
|
|
36
32
|
{ regex: /^\s*(?:sudo\s+)?chmod\s+-R\s+777\b/i, reason: "recursive world-writable chmod" },
|
|
37
33
|
{ regex: /^\s*(?:sudo\s+)?chown\s+-R\s+\S+\s+\/(?:\s|$)/i, reason: "recursive chown on root" },
|
|
38
34
|
];
|
|
39
35
|
export const BUILT_IN_DESTRUCTIVE_GUARDS = [
|
|
40
|
-
{ regex: /\brm\b/, reason: "rm in command chain" },
|
|
41
|
-
{ regex: /\brmdir\b/, reason: "rmdir in command chain" },
|
|
42
|
-
{ regex: /\bunlink\b/, reason: "unlink in command chain" },
|
|
43
|
-
{ regex: /\bshred\b/, reason: "shred in command chain" },
|
|
44
|
-
{ regex: /\btruncate\b/, reason: "truncate in command chain" },
|
|
45
|
-
{ regex: /-delete\b/, reason: "find -delete detected" },
|
|
46
|
-
{ regex: /-exec\s+rm\b/, reason: "find -exec rm detected" },
|
|
47
|
-
{ regex: /\bmv\b/, reason: "mv detected (can overwrite)" },
|
|
48
|
-
{ regex: /\bcp\b.*-f/, reason: "cp -f detected (force overwrite)" },
|
|
49
36
|
{ regex: /(?<![0-9])>\s*\/(?!dev\/null)/, reason: "output redirection to absolute path" },
|
|
50
37
|
{ regex: />\s*~/, reason: "output redirection to home path" },
|
|
51
38
|
];
|
|
@@ -824,7 +811,9 @@ export class SSHConnectionManager {
|
|
|
824
811
|
|| (config.username
|
|
825
812
|
? (config.username === 'root' ? '/root' : `/home/${config.username}`)
|
|
826
813
|
: SSHConnectionManager.DEFAULT_SAFE_DIRECTORY);
|
|
827
|
-
const destructiveReason =
|
|
814
|
+
const destructiveReason = config.disableBuiltinGuards
|
|
815
|
+
? null
|
|
816
|
+
: this.getDestructiveMatch(command);
|
|
828
817
|
if (destructiveReason) {
|
|
829
818
|
// Command contains rm/rmdir - check if it's a simple rm command or hidden in a chain
|
|
830
819
|
const trimmed = command.trim();
|
|
@@ -852,13 +841,15 @@ export class SSHConnectionManager {
|
|
|
852
841
|
// ========================================
|
|
853
842
|
// LAYER 2: Built-in blacklist for high-risk operations
|
|
854
843
|
// ========================================
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
844
|
+
if (!config.disableBuiltinBlacklist) {
|
|
845
|
+
for (const { regex, reason } of BUILT_IN_COMMAND_BLACKLIST) {
|
|
846
|
+
if (regex.test(command)) {
|
|
847
|
+
Logger.log(`Command blocked by built-in blacklist (${reason}): ${command}`, "info");
|
|
848
|
+
return {
|
|
849
|
+
isAllowed: false,
|
|
850
|
+
reason: `Command blocked by built-in blacklist: ${reason}`,
|
|
851
|
+
};
|
|
852
|
+
}
|
|
862
853
|
}
|
|
863
854
|
}
|
|
864
855
|
// ========================================
|
package/package.json
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@aaarc/handfree-ssh-mcp",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Handfree SSH MCP Server - A hands-free SSH automation tool via MCP protocol",
|
|
5
|
-
"main": "build/index.js",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"handfree-ssh-mcp": "build/index.js"
|
|
9
|
-
},
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/Ironboxplus/handfree-ssh-mcp.git"
|
|
13
|
-
},
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://github.com/Ironboxplus/handfree-ssh-mcp/issues"
|
|
16
|
-
},
|
|
17
|
-
"homepage": "https://github.com/Ironboxplus/handfree-ssh-mcp#readme",
|
|
18
|
-
"publishConfig": {
|
|
19
|
-
"access": "public"
|
|
20
|
-
},
|
|
21
|
-
"scripts": {
|
|
22
|
-
"test": "npm run build && node --test build/tests/config.test.js build/tests/command-validation.test.js build/tests/tool-error.test.js build/tests/tools.test.js build/tests/output-collector.test.js build/tests/output-log-writer.test.js build/tests/recent-fixes.test.js",
|
|
23
|
-
"test:config": "npm run build && node --test build/tests/config.test.js",
|
|
24
|
-
"test:cmd": "npm run build && node --test build/tests/command-validation.test.js",
|
|
25
|
-
"test:tools": "npm run build && node --test build/tests/tools.test.js",
|
|
26
|
-
"test:integration": "npm run build && node build/tests/integration.test.js",
|
|
27
|
-
"test:all": "npm run test && npm run test:integration",
|
|
28
|
-
"build": "node scripts/build.js",
|
|
29
|
-
"prepublishOnly": "npm run build"
|
|
30
|
-
},
|
|
31
|
-
"keywords": [
|
|
32
|
-
"ssh",
|
|
33
|
-
"mcp",
|
|
34
|
-
"server",
|
|
35
|
-
"cli"
|
|
36
|
-
],
|
|
37
|
-
"author": "Junki",
|
|
38
|
-
"license": "ISC",
|
|
39
|
-
"dependencies": {
|
|
40
|
-
"@modelcontextprotocol/sdk": "1.17.5",
|
|
41
|
-
"js-yaml": "^4.1.0",
|
|
42
|
-
"socks": "^2.8.6",
|
|
43
|
-
"ssh2": "^1.16.0",
|
|
44
|
-
"zod": "^3.24.2"
|
|
45
|
-
},
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"@types/js-yaml": "^4.0.9",
|
|
48
|
-
"@types/node": "^22.13.10",
|
|
49
|
-
"@types/ssh2": "^1.15.5",
|
|
50
|
-
"typescript": "^5.8.2"
|
|
51
|
-
},
|
|
52
|
-
"files": [
|
|
53
|
-
"build/config/**/*",
|
|
54
|
-
"build/core/**/*",
|
|
55
|
-
"build/models/**/*",
|
|
56
|
-
"build/services/**/*",
|
|
57
|
-
"build/tools/**/*",
|
|
58
|
-
"build/utils/**/*",
|
|
59
|
-
"build/index.js"
|
|
60
|
-
]
|
|
61
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@aaarc/handfree-ssh-mcp",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "Handfree SSH MCP Server - A hands-free SSH automation tool via MCP protocol",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"handfree-ssh-mcp": "build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/Ironboxplus/handfree-ssh-mcp.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/Ironboxplus/handfree-ssh-mcp/issues"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/Ironboxplus/handfree-ssh-mcp#readme",
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"test": "npm run build && node --test build/tests/config.test.js build/tests/command-validation.test.js build/tests/tool-error.test.js build/tests/tools.test.js build/tests/output-collector.test.js build/tests/output-log-writer.test.js build/tests/recent-fixes.test.js",
|
|
23
|
+
"test:config": "npm run build && node --test build/tests/config.test.js",
|
|
24
|
+
"test:cmd": "npm run build && node --test build/tests/command-validation.test.js",
|
|
25
|
+
"test:tools": "npm run build && node --test build/tests/tools.test.js",
|
|
26
|
+
"test:integration": "npm run build && node build/tests/integration.test.js",
|
|
27
|
+
"test:all": "npm run test && npm run test:integration",
|
|
28
|
+
"build": "node scripts/build.js",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"ssh",
|
|
33
|
+
"mcp",
|
|
34
|
+
"server",
|
|
35
|
+
"cli"
|
|
36
|
+
],
|
|
37
|
+
"author": "Junki",
|
|
38
|
+
"license": "ISC",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "1.17.5",
|
|
41
|
+
"js-yaml": "^4.1.0",
|
|
42
|
+
"socks": "^2.8.6",
|
|
43
|
+
"ssh2": "^1.16.0",
|
|
44
|
+
"zod": "^3.24.2"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/js-yaml": "^4.0.9",
|
|
48
|
+
"@types/node": "^22.13.10",
|
|
49
|
+
"@types/ssh2": "^1.15.5",
|
|
50
|
+
"typescript": "^5.8.2"
|
|
51
|
+
},
|
|
52
|
+
"files": [
|
|
53
|
+
"build/config/**/*",
|
|
54
|
+
"build/core/**/*",
|
|
55
|
+
"build/models/**/*",
|
|
56
|
+
"build/services/**/*",
|
|
57
|
+
"build/tools/**/*",
|
|
58
|
+
"build/utils/**/*",
|
|
59
|
+
"build/index.js"
|
|
60
|
+
]
|
|
61
|
+
}
|