A secure shell command execution server implementing the Model Context Protocol (MCP). This server allows remote execution of whitelisted shell commands with support for stdin input.
- Secure Command Execution: Only whitelisted commands can be executed
- Standard Input Support: Pass input to commands via stdin
- Comprehensive Output: Returns stdout, stderr, exit status, and execution time
- Shell Operator Safety: Validates commands after shell operators (; , &&, ||, |)
- Timeout Control: Set maximum execution time for commands
- Background Process Management: Run long-running commands in the background and manage them
- Web Management Interface: Monitor and manage background processes through a web UI
- Multiple Server Modes: Support for stdio (default), SSE, and streamable HTTP modes
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"shell": {
"command": "uvx",
"args": [
"mcp-shell-server"
],
"env": {
"ALLOW_COMMANDS": "ls,cat,pwd,grep,wc,touch,find"
}
},
}
}
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"shell": {
"command": "uv",
"args": [
"--directory",
".",
"run",
"mcp-shell-server"
],
"env": {
"ALLOW_COMMANDS": "ls,cat,pwd,grep,wc,touch,find"
}
},
}
}
pip install mcp-shell-server
# Basic usage (stdio mode)
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server
# Or using the alias
ALLOWED_COMMANDS="ls,cat,echo" uvx mcp-shell-server
# Explicitly specify stdio mode
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server stdio
Start the server in Server-Sent Events (SSE) mode:
# With default settings (host: 127.0.0.1, port: 8000)
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server sse
# With custom host and port
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server sse --host 0.0.0.0 --port 9000
# With custom web path
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server sse --web-path /shell-web
Start the server in streamable HTTP mode:
# With default settings (host: 127.0.0.1, port: 8000, path: /mcp)
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server http
# With custom host, port and path
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server http --host 0.0.0.0 --port 9000 --path /shell-api
# With custom web path
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server http --web-path /shell-web
The server includes a web management interface for monitoring and managing background processes:
# Start with default settings (port 5000)
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server --web
# Specify custom port
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server --web --port 8080
# Running on a specific host
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server --web --host 127.0.0.1
# With URL prefix (for reverse proxy setups)
ALLOW_COMMANDS="ls,cat,echo" uvx mcp-shell-server --web --url-prefix /shell
You can build a standalone executable file that doesn't require Python runtime:
# Simple build with default settings
uv run --extra dev python build_executable.py
# Build with HTTP proxy (useful if you need to download C compiler)
uv run --extra dev python build_executable.py --proxy http://your-proxy:port
# Quick build with minimal optimizations (faster build time)
uv run --extra dev python build_executable.py --quick
# Parallel compilation to speed up the build
uv run --extra dev python build_executable.py --jobs 8
# Testing mode (shows what will be done without executing)
uv run --extra dev python build_executable.py --test
# Verify an existing executable
uv run --extra dev python build_executable.py --verify
The output executable will be located in dist/executable/mcp-shell-server.exe
(on Windows) or dist/executable/mcp-shell-server
(on Linux/macOS).
The ALLOW_COMMANDS
(or its alias ALLOWED_COMMANDS
) environment variable specifies which commands are allowed to be executed. Commands can be separated by commas with optional spaces around them.
Valid formats for ALLOW_COMMANDS or ALLOWED_COMMANDS:
ALLOW_COMMANDS="ls,cat,echo" # Basic format
ALLOWED_COMMANDS="ls ,echo, cat" # With spaces (using alias)
ALLOW_COMMANDS="ls, cat , echo" # Multiple spaces
You can customize the behavior of the MCP Shell Server using the following environment variables:
Environment Variable | Description | Default Value | Example |
---|---|---|---|
ALLOW_COMMANDS | List of allowed commands (comma separated) | (empty - no commands allowed) | ALLOW_COMMANDS="ls,cat,echo,npm,python" |
ALLOWED_COMMANDS | Alias for ALLOW_COMMANDS, merged with it | (empty) | ALLOWED_COMMANDS="git,docker,curl" |
PROCESS_RETENTION_SECONDS | Time to retain completed processes before cleanup (seconds) | 3600 (1 hour) | PROCESS_RETENTION_SECONDS=86400 |
DEFAULT_ENCODING | Default character encoding for process output | System terminal encoding or utf-8 | DEFAULT_ENCODING=gbk |
COMSPEC | Command processor path on Windows | cmd.exe | COMSPEC=C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe |
SHELL | Shell program path on Unix/Linux | /bin/sh | SHELL=/bin/bash |
Basic startup with minimal permissions:
ALLOW_COMMANDS="ls,cat,pwd" uvx mcp-shell-server
Development environment with extended permissions:
ALLOW_COMMANDS="ls,cat,pwd,grep,wc,touch,find" \
ALLOWED_COMMANDS="npm,python,git" \
PROCESS_RETENTION_SECONDS=86400 \
uvx mcp-shell-server
Production environment with custom encoding and longer process retention:
ALLOW_COMMANDS="ls,cat,echo,find,grep" \
DEFAULT_ENCODING=utf-8 \
PROCESS_RETENTION_SECONDS=172800 \
uvx mcp-shell-server
Windows environment with PowerShell:
set ALLOW_COMMANDS=dir,type,echo,findstr
set COMSPEC=C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
uvx mcp-shell-server
The server supports three different operation modes:
Uses standard input/output for communication, ideal for integration with Claude.app and other MCP clients.
Server-Sent Events mode allows the server to push updates to clients over HTTP. This is useful for web-based integrations and real-time updates.
Command-line options:
--host
: Server host address (default: 127.0.0.1)--port
: Server port (default: 8000)--web-path
: Web interface path (default: /web)
Provides a HTTP API endpoint for communication. This mode is suitable for RESTful API integrations.
Command-line options:
--host
: Server host address (default: 127.0.0.1)--port
: Server port (default: 8000)--path
: API endpoint path (default: /mcp)--web-path
: Web interface path (default: /web)
The web interface provides a convenient way to monitor and manage background processes:
- Process List View: See all running and completed processes
- Process Detail View: Examine detailed information about a specific process
- Real-time Output Viewing: Monitor stdout and stderr of running processes
- Process Control: Stop, terminate, and clean up processes
- Filtering: Filter processes by status or labels
(Insert screenshots here when available)
By default, the web interface is accessible at http://localhost:5000 when started with the --web
flag.
Execute a shell command and return the results.
{
"command": ["ls", "-l", "/tmp"],
"directory": "/path/to/working/directory",
"stdin": "Optional input data",
"timeout": 30,
"encoding": "utf-8"
}
{
"type": "text",
"text": "**exit with 0**"
},
{
"type": "text",
"text": "---\nstdout:\n---\ncommand output here\n"
},
{
"type": "text",
"text": "---\nstderr:\n---\nerror output here\n"
}
Field | Type | Required | Description |
---|---|---|---|
command | string[] | Yes | Command and its arguments as array elements |
directory | string | Yes | Working directory for command execution |
stdin | string | No | Input to be passed to the command |
timeout | integer | No | Maximum execution time in seconds (default: 15) |
encoding | string | No | Character encoding for command output (e.g. 'utf-8', 'gbk', 'cp936') |
Field | Type | Description |
---|---|---|
type | string | Always "text" |
text | string | Command output information including exit status, stdout and stderr |
Start a background process for long-running commands.
{
"command": ["npm", "start"],
"directory": "/path/to/project",
"description": "Start Node.js application",
"labels": ["nodejs", "app"],
"stdin": "Optional input data",
"envs": {
"NODE_ENV": "development"
},
"encoding": "utf-8",
"timeout": 3600
}
{
"type": "text",
"text": "Started background process with ID: process_123"
}
Field | Type | Required | Description |
---|---|---|---|
command | string[] | Yes | Command and its arguments as array elements |
directory | string | Yes | Working directory for command execution |
description | string | Yes | Description of the command |
labels | string[] | No | Labels to categorize the command |
stdin | string | No | Input to be passed to the command |
envs | object | No | Additional environment variables for the command |
encoding | string | No | Character encoding for command output |
timeout | integer | No | Maximum execution time in seconds |
Field | Type | Description |
---|---|---|
type | string | Always "text" |
text | string | Confirmation message with process ID |
List running or completed background processes.
{
"labels": ["nodejs"],
"status": "running"
}
{
"type": "text",
"text": "ID | STATUS | START TIME | COMMAND | DESCRIPTION | LABELS\n---------\nprocess_123 | running | 2023-05-06 14:30:00 | npm start | Start Node.js app | nodejs"
}
Field | Type | Required | Description |
---|---|---|---|
labels | string[] | No | Filter processes by labels |
status | string | No | Filter by status ('running', 'completed', 'failed', 'terminated', 'error') |
Field | Type | Description |
---|---|---|
type | string | Always "text" |
text | string | Formatted table of processes |
Stop a running background process.
{
"process_id": "process_123",
"force": false
}
{
"type": "text",
"text": "Process process_123 has been gracefully stopped\nCommand: npm start\nDescription: Start Node.js application"
}
Field | Type | Required | Description |
---|---|---|---|
process_id | string | Yes | ID of the process to stop |
force | boolean | No | Whether to force stop the process (default: false) |
Field | Type | Description |
---|---|---|
type | string | Always "text" |
text | string | Confirmation message with process details |
Get output from a background process.
{
"process_id": "process_123",
"tail": 100,
"since": "2023-05-06T14:30:00",
"until": "2023-05-06T15:30:00",
"with_stdout": true,
"with_stderr": true,
"add_time_prefix": true,
"time_prefix_format": "%Y-%m-%d %H:%M:%S.%f",
"follow_seconds": 5
}
[
{
"type": "text",
"text": "**Process process_123 (status: running)**\nCommand: npm start\nDescription: Start Node.js application\nStatus: Process is still running"
},
{
"type": "text",
"text": "---\nstdout: 5 lines\n---\n[2023-05-06 14:35:27.123456] Server started on port 3000\n[2023-05-06 14:36:01.789012] Connected to database\n"
},
{
"type": "text",
"text": "---\nstderr: 1 line\n---\n[2023-05-06 14:35:26.654321] Warning: Configuration file not found\n"
}
]
Field | Type | Required | Description |
---|---|---|---|
process_id | string | Yes | ID of the process to get output from |
tail | integer | No | Number of lines to show from the end |
since | string | No | Show logs since timestamp (e.g. '2023-05-06T14:30:00') |
until | string | No | Show logs until timestamp (e.g. '2023-05-06T15:30:00') |
with_stdout | boolean | No | Show standard output (default: true) |
with_stderr | boolean | No | Show error output (default: false) |
add_time_prefix | boolean | No | Add timestamp prefix to each output line (default: true) |
time_prefix_format | string | No | Format for timestamp prefix (default: "%Y-%m-%d %H:%M:%S.%f") |
follow_seconds | integer | No | Wait for specified seconds to get new logs |
Field | Type | Description |
---|---|---|
type | string | Always "text" |
text | string | Process information and output with optional timestamps |
Clean up completed or failed background processes.
{
"process_ids": ["process_123", "process_456"]
}
{
"type": "text",
"text": "PROCESS ID | STATUS | MESSAGE\n---------\nprocess_123 | SUCCESS | Process cleaned successfully\nprocess_456 | FAILED | Process is still running"
}
Field | Type | Required | Description |
---|---|---|---|
process_ids | string[] | Yes | List of process IDs to clean up |
Field | Type | Description |
---|---|---|
type | string | Always "text" |
text | string | Formatted table of cleanup results |
Get detailed information about a specific background process.
{
"process_id": "process_123"
}
{
"type": "text",
"text": "### Process Details: process_123\n\n#### Basic Information\n- **Status**: completed\n- **Command**: `npm start`\n- **Description**: Start Node.js application\n- **Labels**: nodejs, app\n\n#### Timing\n- **Started**: 2023-05-06 14:30:00\n- **Ended**: 2023-05-06 14:35:27\n- **Duration**: 0:05:27\n\n#### Execution\n- **Working Directory**: /path/to/project\n- **Exit Code**: 0\n\n#### Output Information\n- Use `shell_bg_logs` tool to view process output\n- Example: `shell_bg_logs(process_id='process_123')`"
}
Field | Type | Required | Description |
---|---|---|---|
process_id | string | Yes | ID of the process to get details for |
Field | Type | Description |
---|---|---|
type | string | Always "text" |
text | string | Formatted detailed information about the process |
The server implements several security measures:
- Command Whitelisting: Only explicitly allowed commands can be executed
- Shell Operator Validation: Commands after shell operators (;, &&, ||, |) are also validated against the whitelist
- No Shell Injection: Commands are executed directly without shell interpretation
- Clone the repository
git clone https://github.com/yourusername/mcp-shell-server.git
cd mcp-shell-server
- Install dependencies including test requirements
pip install -e ".[test]"
pytest
- Python 3.11 or higher
- mcp>=1.1.0
MIT License - See LICENSE file for details