Skip to main content
Glama

shell-mcp

Remote shell + file operations MCP server. Core is pure stdlib (fully unit-testable); only server.py depends on mcp / starlette / uvicorn.

Features

  • Streamable HTTP at /mcp (POST). No long-lived connections, safe behind buffered reverse proxies.

  • Bearer token auth (constant-time compare) + optional IP allowlist + /health endpoint.

  • Two execution modes: restricted (command allowlist, no shell operators) / unrestricted (full shell). Windows: unrestricted mode uses cmd.exe or PowerShell; POSIX: $SHELL -lc.

  • Reliable process execution: stdout+stderr merged in real order; output streamed to temp file (bounded memory, no pipe deadlock); children in their own process group; timeout kills the entire process tree (POSIX killpg / Windows taskkill /T).

  • Background tasks: run_command(background="always") for dev servers / builds; task(action="wait"|"output"|"cancel"|"list") to manage.

  • Sync-first by default: run_command waits up to SHELL_MCP_WAIT_SECONDS (30s) then auto-backgrounds. Short commands return results inline.

  • Safe editing: edit_file exact replacement + atomic write + unified diff; apply_patch multi-file atomic; expected_sha256 precondition prevents stale-read conflicts (returns FILE_CHANGED without touching files).

  • Code search: grep (ripgrep preferred, pure-Python fallback) + glob (sort by path or modified time).

  • Encoding consistency: auto-detect (UTF-8 / Windows code pages / GB18030), preserve original encoding on write.

  • Output governance: line+byte caps, tail truncation, full output spilled to OS temp dir (shell-mcp-spool/), auto-pruned.

  • Machine-readable errors: all failures return code (e.g. OLD_TEXT_NOT_FOUND, FILE_NOT_FOUND) + structured fields.

  • Audit log: JSON lines, auto-rotated.

  • Git inspection: git_log/diff/blame/show/status — all read-only, gated behind SHELL_MCP_EXPOSE_GIT=true.

  • Pi bridge: dispatch prompts to the pi coding agent with session continuity. Gated behind SHELL_MCP_PI_ENABLED=true.

  • Cross-platform: Windows / macOS / Linux. Platform-specific code gated behind os.name == "nt".

Related MCP server: MCP Remote Code

Quick Start

pip install -r requirements.txt
cp .env.example .env   # fill SHELL_MCP_TOKEN (openssl rand -hex 32)
# macOS / Linux:
./run.sh
# Windows:
run.bat

Client config (Streamable HTTP):

{
  "url": "http://127.0.0.1:8000/mcp",
  "headers": { "Authorization": "Bearer <SHELL_MCP_TOKEN>" }
}

Print a ready-to-paste client snippet (with real token + auto-detected Tailscale URL):

python -m shell_mcp.server --print-client

Real-World Stack: Notion + shell-mcp + pi + Tailscale

This project is commonly used as the backend of a four-layer AI coding stack:

┌─────────────────────────────────────┐
│  Notion                             │  ← You write prompts here
│  (MCP connector → AI agent)         │
├─────────────────────────────────────┤
│  shell-mcp (this server)            │  ← Executes commands, reads/writes files
├─────────────────────────────────────┤
│  pi (coding agent, optional)        │  ← Handles complex multi-step tasks
├─────────────────────────────────────┤
│  Tailscale (secure tunnel)          │  ← Connects everything remotely
└─────────────────────────────────────┘

How it works

  1. Start shell-mcp on your development machine (Windows/macOS/Linux).

  2. Expose via Tailscale (tailscale serve --bg 8000). The server stays on 127.0.0.1 — never exposed to the public internet. Tailscale handles TLS and authentication.

  3. Configure Notion's MCP connector to point at your Tailscale URL (https://<machine>.<tailnet>.ts.net/mcp). Notion passes your prompts to an AI model (e.g. Claude), which calls shell-mcp's tools to read files, run commands, search code, and make edits — all on your machine.

  4. Enable pi bridge (optional, SHELL_MCP_PI_ENABLED=true) for complex coding tasks. When the AI at the Notion layer decides a task is too large for one-shot tools, it dispatches the prompt to pi via pi_run. Pi handles multi-step reasoning, file editing, and debugging autonomously, and returns the result.

