shell-mcp
Integrates with GitHub Copilot (VS Code) to allow it to execute shell commands within a defined sandbox, enabling agents to perform local code operations and project tasks.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@shell-mcprun the test suite in the sandbox and show any failures"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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
bashinstalled in its image. The configured shell (defaultbash) is the only shell used, with noshfallback.A microsandbox runtime (
msb) at the version matching the pinned SDK.@edorosh/shell-mcp1.0.0 pinsmicrosandbox(npm SDK) at exactly 0.7.11; the tested pair ismicrosandbox0.7.11 withmsb0.7.11 on Windows (see spike-results.md). shell-mcp uses themsbin 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 --versionDo 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:/workspaceYou 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:/workspacecreate 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 --checkClaude 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 /workspacecmd /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.0Then 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 |
|
| required |
|
| required |
|
| required |
|
|
|
|
|
|
|
|
|
|
| rewriting on |
|
|
|
| none | prints the version and exits |
| none | prints usage and exits |
| 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 osThen 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=1thenecho $Xprints 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 ... EXITorexecin 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
microsandboxSDK and themsbruntime 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 outand 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
msb0.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_gapandlaunch_unconfirmederror 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 buildThe 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.tsExpected: 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.txtUnable 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\@typescriptTypical 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 buildIf 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 SilentlyContinueAn 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 x64The 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.
This server cannot be deployed
Maintenance
Related MCP Connectors
Linux microVM sandboxes for AI agents: run commands, files, processes, pause and wake.
Manage Sprites: sandboxed compute environments with exec, services, and checkpoints.
I run shell commands on your private cloud environment (bash, sh, zsh)
MCP server for Superserve sandboxes: create, exec, and manage Firecracker microVMs
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceEnables 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 npm6MIT
- AlicenseNot gradedqualityDmaintenanceProvides 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 npmMIT
- AlicenseNot gradedqualityCmaintenanceProvides 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 npmMIT
- AlicenseNot gradedqualityFmaintenanceEnables executing bash commands with foreground/background support, timeouts, environment control, and OpenTelemetry observability.14 npm2MIT