Skip to main content
Glama

execute_shell_command

Execute shell commands directly from the Serena MCP server to automate tasks, run scripts, and retrieve command output for development workflows.

Instructions

Execute a shell command and return its output. If there is a memory about suggested commands, read that first. Never execute unsafe shell commands! IMPORTANT: Do not use this tool to start

  • long-running processes (e.g. servers) that are not intended to terminate quickly,

  • processes that require user interaction. Returns a JSON object containing the command's stdout and optionally stderr output.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
commandYesThe shell command to execute.
cwdNoThe working directory to execute the command in. If None, the project root will be used.
capture_stderrNoWhether to capture and return stderr output.
max_answer_charsNoIf the output is longer than this number of characters, no content will be returned. -1 means using the default value, don't adjust unless there is no other way to get the content required for the task.

Implementation Reference

  • ExecuteShellCommandTool class providing the handler logic (apply method) for the execute_shell_command tool. Calls the shell helper, handles cwd resolution, output processing, and truncation.
    class ExecuteShellCommandTool(Tool, ToolMarkerCanEdit): """ Executes a shell command. """ def apply( self, command: str, cwd: str | None = None, capture_stderr: bool = True, max_answer_chars: int = -1, ) -> str: """ Execute a shell command and return its output. If there is a memory about suggested commands, read that first. Never execute unsafe shell commands! IMPORTANT: Do not use this tool to start * long-running processes (e.g. servers) that are not intended to terminate quickly, * processes that require user interaction. :param command: the shell command to execute :param cwd: the working directory to execute the command in. If None, the project root will be used. :param capture_stderr: whether to capture and return stderr output :param max_answer_chars: if the output is longer than this number of characters, no content will be returned. -1 means using the default value, don't adjust unless there is no other way to get the content required for the task. :return: a JSON object containing the command's stdout and optionally stderr output """ if cwd is None: _cwd = self.get_project_root() else: if os.path.isabs(cwd): _cwd = cwd else: _cwd = os.path.join(self.get_project_root(), cwd) if not os.path.isdir(_cwd): raise FileNotFoundError( f"Specified a relative working directory ({cwd}), but the resulting path is not a directory: {_cwd}" ) result = execute_shell_command(command, cwd=_cwd, capture_stderr=capture_stderr) result = result.json() return self._limit_length(result, max_answer_chars)
  • Core implementation executing the shell command using subprocess.Popen and returning a structured ShellCommandResult.
    def execute_shell_command(command: str, cwd: str | None = None, capture_stderr: bool = False) -> ShellCommandResult: """ Execute a shell command and return the output. :param command: The command to execute. :param cwd: The working directory to execute the command in. If None, the current working directory will be used. :param capture_stderr: Whether to capture the stderr output. :return: The output of the command. """ if cwd is None: cwd = os.getcwd() process = subprocess.Popen( command, shell=True, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE if capture_stderr else None, text=True, encoding="utf-8", errors="replace", cwd=cwd, **subprocess_kwargs(), ) stdout, stderr = process.communicate() return ShellCommandResult(stdout=stdout, stderr=stderr, return_code=process.returncode, cwd=cwd)
  • Pydantic model defining the structure of the shell command output, used internally by the handler and serialized to JSON.
    class ShellCommandResult(BaseModel): stdout: str return_code: int cwd: str stderr: str | None = None
  • ToolRegistry singleton that automatically discovers all Tool subclasses (including ExecuteShellCommandTool) and registers them by derived name 'execute_shell_command'.
    class ToolRegistry: def __init__(self) -> None: self._tool_dict: dict[str, RegisteredTool] = {} for cls in iter_subclasses(Tool): if not any(cls.__module__.startswith(pkg) for pkg in tool_packages): continue is_optional = issubclass(cls, ToolMarkerOptional) name = cls.get_name_from_cls() if name in self._tool_dict: raise ValueError(f"Duplicate tool name found: {name}. Tool classes must have unique names.") self._tool_dict[name] = RegisteredTool(tool_class=cls, is_optional=is_optional, tool_name=name)
  • MCP-specific registration where instances from the tool registry are converted to FastMCP tools and added to the MCP server's tool manager using the tool name 'execute_shell_command'.
    def _set_mcp_tools(self, mcp: FastMCP, openai_tool_compatible: bool = False) -> None: """Update the tools in the MCP server""" if mcp is not None: mcp._tool_manager._tools = {} for tool in self._iter_tools(): mcp_tool = self.make_mcp_tool(tool, openai_tool_compatible=openai_tool_compatible) mcp._tool_manager._tools[tool.get_name()] = mcp_tool log.info(f"Starting MCP server with {len(mcp._tool_manager._tools)} tools: {list(mcp._tool_manager._tools.keys())}")

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/oraios/serena'

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