enhanced-terminal

by tsoernes

Not rated
GitHub

About

A shell command / terminal executor with async support

Details

Author
tsoernes
Categories
Developer Tools, Infrastructure, Other

Recommended Setup: Sudoers Timestamp Sharing

For the best experience, configure sudo to share timestamps across all your sessions (not just per-TTY):
- Create/etc/sudoers.d/enhanced-terminal-mcpusingvisudo:

sudo visudo -f /etc/sudoers.d/enhanced-terminal-mcp
Defaults !tty_tickets Defaults timestamp_timeout=10 Defaults use_pty

- Prime sudooncein any terminal:sudo -v
- The MCP server will reuse that timestamp automatically
- No askpass dialog needed (unless timestamp expires)
- Works across all your terminal sessions and the MCP server

Security note:!tty_ticketsmeans any process running as your user can reuse your sudo timestamp while it's valid. Keeptimestamp_timeoutreasonable (e.g., 10 minutes).

A shell command / terminal executor with async support

A standalone Model Context Protocol (MCP) server that provides terminal execution, binary detection, and shell detection capabilities.
-

enhanced_terminal- Execute shell commands with smart async switching

- Streaming Output: Real-time output notifications in sync mode
- Automatically switches to background after 50 seconds (configurable)
- PTY support with proper terminal emulation
- Configurable working directory, shell, timeout, and token preview limits
- Security denylist blocks dangerous commands
- Returns job ID for tracking background tasks

enhanced_terminal_job_status- Get status and output of background jobs

- Check progress of long-running commands
- Retrieve full output when complete
- View exit codes and duration

enhanced_terminal_job_list- List all jobs (running and completed)

- See recent command history
- Filter and limit results
- Quick overview of job statuses

enhanced_terminal_job_cancel- Cancel running background jobs (Unix only)

- Send SIGTERM to running processes
- Graceful termination of long-running commands

enhanced_terminal_job_stdin- Send input to running background jobs

- Write exact UTF-8 text to a job's PTY stdin
- Include\nininputto submit a line
- Useful for prompts after commands switch to background

detect_binaries- Detect developer tools with 16 concurrent checks

- Scans PATH for 190+ common development tools across 26 categories
- Fast parallel version detection
- Supports filtering by category (rust_tools, python_tools, etc.)
- Categories include: package managers, build systems, programming language tools, editors, containers, and more

Note:Shell information is automatically detected at server startup and included in the server instructions, so no separate tool call is needed to discover available shells.

- Streaming Notifications: Emits MCP logging notifications as command output arrives (client support varies)
- Smart Async Switching: Commands automatically move to background after 50 seconds (configurable)
- Security Denylist: Blocks dangerous commands likerm -rf /,shutdown, fork bombs, etc.
- Job Management: Track, monitor, feed stdin to, and cancel background jobs with rich metadata
- Job Filtering: Filter jobs by status, tags, or working directory
- Output Pagination: Seek into specific byte ranges of very long logs
- Job Tags: Categorize jobs with custom tags for easy filtering
- Call Logging: Appends everyenhanced_terminalshell execution request toenhanced_terminal_calls.jsonl
- 16 Concurrent Checks: Fast parallel binary detection
- PTY Support: Full terminal emulation for interactive commands

- Rust with 2024 edition support (Rust 1.85+ recommended)
- Cargo

git clone <repository-url> cd enhanced-terminal-mcp cargo build --release

The binary will be located attarget/release/enhanced-terminal-mcp.

This server handles sudo commands automatically to avoid password prompts during tool execution:
- First sudo command: Triggers an askpass dialog (viasudo -A -v) to authenticate once
- Subsequent sudo commands: Rewritten tosudo -n(non-interactive) and use the cached sudo timestamp
- Keepalive: Background task refreshes the timestamp every 5 minutes to keep it valid

All of this isenabled by default. Thesudo_wrapper_appliedfield in results shows when the-nflag was added.

Recommended Setup: Sudoers Timestamp Sharing

For the best experience, configure sudo to share timestamps across all your sessions (not just per-TTY):
- Create/etc/sudoers.d/enhanced-terminal-mcpusingvisudo:

