Skip to main content
Glama

shell-mcp

What it is

An MCP server (stdio) that runs on your Windows host and executes shell commands inside one existing microsandbox sandbox instead of on the host. It exposes four tools: shell (foreground or background commands with a timeout), shell_output, shell_kill and shell_list. Paths are translated between the host project folder and the sandbox mount, and the working directory is tracked across calls.

Published on npm as @edorosh/shell-mcp. Windows hosts only; see Status.

Related MCP server: Run Command MCP Server

Requirements

  • Windows host (x64 or arm64).

  • Node.js 22 or newer.

  • A sandbox you have already created (shell-mcp never creates or starts one), with bash installed in its image. The configured shell (default bash) is the only shell used, with no sh fallback.

  • A microsandbox runtime (msb) at the version matching the pinned SDK. @edorosh/shell-mcp 1.0.0 pins microsandbox (npm SDK) at exactly 0.7.11; the tested pair is microsandbox 0.7.11 with msb 0.7.11 on Windows (see spike-results.md). shell-mcp uses the msb in your microsandbox home if you have one, and the runtime packaged with the SDK otherwise. A version mismatch is logged to stderr at startup and reported by --check; it never stops the server.

Install

Nothing to clone or build. Warm the npx cache and confirm the package runs:

npx -y @edorosh/shell-mcp@1.0.0 --version

Do not use npx shell-mcp. The npm name shell-mcp belongs to an unrelated package; always use the scoped name @edorosh/shell-mcp with a version.

The client configs below run npx -y @edorosh/shell-mcp@1.0.0 .... That form contacts the npm registry on every start, so it does not start offline. To start offline and instantly, use the global install.

Creating a sandbox

A sandbox belongs to the msb runtime home that created it, so create it with the same msb that shell-mcp will use. Use an image that contains bash, for example ubuntu:24.04.

You already have a separate msb install (the msb in your microsandbox home; shell-mcp uses it). Create the sandbox as usual. Its version must match the SDK (0.7.11 for shell-mcp 1.0.0); --check verifies this.

msb create ubuntu:24.04 --name myproj --mount-dir C:\Users\eugen\dev\myproj:/workspace

You have no msb installed. Use the runtime packaged with the SDK:

npx -y -p microsandbox@0.7.11 msb create ubuntu:24.04 --name myproj --mount-dir C:\Users\eugen\dev\myproj:/workspace

create also starts the sandbox. If it is stopped later, start it with msb start myproj (or the same npx -y -p microsandbox@0.7.11 msb start myproj); until then shell returns a tool error, and the next call works once it runs. The values to give shell-mcp are the sandbox name (myproj), the host folder (C:\Users\eugen\dev\myproj) and the guest path (/workspace).

Check

Run shell-mcp once with --check before configuring a client. It verifies the native module, the runtime version, that the sandbox is reachable, that the shell runs and that the host folder is mounted at the guest path:

npx -y @edorosh/shell-mcp@1.0.0 --sandbox myproj --host-root C:\Users\eugen\dev\myproj --guest-root /workspace --check

Claude Code

Put .mcp.json in your project (example: examples/claude/.mcp.json):

{
  "mcpServers": {
    "sandbox": {
      "command": "cmd",
      "args": [
        "/c", "npx", "-y", "@edorosh/shell-mcp@1.0.0",
        "--sandbox", "myproj",
        "--host-root", "C:\\Users\\eugen\\dev\\myproj",
        "--guest-root", "/workspace"
      ]
    }
  }
}

Or add it from the command line:

claude mcp add sandbox --scope project -- cmd /c npx -y @edorosh/shell-mcp@1.0.0 --sandbox myproj --host-root C:\Users\eugen\dev\myproj --guest-root /workspace

cmd /c is what the Claude Code docs prescribe for npx on native Windows. Bare npx (and shell-mcp after a global install) also start in current Claude Code, and VS Code's newer agent host also reads the project .mcp.json, so one file can serve both clients.

Turn off Claude Code's built-in shell so the agent can only run commands through shell-mcp, in .claude/settings.json (example: examples/claude/.claude/settings.json):

{ "permissions": { "deny": ["Bash"] } }

GitHub Copilot (VS Code)

Put .vscode/mcp.json in your project (example: examples/copilot/.vscode/mcp.json):

{
  "servers": {
    "sandbox": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y", "@edorosh/shell-mcp@1.0.0",
        "--sandbox", "myproj",
        "--host-root", "C:\\Users\\eugen\\dev\\myproj",
        "--guest-root", "/workspace"
      ]
    }
  }
}

