CommandLineExecutor Server
Overview
CommandLineExecutor provides shell command execution capabilities for launching applications and running system commands.
Server Type: Action
Deployment: Local (in-process)
Agent: HostAgent, AppAgent
LLM-Selectable: ✅ Yes
Server Information
| Property | Value |
|---|---|
| Namespace | CommandLineExecutor |
| Server Name | UFO CLI MCP Server |
| Platform | Cross-platform (Windows, Linux, macOS) |
| Tool Type | action |
Tools
run_shell
Execute a shell command to launch applications or perform system operations.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
bash_command |
str |
✅ Yes | Command to execute in shell |
Returns
None - Command is launched asynchronously (5-second wait after execution)
Example
# Launch Notepad
await computer.run_actions([
MCPToolCall(
tool_key="action::run_shell",
tool_name="run_shell",
parameters={"bash_command": "notepad.exe"}
)
])
# Launch PowerPoint with a file
await computer.run_actions([
MCPToolCall(
tool_key="action::run_shell",
tool_name="run_shell",
parameters={"bash_command": "powerpnt \"Desktop\\test.pptx\""}
)
])
# Launch File Explorer
await computer.run_actions([
MCPToolCall(
tool_key="action::run_shell",
tool_name="run_shell",
parameters={"bash_command": "explorer.exe"}
)
])
Error Handling
Raises ToolError if:
- Command is empty
- Execution fails
# Error: Empty command
ToolError("Bash command cannot be empty.")
# Error: Execution failed
ToolError("Failed to launch application: {error_details}")
Implementation Details
- Commands are parsed into an argument list via
shlex.split() - Uses
subprocess.Popenwithshell=Falseto prevent shell injection - Shell metacharacters (
|,&,;,`,$(), etc.) are not interpreted - Shell built-in commands (e.g.,
start,dir,cd) are not available — only executable binaries can be launched - Waits 5 seconds after launch for application to start
- Non-blocking: Returns immediately after launch
Security Note
Commands are executed without a shell (shell=False). This means:
- Shell injection via metacharacters is not possible
- Only direct executable binaries can be invoked
- Shell built-ins (
start,dir,cd,copy, etc.) will not work - Command chaining (
&&,||,|,;) has no effect
Best Practice: Use an allow-list to restrict which executables may be launched.
Configuration
HostAgent:
default:
action:
- namespace: HostUIExecutor
type: local
- namespace: CommandLineExecutor
type: local # Enable shell execution
AppAgent:
default:
action:
- namespace: AppUIExecutor
type: local
- namespace: CommandLineExecutor
type: local # Enable if app needs to launch child processes
Best Practices
1. Validate Commands
Since run_shell executes commands with shell=False, shell injection is already mitigated. However, it is still recommended to restrict which executables can be launched:
def safe_run_shell(command: str):
"""Allow-list-based command validation"""
import shlex
allowed_commands = [
"notepad.exe", "notepad",
"calc.exe", "calc",
"mspaint.exe", "mspaint",
"code", "code.exe",
"explorer", "explorer.exe",
]
tokens = shlex.split(command)
cmd_base = tokens[0].lower()
if cmd_base not in allowed_commands:
raise ValueError(f"Command not allowed: {cmd_base}")
return MCPToolCall(
tool_key="action::run_shell",
tool_name="run_shell",
parameters={"bash_command": command}
)
# Usage
await computer.run_actions([safe_run_shell("notepad.exe test.txt")])
2. Wait for Application Launch
# Launch application
await computer.run_actions([
MCPToolCall(
tool_key="action::run_shell",
parameters={"bash_command": "notepad.exe"}
)
])
# Wait for launch (5 seconds built-in + extra)
await asyncio.sleep(2)
# Get window list
windows = await computer.run_actions([
MCPToolCall(tool_key="data_collection::get_desktop_app_info", ...)
])
# Find Notepad window
notepad_windows = [w for w in windows[0].data if "Notepad" in w["name"]]
3. Platform-Specific Commands
import platform
def get_platform_command(app_name: str) -> str:
"""Get platform-specific command"""
if platform.system() == "Windows":
commands = {
"notepad": "notepad.exe",
"terminal": "cmd.exe",
"browser": "start msedge"
}
elif platform.system() == "Darwin": # macOS
commands = {
"notepad": "open -a TextEdit",
"terminal": "open -a Terminal",
"browser": "open -a Safari"
}
else: # Linux
commands = {
"notepad": "gedit",
"terminal": "gnome-terminal",
"browser": "firefox"
}
return commands.get(app_name, app_name)
# Usage
await computer.run_actions([
MCPToolCall(
tool_key="action::run_shell",
parameters={"bash_command": get_platform_command("notepad")}
)
])
4. Handle Launch Failures
try:
result = await computer.run_actions([
MCPToolCall(
tool_key="action::run_shell",
parameters={"bash_command": "nonexistent.exe"}
)
])
if result[0].is_error:
logger.error(f"Failed to launch: {result[0].content}")
# Retry with alternative command
except Exception as e:
logger.error(f"Command execution exception: {e}")
Use Cases
1. Application Launching
# Launch text editor
await computer.run_actions([
MCPToolCall(
tool_key="action::run_shell",
parameters={"bash_command": "notepad.exe"}
)
])
# Launch browser
await computer.run_actions([
MCPToolCall(
tool_key="action::run_shell",
parameters={"bash_command": "msedge.exe https://www.example.com"}
)
])
2. Open Files with Applications
# Open a document in Word
await computer.run_actions([
MCPToolCall(
tool_key="action::run_shell",
parameters={"bash_command": "winword.exe report.docx"}
)
])
# Open a spreadsheet in Excel
await computer.run_actions([
MCPToolCall(
tool_key="action::run_shell",
parameters={"bash_command": "excel.exe data.xlsx"}
)
])
Note
Shell built-in commands like start, copy, mkdir, and dir are not available because commands run without a shell. Only direct executable binaries (.exe) can be invoked.
Limitations
- No output capture: Command output (stdout/stderr) is not returned
- No exit code: Cannot determine if command succeeded
- Async execution: No way to know when command completes
- No shell built-ins: Commands like
start,dir,copy,cdare not available (runs withshell=False) - No shell features: Piping (
|), redirection (>), chaining (&&) are not supported
Tip: For Linux systems with output capture and better control, use BashExecutor server instead.
Related Documentation
- BashExecutor - Linux command execution with output
- Action Servers - Action server concepts
- HostAgent - HostAgent architecture