sudo visudo -f /etc/sudoers.d/enhanced-terminal-mcp
Defaults !tty_tickets Defaults timestamp_timeout=10 Defaults use_pty

- Prime sudooncein any terminal:sudo -v
- The MCP server will reuse that timestamp automatically
- No askpass dialog needed (unless timestamp expires)
- Works across all your terminal sessions and the MCP server

Security note:!tty_ticketsmeans any process running as your user can reuse your sudo timestamp while it's valid. Keeptimestamp_timeoutreasonable (e.g., 10 minutes).

Alternative: Askpass-based Workflow (Default Behavior)

If you prefer not to change sudoers, the server defaults will work:

- Default askpass path:~/scripts/askpass-zenity.sh
- First sudo command→ askpass dialog
- Server keeps timestamp alive→ no more prompts

The server will automatically pass through these env vars for GUI askpass:

- DISPLAY(defaults to:0)
- WAYLAND_DISPLAY(defaults towayland-0)
- XDG_RUNTIME_DIR
- DBUS_SESSION_BUS_ADDRESS

These environment variables control sudo behavior (all default toON):

# Enable/disable sudo wrapping and keepalive (default: 1) ENHANCED_TERMINAL_SUDO_WRAP=1 ENHANCED_TERMINAL_SUDO_KEEPALIVE=1 ENHANCED_TERMINAL_SUDO_KEEPALIVE_PRIME=1 # Custom askpass path (default: ~/scripts/askpass-zenity.sh) ENHANCED_TERMINAL_SUDO_ASKPASS=/path/to/your/askpass.sh # Keepalive refresh interval in seconds (default: 300, min: 30) ENHANCED_TERMINAL_SUDO_KEEPALIVE_REFRESH_SECS=300

Enable detailed logging to see sudo priming/wrapping behavior:

Look for log lines aboutsudo -A -v(priming) andsudo -n(wrapping).

The server uses stdio transport for MCP communication:

{ "mcpServers": { "enhanced-terminal": { "command": "/path/to/enhanced-terminal-mcp", "args": [] } } }

Everyenhanced_terminaltool call is appended as one JSON object per line toenhanced_terminal_calls.jsonlin the repository root. Each entry includes an RFC3339 UTCdatetime, the tool name, and the full submitted parameters. Writes use an in-process mutex and, on Unix, an exclusive file lock so concurrent tool calls and test server processes do not interleave JSON records.

Override the log path withENHANCED_TERMINAL_CALL_LOG_PATHif needed.

Ifcwdis omitted, it defaults to.. That.is resolved relative to the MCP server process working directory supplied by the caller/client. In practice, when Codex starts this MCP server from a project, omittedcwduses that project/server launch directory. Passcwdexplicitly when you need a specific repository or subdirectory.

Basic synchronous execution (completes quickly).cwdis optional; omitting it uses the MCP server process working directory supplied by the caller/client:

{ "command": "ls -la", "cwd": ".", "shell": "bash" }

Long-running command (auto-switches to background after 50 seconds by default):

{ "command": "npm install", "cwd": "./my-project", "shell": "bash" }

Force immediate async execution (useful for interactive commands that need stdin):

{ "command": "read -p 'stdin> ' value; echo received=$value", "force_async": true }
{ "command": "npm run build", "env_vars": { "NODE_ENV": "production", "API_KEY": "secret123" } }

Force synchronous execution (wait for completion):

{ "command": "cargo build --release", "force_sync": true }
{ "command": "docker run myimage", "custom_denylist": ["docker rm", "docker system prune"] }
{ "command": "cargo build --release", "tags": ["build", "release"] }

Token-bounded preview (GPT-5/o200k_base tokenizer):

{ "command": "cargo test", "preview_tokens": 4000 }

preview_tokensdefaults to 4096. Set it to 0 to disable token truncation for the bounded in-memory preview buffer.

Job IDs are readable adjective-noun-number handles such asbrave-river-1, making them easier to copy and discuss than numeric IDs.

Get full output.job_statusreturns the command summary by default; passfull_command: trueonly when you need the full command text:

{ "job_id": "brave-river-1", "incremental": false, "full_command": true }

