@jadchene/mcp-ssh-service 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -142
- package/dist/tools/definitions.js +96 -76
- package/dist/tools/handlers.js +32 -27
- package/package.json +49 -49
package/README.md
CHANGED
|
@@ -1,143 +1,95 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
# SSH MCP Service
|
|
2
|
+
|
|
3
|
+
A production-ready, highly secure Model Context Protocol (MCP) server for remote server management. It features stateless connections, lazy loading, and a mandatory two-step confirmation flow for high-risk operations.
|
|
4
|
+
|
|
5
|
+
## Core Features
|
|
6
|
+
|
|
7
|
+
- **Stateless & Lazy Loading**: Connections are only established when a tool is called and closed immediately after execution. No persistent SSH tunnels.
|
|
8
|
+
- **Security First**:
|
|
9
|
+
- Mandatory manual confirmation for all "Write Actions" (e.g., `rm`, `restart`, `docker_stop`).
|
|
10
|
+
- Command blacklist (prevents `rm -rf /`, etc.).
|
|
11
|
+
- Restricted directory protection for safe deletions.
|
|
12
|
+
- **Context Aware**: Supports directory aliases and path mapping via `list_working_directories`.
|
|
13
|
+
- **Workflow Automation**: `execute_batch` allows running multiple commands in a single session with state (like `cd`) preserved between steps.
|
|
14
|
+
|
|
15
|
+
## Tool List (45 Total)
|
|
16
|
+
|
|
17
|
+
### 🛠️ Discovery & Core (8)
|
|
18
|
+
- `list_servers`: List all configured SSH servers.
|
|
19
|
+
- `ping_server`: Test connectivity to a specific server.
|
|
20
|
+
- `list_working_directories`: View path mappings/aliases.
|
|
21
|
+
- `check_dependencies`: Verify if required binaries (git, docker, etc.) are installed.
|
|
22
|
+
- `get_system_info`: Get CPU, memory, and kernel details.
|
|
23
|
+
- `pwd`: Show current remote path.
|
|
24
|
+
- `cd`: Change directory (effective within `execute_batch`).
|
|
25
|
+
- `execute_batch`: Run a sequence of tools in one session.
|
|
26
|
+
|
|
27
|
+
### 💻 Shell & Basic (2)
|
|
28
|
+
- `execute_command` (*): Run any arbitrary shell command.
|
|
29
|
+
- `echo`: Print text or variables.
|
|
30
|
+
|
|
31
|
+
### 📂 File Management (5)
|
|
32
|
+
- `upload_file` (*): Transfer file from local to remote.
|
|
33
|
+
- `download_file`: Transfer file from remote to local.
|
|
34
|
+
- `ll`: Detailed directory listing.
|
|
35
|
+
- `cat`: Read file content.
|
|
36
|
+
- `edit_text_file` (*): Replace file content (Safe Base64 transfer).
|
|
37
|
+
- `touch`: Create empty file or update timestamp.
|
|
38
|
+
- `find`: Search for files in a directory hierarchy.
|
|
39
|
+
|
|
40
|
+
### 🐳 Docker & Compose (18)
|
|
41
|
+
- `docker_compose_up` (*), `docker_compose_down` (*), `docker_compose_stop` (*), `docker_compose_restart` (*)
|
|
42
|
+
- `docker_compose_logs`: View compose logs.
|
|
43
|
+
- `docker_ps`, `docker_images`
|
|
44
|
+
- `docker_pull` (*), `docker_cp` (*), `docker_stop` (*), `docker_rm` (*), `docker_start` (*), `docker_rmi` (*), `docker_commit` (*)
|
|
45
|
+
- `docker_logs`: Get container logs.
|
|
46
|
+
- `docker_load` (*), `docker_save` (*)
|
|
47
|
+
|
|
48
|
+
### ⚙️ System Services (4)
|
|
49
|
+
- `systemctl_status`
|
|
50
|
+
- `systemctl_start` (*), `systemctl_stop` (*), `systemctl_restart` (*)
|
|
51
|
+
|
|
52
|
+
### 🌐 Network & Stats (8)
|
|
53
|
+
- `ip_addr`: Show network interfaces.
|
|
54
|
+
- `firewall_cmd` (*): Manage firewall rules.
|
|
55
|
+
- `netstat`: Monitor ports and connections.
|
|
56
|
+
- `nvidia_smi`: GPU status.
|
|
57
|
+
- `ps`: Process snapshot.
|
|
58
|
+
- `df_h`: Disk usage.
|
|
59
|
+
- `du_sh`: Directory size estimation.
|
|
60
|
+
|
|
61
|
+
> (*) Requires manual confirmation.
|
|
62
|
+
|
|
63
|
+
## Confirmation Protocol
|
|
64
|
+
|
|
65
|
+
For any tool marked with `(*)`, the service follows a two-step flow:
|
|
66
|
+
1. **Request**: Call the tool with parameters. The server returns a `confirmationId` and `status: "pending"`.
|
|
67
|
+
2. **Confirm**: Call the **same tool again** with `confirmExecution: true` and the provided `confirmationId`.
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
External configuration `config.json` allows defining multiple servers and their working directory aliases:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"servers": {
|
|
76
|
+
"prod-web": {
|
|
77
|
+
"host": "192.168.1.100",
|
|
78
|
+
"user": "root",
|
|
79
|
+
"keyPath": "~/.ssh/id_rsa",
|
|
80
|
+
"workingDirectories": {
|
|
81
|
+
"app": { "path": "/var/www/html", "desc": "Web Root" },
|
|
82
|
+
"logs": { "path": "/var/log/nginx", "desc": "Nginx Logs" }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Installation
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npm install
|
|
93
|
+
npm run build
|
|
94
|
+
node dist/index.js
|
|
38
95
|
```
|
|
39
|
-
|
|
40
|
-
### Source Setup
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
git clone https://github.com/jadchene/mcp-ssh.git
|
|
44
|
-
cd mcp-ssh
|
|
45
|
-
npm install
|
|
46
|
-
npm run build
|
|
47
|
-
node dist/index.js --config ./config.json
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## ⚙️ Configuration Schema
|
|
53
|
-
|
|
54
|
-
### Global Settings
|
|
55
|
-
| Parameter | Type | Description |
|
|
56
|
-
| --- | --- | --- |
|
|
57
|
-
| `logDir` | string | Directory for logs. Supports env vars like `${HOME}`. |
|
|
58
|
-
| `commandBlacklist` | string[] | Prohibited command regex patterns (e.g., `["^rm -rf"]`). |
|
|
59
|
-
| `defaultTimeout` | number | Command timeout in milliseconds (default: 60000). |
|
|
60
|
-
| `servers` | object | Dictionary of server configs where key is the `serverAlias`. |
|
|
61
|
-
|
|
62
|
-
### Server Object
|
|
63
|
-
| Parameter | Type | Description |
|
|
64
|
-
| --- | --- | --- |
|
|
65
|
-
| `host` | string | Remote IP or hostname. Supports env vars. |
|
|
66
|
-
| `port` | number | SSH port (default: 22). |
|
|
67
|
-
| `username` | string | SSH login user. |
|
|
68
|
-
| `password` | string | SSH password. Use `${VAR}` for security. |
|
|
69
|
-
| `privateKeyPath` | string | Path to private key file. |
|
|
70
|
-
| `passphrase` | string | Passphrase for the private key. |
|
|
71
|
-
| `readOnly` | boolean | Disables all write/modify tools for this server. |
|
|
72
|
-
| `desc` | string | Server description shown in `list_servers`. |
|
|
73
|
-
| `strictHostKeyChecking` | boolean | Set to `false` to bypass host key verification. |
|
|
74
|
-
| `workingDirectories` | object | Semantic path mappings (Key: { path, desc }). |
|
|
75
|
-
| `proxyJump` | object | Optional jump host (recursive server config). |
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## ⚙️ Configuration Example
|
|
80
|
-
|
|
81
|
-
```json
|
|
82
|
-
{
|
|
83
|
-
"logDir": "./logs",
|
|
84
|
-
"defaultTimeout": 60000,
|
|
85
|
-
"commandBlacklist": ["^apt-get upgrade", "curl.*\\|.*sh"],
|
|
86
|
-
"servers": {
|
|
87
|
-
"prod-web": {
|
|
88
|
-
"desc": "Primary API Cluster",
|
|
89
|
-
"host": "10.0.0.5",
|
|
90
|
-
"username": "deploy",
|
|
91
|
-
"privateKeyPath": "~/.ssh/id_rsa",
|
|
92
|
-
"passphrase": "${SSH_KEY_PWD}",
|
|
93
|
-
"workingDirectories": {
|
|
94
|
-
"logs": { "path": "/var/log/nginx", "desc": "Nginx access logs" }
|
|
95
|
-
},
|
|
96
|
-
"proxyJump": {
|
|
97
|
-
"host": "bastion.example.com",
|
|
98
|
-
"username": "jumpuser"
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## 🛠️ Integrated Toolset (45 Tools)
|
|
108
|
-
|
|
109
|
-
### 📂 Discovery & Context
|
|
110
|
-
* `list_servers`: Discovery available hosts.
|
|
111
|
-
* `ping_server`: Test SSH connection & credentials.
|
|
112
|
-
* `list_working_directories`: Get semantic path mappings.
|
|
113
|
-
* `get_system_info`: CPU, Memory, and System Uptime.
|
|
114
|
-
* `check_dependencies`: Verify remote binaries.
|
|
115
|
-
|
|
116
|
-
### 💻 Shell & Files
|
|
117
|
-
* `execute_command`*, `execute_batch`*: Run single or sequenced shell commands.
|
|
118
|
-
* `ll`, `cat`, `tail`, `grep`, `pwd`, `cd`: Browse and search remote files.
|
|
119
|
-
* `upload_file`*, `download_file`: Transfer data.
|
|
120
|
-
* `mkdir`*, `mv`*, `cp`*, `chmod`*, `rm_safe`*, `touch`*: File system management.
|
|
121
|
-
|
|
122
|
-
### 🐳 DevOps & Services
|
|
123
|
-
* `docker_ps`, `docker_logs`, `docker_compose_up`*, `docker_compose_restart`*: Container orchestration.
|
|
124
|
-
* `systemctl_status`, `systemctl_restart`*: System service control.
|
|
125
|
-
* `git_status`, `git_pull`*: Version control.
|
|
126
|
-
* `ip_addr`, `ping`, `netstat`, `df_h`, `nvidia_smi`: Diagnostics.
|
|
127
|
-
|
|
128
|
-
*\* High-risk: Requires `confirmationId` and `confirmExecution: true`.*
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## 🔐 The Confirmation Workflow
|
|
133
|
-
|
|
134
|
-
1. **Request**: AI calls `rm_safe({ path: '/tmp/old' })`.
|
|
135
|
-
2. **Intercept**: Server returns `status: "pending"` with a `confirmationId`.
|
|
136
|
-
3. **Human Input**: You review the action in your chat client and approve.
|
|
137
|
-
4. **Execution**: AI calls `rm_safe` again with the `confirmationId` and `confirmExecution: true`.
|
|
138
|
-
5. **Verify**: Server ensures parameters match exactly and executes the SSH command.
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
## 📄 License
|
|
143
|
-
Released under the [MIT License](./LICENSE).
|
|
@@ -15,7 +15,7 @@ const confirmationParams = {
|
|
|
15
15
|
const grepParam = { grep: { type: 'string', description: 'Filter output using regex pattern.' } };
|
|
16
16
|
const cwdParam = { cwd: { type: 'string', description: 'Execution directory (supports aliases from list_working_directories).' } };
|
|
17
17
|
export const toolDefinitions = [
|
|
18
|
-
// --- Discovery ---
|
|
18
|
+
// --- Discovery (Core) ---
|
|
19
19
|
{
|
|
20
20
|
name: 'list_servers',
|
|
21
21
|
description: 'Discovery tool: List all configured SSH servers, their hosts, and descriptions.',
|
|
@@ -36,7 +36,7 @@ export const toolDefinitions = [
|
|
|
36
36
|
description: 'Environmental pre-check: Verifies if specific binaries exist on the remote server.',
|
|
37
37
|
inputSchema: baseParams({ commands: { type: 'array', items: { type: 'string' } } }, ['commands'])
|
|
38
38
|
},
|
|
39
|
-
// --- System ---
|
|
39
|
+
// --- System (Core) ---
|
|
40
40
|
{
|
|
41
41
|
name: 'get_system_info',
|
|
42
42
|
description: 'System health check: Returns current user, system uptime, kernel, and memory.',
|
|
@@ -52,7 +52,7 @@ export const toolDefinitions = [
|
|
|
52
52
|
description: 'Directory navigation: Changes the working directory (effective within batch).',
|
|
53
53
|
inputSchema: baseParams({ path: { type: 'string' } }, ['path'])
|
|
54
54
|
},
|
|
55
|
-
// --- Batch ---
|
|
55
|
+
// --- Batch (Core) ---
|
|
56
56
|
{
|
|
57
57
|
name: 'execute_batch',
|
|
58
58
|
description: 'Workflow automation: Executes a sequence of multiple tools in a single persistent SSH session. REQUIRES CONFIRMATION if any sub-tool is high-risk.',
|
|
@@ -72,7 +72,7 @@ export const toolDefinitions = [
|
|
|
72
72
|
...confirmationParams
|
|
73
73
|
}, ['commands'])
|
|
74
74
|
},
|
|
75
|
-
// --- Shell ---
|
|
75
|
+
// --- Shell & Basic (Requirements) ---
|
|
76
76
|
{
|
|
77
77
|
name: 'execute_command',
|
|
78
78
|
description: 'Arbitrary execution: Runs any shell command via SSH. REQUIRES CONFIRMATION.',
|
|
@@ -82,7 +82,12 @@ export const toolDefinitions = [
|
|
|
82
82
|
...confirmationParams
|
|
83
83
|
}, ['command'])
|
|
84
84
|
},
|
|
85
|
-
|
|
85
|
+
{
|
|
86
|
+
name: 'echo',
|
|
87
|
+
description: 'Print text or variables.',
|
|
88
|
+
inputSchema: baseParams({ text: { type: 'string' } }, ['text'])
|
|
89
|
+
},
|
|
90
|
+
// --- Files (Requirements) ---
|
|
86
91
|
{
|
|
87
92
|
name: 'upload_file',
|
|
88
93
|
description: 'File transfer (Local -> Remote). REQUIRES CONFIRMATION.',
|
|
@@ -110,11 +115,6 @@ export const toolDefinitions = [
|
|
|
110
115
|
description: 'File reading: Reads text file content.',
|
|
111
116
|
inputSchema: baseParams({ filePath: { type: 'string' }, ...grepParam }, ['filePath'])
|
|
112
117
|
},
|
|
113
|
-
{
|
|
114
|
-
name: 'tail',
|
|
115
|
-
description: 'Log inspection: Reads last N lines of a file.',
|
|
116
|
-
inputSchema: baseParams({ filePath: { type: 'string' }, lines: { type: 'number' }, ...grepParam }, ['filePath'])
|
|
117
|
-
},
|
|
118
118
|
{
|
|
119
119
|
name: 'edit_text_file',
|
|
120
120
|
description: 'File creation/overwrite: Completely replaces file content. REQUIRES CONFIRMATION.',
|
|
@@ -124,67 +124,17 @@ export const toolDefinitions = [
|
|
|
124
124
|
...confirmationParams
|
|
125
125
|
}, ['filePath', 'content'])
|
|
126
126
|
},
|
|
127
|
-
{
|
|
128
|
-
name: 'append_text_file',
|
|
129
|
-
description: 'File appending: Adds text to end of file. REQUIRES CONFIRMATION.',
|
|
130
|
-
inputSchema: baseParams({
|
|
131
|
-
filePath: { type: 'string' },
|
|
132
|
-
content: { type: 'string' },
|
|
133
|
-
...confirmationParams
|
|
134
|
-
}, ['filePath', 'content'])
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
name: 'mkdir',
|
|
138
|
-
description: 'Directory creation: Creates a directory (mkdir -p). REQUIRES CONFIRMATION.',
|
|
139
|
-
inputSchema: baseParams({ path: { type: 'string' }, ...confirmationParams }, ['path'])
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
name: 'chmod',
|
|
143
|
-
description: 'Permission management: Changes file or directory permissions. REQUIRES CONFIRMATION.',
|
|
144
|
-
inputSchema: baseParams({ mode: { type: 'string' }, path: { type: 'string' }, ...confirmationParams }, ['mode', 'path'])
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: 'mv',
|
|
148
|
-
description: 'File movement/rename: Moves or renames files or directories. REQUIRES CONFIRMATION.',
|
|
149
|
-
inputSchema: baseParams({ source: { type: 'string' }, destination: { type: 'string' }, ...confirmationParams }, ['source', 'destination'])
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
name: 'cp',
|
|
153
|
-
description: 'File copy: Copies files or directories. REQUIRES CONFIRMATION.',
|
|
154
|
-
inputSchema: baseParams({
|
|
155
|
-
source: { type: 'string' },
|
|
156
|
-
destination: { type: 'string' },
|
|
157
|
-
recursive: { type: 'boolean' },
|
|
158
|
-
...confirmationParams
|
|
159
|
-
}, ['source', 'destination'])
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
name: 'rm_safe',
|
|
163
|
-
description: 'File deletion: Removes file or directory. REQUIRES CONFIRMATION.',
|
|
164
|
-
inputSchema: baseParams({ path: { type: 'string' }, recursive: { type: 'boolean' }, ...confirmationParams }, ['path'])
|
|
165
|
-
},
|
|
166
127
|
{
|
|
167
128
|
name: 'touch',
|
|
168
|
-
description: 'Timestamp/File creation: Updates access time or creates empty file.
|
|
169
|
-
inputSchema: baseParams({ filePath: { type: 'string' }
|
|
129
|
+
description: 'Timestamp/File creation: Updates access time or creates empty file.',
|
|
130
|
+
inputSchema: baseParams({ filePath: { type: 'string' } }, ['filePath'])
|
|
170
131
|
},
|
|
171
|
-
// --- Git ---
|
|
172
132
|
{
|
|
173
|
-
name: '
|
|
174
|
-
description: '
|
|
175
|
-
inputSchema: baseParams(
|
|
133
|
+
name: 'find',
|
|
134
|
+
description: 'Search for files in a directory hierarchy.',
|
|
135
|
+
inputSchema: baseParams({ path: { type: 'string' }, name: { type: 'string' }, ...grepParam }, ['path'])
|
|
176
136
|
},
|
|
177
|
-
|
|
178
|
-
name: 'git_pull',
|
|
179
|
-
description: 'Git update: Pulls latest changes. REQUIRES CONFIRMATION.',
|
|
180
|
-
inputSchema: baseParams({ ...cwdParam, ...confirmationParams })
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
name: 'git_log',
|
|
184
|
-
description: 'Git history: Shows commit logs.',
|
|
185
|
-
inputSchema: baseParams({ ...cwdParam, count: { type: 'number' } })
|
|
186
|
-
},
|
|
187
|
-
// --- Docker ---
|
|
137
|
+
// --- Docker & Compose (Requirements) ---
|
|
188
138
|
{
|
|
189
139
|
name: 'docker_compose_up',
|
|
190
140
|
description: 'Deploy docker stack. REQUIRES CONFIRMATION.',
|
|
@@ -195,6 +145,11 @@ export const toolDefinitions = [
|
|
|
195
145
|
description: 'Remove docker stack. REQUIRES CONFIRMATION.',
|
|
196
146
|
inputSchema: baseParams({ ...cwdParam, ...confirmationParams }, ['cwd'])
|
|
197
147
|
},
|
|
148
|
+
{
|
|
149
|
+
name: 'docker_compose_stop',
|
|
150
|
+
description: 'Stop docker stack. REQUIRES CONFIRMATION.',
|
|
151
|
+
inputSchema: baseParams({ ...cwdParam, ...confirmationParams }, ['cwd'])
|
|
152
|
+
},
|
|
198
153
|
{
|
|
199
154
|
name: 'docker_compose_logs',
|
|
200
155
|
description: 'View compose logs.',
|
|
@@ -210,12 +165,62 @@ export const toolDefinitions = [
|
|
|
210
165
|
description: 'List docker containers.',
|
|
211
166
|
inputSchema: baseParams(grepParam)
|
|
212
167
|
},
|
|
168
|
+
{
|
|
169
|
+
name: 'docker_images',
|
|
170
|
+
description: 'List docker images.',
|
|
171
|
+
inputSchema: baseParams(grepParam)
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: 'docker_pull',
|
|
175
|
+
description: 'Pull an image from a registry. REQUIRES CONFIRMATION.',
|
|
176
|
+
inputSchema: baseParams({ image: { type: 'string' }, ...confirmationParams }, ['image'])
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: 'docker_cp',
|
|
180
|
+
description: 'Copy files/folders between a container and the local filesystem. REQUIRES CONFIRMATION.',
|
|
181
|
+
inputSchema: baseParams({ source: { type: 'string' }, destination: { type: 'string' }, ...confirmationParams }, ['source', 'destination'])
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: 'docker_stop',
|
|
185
|
+
description: 'Stop one or more running containers. REQUIRES CONFIRMATION.',
|
|
186
|
+
inputSchema: baseParams({ container: { type: 'string' }, ...confirmationParams }, ['container'])
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: 'docker_rm',
|
|
190
|
+
description: 'Remove one or more containers. REQUIRES CONFIRMATION.',
|
|
191
|
+
inputSchema: baseParams({ container: { type: 'string' }, ...confirmationParams }, ['container'])
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
name: 'docker_start',
|
|
195
|
+
description: 'Start one or more stopped containers. REQUIRES CONFIRMATION.',
|
|
196
|
+
inputSchema: baseParams({ container: { type: 'string' }, ...confirmationParams }, ['container'])
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: 'docker_rmi',
|
|
200
|
+
description: 'Remove one or more images. REQUIRES CONFIRMATION.',
|
|
201
|
+
inputSchema: baseParams({ image: { type: 'string' }, ...confirmationParams }, ['image'])
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'docker_commit',
|
|
205
|
+
description: 'Create a new image from a container\'s changes. REQUIRES CONFIRMATION.',
|
|
206
|
+
inputSchema: baseParams({ container: { type: 'string' }, repository: { type: 'string' }, ...confirmationParams }, ['container', 'repository'])
|
|
207
|
+
},
|
|
213
208
|
{
|
|
214
209
|
name: 'docker_logs',
|
|
215
210
|
description: 'Get container logs.',
|
|
216
211
|
inputSchema: baseParams({ container: { type: 'string' }, lines: { type: 'number' }, ...grepParam }, ['container'])
|
|
217
212
|
},
|
|
218
|
-
|
|
213
|
+
{
|
|
214
|
+
name: 'docker_load',
|
|
215
|
+
description: 'Load an image from a tar archive or STDIN. REQUIRES CONFIRMATION.',
|
|
216
|
+
inputSchema: baseParams({ path: { type: 'string' }, ...confirmationParams }, ['path'])
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
name: 'docker_save',
|
|
220
|
+
description: 'Save one or more images to a tar archive. REQUIRES CONFIRMATION.',
|
|
221
|
+
inputSchema: baseParams({ image: { type: 'string' }, path: { type: 'string' }, ...confirmationParams }, ['image', 'path'])
|
|
222
|
+
},
|
|
223
|
+
// --- Service & Network (Requirements) ---
|
|
219
224
|
{
|
|
220
225
|
name: 'systemctl_status',
|
|
221
226
|
description: 'Check systemd service status.',
|
|
@@ -226,22 +231,42 @@ export const toolDefinitions = [
|
|
|
226
231
|
description: 'Restart system service. REQUIRES CONFIRMATION.',
|
|
227
232
|
inputSchema: baseParams({ service: { type: 'string' }, ...confirmationParams }, ['service'])
|
|
228
233
|
},
|
|
234
|
+
{
|
|
235
|
+
name: 'systemctl_start',
|
|
236
|
+
description: 'Start system service. REQUIRES CONFIRMATION.',
|
|
237
|
+
inputSchema: baseParams({ service: { type: 'string' }, ...confirmationParams }, ['service'])
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: 'systemctl_stop',
|
|
241
|
+
description: 'Stop system service. REQUIRES CONFIRMATION.',
|
|
242
|
+
inputSchema: baseParams({ service: { type: 'string' }, ...confirmationParams }, ['service'])
|
|
243
|
+
},
|
|
229
244
|
{
|
|
230
245
|
name: 'ip_addr',
|
|
231
246
|
description: 'Show network interface info.',
|
|
232
247
|
inputSchema: baseParams(grepParam)
|
|
233
248
|
},
|
|
234
249
|
{
|
|
235
|
-
name: '
|
|
236
|
-
description: '
|
|
237
|
-
inputSchema: baseParams({
|
|
250
|
+
name: 'firewall_cmd',
|
|
251
|
+
description: 'Control the runtime/permanent firewall. REQUIRES CONFIRMATION.',
|
|
252
|
+
inputSchema: baseParams({ args: { type: 'string' }, ...confirmationParams }, ['args'])
|
|
238
253
|
},
|
|
239
254
|
{
|
|
240
255
|
name: 'netstat',
|
|
241
256
|
description: 'Monitor ports/connections.',
|
|
242
257
|
inputSchema: baseParams({ args: { type: 'string' }, ...grepParam })
|
|
243
258
|
},
|
|
244
|
-
// --- Stats ---
|
|
259
|
+
// --- Stats & Process (Requirements) ---
|
|
260
|
+
{
|
|
261
|
+
name: 'nvidia_smi',
|
|
262
|
+
description: 'GPU utilization status.',
|
|
263
|
+
inputSchema: baseParams()
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: 'ps',
|
|
267
|
+
description: 'Report a snapshot of the current processes.',
|
|
268
|
+
inputSchema: baseParams(grepParam)
|
|
269
|
+
},
|
|
245
270
|
{
|
|
246
271
|
name: 'df_h',
|
|
247
272
|
description: 'System disk usage.',
|
|
@@ -251,10 +276,5 @@ export const toolDefinitions = [
|
|
|
251
276
|
name: 'du_sh',
|
|
252
277
|
description: 'Directory size estimation.',
|
|
253
278
|
inputSchema: baseParams({ path: { type: 'string' }, ...grepParam }, ['path'])
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
name: 'nvidia_smi',
|
|
257
|
-
description: 'GPU utilization status.',
|
|
258
|
-
inputSchema: baseParams()
|
|
259
279
|
}
|
|
260
280
|
];
|
package/dist/tools/handlers.js
CHANGED
|
@@ -4,18 +4,23 @@ const WRITE_TOOLS = [
|
|
|
4
4
|
'execute_command',
|
|
5
5
|
'upload_file',
|
|
6
6
|
'edit_text_file',
|
|
7
|
-
'append_text_file',
|
|
8
|
-
'mkdir',
|
|
9
|
-
'chmod',
|
|
10
|
-
'mv',
|
|
11
|
-
'cp',
|
|
12
|
-
'rm_safe',
|
|
13
|
-
'touch',
|
|
14
|
-
'git_pull',
|
|
15
7
|
'docker_compose_up',
|
|
16
8
|
'docker_compose_down',
|
|
9
|
+
'docker_compose_stop',
|
|
17
10
|
'docker_compose_restart',
|
|
18
|
-
'
|
|
11
|
+
'docker_pull',
|
|
12
|
+
'docker_cp',
|
|
13
|
+
'docker_stop',
|
|
14
|
+
'docker_rm',
|
|
15
|
+
'docker_start',
|
|
16
|
+
'docker_rmi',
|
|
17
|
+
'docker_commit',
|
|
18
|
+
'docker_load',
|
|
19
|
+
'docker_save',
|
|
20
|
+
'systemctl_restart',
|
|
21
|
+
'systemctl_start',
|
|
22
|
+
'systemctl_stop',
|
|
23
|
+
'firewall_cmd'
|
|
19
24
|
];
|
|
20
25
|
const DEFAULT_BLACKLIST = [
|
|
21
26
|
/rm\s+-(rf|fr|r|f)\s+\//i,
|
|
@@ -63,41 +68,41 @@ export class ToolHandlers {
|
|
|
63
68
|
case 'cd': return `cd ${params.path}`;
|
|
64
69
|
case 'll': return 'ls -l';
|
|
65
70
|
case 'cat': return `cat ${params.filePath}`;
|
|
66
|
-
case 'tail': return `tail -n ${params.lines || 50} ${params.filePath}`;
|
|
67
|
-
case 'mkdir': return `mkdir -p ${params.path}`;
|
|
68
|
-
case 'chmod': return `chmod ${params.mode} ${params.path}`;
|
|
69
|
-
case 'mv': return `mv -f ${params.source} ${params.destination}`;
|
|
70
|
-
case 'cp': return `cp -f ${params.recursive ? '-r' : ''} ${params.source} ${params.destination}`;
|
|
71
|
-
case 'rm_safe':
|
|
72
|
-
const restricted = ['/', '/etc', '/usr', '/bin', '/var', '/root', '/home'];
|
|
73
|
-
if (restricted.includes(params.path.trim()))
|
|
74
|
-
throw new Error(`RM_SAFE: Denied for restricted directory.`);
|
|
75
|
-
return `rm ${params.recursive ? '-rf' : '-f'} ${params.path}`;
|
|
76
|
-
case 'touch': return `touch ${params.filePath}`;
|
|
77
|
-
case 'append_text_file':
|
|
78
|
-
const appB64 = Buffer.from(params.content).toString('base64');
|
|
79
|
-
return `echo "${appB64}" | base64 -d >> ${params.filePath}`;
|
|
80
71
|
case 'edit_text_file':
|
|
81
72
|
const edB64 = Buffer.from(params.content).toString('base64');
|
|
82
73
|
return `echo "${edB64}" | base64 -d > ${params.filePath}`;
|
|
83
|
-
case '
|
|
84
|
-
case '
|
|
85
|
-
case '
|
|
74
|
+
case 'touch': return `touch ${params.filePath}`;
|
|
75
|
+
case 'echo': return `echo "${params.text}"`;
|
|
76
|
+
case 'find': return `find ${params.path} -name "${params.name}"`;
|
|
86
77
|
case 'execute_command': return params.command;
|
|
87
78
|
case 'docker_compose_up': return 'docker-compose up -d';
|
|
88
79
|
case 'docker_compose_down': return 'docker-compose down --remove-orphans';
|
|
80
|
+
case 'docker_compose_stop': return 'docker-compose stop';
|
|
89
81
|
case 'docker_compose_logs': return `docker-compose logs -n ${params.lines || 100}`;
|
|
90
82
|
case 'docker_compose_restart': return 'docker-compose restart';
|
|
91
83
|
case 'docker_ps': return 'docker ps';
|
|
84
|
+
case 'docker_images': return 'docker images';
|
|
85
|
+
case 'docker_pull': return `docker pull ${params.image}`;
|
|
86
|
+
case 'docker_cp': return `docker cp ${params.source} ${params.destination}`;
|
|
87
|
+
case 'docker_stop': return `docker stop ${params.container}`;
|
|
88
|
+
case 'docker_rm': return `docker rm ${params.container}`;
|
|
89
|
+
case 'docker_start': return `docker start ${params.container}`;
|
|
90
|
+
case 'docker_rmi': return `docker rmi ${params.image}`;
|
|
91
|
+
case 'docker_commit': return `docker commit ${params.container} ${params.repository}`;
|
|
92
92
|
case 'docker_logs': return `docker logs -n ${params.lines || 100} ${params.container}`;
|
|
93
|
+
case 'docker_load': return `docker load -i ${params.path}`;
|
|
94
|
+
case 'docker_save': return `docker save -o ${params.path} ${params.image}`;
|
|
93
95
|
case 'systemctl_status': return `systemctl status ${params.service}`;
|
|
94
96
|
case 'systemctl_restart': return `systemctl restart ${params.service}`;
|
|
97
|
+
case 'systemctl_start': return `systemctl start ${params.service}`;
|
|
98
|
+
case 'systemctl_stop': return `systemctl stop ${params.service}`;
|
|
95
99
|
case 'ip_addr': return 'ip addr';
|
|
96
|
-
case '
|
|
100
|
+
case 'firewall_cmd': return `firewall-cmd ${params.args}`;
|
|
97
101
|
case 'netstat': return `netstat ${params.args || '-tuln'}`;
|
|
98
102
|
case 'df_h': return 'df -h';
|
|
99
103
|
case 'du_sh': return `du -sh ${params.path}`;
|
|
100
104
|
case 'nvidia_smi': return 'nvidia-smi';
|
|
105
|
+
case 'ps': return 'ps aux';
|
|
101
106
|
default: return '';
|
|
102
107
|
}
|
|
103
108
|
}
|
package/package.json
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@jadchene/mcp-ssh-service",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A production-ready, highly secure SSH MCP server featuring stateless connections, two-step operation confirmation, and comprehensive DevOps tool integration.",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"mcp-ssh-service": "dist/index.js"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"dist"
|
|
12
|
-
],
|
|
13
|
-
"scripts": {
|
|
14
|
-
"build": "tsc",
|
|
15
|
-
"prepare": "npm run build",
|
|
16
|
-
"watch": "tsc -w",
|
|
17
|
-
"prepublishOnly": "npm run build",
|
|
18
|
-
"start": "node dist/index.js"
|
|
19
|
-
},
|
|
20
|
-
"keywords": [
|
|
21
|
-
"mcp",
|
|
22
|
-
"ssh",
|
|
23
|
-
"model context protocol",
|
|
24
|
-
"automation",
|
|
25
|
-
"stateless"
|
|
26
|
-
],
|
|
27
|
-
"author": "jadchene",
|
|
28
|
-
"license": "MIT",
|
|
29
|
-
"repository": {
|
|
30
|
-
"type": "git",
|
|
31
|
-
"url": "https://github.com/jadchene/mcp-ssh.git"
|
|
32
|
-
},
|
|
33
|
-
"bugs": {
|
|
34
|
-
"url": "https://github.com/jadchene/mcp-ssh/issues"
|
|
35
|
-
},
|
|
36
|
-
"publishConfig": {
|
|
37
|
-
"access": "public"
|
|
38
|
-
},
|
|
39
|
-
"dependencies": {
|
|
40
|
-
"@modelcontextprotocol/sdk": "^1.0.1",
|
|
41
|
-
"ssh2": "^1.15.0",
|
|
42
|
-
"winston": "^3.11.0"
|
|
43
|
-
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@types/node": "^20.10.0",
|
|
46
|
-
"@types/ssh2": "^1.11.19",
|
|
47
|
-
"typescript": "^5.3.3"
|
|
48
|
-
}
|
|
49
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@jadchene/mcp-ssh-service",
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "A production-ready, highly secure SSH MCP server featuring stateless connections, two-step operation confirmation, and comprehensive DevOps tool integration.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-ssh-service": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"prepare": "npm run build",
|
|
16
|
+
"watch": "tsc -w",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"start": "node dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"ssh",
|
|
23
|
+
"model context protocol",
|
|
24
|
+
"automation",
|
|
25
|
+
"stateless"
|
|
26
|
+
],
|
|
27
|
+
"author": "jadchene",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/jadchene/mcp-ssh.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/jadchene/mcp-ssh/issues"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.0.1",
|
|
41
|
+
"ssh2": "^1.15.0",
|
|
42
|
+
"winston": "^3.11.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^20.10.0",
|
|
46
|
+
"@types/ssh2": "^1.11.19",
|
|
47
|
+
"typescript": "^5.3.3"
|
|
48
|
+
}
|
|
49
|
+
}
|