Use a literal host path: VS Code does not substitute ${workspaceFolder} in args (shell-mcp would get the literal string and exit with "host-root must be an absolute path").

Turning off Copilot's built-in shell

What works depends on where Copilot runs. As of 2026-10-25 the Copilot harness hook below is verified with shell-mcp on Windows; its Linux/macOS script, the Local harness and the Copilot CLI options are untested.

VS Code, Local harness: in Agent mode, select Configure Tools in the chat input and deselect the built-in terminal tools (the execute group: runInTerminal, getTerminalOutput, createAndRunTask, ...). The selection applies to the current request. To make it reusable, add a custom agent with an explicit tools list, for example .github/agents/sandbox.agent.md, and pick it in the agent dropdown. With a tools list, only those tools are available:

---
name: Sandbox
description: Coding agent whose commands run only in the shell-mcp sandbox
tools: ['read', 'edit', 'search', 'sandbox/*']
---
Run every command through the sandbox shell tools. Use the file tools with host paths.

VS Code, Copilot harness (Agent Host): the harness's built-in tools are read-only in the Agent Customizations Tools tab, so the shell cannot be deselected there, and approval settings such as chat.tools.terminal.autoApprove only force a confirmation. Use a preToolUse hook instead; Copilot reads repository hooks from .github/hooks/*.json. Copy examples/copilot/.github/hooks/ into your project (deny-shell.json plus deny-shell.ps1 for Windows and deny-shell.sh for Linux and macOS) and reload VS Code. Copilot runs the json's powershell command on Windows and its bash command elsewhere. Both scripts exit non-zero for the built-in shell tools (powershell on Windows, bash elsewhere), which denies the call; every other tool, including shell-mcp's (sandbox-shell and friends in the hook payload), passes. Input that cannot be parsed is let through. deny-shell.sh uses jq when it is installed and falls back to sed otherwise.

Verified on Windows on 2026-10-25 in a Copilot harness session: asked to use its built-in terminal, the agent's two powershell calls were denied, and it then ran uname -a through sandbox-shell and got Linux. The hook payload carries toolName and toolArgs; to debug, add Add-Content "$env:TEMP\copilot-hook.log" $raw after the first line of the script and read the log (in deny-shell.sh, add printf '%s\n' "$raw" >> /tmp/copilot-hook.log after the raw= line). The Linux/macOS script is untested with Copilot; it was only checked against sample payloads from the command line.

References: VS Code: use tools with agents, custom agents, approvals, Copilot hooks reference, Copilot CLI: allowing tools.

Copilot CLI

Add the server with /mcp add, using the same command and arguments as the VS Code example (npx with -y @edorosh/shell-mcp@1.0.0 --sandbox ...) and the name /mcp shows. The CLI does not read .vscode/mcp.json. To deny the built-in shell and allow shell-mcp per session (deny rules win over every allow rule, including --allow-all-tools):

copilot --deny-tool='shell' --allow-tool='sandbox'

These flags are not saved to a config file, so put them in a wrapper script. Unverified on Windows: whether the CLI's PowerShell tool is also covered by shell.

Upgrading

Change the version in the client config (for example @edorosh/shell-mcp@1.0.1) and run --check with the new version. CHANGELOG.md lists the msb version each release expects; if it changed, recreate or update msb to match. Close running clients first (see Troubleshooting).

Global install

npm i -g @edorosh/shell-mcp@1.0.0

Then use shell-mcp as the command, with the same arguments as above and without npx -y @edorosh/shell-mcp@1.0.0: in .vscode/mcp.json "command": "shell-mcp", and in Claude Code's .mcp.json "command": "cmd", "args": ["/c", "shell-mcp", "--sandbox", ...]. The global install starts instantly and works offline.

Configuration

Flags win over environment variables.

Flag

Env

Default

--sandbox

SHELL_MCP_SANDBOX

required

--host-root

SHELL_MCP_HOST_ROOT

required

--guest-root

SHELL_MCP_GUEST_ROOT

required

--default-timeout

SHELL_MCP_DEFAULT_TIMEOUT

120s

--max-timeout

SHELL_MCP_MAX_TIMEOUT

600s

--max-output

SHELL_MCP_MAX_OUTPUT

30000

--no-rewrite-output-paths

SHELL_MCP_REWRITE_OUTPUT_PATHS=0 (or false, no)

rewriting on

--shell

SHELL_MCP_SHELL

