smart-terminal-mcp 1.2.0 → 1.2.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
@@ -2,7 +2,7 @@
2
2
 
3
3
  A Windows-native MCP server that gives AI agents (Claude, Cursor, etc.) real interactive terminal access via pseudo-terminals ([node-pty](https://github.com/microsoft/node-pty)).
4
4
 
5
- Unlike simple `exec`-based approaches, this provides full PTY sessions with bidirectional communication, enabling interactive CLI tools, real-time output streaming, and proper terminal emulation.
5
+ Unlike simple `exec`-based approaches, this provides full PTY sessions with bidirectional communication, enabling interactive CLI tools, incremental terminal reads, and proper terminal emulation.
6
6
 
7
7
  ## Features
8
8
 
@@ -19,19 +19,11 @@ Unlike simple `exec`-based approaches, this provides full PTY sessions with bidi
19
19
  - **CWD tracking** -- Every `terminal_exec` response includes the current working directory
20
20
  - **Output truncation** -- Large outputs are automatically truncated to head + tail
21
21
  - **Session management** -- Named sessions, TTL auto-cleanup, max 10 concurrent sessions
22
- - **Anti-blocking** -- Disables pagers (`GIT_PAGER=cat`), progress bars, and sets UTF-8 on Windows
23
- - **Progress notifications** -- Real-time MCP progress updates during long-running commands
22
+ - **Anti-blocking** -- Disables pagers (`GIT_PAGER=cat`, `PAGER=cat`), suppresses PowerShell progress output, and sets UTF-8 for `cmd.exe` on Windows
23
+ - **Best-effort progress notifications** -- Emits MCP `notifications/progress` for long-running `terminal_exec` / `terminal_wait` calls when the client provides a progress token and surfaces those notifications
24
24
  - **Shell auto-detection** -- Windows: `pwsh.exe` > `powershell.exe` > `cmd.exe`. Linux/macOS: `$SHELL` or `bash`
25
25
 
26
- ## Requirements
27
-
28
- - **Node.js** >= 18
29
-
30
- `node-pty` ships prebuilt binaries for most platforms. If prebuilds are unavailable for your OS/architecture, a C/C++ toolchain is needed as fallback:
31
-
32
- - **Windows**: [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) (select "Desktop development with C++")
33
- - **macOS**: Xcode Command Line Tools (`xcode-select --install`)
34
- - **Linux**: `build-essential` and Python 3 (`sudo apt install build-essential python3`)
26
+ Progress notifications are not the same as full stdout streaming: they currently send periodic status updates for `terminal_exec` and `terminal_wait`, typically based on elapsed time and the latest output line. Whether you actually see them depends on your MCP client.
35
27
 
36
28
  ## Installation
37
29
 
@@ -116,7 +108,7 @@ Start a new interactive terminal session.
116
108
 
117
109
  ### `terminal_exec`
118
110
 
119
- Execute a command with deterministic completion detection.
111
+ Execute a command with deterministic completion detection. If the MCP client sends a `progressToken`, long-running calls may also emit best-effort `notifications/progress` updates.
120
112
 
121
113
  | Param | Type | Default | Description |
122
114
  |-------|------|---------|-------------|
@@ -211,7 +203,7 @@ Send a named special key.
211
203
 
212
204
  ### `terminal_wait`
213
205
 
214
- Wait for a specific pattern in the output stream.
206
+ Wait for a specific pattern in the output stream. If the MCP client sends a `progressToken`, long-running waits may also emit best-effort `notifications/progress` updates.
215
207
 
216
208
  | Param | Type | Default | Description |
217
209
  |-------|------|---------|-------------|
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-terminal-mcp",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "MCP PTY server providing AI agents with real interactive terminal access",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -16,6 +16,23 @@ export const DEFAULT_HISTORY_FORMAT = 'lines';
16
16
  const DEFAULT_WAIT_RETURN_MODE = 'tail';
17
17
  const DEFAULT_WAIT_TAIL_LINES = 50;
18
18
 
19
+ export function buildSessionEnv(customEnv = {}, platformName = platform()) {
20
+ const env = {
21
+ ...process.env,
22
+ ...customEnv,
23
+ GIT_PAGER: 'cat',
24
+ PAGER: 'cat',
25
+ LESS: '-FRX',
26
+ TERM: 'xterm-256color',
27
+ };
28
+
29
+ if (platformName !== 'win32') {
30
+ env.DEBIAN_FRONTEND = 'noninteractive';
31
+ }
32
+
33
+ return env;
34
+ }
35
+
19
36
  function escapeRegExp(value) {
20
37
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
21
38
  }
@@ -100,18 +117,7 @@ export class PtySession {
100
117
  /** @type {((data: string) => void)[]} */
101
118
  this._dataListeners = [];
102
119
 
103
- const env = {
104
- ...process.env,
105
- ...customEnv,
106
- GIT_PAGER: 'cat',
107
- PAGER: 'cat',
108
- LESS: '-FRX',
109
- TERM: 'xterm-256color',
110
- };
111
-
112
- if (platform() !== 'win32') {
113
- env.DEBIAN_FRONTEND = 'noninteractive';
114
- }
120
+ const env = buildSessionEnv(customEnv);
115
121
 
116
122
  this.process = pty.spawn(shell, shellArgs, {
117
123
  name: 'xterm-256color',
@@ -1,6 +1,6 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import { PtySession } from '../src/pty-session.js';
3
+ import { buildSessionEnv, PtySession } from '../src/pty-session.js';
4
4
 
5
5
  function createSession() {
6
6
  return Object.create(PtySession.prototype);
@@ -14,6 +14,23 @@ function createWaitSession(buffer = '') {
14
14
  return session;
15
15
  }
16
16
 
17
+ test('buildSessionEnv applies anti-blocking environment defaults', () => {
18
+ const env = buildSessionEnv({ CUSTOM_ENV: 'yes', GIT_PAGER: 'less' }, 'linux');
19
+
20
+ assert.equal(env.CUSTOM_ENV, 'yes');
21
+ assert.equal(env.GIT_PAGER, 'cat');
22
+ assert.equal(env.PAGER, 'cat');
23
+ assert.equal(env.LESS, '-FRX');
24
+ assert.equal(env.TERM, 'xterm-256color');
25
+ assert.equal(env.DEBIAN_FRONTEND, 'noninteractive');
26
+ });
27
+
28
+ test('buildSessionEnv skips noninteractive override on Windows', () => {
29
+ const env = buildSessionEnv({}, 'win32');
30
+
31
+ assert.equal(env.DEBIAN_FRONTEND, undefined);
32
+ });
33
+
17
34
  test('PowerShell wrapper uses safe marker interpolation', () => {
18
35
  const session = createSession();
19
36
  session.shellType = 'powershell';
@@ -24,6 +41,40 @@ test('PowerShell wrapper uses safe marker interpolation', () => {
24
41
  assert.match(command, /__CWD_\$\(\(Get-Location\)\.Path\)__/);
25
42
  });
26
43
 
44
+ test('_initShell suppresses PowerShell progress output', async () => {
45
+ const session = createSession();
46
+ const writes = [];
47
+ let resetCalls = 0;
48
+ session.shellType = 'powershell';
49
+ session.process = { write: (value) => writes.push(value) };
50
+ session._readUntilIdle = async () => '';
51
+ session._resetBuffer = () => {
52
+ resetCalls++;
53
+ };
54
+
55
+ await session._initShell();
56
+
57
+ assert.deepEqual(writes, ["$ProgressPreference = 'SilentlyContinue'\r"]);
58
+ assert.equal(resetCalls, 1);
59
+ });
60
+
61
+ test('_initShell sets cmd sessions to UTF-8', async () => {
62
+ const session = createSession();
63
+ const writes = [];
64
+ let resetCalls = 0;
65
+ session.shellType = 'cmd';
66
+ session.process = { write: (value) => writes.push(value) };
67
+ session._readUntilIdle = async () => '';
68
+ session._resetBuffer = () => {
69
+ resetCalls++;
70
+ };
71
+
72
+ await session._initShell();
73
+
74
+ assert.deepEqual(writes, ['chcp 65001 > nul\r']);
75
+ assert.equal(resetCalls, 1);
76
+ });
77
+
27
78
  test('_parseOutput ignores echoed wrapper text and keeps real output', () => {
28
79
  const session = createSession();
29
80
  const preMarker = '__MCP_PRE_abc__';