enhanced-terminal
A shell command / terminal executor with async support
Enhanced Terminal MCP Server
A standalone Model Context Protocol (MCP) server that provides terminal execution, binary detection, and shell detection capabilities.
Features
Tools
-
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.
Key Features
- 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 like
rm -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 every
enhanced_terminalshell execution request toenhanced_terminal_calls.jsonl - 16 Concurrent Checks: Fast parallel binary detection
- PTY Support: Full terminal emulation for interactive commands
Installation
Prerequisites
- Rust with 2024 edition support (Rust 1.85+ recommended)
- Cargo
Build from Source
git clone <repository-url>
cd enhanced-terminal-mcp
cargo build --release
The binary will be located at target/release/enhanced-terminal-mcp.
Sudo Workflow (Recommended)
This server handles sudo commands automatically to avoid password prompts during tool execution:
- First sudo command: Triggers an askpass dialog (via
sudo -A -v) to authenticate once - Subsequent sudo commands: Rewritten to
sudo -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 is enabled by default. The sudo_wrapper_applied field in results shows when the -n flag 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
- Add these lines:
Defaults !tty_tickets
Defaults timestamp_timeout=10
Defaults use_pty
-
Benefits:
- Prime sudo once in 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
- Prime sudo once in any terminal:
-
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_DIRDBUS_SESSION_BUS_ADDRESS
Configuration (Optional)
These environment variables control sudo behavior (all default to ON):
# 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
Debugging
Enable detailed logging to see sudo priming/wrapping behavior:
RUST_LOG=debug enhanced-terminal-mcp
Look for log lines about sudo -A -v (priming) and sudo -n (wrapping).
Usage
Running the Server
The server uses stdio transport for MCP communication:
./enhanced-terminal-mcp
Configuration
Add to your MCP client configuration:
{
"mcpServers": {
"enhanced-terminal": {
"command": "/path/to/enhanced-terminal-mcp",
"args": []
}
}
}
Call Logging
Every enhanced_terminal tool call is appended as one JSON object per line to enhanced_terminal_calls.jsonl in the repository root. Each entry includes an RFC3339 UTC datetime, 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 with ENHANCED_TERMINAL_CALL_LOG_PATH if needed.
Working Directory Defaults
If cwd is 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, omitted cwd uses that project/server launch directory. Pass cwd explicitly when you need a specific repository or subdirectory.
Tool Examples
enhanced_terminal
Basic synchronous execution (completes quickly). cwd is 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
}
With environment variables:
{
"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
}
With custom denylist:
{
"command": "docker run myimage",
"custom_denylist": ["docker rm", "docker system prune"]
}
With tags for job categorization:
{
"command": "cargo build --release",
"tags": ["build", "release"]
}
Token-bounded preview (GPT-5/o200k_base tokenizer):
{
"command": "cargo test",
"preview_tokens": 4000
}
preview_tokens defaults 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 as brave-river-1, making them easier to copy and discuss than numeric IDs.
enhanced_terminal_job_status
Get full output. job_status returns the command summary by default; pass full_command: true only 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
}
Get paginated output (next 1000 bytes):
{
"job_id": "brave-river-1",
"offset_bytes": 1000,
"limit_bytes": 1000
}
enhanced_terminal_job_list
List all jobs:
{
"max_jobs": 50
}
Filter by status:
{
"max_jobs": 50,
"status_filter": ["Running", "Completed"]
}
Filter by tag:
{
"max_jobs": 50,
"tag_filter": "build"
}
Filter by working directory:
{
"max_jobs": 50,
"cwd_filter": "/home/user/project"
}
Combined filters with sort order:
{
"max_jobs": 50,
"status_filter": ["Completed"],
"tag_filter": "test",
"sort_order": "oldest"
}
enhanced_terminal_job_cancel
{
"job_id": "brave-river-1"
}
enhanced_terminal_job_stdin
Write input to a running async job. Newlines are not appended automatically, so include \n when you want to submit a line:
{
"job_id": "brave-river-1",
"input": "yes\n"
}
detect_binaries
{
"filter_categories": ["rust_tools", "python_tools"],
"max_concurrency": 16,
"version_timeout_ms": 1500,
"include_missing": false
}
Binary Categories
The detect_binaries tool supports filtering by these categories:
package_managers- npm, pip, cargo, dnf, apt, snap, flatpak, brew, pnpm, uv, poetry, pipxrust_tools- cargo, rustc, rustfmt, clippy-driverpython_tools- python, python3, pip, pytest, black, ruff, mypy, uv, poetry, pipenv, pipx, pyright, pylint, flake8, isort, ipythonbuild_systems- make, cmake, ninja, gradle, maven, mvnc_cpp_tools- gcc, g++, clang, gdb, lldbjava_jvm_tools- java, javac, javadoc, jar, jarsigner, jconsole, jdeps, jlink, jshell, kotlin, kotlinc, scala, scalac, groovy, groovycmaven_tools- mvn, mvnw, mvndnode_js_tools- node, deno, bun, npm, yarn, pnpm, tsx, tsc, biome, prettier, eslintgo_tools- go, gofmteditors_dev- vim, nvim, emacs, code, hx, nano, microsearch_productivity- rg, fd, fzf, jq, bat, tree, exa, sd, zoxide, lsd, dust, btm, broot, choosesystem_perf- htop, ps, top, df, ducontainers- docker, podman, kubectl, helm, docker-compose, kind, minikube, skopeo, buildah, nerdctl, k9snetworking- curl, wget, dig, traceroute, http, nc, nmap, ss, ping, mtr, socatsecurity- openssl, gpg, ssh-keygen, age, sops, vault, passauth_helpers- zenity, ssh-askpass, sshaskpass, ksshaskpass, lxqt-openssh-askpass, gnome-ssh-askpass, x11-ssh-askpass, pinentry variantsdatabases- sqlite3, psql, mysql, redis-cli, mongosh, duckdb, clickhouse-client, redis-servervcs- git, gh, lazygit, tig, gitui, hg, svncloud_cli- aws, gcloud, az, doctl, fly, vercel, wrangleriac_tools- terraform, tofu, pulumi, ansible, ansible-playbook, vagrant, packermedia_tools- ffmpeg, ffprobe, convert, magick, exiftool, yt-dlp, soxai_ml_tools- ollama, huggingface-cli, nvidia-smi, nvcc, rocm-smi, dvc, mlflowdocs_tools- pandoc, sphinx-build, mkdocs, doxygen, asciidoctor, mdbookruby_tools- ruby, gem, bundle, rake, irb, railsdotnet_tools- dotnet, nuget, msbuildcad_utils- ODAFileConverter, dwg2svg, dwg2SVG, dwg2bmp, dwg2pdf, qcad, librecad, freecad, freecadcmd, openscad, dxf2gcode
Development
Building
cargo build
Testing
cargo test
Running Tests for Denylist
cargo test denylist
Running Locally
cargo run
Security
Command Denylist
The server includes a comprehensive denylist that blocks dangerous commands:
Destructive Operations:
rm -rf /,rm -rf /*,rm --no-preserve-rootmkfs,dd if=/dev/zero, filesystem formatting- Writes to
/dev/sda,/dev/hda
System Manipulation:
shutdown,reboot,halt,poweroffinit 0,init 6, systemctl power commands
Fork Bombs:
:(){:|:&};:and variants
Dangerous Permission Changes:
chmod 777 /,chmod -R 777 /chown -R root,chown root /
Package Manager Risks:
- Force uninstall commands across apt, yum, dnf, pacman
Other Risks:
- Kernel module manipulation
- Cron deletion (
crontab -r) - Moving system directories
Custom Denylist
You can add custom patterns via the custom_denylist parameter:
{
"command": "docker run myimage",
"custom_denylist": ["docker rm -f", "kubectl delete"]
}
Async Threshold
Commands that exceed the server async threshold (default: 50 seconds, configurable with ENHANCED_TERMINAL_ASYNC_THRESHOLD_SECS) automatically switch to background execution. This prevents:
- Long-running commands from blocking the MCP server
- Timeout issues with package installations
- Slow build processes hanging the interface
Set force_sync: true to disable this behavior for specific commands. Set force_async: true to return a job ID immediately without waiting for the threshold, which is the recommended flow before using enhanced_terminal_job_stdin.
Incremental Output
Use enhanced_terminal_job_status with incremental: true for efficient polling of long-running jobs:
- First call returns all output accumulated so far
- Subsequent calls return only new output since last check
- Read position tracked per job_id
- Reset by calling with
incremental: false
This enables streaming-like behavior without actual streaming infrastructure.
Interactive Job Input
Use enhanced_terminal_job_stdin to write to a running job's PTY stdin after it has switched to background. For commands that wait for input, start them with force_async: true so the first call returns a job ID immediately. The stdin tool writes exactly the provided input string and does not append a newline automatically.
Output Pagination
For very long outputs, use pagination mode in enhanced_terminal_job_status:
- Set
offset_bytesto starting byte position - Set
limit_bytesto number of bytes to select (0 = all remaining) - Returns
has_moreflag andtotal_length - Allows seeking into specific segments without retrieving full output
Example workflow:
// Get first 1000 bytes
{"job_id": "brave-river-1", "offset_bytes": 0, "limit_bytes": 1000}
// Get next 1000 bytes
{"job_id": "brave-river-1", "offset_bytes": 1000, "limit_bytes": 1000}
// Get all remaining
{"job_id": "brave-river-1", "offset_bytes": 2000, "limit_bytes": 0}
Job Tags and Filtering
Tag jobs when creating them for easier organization:
{
"command": "cargo test",
"tags": ["test", "ci"]
}
Filter jobs by various criteria in enhanced_terminal_job_list:
- status_filter: Match specific statuses (e.g., ["Running", "Completed"])
- tag_filter: Show only jobs with a specific tag
- cwd_filter: Show only jobs from a specific directory
- sort_order: "newest" (default) or "oldest"
All filters can be combined for powerful queries.
Architecture
This server uses a modular structure with Rust 2024 edition:
src/main.rs- Entry point and server initializationsrc/server.rs- MCP server implementation with tool handlerssrc/detection/- Binary and shell detection logicsrc/tools/- Terminal execution, job management, security denylist
Dependencies
- rmcp 0.8 - Official Rust SDK for Model Context Protocol
- tokio 1.x - Async runtime
- portable-pty 0.8 - Cross-platform PTY support for terminal emulation
- serde/serde_json 1.x - Serialization
- schemars 1.0 - JSON Schema generation for tool inputs
- anyhow 1.x - Error handling
- nix 0.29 - Unix signal handling (Unix only)
- tiktoken-rs 0.11 - GPT-5/o200k_base-compatible token counting for previews
- chrono 0.4 - UTC timestamps for call logging
- tracing/tracing-subscriber 0.1/0.3 - structured server logging
Performance
- 16 concurrent binary checks - Fast parallel tool detection (configurable)
- Smart async switching - Auto-background after 50s (configurable)
- Tokio background monitoring - Jobs continue running after smart async switching
- Incremental output capture - Poll new output with read position tracking; byte pagination is available for long logs
- No timeout by default - Set ENHANCED_TERMINAL_TIMEOUT_SECS environment variable to enable
Configuration
Default Values
- Shell:
bash - Working Directory:
.resolved from the MCP server process working directory supplied by the caller/client - Preview Tokens:
4096GPT-5/o200k_base tokens (0disables token truncation) - Async Threshold:
50seconds (ENHANCED_TERMINAL_ASYNC_THRESHOLD_SECS) - Timeout:
Noneby default (ENHANCED_TERMINAL_TIMEOUT_SECSenables a timeout) - Job IDs: readable
adjective-noun-numberhandles - Call Log: concurrent-safe JSONL at
enhanced_terminal_calls.jsonlin the repo root (ENHANCED_TERMINAL_CALL_LOG_PATHoverrides) - Max Binary Detection Concurrency:
16 - Version Probe Timeout:
1500ms
License
MIT License - see LICENSE file for details
Server Terkait
Alpha Vantage MCP Server
sponsorAccess financial market data: realtime & historical stock, ETF, options, forex, crypto, commodities, fundamentals, technical indicators, & more
GoMCP
A Go library for building clients and servers using the Model Context Protocol (MCP).
WebDev MCP
Provides a collection of useful web development tools.
graphql-to-mcp
Turn any GraphQL API into MCP tools. Auto-introspection, flat schemas.
OpenAPI to MCP Server
A server that converts OpenAPI specifications into the Model Context Protocol (MCP).
Foundry MCP Server
A lightweight MCP server for Solidity development using the Foundry toolchain (Forge, Cast, and Anvil).
Cognitive Enhancement MCP Servers
A collection of MCP servers that provide cognitive enhancement tools for large language models.
MCP_Agent:RE
Fetches requirements and defect data from the TAPD platform to provide data support for AI clients.
phantom-secrets
Stop AI coding agents from leaking your API keys. Local proxy + MCP that swaps real secrets for phm_ tokens. Works with Claude Code, Cursor, Windsurf, and Codex.
Nuntly
Send and receive transactional email through Nuntly, a developer-first email platform with EU data hosting. Tools covering emails, domains, webhooks, inboxes, and threads.
Rossum MCP & Agent
MCP server and AI agent toolkit for intelligent document processing with Rossum.