Advanced shell command execution for AI agents — A Model Context Protocol (MCP) server with security policy engine, process lifecycle management, bounded output capture, POSIX signals, and token-efficient responses.
6 tools. Zero configuration. POSIX-native. Security by default.
Existing command execution MCPs are thin wrappers over subprocess.run. Cuba-Exec solves the real problems:
| Problem | Existing MCPs | Cuba-Exec |
|---|---|---|
| Output overflow (cat /dev/urandom) | ❌ OOM crash | ✅ 64KB bounded |
| Background processes | ❌ Sync only | ✅ Start/status/signal |
| Kill child processes (npm run dev) | ❌ Orphaned children | ✅ Process group kill (setsid) |
| Send stdin (REPLs, prompts) | ❌ Not supported | ✅ Full stdin pipe |
| POSIX signals (SIGTERM, SIGKILL) | ❌ Not supported | ✅ 5 signals + graceful shutdown |
| Command allowlist/blocklist | ✅ Both + shell operator validation | |
| Directory restriction | ✅ Path-resolved anti-traversal | |
| Audit logging | ❌ None | ✅ Structured JSON to stderr |
| Token-efficient output | ❌ Verbose JSON | ✅ TOON compact format |
| Idle process cleanup | ❌ Resource leak | ✅ 1-hour TTL auto-cleanup |
| Fork bomb protection | ❌ None | ✅ Semaphore(20) |
| Process discovery | ❌ None | ✅ List all managed processes |
- Python 3.14+
- Linux/macOS (POSIX required for process groups)
git clone https://github.com/LeandroPG19/cuba-exec.git
cd cuba-exec
uv venv && uv pip install -e .{
"mcpServers": {
"cuba-exec": {
"command": "/path/to/cuba-exec/.venv/bin/python",
"args": ["-m", "cuba_exec"]
}
}
}Zero environment variables needed. Zero configuration files. It just works — with 25 dangerous commands blocked by default.
run(command="ls -la", cwd="/tmp", timeout_ms=5000)
| Parameter | Type | Default | Description |
|---|---|---|---|
command |
string | required | Shell command |
cwd |
string | None | Working directory |
env |
dict | None | Environment variables (merged with current) |
timeout_ms |
int | 30000 | Timeout in milliseconds |
max_output |
int | 65536 | Output buffer size (bytes) |
shell |
string | /bin/sh | Shell executable |
Response:
[exit:0 time:12ms trunc:no]
total 156
drwxrwxrwt 22 root root 4096 Mar 8 2026 .
...
start(command="npm run dev", cwd="/app")
Response:
[pid:12345 state:running]
Background process started. Use status(12345) to check output.
status(pid=12345, tail_bytes=4096)
Response:
[pid:12345 state:running exit:- time:5432ms bytes:8192 trunc:no]
Server running on http://localhost:3000
send_signal(pid=12345, sig="SIGTERM")
SIGTERM triggers graceful shutdown: SIGTERM → wait 5s → SIGKILL.
Valid signals: SIGTERM, SIGKILL, SIGINT, SIGHUP, SIGQUIT.
send_input(pid=12345, stdin="print('hello')\n")
For interactive processes (Python REPL, bash prompt, etc.).
list_processes()
Response:
[processes:2]
pid:12345 state:running exit:- time:5432ms bytes:8192 cmd:npm run dev
pid:12346 state:completed exit:0 time:1200ms bytes:256 cmd:echo done
Cuba-Exec includes a multi-layer security engine — the most comprehensive of any MCP command server.
| Layer | Description | Config |
|---|---|---|
| Command Allowlist | Only listed commands can execute | CUBA_EXEC_ALLOWED_COMMANDS |
| Command Blocklist | Dangerous commands always rejected | CUBA_EXEC_BLOCKED_COMMANDS |
| Shell Operator Validation | Validates each sub-command after ;, &&, ||, | |
Automatic |
| Directory Restriction | Restrict cwd to allowed paths (anti-traversal) |
CUBA_EXEC_ALLOWED_DIRS |
| Audit Logging | Structured JSON log of every execution | CUBA_EXEC_AUDIT |
Out of the box, Cuba-Exec blocks 25 dangerous commands:
rm, dd, mkfs, shutdown, reboot, halt, poweroff, init, systemctl,
passwd, chown, chmod, chgrp, mount, umount, fdisk, parted,
iptables, nft, ip6tables, crontab, at, useradd, userdel,
groupadd, groupdel, visudo
export CUBA_EXEC_ALLOWED_COMMANDS="ls,cat,echo,grep,find,head,tail,wc,git,python3,node,npm"
export CUBA_EXEC_BLOCKED_COMMANDS="rm,dd,mkfs,shutdown"
export CUBA_EXEC_ALLOWED_DIRS="/home/user/project,/tmp"
export CUBA_EXEC_AUDIT=1ls && rm -rf / — the rm after && is validated against blocklist/allowlist too.
Operators parsed: ;, &&, ||, | — each sub-command checked independently.
{"ts":"2026-03-08T15:00:00-0600","event":"exec","command":"ls -la","pid":12345,"exit":0,"ms":12,"ok":true}All responses use Token-Oriented Object Notation — compact headers that save ~200 tokens per tool call vs verbose JSON.
[exit:0 time:1543ms trunc:no]
...output...
| Error | Exit Code | Field | Example |
|---|---|---|---|
| Command not found | 127 | ENOENT |
nonexistent_binary |
| Permission denied | 126 | EACCES |
cat /etc/shadow |
| Timeout | -1 | TIMEOUT |
sleep 60 with 1s timeout |
| Signal killed | -9 | SIGKILL |
Process killed by signal |
| Blocked by policy | — | BLOCKED |
rm -rf / |
Command output has high entropy at the extremes (preamble + results/errors) and low entropy in the middle (progress bars, repetitive logs).
┌─────────────┬───────────────────────────────┬──────────────────────────────────────────┐
│ Head (25%) │ Truncated middle │ Tail (75%) │
│ ~16KB │ [... N bytes truncated ...] │ ~48KB (ring buffer) │
└─────────────┴───────────────────────────────┴──────────────────────────────────────────┘
- Head: First 25% of buffer — captures headers, version info
- Tail: Last 75% via ring buffer — captures results, errors (highest entropy)
- Ring buffer: O(1) write, O(C) memory (Cormen et al., CLRS 4th ed.)
- Default: 64KB per process. Max memory: 20 × 64KB = 1.28MB
npm run dev spawns child processes. Sending SIGTERM to the parent doesn't kill children.
Cuba-Exec creates process groups via setsid:
asyncio.create_subprocess_exec(..., start_new_session=True)
os.killpg(os.getpgid(pid), signal.SIGTERM) # Kills entire treeSIGTERM → wait 5s → SIGKILL (if still alive)
Two-phase shutdown (Stevens & Rago, 2013): SIGTERM allows cleanup, SIGKILL is uncatchable.
All defaults work out of the box. Override via environment variables:
| Setting | Default | Env Var |
|---|---|---|
| Max concurrent processes | 20 | CUBA_EXEC_MAX_PROCS |
| Output buffer size | 64KB | CUBA_EXEC_BUFFER_SIZE |
| Idle process TTL | 1 hour | CUBA_EXEC_TTL |
| Shutdown timeout | 5s | CUBA_EXEC_SHUTDOWN_TIMEOUT |
| Allowed commands | — (all) | CUBA_EXEC_ALLOWED_COMMANDS |
| Blocked commands | 25 defaults | CUBA_EXEC_BLOCKED_COMMANDS |
| Allowed directories | — (all) | CUBA_EXEC_ALLOWED_DIRS |
| Audit logging | off | CUBA_EXEC_AUDIT |
cuba-exec/
├── pyproject.toml # 1 dependency: fastmcp
└── src/
└── cuba_exec/
├── __init__.py
├── __main__.py # Entry point
├── server.py # FastMCP 6 tool definitions (~105 LOC)
├── security.py # SecurityPolicy engine (~135 LOC)
├── process_manager.py # Lifecycle FSM + signals + TTL (~520 LOC)
└── output_buffer.py # Head+Tail ring buffer (~110 LOC)
Total: ~880 LOC. FastMCP SDK handles protocol boilerplate.
| Package | Purpose |
|---|---|
fastmcp |
MCP protocol server — auto tool schemas from type hints, Pydantic validation |
Everything else is Python stdlib: asyncio, os, signal, time, json, re, pathlib.
| Project | Purpose |
|---|---|
| Cuba-Memorys | Persistent memory — knowledge graph, Hebbian learning |
| Cuba-Thinking | Sequential reasoning — cognitive engine, NLI, MCTS |
| Cuba-Search | Web search — research, scraping, validation, documentation lookup |
| Cuba-Exec | Shell execution — process lifecycle, security, bounded output, POSIX signals |
Together: memory + reasoning + search + execution — the four pillars of capable AI agents.
| # | Citation | Used For |
|---|---|---|
| 1 | Yang et al. (2024). "SWE-agent: Agent-Computer Interfaces." NeurIPS | ACI design, output truncation, guardrails |
| 2 | Shannon (1948). "A Mathematical Theory of Communication" | Information-theoretic output strategy |
| 3 | IEEE Std 1003.1-2024. "POSIX.1: System Interfaces" | Process groups, setsid, signals |
| 4 | Cormen et al. (2022). "Introduction to Algorithms." 4th ed. | Ring buffer O(1) analysis |
| 5 | Dijkstra (1965). "Cooperating Sequential Processes" | Semaphore concurrency limiting |
| 6 | Stevens & Rago (2013). "APUE" 3rd ed. | Process lifecycle, graceful shutdown |
| 7 | TOON (2025). "Token-Oriented Object Notation" | 95-97% token reduction |
| 8 | OWASP (2025). "Top 10 for Agentic Applications" | Security policy design, allowlist/blocklist |
CC BY-NC 4.0 — Free to use and modify, not for commercial use.
Leandro Pérez G.
- GitHub: @LeandroPG19
- Email: leandropatodo@gmail.com