mcp-ssh-pty 1.2.0 → 1.2.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.
@@ -3,6 +3,7 @@ import { ShellResult, ShellConfig } from "./types.js";
3
3
  export declare class ShellManager {
4
4
  private shell;
5
5
  private localProcess;
6
+ private ptyProcess;
6
7
  private outputBuffer;
7
8
  private outputLines;
8
9
  private lastOutputTime;
@@ -14,7 +15,7 @@ export declare class ShellManager {
14
15
  */
15
16
  open(client: Client): Promise<void>;
16
17
  /**
17
- * 打开本地 Shell
18
+ * 打开本地 Shell(使用 node-pty 创建真正的 PTY)
18
19
  */
19
20
  openLocal(): Promise<void>;
20
21
  /**
@@ -1,4 +1,4 @@
1
- import { spawn } from "child_process";
1
+ import * as pty from "node-pty";
2
2
  const DEFAULT_CONFIG = {
3
3
  quickTimeout: 2000,
4
4
  maxTimeout: 5000,
@@ -8,6 +8,7 @@ const DEFAULT_CONFIG = {
8
8
  export class ShellManager {
9
9
  shell = null;
10
10
  localProcess = null;
11
+ ptyProcess = null;
11
12
  outputBuffer = "";
12
13
  outputLines = [];
13
14
  lastOutputTime = 0;
@@ -37,42 +38,39 @@ export class ShellManager {
37
38
  });
38
39
  }
39
40
  /**
40
- * 打开本地 Shell
41
+ * 打开本地 Shell(使用 node-pty 创建真正的 PTY)
41
42
  */
42
43
  async openLocal() {
43
44
  return new Promise((resolve, reject) => {
44
45
  try {
45
46
  // 检测系统默认 shell
46
- const shellPath = process.env.SHELL || (process.platform === "win32" ? "cmd.exe" : "/bin/sh");
47
- const proc = spawn(shellPath, [], {
48
- stdio: ["pipe", "pipe", "pipe"],
49
- env: { ...process.env, TERM: "xterm-256color" },
47
+ const shellPath = process.env.SHELL || (process.platform === "win32" ? "powershell.exe" : "/bin/sh");
48
+ // 使用 node-pty 创建真正的 PTY
49
+ const ptyProc = pty.spawn(shellPath, [], {
50
+ name: "xterm-256color",
51
+ cols: 120,
52
+ rows: 40,
53
+ cwd: process.cwd(),
54
+ env: process.env,
50
55
  });
51
- this.localProcess = proc;
56
+ this.ptyProcess = ptyProc;
52
57
  this.isLocal = true;
53
58
  // 创建统一的 stream 接口
54
59
  const dataListeners = [];
55
60
  const closeListeners = [];
56
61
  const errorListeners = [];
57
- proc.stdout?.on("data", (data) => {
58
- dataListeners.forEach((l) => l(data));
62
+ ptyProc.onData((data) => {
63
+ dataListeners.forEach((l) => l(Buffer.from(data)));
59
64
  });
60
- proc.stderr?.on("data", (data) => {
61
- dataListeners.forEach((l) => l(data));
62
- });
63
- proc.on("close", () => {
65
+ ptyProc.onExit(() => {
64
66
  closeListeners.forEach((l) => l());
65
67
  });
66
- proc.on("error", (err) => {
67
- errorListeners.forEach((l) => l(err));
68
- });
69
68
  const stream = {
70
69
  write: (data) => {
71
- proc.stdin?.write(data);
70
+ ptyProc.write(data);
72
71
  },
73
72
  end: () => {
74
- proc.stdin?.end();
75
- proc.kill();
73
+ ptyProc.kill();
76
74
  },
77
75
  on: ((event, listener) => {
78
76
  if (event === "data") {
@@ -88,10 +86,10 @@ export class ShellManager {
88
86
  };
89
87
  this.shell = stream;
90
88
  this.setupStream(stream);
91
- // 等待初始化
89
+ // 等待初始提示符
92
90
  setTimeout(() => {
93
91
  resolve();
94
- }, 300);
92
+ }, 500);
95
93
  }
96
94
  catch (error) {
97
95
  reject(new Error(`无法打开本地 shell: ${error instanceof Error ? error.message : String(error)}`));
@@ -124,6 +122,7 @@ export class ShellManager {
124
122
  stream.on("close", () => {
125
123
  this.shell = null;
126
124
  this.localProcess = null;
125
+ this.ptyProcess = null;
127
126
  });
128
127
  stream.on("error", (err) => {
129
128
  console.error("Shell error:", err.message);
@@ -223,6 +222,10 @@ export class ShellManager {
223
222
  this.localProcess.kill();
224
223
  this.localProcess = null;
225
224
  }
225
+ if (this.ptyProcess) {
226
+ this.ptyProcess.kill();
227
+ this.ptyProcess = null;
228
+ }
226
229
  this.outputLines = [];
227
230
  this.outputBuffer = "";
228
231
  this.isLocal = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-ssh-pty",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "MCP Server for SSH remote command execution with PTY shell support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -33,6 +33,7 @@
33
33
  "@inquirer/prompts": "^8.1.0",
34
34
  "@modelcontextprotocol/sdk": "^1.0.0",
35
35
  "commander": "^14.0.2",
36
+ "node-pty": "^1.1.0",
36
37
  "ssh2": "^1.16.0",
37
38
  "zod": "^3.24.0"
38
39
  },