@jadchene/mcp-ssh-service 1.4.0 → 1.4.2

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 CHANGED
@@ -189,17 +189,31 @@ args = ["--config", "./config.json"]
189
189
  * `cd`
190
190
  * `execute_batch` [Auth Required if any sub-command is high-risk]
191
191
 
192
+ ### System (9)
193
+ * `get_system_info`
194
+ * `hostname`
195
+ * `id`
196
+ * `uname`
197
+ * `uptime`
198
+ * `free`
199
+ * `env`
200
+ * `pwd`
201
+ * `cd`
202
+
192
203
  ### Shell & Basic (2)
193
204
  * `execute_command` [Auth Required, single command only]
194
205
  * `echo`
195
206
 
196
- ### File Management (15)
207
+ ### File Management (18)
197
208
  * `upload_file` [Auth Required]
198
209
  * `download_file`
199
210
  * `ll`
200
211
  * `cat`
212
+ * `head`
201
213
  * `tail`
214
+ * `sed`
202
215
  * `grep`
216
+ * `grep_r`
203
217
  * `edit_text_file` [Auth Required]
204
218
  * `touch`
205
219
  * `mkdir` [Auth Required]
@@ -218,12 +232,16 @@ args = ["--config", "./config.json"]
218
232
  * `git_branch`
219
233
  * `git_log`
220
234
 
221
- ### Docker & Compose (21)
235
+ ### Docker & Compose (26)
222
236
  * `docker_compose_up` [Auth Required]
223
237
  * `docker_compose_down` [Auth Required]
224
238
  * `docker_compose_stop` [Auth Required]
225
239
  * `docker_compose_logs`
226
240
  * `docker_compose_restart` [Auth Required]
241
+ * `docker_compose_pull` [Auth Required]
242
+ * `docker_compose_ps`
243
+ * `docker_compose_config`
244
+ * `docker_compose_exec` [Auth Required]
227
245
  * `docker_ps`
228
246
  * `docker_images`
229
247
  * `docker_exec` [Auth Required]
@@ -240,13 +258,18 @@ args = ["--config", "./config.json"]
240
258
  * `docker_logs`
241
259
  * `docker_load` [Auth Required]
242
260
  * `docker_save` [Auth Required]
261
+ * `docker_build` [Auth Required, supports `networkHost` for `--network=host`]
243
262
 
244
- ### Service & Network (14)
263
+ ### Service & Network (18)
245
264
  * `systemctl_status`
246
265
  * `systemctl_restart` [Auth Required]
247
266
  * `systemctl_start` [Auth Required]
248
267
  * `systemctl_stop` [Auth Required]
268
+ * `systemctl_enable` [Auth Required]
269
+ * `systemctl_disable` [Auth Required]
249
270
  * `ip_addr`
271
+ * `ip_route`
272
+ * `mount`
250
273
  * `journalctl`
251
274
  * `firewall_cmd` [Auth Required, structured actions only]
252
275
  * `netstat` [uses `args: string[]`]
@@ -257,13 +280,18 @@ args = ["--config", "./config.json"]
257
280
  * `dig`
258
281
  * `curl_http` [Auth Required]
259
282
 
260
- ### Stats & Process (13)
283
+ ### Stats & Process (19)
261
284
  * `nvidia_smi`
262
285
  * `ps`
263
286
  * `pgrep`
264
287
  * `kill_process` [Auth Required]
265
288
  * `df_h`
289
+ * `df_inode`
266
290
  * `du_sh`
291
+ * `which`
292
+ * `lsof`
293
+ * `file`
294
+ * `stat`
267
295
  * `chmod` [Auth Required]
268
296
  * `chown` [Auth Required]
269
297
  * `ln` [Auth Required]
@@ -272,7 +300,7 @@ args = ["--config", "./config.json"]
272
300
  * `zip` [Auth Required]
273
301
  * `unzip` [Auth Required]
274
302
 
275
- Total: 79 tools.
303
+ Total: 103 tools.
276
304
 
277
305
  ---
278
306
 