bash

--version

none

prints the version and exits

--help

none

prints usage and exits

--check

none

verifies native module, runtime version, sandbox, shell and mount, then exits

--host-root must be an absolute path. It is normalized (path.win32.normalize: / becomes \, . and .. segments are collapsed), a trailing separator is stripped, and it must exist on disk. The guest root must be an absolute POSIX path; a trailing / is stripped.

Path rewriting is turned off only by --no-rewrite-output-paths or by SHELL_MCP_REWRITE_OUTPUT_PATHS set to 0, false or no (any case). Any other value leaves it on; the flag wins over the variable.

Verify

Ask the agent to run uname -a. It should report Linux (the sandbox kernel). If it does not report Linux, the agent may still be using a built-in shell; if it fails, check that the sandbox is running and reachable.

Client timeouts

GitHub Copilot (VS Code), checked on Windows on 2026-10-25: foreground calls up to the 600 s max-timeout were not cut off by the client. A sleep 300 call and a sleep 540 call (timeout_ms: 600000) both completed and returned their output. No client setting was changed. Copilot showed no progress indication while waiting. Background jobs, shell_output, shell_kill and shell_list worked as expected, including a sleep 700 job that was killed with its process gone.

Claude Code, checked on Windows on 2026-10-25: all steps passed with MCP_TOOL_TIMEOUT unset. Calls longer than 120 s are not cut off: Claude Code moves the still-open call to a background task ("still running after 120s ... moved to the background") and the agent picks up the result when it completes. sleep 300 and sleep 540 (timeout_ms: 600000) both finished with their output. Such a background task does not survive exiting the Claude Code session. No progress indication was shown beyond that one notice. If your Claude Code version cuts long calls off instead, raise MCP_TOOL_TIMEOUT (milliseconds) above your max-timeout.

Leave headroom under the timeout. In the sandbox, sleep ran about 3% longer than requested (90 s took 93 s, 300 s took 310 s, 540 s took 556 s), so sleep 590 with timeout_ms: 600000 hit shell-mcp's own 600 s deadline. That result is shell-mcp's timed out after 600s (process killed), not a client error. Give foreground commands a few percent of slack, or run anything long in the background. To allow longer foreground calls, raise --max-timeout (for example --max-timeout 15m), but no client has been checked beyond 600 s.

Troubleshooting

Native module failure in --check on Windows

npm config get os must print nothing on Windows. An os=linux line in a user or project .npmrc makes npm fetch the Linux binaries, and --check reports it as a native-module failure. Fix it with:

npm config delete os

Then re-run the --check command. If the Linux package is already cached, clear the npx cache (see the next entry) before retrying.

Access denied when clearing the npx cache or upgrading

Deleting %LOCALAPPDATA%\npm-cache\_npx, or an upgrade that replaces it, fails with "access denied" on microsandbox.win32-x64-msvc.node while a client is running shell-mcp (Windows locks loaded DLLs). Close the clients first.

A sandbox created with the packaged runtime (npx -y -p microsandbox@… msb create) keeps msb.exe running from inside that npx cache or node_modules folder, so msb.exe and libkrunfw.dll stay locked too. Stop the sandbox first (msb stop <name> with the same runtime and MSB_HOME), or find the process with Get-Process msb | Select-Object Id, Path and stop it.

Limitations

  • No interactive programs: stdin is closed for every command.

  • Environment variables do not persist between calls (export X=1 then echo $X prints an empty line). The working directory does persist.

  • Background jobs are not listed after a server restart. Only jobs started by the running server instance are visible and killable.

  • Output paths containing spaces are rewritten from guest to host only up to the first space.

  • A user trap ... EXIT or exec in a command disables working-directory tracking for that call; the working directory stays as it was.

  • A newline in a working-directory path is not supported.

  • Job-output retention gaps are detected only when a read follows a cursor. If output was discarded before the first read of a job, that gap is not flagged.

  • The microsandbox SDK and the msb runtime must be the same version; the SDK is pinned to 0.7.11 for that reason.

  • The sandbox sees host-side changes to the mounted folder with a short delay. Right after a host-side delete of the current directory the guest may still resolve it (measured: still visible right after, gone after about 5 s), so the next call runs there instead of resetting to the workspace root; later calls reset normally.

  • Parallel calls run concurrently; the last to finish sets the working directory.

  • A command killed by a signal other than the timeout (for example kill -9 $$, or the out-of-memory killer) reports exit code -1, not 128+N: the sandbox does not pass the signal number through.

  • If the sandbox never confirms the exit after a timeout kill, the result still says timed out and adds a note that the exit was not confirmed.

  • Timeout detection relies on the sandbox reporting exit code -1 when the SDK's deadline kills the shell. The spike confirmed this on Windows with msb 0.7.11 (output produced before the deadline is kept and the process group dies). shell-mcp's own kill half a second past the deadline is only a fallback.

  • Not yet verified on a real host: the output_gap and launch_unconfirmed error paths.

