mcp-secure-exec
Secure MCP server for executing user-defined shell commands via templates.
Overview
mcp-secure-exec is a robust Model Context Protocol (MCP) server designed to safely expose shell command functionality to AI clients. It bridges the gap between LLMs and system operations by enforcing strict security policies, input validation, and execution limits. The server supports multiple transport layers, with Streamable HTTP as the recommended default for remote deployments, alongside Stdio for local integrations.
Data Access Modes
The server supports two primary transport mechanisms for MCP communication:
- Streamable HTTP (Recommended): Suitable for remote connections, supporting stateful sessions, authentication and health checks. Ideal for containerized and cloud deployments.
- Stdio: Ideal for local integrations and piping within existing workflows (e.g., Claude Desktop, local scripts).
Features
- Command Templating Engine: Define safe command structures with named placeholders for arguments.
- Strict Input Validation: Prevents path traversal, shell injection, and dangerous pattern usage.
- Multi-Transport Support: Seamlessly switch between Stdio and Streamable HTTP transports.
- Rate Limiting & Concurrency Control: Protects resources with configurable request limits and concurrent execution caps.
- Circuit Breaker Protection: Automatically halts execution during repeated failures to prevent cascading errors.
- Comprehensive Audit Logging: Tracks command invocations and security events with redacted sensitive data.
- Graceful Shutdown: Handles SIGINT/SIGTERM for clean termination.
Installation
Docker Compose Integration
services:
mcp-secure-exec:
image: timasoft/mcp-secure-exec:0.1.0
container_name: mcp-secure-exec
restart: unless-stopped
environment:
MCP_EXEC_COMMANDS: 'echo|"echo {message}"'
MCP_EXEC_TRANSPORT: streamable-http
MCP_EXEC_BIND: 0.0.0.0:3344
MCP_EXEC_AUTH_TOKEN: 'very_secret_token'
MCP_EXEC_LOG_LEVEL: info
security_opt:
- no-new-privileges: true
read_only: true
tmpfs:
- /tmp
ports:
- "127.0.0.1:3344:3344"
⚠️ YAML Quoting: Always quote environment variable values containing special characters like
|or{}to prevent YAML parsing errors.
Important notes about configuration:
- Security Context: Always run with
no-new-privilegesand read-only filesystem where possible. - Command Definition: Commands must be defined via environment variables or CLI arguments; no commands are allowed by default.
- Network Binding: When using HTTP transport, bind to
127.0.0.1unless external access is explicitly required. - Authentication: Enable
MCP_EXEC_AUTH_TOKENfor HTTP transport to require Bearer token authentication. - Sensitive Data: Use
MCP_EXEC_SENSITIVE_KEYSto ensure secrets are not logged in plain text.
Make sure to:
- Define at least one command template using
MCP_EXEC_COMMANDS. - Set
MCP_EXEC_TRANSPORT=streamable-httpfor remote access (default isstdio). - Verify binary availability within the container environment.
After adding the service, run:
Verify HTTP server is running:
Nix
If you're using Nix or NixOS, you can build and run the application directly:
Streamable HTTP mode (recommended for remote/server use):
Stdio mode (for local MCP clients like Claude Desktop):
With path restrictions and security hardening:
From Source
-
Install Rust toolchain:
| -
Install the project:
-
Run the application:
Streamable HTTP mode (recommended):
Stdio mode (for local MCP clients):
Environment variable configuration (recommended):
Dry-run validation (test configuration without starting server):
Configuration
Environment Variables
All configuration options can be set via environment variables. CLI arguments take precedence over environment variables. Multiple commands can be specified using semicolon delimiter in MCP_EXEC_COMMANDS.
Command & Tool Configuration
| Variable | Description | Default |
|---|---|---|
MCP_EXEC_COMMANDS |
Command definitions in format name|"template" (semicolon-delimited for multiple) |
Required |
MCP_EXEC_DANGEROUS |
Comma-separated list of restricted binaries (case-insensitive matching) | rm,dd,mkfs,chmod,chown,sudo,su,curl,wget,sh,bash,dash,zsh,python,python3,perl,ruby,node,lua,php,awk,sed,gawk,git,ssh,scp,rsync,tar,zip,unzip,gzip,bzip2,find,xargs,env,nice,timeout,strace,ltrace,ncat,netcat,nc,telnet,ftp,sftp,rbash,rsh |
MCP_EXEC_ALLOW_DANGEROUS |
Allow execution of restricted binaries (true/false) |
false |
MCP_EXEC_BASE_PATH |
Restrict path-like arguments to this directory | None |
MCP_EXEC_NO_VALIDATE_PATHS |
Disable path traversal protection (true/false) |
false |
MCP_EXEC_ALLOW_MISSING_BINARIES |
Allow commands whose binaries are not in PATH at startup (true/false) |
false |
⚠️
--allow-missing-binariesbehavior: This flag defers binary existence checks from startup to runtime. While useful for testing or dynamic environments, it increases runtime risk: a command may fail unexpectedly if the binary is missing or has been tampered with.
Security & Logging
| Variable | Description | Default |
|---|---|---|
MCP_EXEC_SENSITIVE_KEYS |
Comma-separated list of argument names to mask in logs (case-insensitive) | password,token,secret,key,auth,credential |
MCP_EXEC_AUTH_TOKEN |
Optional Bearer token for HTTP authentication | None |
MCP_EXEC_LOG_LEVEL |
Logging verbosity level | info |
MCP_EXEC_DRY_RUN |
Validate configuration and exit (true/false) |
false |
Transport & Network
| Variable | Description | Default |
|---|---|---|
MCP_EXEC_TRANSPORT |
Communication protocol (stdio or streamable-http) |
stdio |
MCP_EXEC_BIND |
Network address for HTTP server | 127.0.0.1:3344 |
MCP_EXEC_STATEFUL |
Enable stateful sessions for HTTP transport (true/false) |
false |
Performance & Limits
| Variable | Description | Default |
|---|---|---|
MCP_EXEC_CMD_TIMEOUT_SECS |
Maximum execution time per command in seconds | 30 |
MCP_EXEC_RATE_LIMIT_RPS |
Maximum requests per second | 10 |
MCP_EXEC_RATE_LIMIT_BURST |
Burst size for rate limiting | 20 |
MCP_EXEC_MAX_CONCURRENT |
Maximum concurrent command executions | 50 |
MCP_EXEC_CIRCUIT_THRESHOLD |
Circuit breaker failure threshold | 10 |
MCP_EXEC_CIRCUIT_TIMEOUT_SECS |
Circuit breaker timeout in seconds | 60 |
Default Security Posture:
MCP_EXEC_DANGEROUSincludes common system utilities likerm,sudo, and shells to prevent accidental system damage. Blacklist matching is case-insensitive —RM,Rm, andrmare all blocked.
Command Line Arguments
| ; )
)
)
Placeholder Naming Conventions
Placeholder names in command templates trigger specific validation behaviors:
| Placeholder Pattern | Effect | Example |
|---|---|---|
path, file, dir, filepath |
Enables path traversal protection; requires --base-path for relative paths |
{path}, {file} |
*_flag, *_opt |
Allows safe single-dash flags like -h; dangerous flags (e.g., -v, -x, -e) are blocked regardless |
{verbose_flag} → -h OK, -v rejected |
| Any other name | Blocks shell metacharacters and command-like patterns | {message} → hello;rm rejected |
💡 Note: Even with
*_flagsuffix, flags listed in the dangerous patterns blacklist (like-v,-x,-e,--exec, etc.) are always blocked for security. Use only safe, non-dangerous flags with flag placeholders.
Usage Examples
Streamable HTTP Mode (Recommended)
Remote Server with Authentication
Environment Variable HTTP Configuration
Health Check Verification
Multiple Tools with HTTP
Stdio Mode (Local Use)
Basic Echo Tool
File Listing with Path Validation
Multiple Tools Configuration
OR
Dry-Run Validation
MCP_EXEC_DRY_RUN=true MCP_EXEC_COMMANDS='test|"echo {arg}"'
MCP Client Integration
For Remote Clients (HTTP Transport):
- Use
streamable-httptransport with the server URL:http://host:3344 - Include
Authorization: Bearer <token>header ifMCP_EXEC_AUTH_TOKENis set - Health endpoint:
GET /healthreturnsOK
For Claude Desktop (Stdio Transport) (Not tested):
- Use
stdiotransport for local subprocess execution inclaude_desktop_config.json - Example configuration:
For IDE Extensions (Not tested):
transport- Ensure the client supports the selected transport protocol.commands- Verify tool names match the--cmdname definition exactly.
Install MCP Clients using:
Architecture
mcp-secure-exec follows a layered security architecture designed to isolate command execution from the MCP protocol handling.
Streamable HTTP Transport (Recommended)
- Implements Streamable HTTP Server spec for MCP.
- Supports optional Bearer token authentication via
Authorizationheader. - Includes
/healthendpoint for load balancer and orchestration checks. - Graceful shutdown via SIGINT/SIGTERM handling with
CancellationToken.
Stdio Transport
- Direct pipe communication between client and server.
- Minimal overhead, suitable for local agents.
- Inherits parent process environment and permissions.
- Terminates when stdin is closed.
Core Features
- Security Layer: Validates arguments against injection patterns and path traversal attempts.
- Recursive URL-decoding protection (prevents
%252e%252e→..attacks) - Unicode normalization (NFC/NFD) to block homoglyph bypasses
- Contextual shell metacharacter filtering
- Recursive URL-decoding protection (prevents
- Execution Engine: Spawns processes with timeout enforcement and output capture.
- Rate Limiter: Token bucket algorithm to prevent abuse.
- Circuit Breaker: Opens circuit after threshold failures to protect stability.
- Audit System: Logs all invocations with sensitive data masking.
Advanced Security Features
URL Encoding Protection
The server recursively decodes URL-encoded input (up to 5 iterations) to detect and block encoded path traversal attempts like %252e%252e%252f (triple-encoded ../).
Unicode Normalization
Input is normalized to both NFC and NFD forms to prevent bypasses using Unicode homoglyphs or combining characters.
Context-Aware Validation
- Path placeholders (
{path},{file}, etc.) allow quoted metacharacters for legitimate use cases. - Non-path placeholders strictly block shell metacharacters outside quotes.
- Flag placeholders (
*_flag) permit safe single-dash options while still blocking dangerous patterns like-v,-x,--exec, etc.
Troubleshooting
Enable Debug Logging
MCP_EXEC_LOG_LEVEL=trace
Verify Binary Availability
- Check PATH:
which <binary>orecho $PATH - Allow Missing: Use
--allow-missing-binariesfor testing (defers check to runtime)
Health Check Failure (HTTP Mode)
- Verify Binding: Ensure
--bindaddress is accessible from the checker. - Check Logs: Review stdout/stderr for startup errors like
FATAL: Binary not found. - Firewall: Confirm port 3344 (or custom bind) is not blocked by host firewall.
- Authentication: If
MCP_EXEC_AUTH_TOKENis set, includeAuthorization: Bearer <token>in requests.
Security
mcp-secure-exec is designed with security as a primary concern. However, please note:
- Never use
--allow-dangerousunless you fully understand the risks. - Always use
--base-pathwhen exposing file operations. - Enable
MCP_EXEC_AUTH_TOKENfor HTTP transport. - Blacklist matching is case-insensitive:
RM,Sudo, andbaShare blocked just like their lowercase forms. --allow-missing-binariesdefers security checks: A command may pass startup validation but fail at runtime if the binary is missing or has been replaced.- Audit logs redact sensitive data: Arguments matching
MCP_EXEC_SENSITIVE_KEYSare masked as[REDACTED]. - Dangerous flags are always blocked: Even with
*_flagplaceholders, flags like-v,-x,-e,--exec, etc. are rejected regardless of context.