ssh-mcp 1.4.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/README.md +2 -0
- package/build/index.js +16 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,11 +44,13 @@
|
|
|
44
44
|
- `exec`: Execute a shell command on the remote server
|
|
45
45
|
- **Parameters:**
|
|
46
46
|
- `command` (required): Shell command to execute on the remote SSH server
|
|
47
|
+
- `description` (optional): Optional description of what this command will do (appended as a comment)
|
|
47
48
|
- **Timeout Configuration:**
|
|
48
49
|
|
|
49
50
|
- `sudo-exec`: Execute a shell command with sudo elevation
|
|
50
51
|
- **Parameters:**
|
|
51
52
|
- `command` (required): Shell command to execute as root using sudo
|
|
53
|
+
- `description` (optional): Optional description of what this command will do (appended as a comment)
|
|
52
54
|
- **Notes:**
|
|
53
55
|
- Requires `--sudoPassword` to be set for password-protected sudo
|
|
54
56
|
- Can be disabled by passing the `--disableSudo` flag at startup if sudo access is not needed or not available
|
package/build/index.js
CHANGED
|
@@ -302,7 +302,7 @@ export class SSHConnectionManager {
|
|
|
302
302
|
let connectionManager = null;
|
|
303
303
|
const server = new McpServer({
|
|
304
304
|
name: 'SSH MCP Server',
|
|
305
|
-
version: '1.
|
|
305
|
+
version: '1.5.0',
|
|
306
306
|
capabilities: {
|
|
307
307
|
resources: {},
|
|
308
308
|
tools: {},
|
|
@@ -310,7 +310,8 @@ const server = new McpServer({
|
|
|
310
310
|
});
|
|
311
311
|
server.tool("exec", "Execute a shell command on the remote SSH server and return the output.", {
|
|
312
312
|
command: z.string().describe("Shell command to execute on the remote SSH server"),
|
|
313
|
-
|
|
313
|
+
description: z.string().optional().describe("Optional description of what this command will do"),
|
|
314
|
+
}, async ({ command, description }) => {
|
|
314
315
|
// Sanitize command input
|
|
315
316
|
const sanitizedCommand = sanitizeCommand(command);
|
|
316
317
|
try {
|
|
@@ -354,7 +355,11 @@ server.tool("exec", "Execute a shell command on the remote SSH server and return
|
|
|
354
355
|
// Log but don't fail; fall back to non-elevated execution if elevation times out
|
|
355
356
|
}
|
|
356
357
|
}
|
|
357
|
-
|
|
358
|
+
// Append description as comment if provided
|
|
359
|
+
const commandWithDescription = description
|
|
360
|
+
? `${sanitizedCommand} # ${description.replace(/#/g, '\\#')}`
|
|
361
|
+
: sanitizedCommand;
|
|
362
|
+
const result = await execSshCommandWithConnection(connectionManager, commandWithDescription);
|
|
358
363
|
return result;
|
|
359
364
|
}
|
|
360
365
|
catch (err) {
|
|
@@ -368,7 +373,8 @@ server.tool("exec", "Execute a shell command on the remote SSH server and return
|
|
|
368
373
|
if (!DISABLE_SUDO) {
|
|
369
374
|
server.tool("sudo-exec", "Execute a shell command on the remote SSH server using sudo. Will use sudo password if provided, otherwise assumes passwordless sudo.", {
|
|
370
375
|
command: z.string().describe("Shell command to execute with sudo on the remote SSH server"),
|
|
371
|
-
|
|
376
|
+
description: z.string().optional().describe("Optional description of what this command will do"),
|
|
377
|
+
}, async ({ command, description }) => {
|
|
372
378
|
const sanitizedCommand = sanitizeCommand(command);
|
|
373
379
|
try {
|
|
374
380
|
if (!connectionManager) {
|
|
@@ -409,15 +415,19 @@ if (!DISABLE_SUDO) {
|
|
|
409
415
|
}
|
|
410
416
|
let wrapped;
|
|
411
417
|
const sudoPassword = connectionManager.getSudoPassword();
|
|
418
|
+
// Append description as comment if provided
|
|
419
|
+
const commandWithDescription = description
|
|
420
|
+
? `${sanitizedCommand} # ${description.replace(/#/g, '\\#')}`
|
|
421
|
+
: sanitizedCommand;
|
|
412
422
|
if (!sudoPassword) {
|
|
413
423
|
// No password provided, use -n to fail if sudo requires a password
|
|
414
|
-
wrapped = `sudo -n sh -c '${
|
|
424
|
+
wrapped = `sudo -n sh -c '${commandWithDescription.replace(/'/g, "'\\''")}'`;
|
|
415
425
|
}
|
|
416
426
|
else {
|
|
417
427
|
// Password provided — pipe it into sudo using printf. This avoids complex
|
|
418
428
|
// PTY/stdin handling on the SSH channel and is simpler and more reliable.
|
|
419
429
|
const pwdEscaped = sudoPassword.replace(/'/g, "'\\''");
|
|
420
|
-
wrapped = `printf '%s\\n' '${pwdEscaped}' | sudo -p "" -S sh -c '${
|
|
430
|
+
wrapped = `printf '%s\\n' '${pwdEscaped}' | sudo -p "" -S sh -c '${commandWithDescription.replace(/'/g, "'\\''")}'`;
|
|
421
431
|
}
|
|
422
432
|
return await execSshCommandWithConnection(connectionManager, wrapped);
|
|
423
433
|
}
|