@ebowwa/mcp-terminal 1.0.8 → 1.0.9
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 +194 -0
- package/package.json +16 -3
- package/BUG-ANALYSIS.md +0 -148
- package/FIX-QUICK-REF.md +0 -67
- package/ROLLBACK.md +0 -388
- package/bun.lock +0 -323
- package/lmdb.db +0 -0
- package/lmdb.db-lock +0 -0
- package/test-fix.sh +0 -273
- package/wrapper.mjs +0 -10
package/README.md
CHANGED
|
@@ -166,10 +166,204 @@ curl -X POST http://localhost:8913/mcp \
|
|
|
166
166
|
}'
|
|
167
167
|
```
|
|
168
168
|
|
|
169
|
+
## Environment Variables
|
|
170
|
+
|
|
171
|
+
| Variable | Description | Default |
|
|
172
|
+
|----------|-------------|---------|
|
|
173
|
+
| `MCP_PORT` | Port for MCP HTTP server | `8913` |
|
|
174
|
+
| `SSH_KEY_PATH` | Path to SSH private key | `~/.ssh/id_rsa` |
|
|
175
|
+
| `SSH_TIMEOUT` | SSH connection timeout (ms) | `30000` |
|
|
176
|
+
| `TMUX_SOCKET_PATH` | Custom tmux socket path | (system default) |
|
|
177
|
+
| `DEBUG_TERMINAL_MCP` | Enable debug logging | `false` |
|
|
178
|
+
|
|
179
|
+
## Common Workflows
|
|
180
|
+
|
|
181
|
+
### SSH Connection Testing
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Test if a host is reachable
|
|
185
|
+
curl -X POST http://localhost:8913/mcp \
|
|
186
|
+
-H "Content-Type: application/json" \
|
|
187
|
+
-d '{
|
|
188
|
+
"tool": "test_connection",
|
|
189
|
+
"args": {
|
|
190
|
+
"host": "user@server.com"
|
|
191
|
+
}
|
|
192
|
+
}'
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Response:
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"success": true,
|
|
199
|
+
"host": "user@server.com",
|
|
200
|
+
"message": "Connection successful"
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Creating and Managing Sessions
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# 1. Create a session
|
|
208
|
+
curl -X POST http://localhost:8913/mcp \
|
|
209
|
+
-H "Content-Type: application/json" \
|
|
210
|
+
-d '{
|
|
211
|
+
"tool": "create_session",
|
|
212
|
+
"args": {
|
|
213
|
+
"host": "user@server.com",
|
|
214
|
+
"type": "ssh",
|
|
215
|
+
"command": "bash"
|
|
216
|
+
}
|
|
217
|
+
}'
|
|
218
|
+
|
|
219
|
+
# Response includes session_id
|
|
220
|
+
|
|
221
|
+
# 2. Write commands to the session
|
|
222
|
+
curl -X POST http://localhost:8913/mcp \
|
|
223
|
+
-H "Content-Type: application/json" \
|
|
224
|
+
-d '{
|
|
225
|
+
"tool": "write_command",
|
|
226
|
+
"args": {
|
|
227
|
+
"session_id": "abc123",
|
|
228
|
+
"command": "ls -la /var/log"
|
|
229
|
+
}
|
|
230
|
+
}'
|
|
231
|
+
|
|
232
|
+
# 3. Close session when done
|
|
233
|
+
curl -X POST http://localhost:8913/mcp \
|
|
234
|
+
-H "Content-Type: application/json" \
|
|
235
|
+
-d '{
|
|
236
|
+
"tool": "close_session",
|
|
237
|
+
"args": {
|
|
238
|
+
"session_id": "abc123"
|
|
239
|
+
}
|
|
240
|
+
}'
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Parallel SSH Execution
|
|
244
|
+
|
|
245
|
+
Execute commands on multiple hosts simultaneously:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
curl -X POST http://localhost:8913/mcp \
|
|
249
|
+
-H "Content-Type: application/json" \
|
|
250
|
+
-d '{
|
|
251
|
+
"tool": "exec_ssh_parallel",
|
|
252
|
+
"args": {
|
|
253
|
+
"hosts": ["web1.example.com", "web2.example.com", "web3.example.com"],
|
|
254
|
+
"command": "systemctl status nginx"
|
|
255
|
+
}
|
|
256
|
+
}'
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### File Transfer Operations
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# Upload a configuration file
|
|
263
|
+
curl -X POST http://localhost:8913/mcp \
|
|
264
|
+
-H "Content-Type: application/json" \
|
|
265
|
+
-d '{
|
|
266
|
+
"tool": "upload_file",
|
|
267
|
+
"args": {
|
|
268
|
+
"host": "user@server.com",
|
|
269
|
+
"local_path": "./nginx.conf",
|
|
270
|
+
"remote_path": "/etc/nginx/nginx.conf"
|
|
271
|
+
}
|
|
272
|
+
}'
|
|
273
|
+
|
|
274
|
+
# Download log files
|
|
275
|
+
curl -X POST http://localhost:8913/mcp \
|
|
276
|
+
-H "Content-Type: application/json" \
|
|
277
|
+
-d '{
|
|
278
|
+
"tool": "download_file",
|
|
279
|
+
"args": {
|
|
280
|
+
"host": "user@server.com",
|
|
281
|
+
"remote_path": "/var/log/app/error.log",
|
|
282
|
+
"local_path": "./error.log"
|
|
283
|
+
}
|
|
284
|
+
}'
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Tmux Session Management
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# List all tmux sessions on a remote host
|
|
291
|
+
curl -X POST http://localhost:8913/mcp \
|
|
292
|
+
-H "Content-Type: application/json" \
|
|
293
|
+
-d '{
|
|
294
|
+
"tool": "list_tmux_sessions",
|
|
295
|
+
"args": {
|
|
296
|
+
"host": "user@server.com"
|
|
297
|
+
}
|
|
298
|
+
}'
|
|
299
|
+
|
|
300
|
+
# Create a new tmux session
|
|
301
|
+
curl -X POST http://localhost:8913/mcp \
|
|
302
|
+
-H "Content-Type: application/json" \
|
|
303
|
+
-d '{
|
|
304
|
+
"tool": "create_tmux_session",
|
|
305
|
+
"args": {
|
|
306
|
+
"host": "user@server.com",
|
|
307
|
+
"session_name": "my-app"
|
|
308
|
+
}
|
|
309
|
+
}'
|
|
310
|
+
|
|
311
|
+
# Send command to tmux pane
|
|
312
|
+
curl -X POST http://localhost:8913/mcp \
|
|
313
|
+
-H "Content-Type: application/json" \
|
|
314
|
+
-d '{
|
|
315
|
+
"tool": "send_to_tmux_pane",
|
|
316
|
+
"args": {
|
|
317
|
+
"host": "user@server.com",
|
|
318
|
+
"session_name": "my-app",
|
|
319
|
+
"command": "npm run dev"
|
|
320
|
+
}
|
|
321
|
+
}'
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Error Handling
|
|
325
|
+
|
|
326
|
+
All tools return structured error responses:
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
{
|
|
330
|
+
"success": false,
|
|
331
|
+
"error": {
|
|
332
|
+
"code": "SSH_CONNECTION_FAILED",
|
|
333
|
+
"message": "Failed to connect to host",
|
|
334
|
+
"details": "Connection refused"
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Common error codes:
|
|
340
|
+
- `SSH_CONNECTION_FAILED`: Could not establish SSH connection
|
|
341
|
+
- `SESSION_NOT_FOUND`: Requested session does not exist
|
|
342
|
+
- `INVALID_ARGUMENTS`: Missing or invalid arguments
|
|
343
|
+
- `COMMAND_FAILED`: Command execution failed
|
|
344
|
+
- `FILE_TRANSFER_FAILED`: SCP operation failed
|
|
345
|
+
|
|
169
346
|
## Integration with Claude
|
|
170
347
|
|
|
171
348
|
This MCP server can be integrated with Claude Code or other MCP-compatible clients to provide terminal management capabilities.
|
|
172
349
|
|
|
350
|
+
### Claude Desktop Configuration
|
|
351
|
+
|
|
352
|
+
```json
|
|
353
|
+
{
|
|
354
|
+
"mcpServers": {
|
|
355
|
+
"terminal": {
|
|
356
|
+
"command": "bun",
|
|
357
|
+
"args": ["run", "/path/to/mcp-terminal/src/index.ts"],
|
|
358
|
+
"env": {
|
|
359
|
+
"MCP_PORT": "8913",
|
|
360
|
+
"DEBUG_TERMINAL_MCP": "false"
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
173
367
|
## Dependencies
|
|
174
368
|
|
|
175
369
|
- `node-ssh`: SSH client functionality
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ebowwa/mcp-terminal",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Terminal session management MCP server with SSH, tmux, and file operations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "stdio.js",
|
|
@@ -10,10 +10,15 @@
|
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./stdio.js"
|
|
12
12
|
},
|
|
13
|
+
"files": [
|
|
14
|
+
"stdio.js",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
13
17
|
"scripts": {
|
|
14
18
|
"dev": "bun --hot stdio.ts",
|
|
15
19
|
"start": "bun stdio.ts",
|
|
16
|
-
"build": "npx esbuild stdio.ts --bundle --external:@ebowwa/terminal --external:@ebowwa/codespaces-types --external:@modelcontextprotocol/sdk --external:zod --platform=node --format=esm --outfile=stdio.js"
|
|
20
|
+
"build": "npx esbuild stdio.ts --bundle --external:@ebowwa/terminal --external:@ebowwa/codespaces-types --external:@modelcontextprotocol/sdk --external:zod --platform=node --format=esm --outfile=stdio.js",
|
|
21
|
+
"test": "bun test"
|
|
17
22
|
},
|
|
18
23
|
"keywords": [
|
|
19
24
|
"mcp",
|
|
@@ -26,7 +31,7 @@
|
|
|
26
31
|
"license": "MIT",
|
|
27
32
|
"dependencies": {
|
|
28
33
|
"@ebowwa/codespaces-types": "^1.1.0",
|
|
29
|
-
"@ebowwa/terminal": "^0.
|
|
34
|
+
"@ebowwa/terminal": "^0.3.9",
|
|
30
35
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
31
36
|
"zod": "^3.24.1"
|
|
32
37
|
},
|
|
@@ -36,5 +41,13 @@
|
|
|
36
41
|
},
|
|
37
42
|
"peerDependencies": {
|
|
38
43
|
"bun": ">=1.0.0"
|
|
44
|
+
},
|
|
45
|
+
"ownership": {
|
|
46
|
+
"domain": "mcp",
|
|
47
|
+
"responsibilities": [
|
|
48
|
+
"terminal-mcp",
|
|
49
|
+
"ssh-management",
|
|
50
|
+
"tmux-operations"
|
|
51
|
+
]
|
|
39
52
|
}
|
|
40
53
|
}
|
package/BUG-ANALYSIS.md
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
# Terminal MCP Recursive Loop Bug Analysis
|
|
2
|
-
|
|
3
|
-
## Date: 2026-02-05
|
|
4
|
-
## Team: terminal-mcp-fix
|
|
5
|
-
## Status: Analysis Complete
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Bug Description
|
|
10
|
-
|
|
11
|
-
The `execSSHTool` function in `/packages/src/terminal/mcp/stdio.ts` has a **parameter order mismatch** causing recursive loop behavior.
|
|
12
|
-
|
|
13
|
-
### Location of Bug
|
|
14
|
-
|
|
15
|
-
**File:** `/packages/src/terminal/mcp/stdio.ts`
|
|
16
|
-
**Line:** 223-225
|
|
17
|
-
|
|
18
|
-
```typescript
|
|
19
|
-
async function execSSHTool(host: string, command: string, options?: Partial<SSHOptions>): Promise<string> {
|
|
20
|
-
try {
|
|
21
|
-
const result = await execSSH(host, command, options); // ❌ WRONG PARAMETER ORDER
|
|
22
|
-
return result.stdout || result.stderr || "Command executed";
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### Root Cause
|
|
26
|
-
|
|
27
|
-
**Function Signature Mismatch:**
|
|
28
|
-
|
|
29
|
-
The `execSSH` function from `client.ts` expects:
|
|
30
|
-
```typescript
|
|
31
|
-
export async function execSSH(
|
|
32
|
-
command: string, // 1st param: command string
|
|
33
|
-
options: SSHOptions, // 2nd param: SSH options including host
|
|
34
|
-
): Promise<string>
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
But `execSSHTool` calls it with:
|
|
38
|
-
```typescript
|
|
39
|
-
execSSH(host, command, options) // ❌ WRONG
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### Impact
|
|
43
|
-
|
|
44
|
-
1. **Wrong command execution:** The `host` string is executed as a shell command
|
|
45
|
-
2. **Options misinterpretation:** The actual `command` is treated as SSH options
|
|
46
|
-
3. **Potential recursion:** If options contain objects that trigger re-execution
|
|
47
|
-
4. **Silent failures:** Errors may be masked by fallback return values
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Fix Required
|
|
52
|
-
|
|
53
|
-
### Option 1: Fix the call (RECOMMENDED)
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
async function execSSHTool(host: string, command: string, options?: Partial<SSHOptions>): Promise<string> {
|
|
57
|
-
try {
|
|
58
|
-
const result = await execSSH(command, { // ✅ CORRECT ORDER
|
|
59
|
-
...options,
|
|
60
|
-
host,
|
|
61
|
-
});
|
|
62
|
-
return result.stdout || result.stderr || "Command executed";
|
|
63
|
-
} catch (error) {
|
|
64
|
-
throw new Error(`SSH command failed: ${error}`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Option 2: Change function signature (ALTERNATIVE)
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
async function execSSHTool(command: string, options: SSHOptions): Promise<string> {
|
|
73
|
-
try {
|
|
74
|
-
const result = await execSSH(command, options); // ✅ MATCHES SIGNATURE
|
|
75
|
-
return result.stdout || result.stderr || "Command executed";
|
|
76
|
-
} catch (error) {
|
|
77
|
-
throw new Error(`SSH command failed: ${error}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## Test Coverage
|
|
85
|
-
|
|
86
|
-
### Test Suite Location
|
|
87
|
-
|
|
88
|
-
`/packages/src/terminal/mcp/test-fix.sh`
|
|
89
|
-
|
|
90
|
-
### Test Cases
|
|
91
|
-
|
|
92
|
-
1. **Server Startup:** Verify MCP server starts without errors
|
|
93
|
-
2. **No Recursion:** Execute safe commands and detect infinite loops
|
|
94
|
-
3. **Memory Leaks:** Monitor memory growth over multiple executions
|
|
95
|
-
4. **Parameter Validation:** Test missing/invalid parameter handling
|
|
96
|
-
5. **Tool Discovery:** Verify `exec_ssh` appears in tools list
|
|
97
|
-
|
|
98
|
-
### Safe Test Commands
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
echo 'test' # Safe echo
|
|
102
|
-
whoami # Current user
|
|
103
|
-
pwd # Current directory
|
|
104
|
-
uname -m # Machine architecture
|
|
105
|
-
date +%s # Unix timestamp
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## Risk Assessment
|
|
111
|
-
|
|
112
|
-
### Severity: HIGH
|
|
113
|
-
|
|
114
|
-
- **Impact:** Can execute hostnames as shell commands
|
|
115
|
-
- **Scope:** Affects all `exec_ssh` tool calls via MCP
|
|
116
|
-
- **Exploitability:** High if user-provided hosts are not validated
|
|
117
|
-
|
|
118
|
-
### Mitigation
|
|
119
|
-
|
|
120
|
-
1. Apply fix immediately to `stdio.ts`
|
|
121
|
-
2. Add unit tests for parameter validation
|
|
122
|
-
3. Add integration tests for exec_ssh tool
|
|
123
|
-
4. Review all MCP tool implementations for similar issues
|
|
124
|
-
|
|
125
|
-
---
|
|
126
|
-
|
|
127
|
-
## Related Files
|
|
128
|
-
|
|
129
|
-
- `/packages/src/terminal/mcp/stdio.ts` - **NEEDS FIX**
|
|
130
|
-
- `/packages/src/terminal/mcp/index.ts` - May have same issue
|
|
131
|
-
- `/packages/src/terminal/client.ts` - Reference implementation
|
|
132
|
-
- `/packages/src/terminal/mcp/test-fix.sh` - Test suite
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
## Next Steps
|
|
137
|
-
|
|
138
|
-
1. ✅ Analysis complete
|
|
139
|
-
2. ⏳ Fixers implementing fix
|
|
140
|
-
3. ⏳ Testers running test suite
|
|
141
|
-
4. ⏳ Verify no regression
|
|
142
|
-
5. ⏳ Deploy to production
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
**Author:** Test Engineer
|
|
147
|
-
**Reviewed by:** team-lead
|
|
148
|
-
**Priority:** CRITICAL
|
package/FIX-QUICK-REF.md
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# Terminal MCP Fix - Quick Reference
|
|
2
|
-
|
|
3
|
-
## TL;DR
|
|
4
|
-
|
|
5
|
-
**File:** `stdio.ts` line 225
|
|
6
|
-
**Bug:** Wrong parameter order to `execSSH()`
|
|
7
|
-
**Fix:** Swap parameters to match function signature
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## The Fix
|
|
12
|
-
|
|
13
|
-
### BEFORE (Line 223-225):
|
|
14
|
-
```typescript
|
|
15
|
-
async function execSSHTool(host: string, command: string, options?: Partial<SSHOptions>): Promise<string> {
|
|
16
|
-
try {
|
|
17
|
-
const result = await execSSH(host, command, options); // ❌ WRONG
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
### AFTER:
|
|
21
|
-
```typescript
|
|
22
|
-
async function execSSHTool(host: string, command: string, options?: Partial<SSHOptions>): Promise<string> {
|
|
23
|
-
try {
|
|
24
|
-
const result = await execSSH(command, { // ✅ CORRECT
|
|
25
|
-
...options,
|
|
26
|
-
host,
|
|
27
|
-
});
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## Why This Works
|
|
33
|
-
|
|
34
|
-
The `execSSH` function signature is:
|
|
35
|
-
```typescript
|
|
36
|
-
execSSH(command: string, options: SSHOptions)
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
So we need to pass:
|
|
40
|
-
1. `command` as first parameter
|
|
41
|
-
2. Object with `host` field merged with `options` as second parameter
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## Same Issue in index.ts
|
|
46
|
-
|
|
47
|
-
**File:** `index.ts` line 215
|
|
48
|
-
|
|
49
|
-
Same fix needed there too!
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## Testing
|
|
54
|
-
|
|
55
|
-
After fix, run:
|
|
56
|
-
```bash
|
|
57
|
-
cd /Users/ebowwa/Desktop/codespaces/packages/src/terminal/mcp
|
|
58
|
-
./test-fix.sh
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## Status
|
|
64
|
-
|
|
65
|
-
- ✅ Analysis complete
|
|
66
|
-
- ⏳ Fix pending
|
|
67
|
-
- ⏳ Test suite ready
|