Why this works

Layer

Role

Why it matters

Notion

Prompt interface

Your existing Notion workspace becomes an AI coding environment. No separate chat app.

shell-mcp

Execution runtime

File read/write, shell commands, code search, git inspection — all the tools an AI needs to work on a real codebase.

pi

Autonomous agent

Handles complex multi-step tasks that require planning, iteration, and debugging. Session continuity across calls.

Tailscale

Secure transport

Zero-config VPN. No open ports, no public IPs, no firewall rules. Works across NAT, on any network.

Quick setup

# 1. Server (your dev machine)
git clone https://github.com/takereshui/shell-mcp.git
cd shell-mcp
pip install -r requirements.txt
cp .env.example .env
# Edit .env: set SHELL_MCP_TOKEN, optionally SHELL_MCP_PI_ENABLED=true

# 2. Start
./run.sh  # or run.bat on Windows

# 3. Expose via Tailscale
tailscale serve --bg 8000

# 4. Print client config (includes Tailscale URL + token)
python -m shell_mcp.server --print-client

# 5. Copy the JSON into Notion's MCP connector settings

That's it. Your Notion workspace can now read, edit, test, and debug code on your machine — remotely, securely, with AI assistance at every step.

Tools

Default surface (13 tools):

Tool

Description

run_command

Execute a shell command. background="auto" (default): sync-first, auto-backgrounds after wait_seconds. Optional cwd, timeout, detail level.

task

Unified background task lifecycle. action: wait / output / cancel / list.

grep

Regex search. Structured results: [{path, line, text}]. Ripgrep preferred, pure-Python fallback.

glob

File pattern matching. Sort by path (stable) or modified (newest first).

list_dir

Directory listing with optional depth recursion.

read_file

Read a text file with paging. Returns sha256 + next_start_line. Images (png/jpeg/gif/webp) returned as image content.

read_files

Batch read up to 20 files. Partial failures don't block other files.

write_file

Atomic write. Optional expected_sha256 precondition. append mode supported.

edit_file

Exact string replacement with {old, new, replace_all?}. Returns unified diff.

apply_patch

Multi-file patch (*** Begin Patch envelope): add / update / delete / move. All-or-nothing.

set_workdir

Change working directory (convenience; prefer per-call cwd).

outline

Extract code symbols per language (regex-based, shebang-aware).

review_file

One-shot audit: read file + recent commits + diff (parallel via anyio).

Low-level tools (task_output, kill_task, list_tasks, delete_file, make_dir, rename_file) hidden by default; enable with SHELL_MCP_EXPOSE_LOWLEVEL=true.

Gated tools:

Gate

Tools

SHELL_MCP_EXPOSE_GIT=true

git_log — commit log with path filter, git_diff — working tree/staged diff, git_blame — line annotations, git_show — commit details, git_status — working tree status

SHELL_MCP_PI_ENABLED=true

pi_run — dispatch prompt to pi (sync-first, auto-session), pi_status — check running task, pi_cancel — kill running task

Configuration

All via environment variables (see .env.example for full list):

Variable

Default

Description

SHELL_MCP_TOKEN

(required)

Bearer token for auth

SHELL_MCP_HOST

127.0.0.1

Bind address

SHELL_MCP_PORT

8000

Bind port

SHELL_MCP_WORKDIR

./default

Working directory

SHELL_MCP_UNRESTRICTED

false

Full shell vs. allowlist

SHELL_MCP_READONLY

true

Disable write/edit/patch tools

SHELL_MCP_TIMEOUT

120

Default command timeout (seconds)

SHELL_MCP_WAIT_SECONDS

30

Sync-first wait before auto-background

SHELL_MCP_ALLOWLIST

(built-in)