Get incremental output (only new since last check):

{ "job_id": "brave-river-1", "incremental": true }

Get paginated output (first 1000 bytes):

{ "job_id": "brave-river-1", "offset_bytes": 0, "limit_bytes": 1000 }
{ "job_id": "brave-river-1", "offset_bytes": 1000, "limit_bytes": 1000 }
{ "max_jobs": 50, "status_filter": ["Running", "Completed"] }
{ "max_jobs": 50, "tag_filter": "build" }
{ "max_jobs": 50, "cwd_filter": "/home/user/project" }
{ "max_jobs": 50, "status_filter": ["Completed"], "tag_filter": "test", "sort_order": "oldest" }
{ "job_id": "brave-river-1" }

Write input to a running async job. Newlines are not appended automatically, so include\nwhen you want to submit a line:

{ "job_id": "brave-river-1", "input": "yes\n" }
{ "filter_categories": ["rust_tools", "python_tools"], "max_concurrency": 16, "version_timeout_ms": 1500, "include_missing": false }

Thedetect_binariestool supports filtering by these categories:

- package_managers- npm, pip, cargo, dnf, apt, snap, flatpak, brew, pnpm, uv, poetry, pipx
- rust_tools- cargo, rustc, rustfmt, clippy-driver
- python_tools- python, python3, pip, pytest, black, ruff, mypy, uv, poetry, pipenv, pipx, pyright, pylint, flake8, isort, ipython
- build_systems- make, cmake, ninja, gradle, maven, mvn
- c_cpp_tools- gcc, g++, clang, gdb, lldb
- java_jvm_tools- java, javac, javadoc, jar, jarsigner, jconsole, jdeps, jlink, jshell, kotlin, kotlinc, scala, scalac, groovy, groovyc
- maven_tools- mvn, mvnw, mvnd
- node_js_tools- node, deno, bun, npm, yarn, pnpm, tsx, tsc, biome, prettier, eslint
- go_tools- go, gofmt
- editors_dev- vim, nvim, emacs, code, hx, nano, micro
- search_productivity- rg, fd, fzf, jq, bat, tree, exa, sd, zoxide, lsd, dust, btm, broot, choose
- system_perf- htop, ps, top, df, du
- containers- docker, podman, kubectl, helm, docker-compose, kind, minikube, skopeo, buildah, nerdctl, k9s
- networking- curl, wget, dig, traceroute, http, nc, nmap, ss, ping, mtr, socat
- security- openssl, gpg, ssh-keygen, age, sops, vault, pass
- auth_helpers- zenity, ssh-askpass, sshaskpass, ksshaskpass, lxqt-openssh-askpass, gnome-ssh-askpass, x11-ssh-askpass, pinentry variants
- databases- sqlite3, psql, mysql, redis-cli, mongosh, duckdb, clickhouse-client, redis-server
- vcs- git, gh, lazygit, tig, gitui, hg, svn
- cloud_cli- aws, gcloud, az, doctl, fly, vercel, wrangler
- iac_tools- terraform, tofu, pulumi, ansible, ansible-playbook, vagrant, packer
- media_tools- ffmpeg, ffprobe, convert, magick, exiftool, yt-dlp, sox
- ai_ml_tools- ollama, huggingface-cli, nvidia-smi, nvcc, rocm-smi, dvc, mlflow
- docs_tools- pandoc, sphinx-build, mkdocs, doxygen, asciidoctor, mdbook
- ruby_tools- ruby, gem, bundle, rake, irb, rails
- dotnet_tools- dotnet, nuget, msbuild
- cad_utils- ODAFileConverter, dwg2svg, dwg2SVG, dwg2bmp, dwg2pdf, qcad, librecad, freecad, freecadcmd, openscad, dxf2gcode

The server includes a comprehensive denylist that blocks dangerous commands:

- rm -rf /,rm -rf /*,rm --no-preserve-root
- mkfs,dd if=/dev/zero, filesystem formatting
- Writes to/dev/sda,/dev/hda

- shutdown,reboot,halt,poweroff
- init 0,init 6, systemctl power commands

- chmod 777 /,chmod -R 777 /
- chown -R root,chown root /

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.