@@ -42,6 +42,36 @@ export const toolDefinitions = [
42
42
  description: 'System health check: Returns current user, system uptime, kernel, and memory.',
43
43
  inputSchema: baseParams()
44
44
  },
45
+ {
46
+ name: 'hostname',
47
+ description: 'Show the current host name.',
48
+ inputSchema: baseParams(grepParam)
49
+ },
50
+ {
51
+ name: 'id',
52
+ description: 'Show current user identity and group information.',
53
+ inputSchema: baseParams(grepParam)
54
+ },
55
+ {
56
+ name: 'uname',
57
+ description: 'Show kernel and operating system information.',
58
+ inputSchema: baseParams({ all: { type: 'boolean' }, ...grepParam })
59
+ },
60
+ {
61
+ name: 'uptime',
62
+ description: 'Show system uptime and load averages.',
63
+ inputSchema: baseParams(grepParam)
64
+ },
65
+ {
66
+ name: 'free',
67
+ description: 'Show memory usage in megabytes.',
68
+ inputSchema: baseParams(grepParam)
69
+ },
70
+ {
71
+ name: 'env',
72
+ description: 'Show environment variables visible to the remote session.',
73
+ inputSchema: baseParams(grepParam)
74
+ },
45
75
  {
46
76
  name: 'pwd',
47
77
  description: 'Current path: Returns the absolute path of the current directory on remote.',
@@ -108,23 +138,52 @@ export const toolDefinitions = [
108
138
  {
109
139
  name: 'll',
110
140
  description: 'Directory listing: Lists files in a directory with detailed information.',
111
- inputSchema: baseParams({ ...cwdParam, ...grepParam })
141
+ inputSchema: baseParams({ ...cwdParam, all: { type: 'boolean' }, ...grepParam })
112
142
  },
113
143
  {
114
144
  name: 'cat',
115
145
  description: 'File reading: Reads text file content.',
116
146
  inputSchema: baseParams({ filePath: { type: 'string' }, ...grepParam }, ['filePath'])
117
147
  },
148
+ {
149
+ name: 'head',
150
+ description: 'File preview: Reads the first N lines of a file.',
151
+ inputSchema: baseParams({ filePath: { type: 'string' }, lines: { type: 'number' }, ...grepParam }, ['filePath'])
152
+ },
118
153
  {
119
154
  name: 'tail',
120
155
  description: 'Log inspection: Reads last N lines of a file.',
121
156
  inputSchema: baseParams({ filePath: { type: 'string' }, lines: { type: 'number' }, ...grepParam }, ['filePath'])
122
157
  },
158
+ {
159
+ name: 'sed',
160
+ description: 'Line range reading: Reads an inclusive line range from a text file.',
161
+ inputSchema: baseParams({
162
+ filePath: { type: 'string' },
163
+ startLine: { type: 'number' },
164
+ endLine: { type: 'number' },
165
+ ...grepParam
166
+ }, ['filePath', 'startLine', 'endLine'])
167
+ },
123
168
  {
124
169
  name: 'grep',
125
170
  description: 'Pattern search: Search for a regex pattern in a file.',
126
171
  inputSchema: baseParams({ filePath: { type: 'string' }, pattern: { type: 'string' }, ignoreCase: { type: 'boolean' } }, ['filePath', 'pattern'])
127
172
  },
173
+ {
174
+ name: 'grep_r',
175
+ description: 'Recursive pattern search: Search for a regex pattern across files under a directory tree.',
176
+ inputSchema: baseParams({
177
+ path: { type: 'string' },
178
+ pattern: { type: 'string' },
179
+ ignoreCase: { type: 'boolean' },
180
+ beforeContext: { type: 'number' },
181
+ afterContext: { type: 'number' },
182
+ context: { type: 'number' },
183
+ include: { type: 'array', items: { type: 'string' } },
184
+ excludeDir: { type: 'array', items: { type: 'string' } }
185
+ }, ['path', 'pattern'])
186
+ },
128
187
  {
129
188
  name: 'edit_text_file',
130
189
  description: 'File creation/overwrite: Completely replaces file content. REQUIRES CONFIRMATION.',
@@ -172,7 +231,14 @@ export const toolDefinitions = [
172
231
  {
173
232
  name: 'find',
174
233
  description: 'Search for files in a directory hierarchy.',
175
- inputSchema: baseParams({ path: { type: 'string' }, name: { type: 'string' }, ...grepParam }, ['path'])
234
+ inputSchema: baseParams({
235
+ path: { type: 'string' },
236
+ name: { type: 'string' },
237
+ type: { type: 'string', enum: ['f', 'd', 'l'] },
238
+ maxDepth: { type: 'number' },
239
+ pathPattern: { type: 'string' },
240
+ ...grepParam
241
+ }, ['path'])
176
242
  },
177
243
  // --- Git ---
178
244
  {
@@ -231,6 +297,33 @@ export const toolDefinitions = [
231
297
  description: 'Restart compose stack. REQUIRES CONFIRMATION.',
232
298
  inputSchema: baseParams({ ...cwdParam, ...confirmationParams }, ['cwd'])
233
299
  },
300
+ {
301
+ name: 'docker_compose_pull',
302
+ description: 'Pull images defined by the compose stack. REQUIRES CONFIRMATION.',
303
+ inputSchema: baseParams({ ...cwdParam, service: { type: 'string' }, ...confirmationParams }, ['cwd'])
304
+ },
305
+ {
306
+ name: 'docker_compose_ps',
307
+ description: 'List compose services and their current state.',
308
+ inputSchema: baseParams({ ...cwdParam, service: { type: 'string' }, ...grepParam }, ['cwd'])
309
+ },
310
+ {
311
+ name: 'docker_compose_config',
312
+ description: 'Render the fully resolved compose configuration for inspection.',
313
+ inputSchema: baseParams({ ...cwdParam, ...grepParam }, ['cwd'])
314
+ },
315
+ {
316
+ name: 'docker_compose_exec',
317
+ description: 'Run one process inside a compose service container without shell expansion. REQUIRES CONFIRMATION unless the final command is whitelisted.',
318
+ inputSchema: baseParams({
319
+ ...cwdParam,
320
+ service: { type: 'string' },
321
+ command: { type: 'string' },
322
+ args: { type: 'array', items: { type: 'string' } },
323
+ user: { type: 'string' },
324
+ ...confirmationParams
325
+ }, ['cwd', 'service', 'command'])
326
+ },
234
327
  {
235
328
  name: 'docker_ps',
236
329
  description: 'List docker containers.',
@@ -311,6 +404,20 @@ export const toolDefinitions = [
311
404
  description: 'Save one or more images to a tar archive. REQUIRES CONFIRMATION.',
312
405
  inputSchema: baseParams({ image: { type: 'string' }, path: { type: 'string' }, ...confirmationParams }, ['image', 'path'])
313
406
  },
407
+ {
408
+ name: 'docker_build',
409
+ description: 'Build a docker image from a build context. Supports options such as tag, dockerfile, build args, no-cache, and fixed host networking. REQUIRES CONFIRMATION unless the final command is whitelisted.',
410
+ inputSchema: baseParams({
411
+ ...cwdParam,
412
+ context: { type: 'string' },
413
+ tag: { type: 'string' },
414
+ dockerfile: { type: 'string' },
415
+ buildArgs: { type: 'array', items: { type: 'string' } },
416
+ noCache: { type: 'boolean' },
417
+ networkHost: { type: 'boolean' },
418
+ ...confirmationParams
419
+ }, ['context'])
420
+ },
314
421
  // --- Service & Network (Requirements) ---
315
422
  {
316
423
  name: 'systemctl_status',
@@ -332,15 +439,43 @@ export const toolDefinitions = [
332
439
  description: 'Stop system service. REQUIRES CONFIRMATION.',
333
440
  inputSchema: baseParams({ service: { type: 'string' }, ...confirmationParams }, ['service'])
334
441
  },
442
+ {
443
+ name: 'systemctl_enable',
444
+ description: 'Enable system service at boot. REQUIRES CONFIRMATION unless the final command is whitelisted.',
445
+ inputSchema: baseParams({ service: { type: 'string' }, ...confirmationParams }, ['service'])
446
+ },
447
+ {
448
+ name: 'systemctl_disable',
449
+ description: 'Disable system service at boot. REQUIRES CONFIRMATION unless the final command is whitelisted.',
450
+ inputSchema: baseParams({ service: { type: 'string' }, ...confirmationParams }, ['service'])
451
+ },
335
452
  {
336
453
  name: 'ip_addr',
337
454
  description: 'Show network interface info.',
338
455
  inputSchema: baseParams(grepParam)
339
456
  },
457
+ {
458
+ name: 'ip_route',
459
+ description: 'Show routing table information.',
460
+ inputSchema: baseParams(grepParam)
461
+ },
462
+ {
463
+ name: 'mount',
464
+ description: 'Show mounted filesystems.',
465
+ inputSchema: baseParams(grepParam)
466
+ },
340
467
  {
341
468
  name: 'journalctl',
342
- description: 'Read systemd journal logs with optional unit, since, and priority filters.',
343
- inputSchema: baseParams({ unit: { type: 'string' }, lines: { type: 'number' }, since: { type: 'string' }, priority: { type: 'string' }, grep: { type: 'string' } })
469
+ description: 'Read systemd journal logs with optional unit, since, until, priority, and follow filters.',
470
+ inputSchema: baseParams({
471
+ unit: { type: 'string' },
472
+ lines: { type: 'number' },
473
+ since: { type: 'string' },
474
+ until: { type: 'string' },
475
+ priority: { type: 'string' },
476
+ follow: { type: 'boolean' },
477
+ grep: { type: 'string' }
478
+ })
344
479
  },
345
480
  {
346
481
  name: 'firewall_cmd',
@@ -415,11 +550,41 @@ export const toolDefinitions = [
415
550
  description: 'System disk usage.',
416
551
  inputSchema: baseParams(grepParam)
417
552
  },
553
+ {
554
+ name: 'df_inode',
555
+ description: 'Filesystem inode usage.',
556
+ inputSchema: baseParams(grepParam)
557
+ },
418
558
  {
419
559
  name: 'du_sh',
420
560
  description: 'Directory size estimation.',
421
561
  inputSchema: baseParams({ path: { type: 'string' }, ...grepParam }, ['path'])
422
562
  },
563
+ {
564
+ name: 'which',
565
+ description: 'Resolve the executable path of a command available on the remote host.',
566
+ inputSchema: baseParams({ commandName: { type: 'string' }, ...grepParam }, ['commandName'])
567
+ },
568
+ {
569
+ name: 'lsof',
570
+ description: 'Inspect open files, ports, and process-file relationships.',
571
+ inputSchema: baseParams({
572
+ path: { type: 'string' },
573
+ process: { type: 'string' },
574
+ port: { type: 'number' },
575
+ ...grepParam
576
+ })
577
+ },
578
+ {
579
+ name: 'file',
580
+ description: 'Detect file type and encoding information.',
581
+ inputSchema: baseParams({ path: { type: 'string' }, ...grepParam }, ['path'])
582
+ },
583
+ {
584
+ name: 'stat',
585
+ description: 'File metadata inspection: Shows size, timestamps, mode bits, and related file details.',
586
+ inputSchema: baseParams({ filePath: { type: 'string' }, ...grepParam }, ['filePath'])
587
+ },
423
588
  {
424
589
  name: 'chmod',
425
590
  description: 'Change file mode bits. REQUIRES CONFIRMATION unless the final command is whitelisted.',
@@ -17,8 +17,11 @@ const WRITE_TOOLS = [
17
17
  'docker_compose_down',
18
18
  'docker_compose_stop',
19
19
  'docker_compose_restart',
20
+ 'docker_compose_pull',
21
+ 'docker_compose_exec',
20
22
  'docker_exec',
21
23
  'docker_pull',
24
+ 'docker_build',
22
25
  'docker_cp',
23
26
  'docker_stop',
24
27
  'docker_rm',
@@ -31,6 +34,8 @@ const WRITE_TOOLS = [
31
34
  'systemctl_restart',
32
35
  'systemctl_start',
33
36
  'systemctl_stop',
37
+ 'systemctl_enable',
38
+ 'systemctl_disable',
34
39
  'firewall_cmd',
35
40
  'kill_process',
36
41
  'chmod',
@@ -117,6 +122,14 @@ export class ToolHandlers {
117
122
  this.validateShellToken(value, `${fieldName}[${index}]`);
118
123
  }
119
124
  }
125
+ /**
126
+ * Validate positive line counts for text inspection helpers.
127
+ */
128
+ validatePositiveInteger(value, fieldName) {
129
+ if (!Number.isInteger(value) || value <= 0) {
130
+ throw new Error(`${fieldName} must be a positive integer.`);
131
+ }
132
+ }
120
133
  escapePerlEnvBase64(value) {
121
134
  return Buffer.from(value).toString('base64');
122
135
  }
@@ -212,11 +225,37 @@ export class ToolHandlers {
212
225
  if ((name === 'netstat' || name === 'ss') && Array.isArray(params.args)) {
213
226
  this.validateTokenArray(params.args, `${name}.args`);
214
227
  }
228
+ if ((name === 'head' || name === 'tail') && params.lines !== undefined) {
229
+ this.validatePositiveInteger(params.lines, `${name}.lines`);
230
+ }
231
+ if (name === 'find' && params.maxDepth !== undefined) {
232
+ this.validatePositiveInteger(params.maxDepth, 'find.maxDepth');
233
+ }
234
+ if (name === 'sed') {
235
+ this.validatePositiveInteger(params.startLine, 'sed.startLine');
236
+ this.validatePositiveInteger(params.endLine, 'sed.endLine');
237
+ if (params.endLine < params.startLine) {
238
+ throw new Error(`sed.endLine must be greater than or equal to sed.startLine.`);
239
+ }
240
+ }
215
241
  if (name === 'docker_exec' && Array.isArray(params.args)) {
216
242
  for (const [index, arg] of params.args.entries()) {
217
243
  this.validateShellFragment(arg, `docker_exec.args[${index}]`);
218
244
  }
219
245
  }
246
+ if (name === 'docker_compose_exec' && Array.isArray(params.args)) {
247
+ for (const [index, arg] of params.args.entries()) {
248
+ this.validateShellFragment(arg, `docker_compose_exec.args[${index}]`);
249
+ }
250
+ }
251
+ if (name === 'docker_build') {
252
+ if (params.tag) {
253
+ this.validateShellToken(params.tag, 'docker_build.tag');
254
+ }
255
+ for (const [index, buildArg] of (params.buildArgs || []).entries()) {
256
+ this.validateShellFragment(buildArg, `docker_build.buildArgs[${index}]`);
257
+ }
258
+ }
220
259
  if ((name === 'tar_create' || name === 'zip') && Array.isArray(params.sourcePaths)) {
221
260
  if (params.sourcePaths.length === 0) {
222
261
  throw new Error(`${name}.sourcePaths must contain at least one path.`);
@@ -236,13 +275,29 @@ export class ToolHandlers {
236
275
  getCommandForTool(name, params) {
237
276
  switch (name) {
238
277
  case 'get_system_info': return 'echo "USER: $(whoami)"; echo "UPTIME: $(uptime)"; echo "KERNEL: $(uname -a)"; echo "MEMORY:"; free -m';
278
+ case 'hostname': return 'hostname';
279
+ case 'id': return 'id';
280
+ case 'uname': return `uname ${params.all === false ? '-s' : '-a'}`;
281
+ case 'uptime': return 'uptime';
282
+ case 'free': return 'free -m';
283
+ case 'env': return 'env';
239
284
  case 'check_dependencies': return `for cmd in ${params.commands.map((cmd) => this.shellEscape(cmd)).join(' ')}; do which "$cmd" || echo "$cmd not found"; done`;
240
285
  case 'pwd': return 'pwd';
241
286
  case 'cd': return `cd ${this.shellEscape(params.path)}`;
242
- case 'll': return 'ls -l';
287
+ case 'll': return `ls -l${params.all ? 'a' : ''}`;
243
288
  case 'cat': return `cat ${this.shellEscape(params.filePath)}`;
289
+ case 'head': return `head -n ${params.lines || 40} ${this.shellEscape(params.filePath)}`;
244
290
  case 'tail': return `tail -n ${params.lines || 50} ${this.shellEscape(params.filePath)}`;
291
+ case 'sed': return `sed -n '${params.startLine},${params.endLine}p' ${this.shellEscape(params.filePath)}`;
245
292
  case 'grep': return `grep ${params.ignoreCase ? '-inE' : '-nE'} ${this.shellEscape(params.pattern)} ${this.shellEscape(params.filePath)}`;
293
+ case 'grep_r': {
294
+ const includeArgs = (params.include || []).map((value) => ` --include ${this.shellEscape(value)}`).join('');
295
+ const excludeDirArgs = (params.excludeDir || []).map((value) => ` --exclude-dir ${this.shellEscape(value)}`).join('');
296
+ const contextArgs = params.context !== undefined
297
+ ? ` -C ${params.context}`
298
+ : `${params.beforeContext !== undefined ? ` -B ${params.beforeContext}` : ''}${params.afterContext !== undefined ? ` -A ${params.afterContext}` : ''}`;
299
+ return `grep ${params.ignoreCase ? '-RinE' : '-RnE'}${contextArgs}${includeArgs}${excludeDirArgs} ${this.shellEscape(params.pattern)} ${this.shellEscape(params.path)}`;
300
+ }
246
301
  case 'edit_text_file':
247
302
  const edB64 = Buffer.from(params.content).toString('base64');
248
303
  return `printf '%s' ${this.shellEscape(edB64)} | base64 -d > ${this.shellEscape(params.filePath)}`;
@@ -265,7 +320,8 @@ export class ToolHandlers {
265
320
  throw new Error(`RM_SAFE: Denied for restricted directory.`);
266
321
  return `rm ${params.recursive ? '-rf' : '-f'} ${this.shellEscape(params.path)}`;
267
322
  case 'echo': return `echo ${this.shellEscape(params.text)}`;
268
- case 'find': return `find ${this.shellEscape(params.path)} -name ${this.shellEscape(params.name)}`;
323
+ case 'find':
324
+ return `find ${this.shellEscape(params.path)}${params.maxDepth !== undefined ? ` -maxdepth ${params.maxDepth}` : ''}${params.type ? ` -type ${params.type}` : ''}${params.name ? ` -name ${this.shellEscape(params.name)}` : ''}${params.pathPattern ? ` -path ${this.shellEscape(params.pathPattern)}` : ''}`;
269
325
  case 'git_status': return 'git status';
270
326
  case 'git_fetch': return `git fetch ${params.all ? '--all ' : ''}${params.prune ? '--prune' : ''}`.trim();
271
327
  case 'git_pull': return 'git pull --no-edit';
@@ -285,6 +341,11 @@ export class ToolHandlers {
285
341
  case 'docker_compose_stop': return 'docker-compose stop';
286
342
  case 'docker_compose_logs': return `docker-compose logs -n ${params.lines || 100}`;
287
343
  case 'docker_compose_restart': return 'docker-compose restart';
344
+ case 'docker_compose_pull': return `docker-compose pull${params.service ? ` ${this.shellEscape(params.service)}` : ''}`;
345
+ case 'docker_compose_ps': return `docker-compose ps${params.service ? ` ${this.shellEscape(params.service)}` : ''}`;
346
+ case 'docker_compose_config': return 'docker-compose config';
347
+ case 'docker_compose_exec':
348
+ return `docker-compose exec -T${params.user ? ` --user ${this.shellEscape(params.user)}` : ''} ${this.shellEscape(params.service)} ${this.shellEscape(params.command)}${params.args?.length ? ` ${this.shellEscapeList(params.args)}` : ''}`;
288
349
  case 'docker_ps': return 'docker ps';
289
350
  case 'docker_images': return 'docker images';
290
351
  case 'docker_exec':
@@ -304,13 +365,21 @@ export class ToolHandlers {
304
365
  case 'docker_logs': return `docker logs -n ${params.lines || 100} ${this.shellEscape(params.container)}`;
305
366
  case 'docker_load': return `docker load -i ${this.shellEscape(params.path)}`;
306
367
  case 'docker_save': return `docker save -o ${this.shellEscape(params.path)} ${this.shellEscape(params.image)}`;
368
+ case 'docker_build': {
369
+ const buildArgs = (params.buildArgs || []).map((value) => ` --build-arg ${this.shellEscape(value)}`).join('');
370
+ return `docker build${params.tag ? ` -t ${this.shellEscape(params.tag)}` : ''}${params.dockerfile ? ` -f ${this.shellEscape(params.dockerfile)}` : ''}${params.noCache ? ' --no-cache' : ''}${params.networkHost ? ' --network=host' : ''}${buildArgs} ${this.shellEscape(params.context)}`;
371
+ }
307
372
  case 'systemctl_status': return `systemctl status ${this.shellEscape(params.service)}`;
308
373
  case 'systemctl_restart': return `systemctl restart ${this.shellEscape(params.service)}`;
309
374
  case 'systemctl_start': return `systemctl start ${this.shellEscape(params.service)}`;
310
375
  case 'systemctl_stop': return `systemctl stop ${this.shellEscape(params.service)}`;
376
+ case 'systemctl_enable': return `systemctl enable ${this.shellEscape(params.service)}`;
377
+ case 'systemctl_disable': return `systemctl disable ${this.shellEscape(params.service)}`;
311
378
  case 'ip_addr': return 'ip addr';
379
+ case 'ip_route': return 'ip route';
380
+ case 'mount': return 'mount';
312
381
  case 'journalctl':
313
- return `journalctl --no-pager${params.unit ? ` -u ${this.shellEscape(params.unit)}` : ''}${params.priority ? ` -p ${this.shellEscape(params.priority)}` : ''}${params.since ? ` --since ${this.shellEscape(params.since)}` : ''} -n ${params.lines || 100}`;
382
+ return `journalctl --no-pager${params.unit ? ` -u ${this.shellEscape(params.unit)}` : ''}${params.priority ? ` -p ${this.shellEscape(params.priority)}` : ''}${params.since ? ` --since ${this.shellEscape(params.since)}` : ''}${params.until ? ` --until ${this.shellEscape(params.until)}` : ''}${params.follow ? ' -f' : ''} -n ${params.lines || 100}`;
314
383
  case 'firewall_cmd':
315
384
  return this.buildFirewallCommand(params);
316
385
  case 'netstat':
@@ -336,7 +405,13 @@ export class ToolHandlers {
336
405
  return common;
337
406
  }
338
407
  case 'df_h': return 'df -h';
408
+ case 'df_inode': return 'df -i';
339
409
  case 'du_sh': return `du -sh ${this.shellEscape(params.path)}`;
410
+ case 'which': return `which ${this.shellEscape(params.commandName)}`;
411
+ case 'lsof':
412
+ return `lsof${params.path ? ` ${this.shellEscape(params.path)}` : ''}${params.process ? ` -c ${this.shellEscape(params.process)}` : ''}${params.port !== undefined ? ` -i :${params.port}` : ''}`;
413
+ case 'file': return `file ${this.shellEscape(params.path)}`;
414
+ case 'stat': return `stat ${this.shellEscape(params.filePath)}`;
340
415
  case 'nvidia_smi': return 'nvidia-smi';
341
416
  case 'ps': return 'ps aux';
342
417
  case 'pgrep': return `pgrep ${params.fullCommand ? '-af ' : '-a '}${this.shellEscape(params.pattern)}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jadchene/mcp-ssh-service",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "A production-ready, highly secure SSH MCP server featuring stateless connections, two-step operation confirmation, and comprehensive DevOps tool integration.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",