Comma-separated command list (restricted mode)

SHELL_MCP_ALLOWED_IPS

(empty)

Comma-separated IP allowlist

SHELL_MCP_ENCODING

auto

Output/file encoding

SHELL_MCP_LOG

shell-mcp-audit.log

Audit log path

SHELL_MCP_MAX_OUTPUT

51200

Max bytes returned per call

SHELL_MCP_MAX_LINES

2000

Max lines returned per call

SHELL_MCP_MAX_CAPTURE

5242880

Hard cap on in-memory output

SHELL_MCP_SPOOL_MAX_FILES

50

Max spilled output files kept

SHELL_MCP_EXPOSE_LOWLEVEL

false

Expose low-level task/file tools

SHELL_MCP_EXPOSE_GIT

false

Expose git inspection tools

SHELL_MCP_PI_ENABLED

false

Enable pi coding agent bridge

SHELL_MCP_PI_COMMAND

pi

Pi binary/command path

SHELL_MCP_PI_ARGS

""

Extra arguments to pi

SHELL_MCP_PI_WAIT_SECONDS

120

Default wait for pi_run

Exposing via Tailscale

Keep SHELL_MCP_HOST=127.0.0.1 (never bind to public interfaces). Let tailscaled handle TLS:

# Tailnet-only (auto-HTTPS):
tailscale serve --bg 8000

# Public internet (Funnel; requires Funnel enabled in admin console):
tailscale funnel --bg 8000

# Check status / stop:
tailscale serve status
tailscale funnel --bg off 8000

Client URL: https://<machine>.<tailnet>.ts.net/mcp

Security notes:

  • Funnel = anyone on the internet can reach this port. Use a long random token (openssl rand -hex 32). Keep SHELL_MCP_UNRESTRICTED=false.

  • Tailscale serve forwards real client IPs (100.x.y.z). Pin them with SHELL_MCP_ALLOWED_IPS for token+IP dual defense (tailnet only; don't use with Funnel).

  • Funnel only supports ports 443/8443/10000 for HTTPS. TLS terminated by Tailscale.

  • Audit log records commands and paths. Restrict file permissions on the log.

Architecture

shell_mcp/
├── config.py          # env → Config; SessionState
├── errors.py          # ToolFailure → MCP isError
├── paths.py           # Path resolution + sandbox enforcement
├── encoding.py        # Auto-detect encoding (UTF-8 / Windows / GB18030)
├── output.py          # Line+byte truncation, spool spill, pruning
├── process.py         # Command parse/execute: merged output, file capture, tree kill
├── tasks.py           # Background task registry
├── mutation_queue.py  # Per-path serialized write queue
├── editing.py         # Transactional edits: validate → atomic write → diff
├── audit.py           # JSON lines audit log
├── tools/
│   ├── shell.py       # run_command / task
│   ├── files.py       # File tools (read/write/edit/patch)
│   ├── search.py      # grep / glob
│   ├── audit.py       # outline / review_file / git_* tools
│   └── pi.py          # pi_run/status/cancel (gated)
└── server.py          # FastMCP + auth middleware (only third-party deps)

spool:// Resources

Truncated command output and background task logs are served as spool://<name> MCP resources. Tool results include full_output_resource / log_resource fields. Files live in the OS temp directory (shell-mcp-spool/) and are auto-pruned.

Design: Stale-Read Protection

read_file(path) → {text, sha256}
write_file(path, content, expected_sha256=<from read>)
→ server re-reads file, computes sha256(disk)
→ match? write. mismatch? FILE_CHANGED (file untouched)

No server-side cache. The SHA256 is computed from disk at read time and re-verified at write time. This is optimistic concurrency (ETag/If-Match pattern), not a cache.

Tests

Core is dependency-free; run directly:

python3 -m unittest discover -s tests -v

License

MIT — see LICENSE.

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Operate your own Linux servers from your LLM. Requires the SentinelX agent installed per host.

  • Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.

  • Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/takereshui/shell-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server