Status

The microsandbox SDK spike (spike/) has been run on Windows (results in spike-results.md). The integration suite (test/integration.test.ts) passes all 12 acceptance criteria against a real sandbox on Windows (with SHELL_MCP_IT_ALLOW_STOP=1; see spike-results.md). The manual client check passed for GitHub Copilot and Claude Code (see Client timeouts). Behaviors that depend on the real SDK are listed under Limitations. Linux and macOS hosts are deferred; see ROADMAP.md.

Development

To work on shell-mcp itself, clone the repository and build it:

cd C:\Users\eugen\dev\shell-mcp
npm ci
npm run build

The server is then node C:\Users\eugen\dev\shell-mcp\dist\index.js, with the same flags as above.

To run the integration suite and the SDK spike, in PowerShell, with a running sandbox:

# Integration suite (repo root)
$env:SHELL_MCP_IT_SANDBOX="myproj"; $env:SHELL_MCP_IT_HOST_ROOT="C:\Users\eugen\dev\myproj"; $env:SHELL_MCP_IT_GUEST_ROOT="/workspace"; npx vitest run test/integration.test.ts

Expected: 12 pass, or 11 pass and 1 skipped.

# SDK spike (see spike\README.md)
mkdir C:\temp\spike-ws -Force
msb create <image> --name spike --mount-dir C:\temp\spike-ws:/workspace
msb start spike          # skip if create already starts it
msb --version
cd spike
npm install
node sdk-check.mjs spike *>&1 | Tee-Object -FilePath spike-output.txt

# Optional: probe a stopped sandbox too
msb create <image> --name spike-stopped
msb stop spike-stopped
$env:SPIKE_STOPPED = "spike-stopped"
node sdk-check.mjs spike *>&1 | Tee-Object -FilePath spike-output.txt

Unable to resolve @typescript/typescript-win32-x64 on npm run build or npm run typecheck

The project builds with TypeScript 7, which runs a compiler from a per-platform package (@typescript/typescript-<os>-<cpu>). The lockfile lists all of them, and npm installs only the one matching the machine. This error means node_modules contains a different platform's package, for example @typescript/typescript-linux-x64. Check with:

dir node_modules\@typescript

Typical causes: node_modules was installed on another OS (for example by copying a folder, or from a Linux sandbox sharing the folder), or npm detected the wrong platform on your machine. Fix it by reinstalling with the platform stated explicitly:

Remove-Item -Recurse -Force node_modules
npm ci --os=win32 --cpu=x64
dir node_modules\@typescript     # should now list typescript-win32-x64
npm run build

If a plain npm ci keeps installing the wrong package, find out why npm thinks it is on another platform:

node -p "process.platform + ' ' + process.arch"      # expect: win32 x64
where.exe node                                       # a Windows install, not a WSL or Git Bash shim
npm config get os
npm config get cpu
Get-ChildItem Env: | Where-Object Name -like 'npm_config*'
Get-Content $HOME\.npmrc -ErrorAction SilentlyContinue

An os or cpu setting, an npm_config_os/npm_config_cpu variable, or an .npmrc line that names linux is the override: remove it. As a last resort, pin the platform in your user npm config (not in the repository, because Linux CI needs the default):

npm config set os win32
npm config set cpu x64

The same wrong-platform install would also break the native microsandbox package, so fix it before running the spike or the integration suite. Do not install dependencies in a folder that a Linux sandbox shares with your Windows checkout; use a separate clone for each.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Enables secure execution of shell commands and file operations within isolated Docker containers. Provides process management, interactive input handling, and comprehensive file system operations for containerized development environments.
    39 npm
    6
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides tools for executing shell commands both synchronously and asynchronously with real-time output streaming and process management capabilities. It enables users to start background tasks, monitor progress, and manage long-running processes via Stdio or HTTP transports.
    294 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides a secure environment for executing shell commands with restricted directory access and timeout enforcement. It includes tools for running commands, managing execution history, and isolating environment variables.
    24 npm
    MIT