Skip to main content
Glama
GongRzhe

Terminal Controller for MCP

execute_command

Executes terminal commands and returns output. Supports setting a timeout in seconds to control execution duration.

Instructions

Execute terminal command and return results

Args:
    command: Command line command to execute
    timeout: Command timeout in seconds, default is 30 seconds

Returns:
    Output of the command execution

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
commandYes
timeoutNo

Implementation Reference

  • The MCP tool handler for 'execute_command' — decorated with @mcp.tool(), it takes a command string and optional timeout, checks for dangerous commands, delegates execution to run_command(), and formats the result.
    @mcp.tool()
    async def execute_command(command: str, timeout: int = 30) -> str:
        """
        Execute terminal command and return results
        
        Args:
            command: Command line command to execute
            timeout: Command timeout in seconds, default is 30 seconds
        
        Returns:
            Output of the command execution
        """
        # Check for dangerous commands (can add more security checks)
        dangerous_commands = ["rm -rf /", "mkfs"]
        if any(dc in command.lower() for dc in dangerous_commands):
            return "For security reasons, this command is not allowed."
        
        result = await run_command(command, timeout)
        
        if result["success"]:
            output = f"Command executed successfully (duration: {result['duration']})\n\n"
            
            if result["stdout"]:
                output += f"Output:\n{result['stdout']}\n"
            else:
                output += "Command had no output.\n"
                
            if result["stderr"]:
                output += f"\nWarnings/Info:\n{result['stderr']}"
                
            return output
        else:
            output = f"Command execution failed (duration: {result['duration']})\n"
            
            if result["stdout"]:
                output += f"\nOutput:\n{result['stdout']}\n"
                
            if result["stderr"]:
                output += f"\nError:\n{result['stderr']}"
                
            output += f"\nReturn code: {result['return_code']}"
            return output
  • Helper function 'run_command' that asynchronously executes a shell command via subprocess, handling timeouts, error handling, and recording command history.
    async def run_command(cmd: str, timeout: int = 30) -> Dict:
        """
        Execute command and return results
        
        Args:
            cmd: Command to execute
            timeout: Command timeout in seconds
            
        Returns:
            Dictionary containing command execution results
        """
        start_time = datetime.now()
        
        try:
            # Create command appropriate for current OS
            if platform.system() == "Windows":
                process = await asyncio.create_subprocess_shell(
                    cmd,
                    stdout=asyncio.subprocess.PIPE,
                    stderr=asyncio.subprocess.PIPE,
                    shell=True
                )
            else:
                process = await asyncio.create_subprocess_shell(
                    cmd,
                    stdout=asyncio.subprocess.PIPE,
                    stderr=asyncio.subprocess.PIPE,
                    shell=True,
                    executable="/bin/bash"
                )
            
            try:
                stdout, stderr = await asyncio.wait_for(process.communicate(), timeout)
                stdout = stdout.decode('utf-8', errors='replace')
                stderr = stderr.decode('utf-8', errors='replace')
                return_code = process.returncode
            except asyncio.TimeoutError:
                try:
                    process.kill()
                except:
                    pass
                return {
                    "success": False,
                    "stdout": "",
                    "stderr": f"Command timed out after {timeout} seconds",
                    "return_code": -1,
                    "duration": str(datetime.now() - start_time),
                    "command": cmd
                }
        
            duration = datetime.now() - start_time
            result = {
                "success": return_code == 0,
                "stdout": stdout,
                "stderr": stderr,
                "return_code": return_code,
                "duration": str(duration),
                "command": cmd
            }
            
            # Add to history
            command_history.append({
                "timestamp": datetime.now().isoformat(),
                "command": cmd,
                "success": return_code == 0
            })
            
            # If history is too long, remove oldest record
            if len(command_history) > MAX_HISTORY_SIZE:
                command_history.pop(0)
                
            return result
        
        except Exception as e:
            return {
                "success": False,
                "stdout": "",
                "stderr": f"Error executing command: {str(e)}",
                "return_code": -1,
                "duration": str(datetime.now() - start_time),
                "command": cmd
            }
  • Registration via FastMCP — the MCP server is initialized and tools are registered using the @mcp.tool() decorator.
    from mcp.server.fastmcp import FastMCP
    
    # Initialize MCP server
    mcp = FastMCP("terminal-controller", log_level="INFO")
    
    # List to store command history
    command_history = []
    
    # Maximum history size
    MAX_HISTORY_SIZE = 50
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description bears full burden for behavioral disclosure. It mentions returning output but omits critical traits like execution directory, security restrictions, error handling, or whether multi-line commands are supported. This leaves significant ambiguity.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Description is extremely concise with two sentences for the summary and structured Args/Returns. No redundant information, and the purpose is front-loaded. It earns its length efficiently.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool lacking annotations and output schema, the description omits important context: safety warnings, return format details, error behavior, and interaction with the workspace. This inadequately equips an agent to use it reliably.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% (no parameter descriptions in schema). The description compensates by adding 'Command line command to execute' for command and 'Command timeout in seconds, default is 30 seconds' for timeout. These provide basic meaning beyond name and type but are not detailed, e.g., no format or constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states it executes a terminal command and returns results. The verb 'execute' and resource 'terminal command' are specific, distinguishing it from file operations like read_file or change_directory. However, it lacks clarity on scope or safety limitations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use vs. alternatives. The description does not mention precautions, such as for destructive commands or when to prefer other tools like list_directory. This omission leaves the agent without context to choose appropriately.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/GongRzhe/terminal-controller-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server