mcp-yieldshell 0.1.7__tar.gz

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.
@@ -0,0 +1,166 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ bin/
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nosenv/
43
+ .pytest_cache/
44
+ .tox/
45
+ .grudge/
46
+ .htmlcov/
47
+ .coverage
48
+ .coverage.*
49
+ .cache
50
+ nosetests.xml
51
+ coverage.xml
52
+ *.cover
53
+ *.py,cover
54
+ .hypothesis/
55
+ .pytest_cache/
56
+ .ruff_cache/
57
+
58
+ # Translations
59
+ *.mo
60
+ *.pot
61
+
62
+ # Django stuff:
63
+ *.log
64
+ local_settings.py
65
+ db.sqlite3
66
+ db.sqlite3-journal
67
+
68
+ # Sphinx documentation
69
+ docs/_build/
70
+
71
+ # PyBuilder
72
+ .pybuilder/
73
+ target/
74
+
75
+ # Jupyter Notebook
76
+ .ipynb_checkpoints
77
+
78
+ # IPython
79
+ profile_default/
80
+ ipython_config.py
81
+
82
+ # pyenv
83
+ # For a library or package, you might want to share your .python-version.
84
+ # For an app, this is usually fine to prevent.
85
+ # .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if Pipfile.lock is not desired, it can be added here.
90
+ #Pipfile.lock
91
+
92
+ # poetry
93
+ # Similar to Pipfile.lock, poetry.lock is generally recommended to be committed.
94
+ #poetry.lock
95
+
96
+ # pdm
97
+ # Similar to Pipfile.lock, pdm.lock is generally recommended to be committed.
98
+ #pdm.lock
99
+
100
+ # PEP 582; project local packages directory (PDM, Poetry)
101
+ __pypackages__/
102
+
103
+ # Celery stuff
104
+ celerybeat-schedule
105
+ celerybeat.pid
106
+
107
+ # SageMath parsed files
108
+ *.sage.py
109
+
110
+ # Environments
111
+ .env
112
+ .venv
113
+ env/
114
+ venv/
115
+ ENV/
116
+ env.bak/
117
+ venv.bak/
118
+
119
+ # Spyder project settings
120
+ .spyderproject
121
+ .spyproject
122
+
123
+ # Rope project settings
124
+ .ropeproject
125
+
126
+ # mkdocs documentation
127
+ /site
128
+
129
+ # mypy
130
+ .mypy_cache/
131
+ .dmypy.json
132
+ dmypy.json
133
+
134
+ # Pyre type checker
135
+ .pyre/
136
+
137
+ # pytype static analyzer
138
+ .pytype/
139
+
140
+ # Cython debug symbols
141
+ cython_debug/
142
+
143
+ # OS-specific files
144
+ .DS_Store
145
+ .DS_Store?
146
+ ._*
147
+ .Spotlight-V100
148
+ .Trashes
149
+ ehthumbs.db
150
+ Thumbs.db
151
+
152
+ # IDEs
153
+ .vscode/
154
+ .idea/
155
+ *.suo
156
+ *.ntvs*
157
+ *.njsproj
158
+ *.sln
159
+ *.sw?
160
+
161
+ # Project specific
162
+ .cybervisor/
163
+ .prompts/
164
+ .antigravitycli/
165
+
166
+
@@ -0,0 +1,266 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-yieldshell
3
+ Version: 0.1.7
4
+ Summary: A drop-in shell MCP that auto-yields long-running commands into managed background processes.
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: mcp<2,>=1.9.0
7
+ Description-Content-Type: text/markdown
8
+
9
+ # YieldShell MCP
10
+
11
+ A drop-in shell MCP server that auto-yields long-running commands into managed background processes.
12
+
13
+ ## Why Auto-Yielding?
14
+
15
+ Most shell tools present a frustrating choice: either block the LLM agent until the command finishes, or force the agent to decide upfront that a command should run in the background.
16
+
17
+ **YieldShell MCP** solves this by keeping normal foreground semantics for fast commands, then automatically promoting long-running commands into managed background processes after a brief delay (`yield_ms`, default: 1 second).
18
+
19
+ ```mermaid
20
+ graph TD
21
+ A[exec_command] --> B["Wait for yield_ms (default: 1s)"]
22
+ B --> C{Is process still running?}
23
+ C -->|Yes| D["backgrounded<br>Returns process_id"]
24
+ C -->|No| E["completed<br>Returns full output"]
25
+ ```
26
+
27
+ - **Fast Commands** (e.g., `echo hello`, `ls`): Complete instantly, returning the output immediately.
28
+ - **Long-Running Commands** (e.g., `npm run dev`, `docker build`, `sleep 60`): Automatically yield control back to the agent with a `process_id` and a snapshot of initial output, letting the agent decide when to `read`, `wait`, or `stop` the process.
29
+
30
+ ---
31
+
32
+ ## Installation
33
+
34
+ ### From Registry (Recommended)
35
+
36
+ To run the published package via `uv`:
37
+
38
+ ```bash
39
+ uv tool install mcp-yieldshell
40
+ ```
41
+
42
+ ### Local Development
43
+
44
+ To clone and run locally:
45
+
46
+ ```bash
47
+ git clone <repo-url> && cd mcp-yieldshell
48
+ uv sync
49
+ uv run mcp-yieldshell
50
+ ```
51
+
52
+ ---
53
+
54
+ ## MCP Client Configuration
55
+
56
+ ### Claude Desktop
57
+
58
+ To configure the server in Claude Desktop, add the configuration below to your Claude Desktop config file:
59
+
60
+ * **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
61
+ * **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
62
+
63
+ #### Production (via uvx)
64
+
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "yieldshell": {
69
+ "command": "uvx",
70
+ "args": ["mcp-yieldshell"]
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ #### Production with Security Restrictions
77
+
78
+ ```json
79
+ {
80
+ "mcpServers": {
81
+ "yieldshell": {
82
+ "command": "uvx",
83
+ "args": ["mcp-yieldshell"],
84
+ "env": {
85
+ "YIELDSHELL_ALLOWED_CWDS": "/home/user/projects:/tmp/build",
86
+ "YIELDSHELL_DEFAULT_TIMEOUT_MS": "300000"
87
+ }
88
+ }
89
+ }
90
+ }
91
+ ```
92
+
93
+ #### Local Development Setup
94
+
95
+ Replace `/path/to/mcp-yieldshell` with the absolute path to your cloned repository:
96
+
97
+ ```json
98
+ {
99
+ "mcpServers": {
100
+ "yieldshell": {
101
+ "command": "uv",
102
+ "args": [
103
+ "--directory",
104
+ "/path/to/mcp-yieldshell",
105
+ "run",
106
+ "mcp-yieldshell"
107
+ ]
108
+ }
109
+ }
110
+ }
111
+ ```
112
+
113
+ ### Cursor
114
+
115
+ To configure the server in Cursor:
116
+ 1. Open **Cursor Settings** -> **Features** -> **MCP**.
117
+ 2. Click **+ Add New MCP Server**.
118
+ 3. Fill out the form:
119
+ - **Name**: `yieldshell`
120
+ - **Type**: `stdio`
121
+ - **Command**: `uvx mcp-yieldshell` (or `uv --directory /path/to/mcp-yieldshell run mcp-yieldshell` for local development)
122
+
123
+ ### OpenCode
124
+
125
+ Add to your OpenCode MCP settings:
126
+
127
+ ```json
128
+ {
129
+ "mcpServers": {
130
+ "yieldshell": {
131
+ "command": "uvx",
132
+ "args": ["mcp-yieldshell"]
133
+ }
134
+ }
135
+ }
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Tool Reference
141
+
142
+ ### `exec`
143
+ Execute a shell command. If the command runs longer than `yield_ms`, it yields a `process_id` and runs in the background.
144
+
145
+ * **Parameters**:
146
+ * `command` (string, **required**): The command string to execute in the shell.
147
+ * `cwd` (string, optional): Working directory for the command. Must be under allowed roots if `YIELDSHELL_ALLOWED_CWDS` is set. Defaults to `YIELDSHELL_DEFAULT_CWD`.
148
+ * `env` (object of string to string, optional): Additive environment variable overlay. Merged into the parent environment.
149
+ * `shell` (string, optional): A custom shell path to execute commands (e.g. `/bin/zsh`). Internally executed using the platform's default shell handler if omitted.
150
+ * `stdin` (string, optional): Initial text input written to standard input immediately after spawning.
151
+ * `name` (string, optional): A human-readable label/name to identify this process.
152
+ * `yield_ms` (integer, optional): Milliseconds to wait before yielding execution to background. Clamped by `YIELDSHELL_MAX_YIELD_MS`. Defaults to `YIELDSHELL_DEFAULT_YIELD_MS` (5000ms).
153
+ * `timeout_ms` (integer, optional): Total execution runtime limit in milliseconds. Process is killed if it runs longer than this. Defaults to `YIELDSHELL_DEFAULT_TIMEOUT_MS` (0 = no limit).
154
+ * `max_output_bytes` (integer, optional): Maximum output bytes to capture in stdout/stderr ring buffers. Subject to `YIELDSHELL_MAX_OUTPUT_BYTES` cap.
155
+
156
+ * **Output Statuses**:
157
+ * `completed`: Process finished within `yield_ms`. Returns exit code, stdout, and stderr.
158
+ * `backgrounded`: Process auto-yielded. Returns `process_id` and `pid` for tracking.
159
+ * `timed_out`: Process exceeded `timeout_ms` and was terminated.
160
+ * `stopped`: Process was explicitly terminated.
161
+ * `failed_to_start`: Command could not be spawned (e.g., bad directory or policy violation).
162
+ * `failed`: An internal execution error occurred.
163
+
164
+ ### `read`
165
+ Read stdout and/or stderr output from a running or completed background process.
166
+
167
+ * **Parameters**:
168
+ * `process_id` (string, **required**): Unique identifier of the process.
169
+ * `since_seq` (integer, optional): Return only output appended after this sequence number. Enables efficient incremental log polling.
170
+ * `max_output_bytes` (integer, optional): Clamps the response size. Defaults to the server cap.
171
+ * `streams` (string, default: `"both"`): The streams to read. Options: `"both"`, `"stdout"`, or `"stderr"`.
172
+
173
+ * **Returns**:
174
+ * `process_id`, `status`, `exit_code`, `signal`, `next_seq` (sequence index to use in subsequent `since_seq` reads), `stdout`/`stderr` text, and a `truncated` flag.
175
+
176
+ ### `write`
177
+ Write text input to the standard input (`stdin`) of a running process.
178
+
179
+ * **Parameters**:
180
+ * `process_id` (string, **required**): Unique identifier of the process.
181
+ * `input` (string, **required**): Text input to write.
182
+ * `newline` (boolean, default: `false`): If `true`, appends `\n` to the input.
183
+
184
+ ### `wait`
185
+ Block execution until the process exits or the wait timeout expires. This allows the LLM to pause and await completion without spawning a new execution loop.
186
+
187
+ * **Parameters**:
188
+ * `process_id` (string, **required**): Unique identifier of the process.
189
+ * `timeout_ms` (integer, default: `30000`): Maximum time to wait.
190
+ * `max_output_bytes` (integer, optional): Maximum output bytes to return in the response.
191
+
192
+ * **Important**: If the wait timeout expires, `wait` returns the current status but **does not kill** the process. It continues running in the background.
193
+
194
+ ### `stop`
195
+ Gracefully terminate or force kill a running process.
196
+
197
+ * **Parameters**:
198
+ * `process_id` (string, **required**): Unique identifier of the process.
199
+ * `signal` (string, default: `"SIGTERM"`): OS signal to send (e.g. `SIGTERM`, `SIGKILL`, `SIGINT`). Ignored on Windows.
200
+ * `force_after_ms` (integer, default: `3000`): Grace period before escalating to force kill (`SIGKILL`).
201
+
202
+ ### `ps`
203
+ List all managed processes.
204
+
205
+ * **Parameters**:
206
+ * `include_completed` (boolean, default: `true`): If `false`, finished/stopped processes are excluded from the output.
207
+ * `limit` (integer, default: `50`): Maximum number of entries.
208
+
209
+ ### `cleanup`
210
+ Prune completed or stopped process records to free memory.
211
+
212
+ * **Parameters**:
213
+ * `completed_older_than_ms` (integer, default: `3600000`): Prunes completed processes older than this threshold (1 hour default).
214
+ * `stopped_older_than_ms` (integer, default: `3600000`): Prunes stopped, timed-out, or failed processes older than this threshold (1 hour default).
215
+
216
+ ---
217
+
218
+ ## Sequence Number & Incremental Reads
219
+
220
+ To avoid sending duplicate data over the MCP protocol (which can consume context window space), the server implements a sequence-based polling protocol:
221
+
222
+ 1. Every output chunk appended to a process's ring buffer receives a unique, incremental sequence number (`seq`).
223
+ 2. When calling `exec`, `read`, or `wait`, the response includes a `next_seq` value representing the index of the next chunk to be written.
224
+ 3. To retrieve only *new* output, call `read` with `since_seq` set to the previously received `next_seq`.
225
+ 4. Omitting `since_seq` returns the entire contents currently stored in the buffer (clamped by `max_output_bytes`).
226
+
227
+ ---
228
+
229
+ ## Configuration Variables
230
+
231
+ Configure the server by setting these environment variables prior to launch:
232
+
233
+ | Environment Variable | Default Value | Description |
234
+ |---|---|---|
235
+ | `YIELDSHELL_DEFAULT_CWD` | Current directory | The fallback working directory for commands. |
236
+ | `YIELDSHELL_ALLOWED_CWDS` | *(none)* | A list of allowed directory paths separated by `os.pathsep` (e.g., `:` on UNIX, `;` on Windows). If set, all command execution paths must resolve inside one of these roots. |
237
+ | `YIELDSHELL_MAX_OUTPUT_BYTES` | `20000` | The default and maximum capacity of the ring buffers for stdout/stderr. |
238
+ | `YIELDSHELL_MAX_PROCESSES` | `50` | Maximum concurrent managed processes. Spawning a new command when this limit is reached will return `failed_to_start`. |
239
+ | `YIELDSHELL_DEFAULT_YIELD_MS` | `5000` | Fallback delay before auto-yielding. |
240
+ | `YIELDSHELL_MAX_YIELD_MS` | `300000` | The maximum allowed value for the `yield_ms` parameter. |
241
+ | `YIELDSHELL_DEFAULT_TIMEOUT_MS` | `0` | Default hard runtime limit (0 means no limit). |
242
+ | `YIELDSHELL_DENY_COMMAND_REGEX` | *(none)* | A regular expression pattern. Commands matching this pattern are blocked before starting. |
243
+ | `YIELDSHELL_ALLOW_COMMAND_REGEX` | *(none)* | A regular expression pattern. If set, only commands matching this pattern are permitted. |
244
+ | `YIELDSHELL_REDACT_ENV_REGEX` | `TOKEN\|KEY\|SECRET\|PASSWORD` | Regex to identify sensitive environment variable keys. Their values are redacted in stdout/stderr outputs. |
245
+
246
+ ---
247
+
248
+ ## Security Notes
249
+
250
+ * **Arbitrary Code Execution**: This server executes shell commands on the host system. Always run the server inside a container, sandbox, or isolated development VM.
251
+ * **Path Validation**: CWD path verification uses absolute paths (`resolve()`), preventing path-traversal attacks (`../`) outside the allowed roots.
252
+ * **Additive Environments**: The `env` argument overlays existing env parameters. It merges with the parent process environment instead of completely replacing it, protecting critical OS vars.
253
+ * **Best-effort Redaction**: While values of variables matching `YIELDSHELL_REDACT_ENV_REGEX` are scrubbed from outputs, this is a best-effort system. Sensitive data printed through complex formats or argument lists might not be caught.
254
+
255
+ ---
256
+
257
+ ## Platform Support
258
+
259
+ * **POSIX (Linux & macOS)**: Fully supported. Spawns processes in distinct sessions (`start_new_session=True`), allowing signals (`SIGTERM`/`SIGKILL`) to target the entire process group. This ensures child processes started by commands (such as npm dev tasks) are completely cleaned up.
260
+ * **Windows**: Supported with best-effort process group controls. Windows lacks native POSIX signals, meaning `stop` and `timeout_ms` act on the primary process, and child subprocesses might persist if they do not exit cleanly.
261
+
262
+ ---
263
+
264
+ ## License
265
+
266
+ MIT
@@ -0,0 +1,258 @@
1
+ # YieldShell MCP
2
+
3
+ A drop-in shell MCP server that auto-yields long-running commands into managed background processes.
4
+
5
+ ## Why Auto-Yielding?
6
+
7
+ Most shell tools present a frustrating choice: either block the LLM agent until the command finishes, or force the agent to decide upfront that a command should run in the background.
8
+
9
+ **YieldShell MCP** solves this by keeping normal foreground semantics for fast commands, then automatically promoting long-running commands into managed background processes after a brief delay (`yield_ms`, default: 1 second).
10
+
11
+ ```mermaid
12
+ graph TD
13
+ A[exec_command] --> B["Wait for yield_ms (default: 1s)"]
14
+ B --> C{Is process still running?}
15
+ C -->|Yes| D["backgrounded<br>Returns process_id"]
16
+ C -->|No| E["completed<br>Returns full output"]
17
+ ```
18
+
19
+ - **Fast Commands** (e.g., `echo hello`, `ls`): Complete instantly, returning the output immediately.
20
+ - **Long-Running Commands** (e.g., `npm run dev`, `docker build`, `sleep 60`): Automatically yield control back to the agent with a `process_id` and a snapshot of initial output, letting the agent decide when to `read`, `wait`, or `stop` the process.
21
+
22
+ ---
23
+
24
+ ## Installation
25
+
26
+ ### From Registry (Recommended)
27
+
28
+ To run the published package via `uv`:
29
+
30
+ ```bash
31
+ uv tool install mcp-yieldshell
32
+ ```
33
+
34
+ ### Local Development
35
+
36
+ To clone and run locally:
37
+
38
+ ```bash
39
+ git clone <repo-url> && cd mcp-yieldshell
40
+ uv sync
41
+ uv run mcp-yieldshell
42
+ ```
43
+
44
+ ---
45
+
46
+ ## MCP Client Configuration
47
+
48
+ ### Claude Desktop
49
+
50
+ To configure the server in Claude Desktop, add the configuration below to your Claude Desktop config file:
51
+
52
+ * **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
53
+ * **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
54
+
55
+ #### Production (via uvx)
56
+
57
+ ```json
58
+ {
59
+ "mcpServers": {
60
+ "yieldshell": {
61
+ "command": "uvx",
62
+ "args": ["mcp-yieldshell"]
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ #### Production with Security Restrictions
69
+
70
+ ```json
71
+ {
72
+ "mcpServers": {
73
+ "yieldshell": {
74
+ "command": "uvx",
75
+ "args": ["mcp-yieldshell"],
76
+ "env": {
77
+ "YIELDSHELL_ALLOWED_CWDS": "/home/user/projects:/tmp/build",
78
+ "YIELDSHELL_DEFAULT_TIMEOUT_MS": "300000"
79
+ }
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ #### Local Development Setup
86
+
87
+ Replace `/path/to/mcp-yieldshell` with the absolute path to your cloned repository:
88
+
89
+ ```json
90
+ {
91
+ "mcpServers": {
92
+ "yieldshell": {
93
+ "command": "uv",
94
+ "args": [
95
+ "--directory",
96
+ "/path/to/mcp-yieldshell",
97
+ "run",
98
+ "mcp-yieldshell"
99
+ ]
100
+ }
101
+ }
102
+ }
103
+ ```
104
+
105
+ ### Cursor
106
+
107
+ To configure the server in Cursor:
108
+ 1. Open **Cursor Settings** -> **Features** -> **MCP**.
109
+ 2. Click **+ Add New MCP Server**.
110
+ 3. Fill out the form:
111
+ - **Name**: `yieldshell`
112
+ - **Type**: `stdio`
113
+ - **Command**: `uvx mcp-yieldshell` (or `uv --directory /path/to/mcp-yieldshell run mcp-yieldshell` for local development)
114
+
115
+ ### OpenCode
116
+
117
+ Add to your OpenCode MCP settings:
118
+
119
+ ```json
120
+ {
121
+ "mcpServers": {
122
+ "yieldshell": {
123
+ "command": "uvx",
124
+ "args": ["mcp-yieldshell"]
125
+ }
126
+ }
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Tool Reference
133
+
134
+ ### `exec`
135
+ Execute a shell command. If the command runs longer than `yield_ms`, it yields a `process_id` and runs in the background.
136
+
137
+ * **Parameters**:
138
+ * `command` (string, **required**): The command string to execute in the shell.
139
+ * `cwd` (string, optional): Working directory for the command. Must be under allowed roots if `YIELDSHELL_ALLOWED_CWDS` is set. Defaults to `YIELDSHELL_DEFAULT_CWD`.
140
+ * `env` (object of string to string, optional): Additive environment variable overlay. Merged into the parent environment.
141
+ * `shell` (string, optional): A custom shell path to execute commands (e.g. `/bin/zsh`). Internally executed using the platform's default shell handler if omitted.
142
+ * `stdin` (string, optional): Initial text input written to standard input immediately after spawning.
143
+ * `name` (string, optional): A human-readable label/name to identify this process.
144
+ * `yield_ms` (integer, optional): Milliseconds to wait before yielding execution to background. Clamped by `YIELDSHELL_MAX_YIELD_MS`. Defaults to `YIELDSHELL_DEFAULT_YIELD_MS` (5000ms).
145
+ * `timeout_ms` (integer, optional): Total execution runtime limit in milliseconds. Process is killed if it runs longer than this. Defaults to `YIELDSHELL_DEFAULT_TIMEOUT_MS` (0 = no limit).
146
+ * `max_output_bytes` (integer, optional): Maximum output bytes to capture in stdout/stderr ring buffers. Subject to `YIELDSHELL_MAX_OUTPUT_BYTES` cap.
147
+
148
+ * **Output Statuses**:
149
+ * `completed`: Process finished within `yield_ms`. Returns exit code, stdout, and stderr.
150
+ * `backgrounded`: Process auto-yielded. Returns `process_id` and `pid` for tracking.
151
+ * `timed_out`: Process exceeded `timeout_ms` and was terminated.
152
+ * `stopped`: Process was explicitly terminated.
153
+ * `failed_to_start`: Command could not be spawned (e.g., bad directory or policy violation).
154
+ * `failed`: An internal execution error occurred.
155
+
156
+ ### `read`
157
+ Read stdout and/or stderr output from a running or completed background process.
158
+
159
+ * **Parameters**:
160
+ * `process_id` (string, **required**): Unique identifier of the process.
161
+ * `since_seq` (integer, optional): Return only output appended after this sequence number. Enables efficient incremental log polling.
162
+ * `max_output_bytes` (integer, optional): Clamps the response size. Defaults to the server cap.
163
+ * `streams` (string, default: `"both"`): The streams to read. Options: `"both"`, `"stdout"`, or `"stderr"`.
164
+
165
+ * **Returns**:
166
+ * `process_id`, `status`, `exit_code`, `signal`, `next_seq` (sequence index to use in subsequent `since_seq` reads), `stdout`/`stderr` text, and a `truncated` flag.
167
+
168
+ ### `write`
169
+ Write text input to the standard input (`stdin`) of a running process.
170
+
171
+ * **Parameters**:
172
+ * `process_id` (string, **required**): Unique identifier of the process.
173
+ * `input` (string, **required**): Text input to write.
174
+ * `newline` (boolean, default: `false`): If `true`, appends `\n` to the input.
175
+
176
+ ### `wait`
177
+ Block execution until the process exits or the wait timeout expires. This allows the LLM to pause and await completion without spawning a new execution loop.
178
+
179
+ * **Parameters**:
180
+ * `process_id` (string, **required**): Unique identifier of the process.
181
+ * `timeout_ms` (integer, default: `30000`): Maximum time to wait.
182
+ * `max_output_bytes` (integer, optional): Maximum output bytes to return in the response.
183
+
184
+ * **Important**: If the wait timeout expires, `wait` returns the current status but **does not kill** the process. It continues running in the background.
185
+
186
+ ### `stop`
187
+ Gracefully terminate or force kill a running process.
188
+
189
+ * **Parameters**:
190
+ * `process_id` (string, **required**): Unique identifier of the process.
191
+ * `signal` (string, default: `"SIGTERM"`): OS signal to send (e.g. `SIGTERM`, `SIGKILL`, `SIGINT`). Ignored on Windows.
192
+ * `force_after_ms` (integer, default: `3000`): Grace period before escalating to force kill (`SIGKILL`).
193
+
194
+ ### `ps`
195
+ List all managed processes.
196
+
197
+ * **Parameters**:
198
+ * `include_completed` (boolean, default: `true`): If `false`, finished/stopped processes are excluded from the output.
199
+ * `limit` (integer, default: `50`): Maximum number of entries.
200
+
201
+ ### `cleanup`
202
+ Prune completed or stopped process records to free memory.
203
+
204
+ * **Parameters**:
205
+ * `completed_older_than_ms` (integer, default: `3600000`): Prunes completed processes older than this threshold (1 hour default).
206
+ * `stopped_older_than_ms` (integer, default: `3600000`): Prunes stopped, timed-out, or failed processes older than this threshold (1 hour default).
207
+
208
+ ---
209
+
210
+ ## Sequence Number & Incremental Reads
211
+
212
+ To avoid sending duplicate data over the MCP protocol (which can consume context window space), the server implements a sequence-based polling protocol:
213
+
214
+ 1. Every output chunk appended to a process's ring buffer receives a unique, incremental sequence number (`seq`).
215
+ 2. When calling `exec`, `read`, or `wait`, the response includes a `next_seq` value representing the index of the next chunk to be written.
216
+ 3. To retrieve only *new* output, call `read` with `since_seq` set to the previously received `next_seq`.
217
+ 4. Omitting `since_seq` returns the entire contents currently stored in the buffer (clamped by `max_output_bytes`).
218
+
219
+ ---
220
+
221
+ ## Configuration Variables
222
+
223
+ Configure the server by setting these environment variables prior to launch:
224
+
225
+ | Environment Variable | Default Value | Description |
226
+ |---|---|---|
227
+ | `YIELDSHELL_DEFAULT_CWD` | Current directory | The fallback working directory for commands. |
228
+ | `YIELDSHELL_ALLOWED_CWDS` | *(none)* | A list of allowed directory paths separated by `os.pathsep` (e.g., `:` on UNIX, `;` on Windows). If set, all command execution paths must resolve inside one of these roots. |
229
+ | `YIELDSHELL_MAX_OUTPUT_BYTES` | `20000` | The default and maximum capacity of the ring buffers for stdout/stderr. |
230
+ | `YIELDSHELL_MAX_PROCESSES` | `50` | Maximum concurrent managed processes. Spawning a new command when this limit is reached will return `failed_to_start`. |
231
+ | `YIELDSHELL_DEFAULT_YIELD_MS` | `5000` | Fallback delay before auto-yielding. |
232
+ | `YIELDSHELL_MAX_YIELD_MS` | `300000` | The maximum allowed value for the `yield_ms` parameter. |
233
+ | `YIELDSHELL_DEFAULT_TIMEOUT_MS` | `0` | Default hard runtime limit (0 means no limit). |
234
+ | `YIELDSHELL_DENY_COMMAND_REGEX` | *(none)* | A regular expression pattern. Commands matching this pattern are blocked before starting. |
235
+ | `YIELDSHELL_ALLOW_COMMAND_REGEX` | *(none)* | A regular expression pattern. If set, only commands matching this pattern are permitted. |
236
+ | `YIELDSHELL_REDACT_ENV_REGEX` | `TOKEN\|KEY\|SECRET\|PASSWORD` | Regex to identify sensitive environment variable keys. Their values are redacted in stdout/stderr outputs. |
237
+
238
+ ---
239
+
240
+ ## Security Notes
241
+
242
+ * **Arbitrary Code Execution**: This server executes shell commands on the host system. Always run the server inside a container, sandbox, or isolated development VM.
243
+ * **Path Validation**: CWD path verification uses absolute paths (`resolve()`), preventing path-traversal attacks (`../`) outside the allowed roots.
244
+ * **Additive Environments**: The `env` argument overlays existing env parameters. It merges with the parent process environment instead of completely replacing it, protecting critical OS vars.
245
+ * **Best-effort Redaction**: While values of variables matching `YIELDSHELL_REDACT_ENV_REGEX` are scrubbed from outputs, this is a best-effort system. Sensitive data printed through complex formats or argument lists might not be caught.
246
+
247
+ ---
248
+
249
+ ## Platform Support
250
+
251
+ * **POSIX (Linux & macOS)**: Fully supported. Spawns processes in distinct sessions (`start_new_session=True`), allowing signals (`SIGTERM`/`SIGKILL`) to target the entire process group. This ensures child processes started by commands (such as npm dev tasks) are completely cleaned up.
252
+ * **Windows**: Supported with best-effort process group controls. Windows lacks native POSIX signals, meaning `stop` and `timeout_ms` act on the primary process, and child subprocesses might persist if they do not exit cleanly.
253
+
254
+ ---
255
+
256
+ ## License
257
+
258
+ MIT