Skip to main content
Glama
uditk2

mcp-bash-server

by uditk2
README.md
# mcp-bash-server

## The problem

Cowork (and Claude Desktop) run in a sandbox and can't execute commands on your
own machine. This server bridges that gap — it connects Cowork to your local
`bash` so Claude can run shell commands directly on your computer, then read
their output.

## What it is

A tiny [Model Context Protocol](https://modelcontextprotocol.io) server that lets
an MCP-aware client run shell commands on your local machine. It exposes one
tool, `run_bash`, and communicates over stdio.

From the client's side, running a command is just a tool call. On this side, the
command runs via `bash -c` with your user's permissions, and its exit code,
stdout, and stderr are returned.

## ⚠️ Security

By default this is an **open shell**: whatever connects can run anything you can.
Only connect clients you trust, and consider using the allowlist below.

## Install (easy way — double-click, no terminal)

Download **`mcp-bash-server.mcpb`** and double-click it. Claude Desktop opens an
install dialog — review the permissions, optionally set an allowlist and default
working directory, and click **Install**. That's it: no Terminal, no `pip`, no
config files. Claude Desktop manages the runtime for you, and because the server
is registered locally, it also becomes available inside **Cowork** sessions.

> An `.mcpb` (MCP Bundle) is the one-click install format for local MCP servers,
> like a browser extension. This bundle uses the `uv` runtime, so you don't even
> need Python pre-installed.

The rest of this README is the manual route, for development or if you'd rather
run it yourself.

## Requirements (manual route)

- Python 3.10+
- `bash` on your `PATH`

## Install

```bash
cd mcp-bash-server
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

## Run

The server supports two transports:

```bash
python server.py                      # stdio (default) — for the Claude Desktop bridge
python server.py --transport http     # HTTP — serves MCP at http://127.0.0.1:8001/mcp
```

- **stdio** is the default. You normally don't run it by hand — the client
  launches it for you (see "Connect it to Claude Desktop" below). This is the
  simplest path: Claude Desktop runs the server as a subprocess and bridges it
  into Cowork automatically.
- **http** serves the MCP *streamable-http* transport natively (no
  supergateway needed). Use it when you want to register the server as a custom
  connector by URL. Change host/port with `--host` / `--port`.

## Connect it to Claude Desktop

Add an entry to your `claude_desktop_config.json`
(macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "bash": {
      "command": "/absolute/path/to/mcp-bash-server/.venv/bin/python",
      "args": ["/absolute/path/to/mcp-bash-server/server.py"]
    }
  }
}
```

Use absolute paths. Restart Claude Desktop; the `run_bash` tool should appear.

## Connect it as a custom connector (HTTP / URL)

If you'd rather register it by URL (e.g. for Cowork's custom connector flow),
run the HTTP transport and point the connector at it:

```bash
python server.py --transport http --port 8001
# -> serves http://127.0.0.1:8001/mcp
```

Then add a custom connector with URL `http://localhost:8001/mcp`. To keep it
running across reboots, manage it with a process manager (e.g. `pm2`,
`launchd`, or `systemd`).

## The tool

`run_bash(command: str, cwd?: str, timeout?: int)` → text with exit code, stdout,
stderr.

- `command` — the shell command, run via `bash -c`.
- `cwd` — working directory (defaults to where the server started).
- `timeout` — seconds before the command is killed (capped by `BASH_MCP_MAX_TIMEOUT`).

## Configuration (environment variables)

| Variable | Default | Meaning |
|---|---|---|
| `BASH_MCP_ALLOWED` | *(unset)* | Comma-separated command prefixes to allow, e.g. `git,ls,cat,npm`. Unset = unrestricted. |
| `BASH_MCP_CWD` | server's cwd | Default working directory for commands. |
| `BASH_MCP_MAX_TIMEOUT` | `300` | Hard ceiling (seconds) on any command's runtime. |
| `BASH_MCP_TRANSPORT` | `stdio` | `stdio` or `http` (same as `--transport`). |
| `BASH_MCP_HOST` | `127.0.0.1` | Bind host for `--transport http`. |
| `BASH_MCP_PORT` | `8001` | Bind port for `--transport http`. |

Example — restrict to a safe set:

```json
{
  "mcpServers": {
    "bash": {
      "command": "/absolute/path/to/.venv/bin/python",
      "args": ["/absolute/path/to/server.py"],
      "env": { "BASH_MCP_ALLOWED": "git,ls,cat,grep,npm,node,python3" }
    }
  }
}
```

## Building the .mcpb yourself

```bash
npx @anthropic-ai/mcpb pack . mcp-bash-server.mcpb
```

This validates `manifest.json` and produces the installable bundle. The `uv`
server type means dependencies are resolved from `pyproject.toml` at install
time — nothing is vendored, so the same bundle works on macOS, Windows, and
Linux.

## License

MIT — see [LICENSE](LICENSE).