shell-mcp
Enables remote shell command execution and file operations with restricted/unrestricted modes, background tasks, safe editing, and code search.
README
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 +
/healthendpoint. - Two execution modes: restricted (command allowlist, no shell operators) / unrestricted (full shell). Windows: unrestricted mode uses
cmd.exeor 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/ Windowstaskkill /T). - Background tasks:
run_command(background="always")for dev servers / builds;task(action="wait"|"output"|"cancel"|"list")to manage. - Sync-first by default:
run_commandwaits up toSHELL_MCP_WAIT_SECONDS(30s) then auto-backgrounds. Short commands return results inline. - Safe editing:
edit_fileexact replacement + atomic write + unified diff;apply_patchmulti-file atomic;expected_sha256precondition prevents stale-read conflicts (returnsFILE_CHANGEDwithout 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 behindSHELL_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".
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
- Start shell-mcp on your development machine (Windows/macOS/Linux).
- Expose via Tailscale (
tailscale serve --bg 8000). The server stays on127.0.0.1— never exposed to the public internet. Tailscale handles TLS and authentication. - 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. - 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 viapi_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). KeepSHELL_MCP_UNRESTRICTED=false. - Tailscale serve forwards real client IPs (
100.x.y.z). Pin them withSHELL_MCP_ALLOWED_IPSfor 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.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.