Skip to main content
Glama
mhingston

shell-mcp

by mhingston
README.md
# shell-mcp

A deliberately small MCP server that exposes a single tool, `run_shell`, for executing arbitrary shell commands over **Streamable HTTP**.

It uses the stable v2 Model Context Protocol TypeScript SDK (`@modelcontextprotocol/server` and `@modelcontextprotocol/node`) and runs on Node.js 20+.

> [!WARNING]
> `run_shell` has the same operating-system permissions as the `shell-mcp` process. Treat access to this server as equivalent to shell access. The default bind address is loopback-only. A bearer token is required if you bind to a non-loopback address.

## Tool

### `run_shell`

| Input | Required | Description |
| --- | --- | --- |
| `command` | yes | Command string to execute. |
| `shell` | no | Shell executable/path, e.g. `bash`, `sh`, `zsh`, `pwsh`, `powershell.exe`, or `cmd.exe`. Defaults to the platform shell. |
| `cwd` | no | Working directory. Defaults to the server process working directory. |
| `env` | no | Environment variables to add or override for the command. |
| `timeoutMs` | no | Command timeout in milliseconds. Defaults to 30 seconds. |

The result includes stdout, stderr, exit code, terminating signal, duration, timeout state, and whether the output limit was exceeded.

## Run

```bash
npm install
npm run build
npm start
```

The MCP endpoint defaults to:

```text
http://127.0.0.1:3000/mcp
```

For development:

```bash
npm run dev
```

## Configuration

| Environment variable | Default | Purpose |
| --- | --- | --- |
| `HOST` | `127.0.0.1` | HTTP listen address. |
| `PORT` | `3000` | HTTP listen port. |
| `SHELL_MCP_TOKEN` | unset | Optional bearer token on loopback; required for non-loopback binds. |
| `SHELL_MCP_DEFAULT_TIMEOUT_MS` | `30000` | Default command timeout. |
| `SHELL_MCP_MAX_TIMEOUT_MS` | `600000` | Maximum timeout accepted by the tool. |
| `SHELL_MCP_MAX_OUTPUT_BYTES` | `1048576` | Maximum combined stdout/stderr retained before the command is terminated. |

Example network bind:

```bash
HOST=0.0.0.0 \
SHELL_MCP_TOKEN='use-a-long-random-secret' \
npm start
```

Configure the MCP client to send:

```text
Authorization: Bearer use-a-long-random-secret
```

For anything beyond a trusted local network, put the endpoint behind TLS and an authenticated reverse proxy rather than exposing the Node process directly.

## Examples

Bash:

```json
{
  "command": "uname -a && pwd",
  "shell": "bash"
}
```

PowerShell:

```json
{
  "command": "Get-ChildItem Env: | Select-Object -First 5",
  "shell": "pwsh"
}
```

## Development

```bash
npm run check
```

## Design

- One MCP tool; no resources or prompts.
- Streamable HTTP only; no stdio transport.
- Stateless MCP handler with a fresh `McpServer` per request, following the v2 SDK serving model.
- Explicit shell invocation for POSIX shells, PowerShell, and `cmd.exe`.
- Process-tree termination on timeout or output overflow.
- Loopback binding by default, with bearer authentication required for non-loopback binds.

## License

MIT