Skip to main content
Glama
mkusaka
by mkusaka

shell_exec

Execute shell commands with detailed error handling and output capture, optionally specifying a working directory, to safely manage tasks on the host system.

Instructions

Executes commands in the specified shell with detailed error handling and output capture

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
commandYesThe shell command to execute in the configured shell environment
workingDirNoOptional working directory to execute the command in (must be under $HOME for security)

Implementation Reference

  • Executes the provided shell command using the configured shell and zx library. Validates working directory security, handles stdout/stderr output, logs activity, and returns structured content with error status.
      async ({ command, workingDir: cmdWorkingDir }) => {
        try {
          logger.info(`Executing command: ${command}`);
    
          // Use command-specific working directory or fall back to global setting
          const execWorkingDir = cmdWorkingDir || workingDir;
    
          if (execWorkingDir && !isUnderHome(execWorkingDir)) {
            logger.error(
              `Working directory must be under $HOME: ${execWorkingDir}`,
            );
            return {
              content: [
                {
                  type: "text",
                  text: `Error: Working directory must be under $HOME: ${execWorkingDir}`,
                },
              ],
              isError: true,
            };
          }
    
          try {
            // Execute command using zx
            // Pass the command to the shell with -c option
            if (execWorkingDir) {
              $.cwd = execWorkingDir;
            }
            const result = await $`${shell} -c ${command}`;
    
            if (result.stderr) {
              logger.info(`Command warning: ${result.stderr}`);
            }
    
            // Return successful execution result
            return {
              content: [
                {
                  type: "text",
                  text:
                    result.stdout ||
                    "(Command executed successfully but produced no output)",
                },
              ],
            };
          } catch (execError) {
            // Command execution error (non-zero exit code)
            const error = execError as ProcessOutput;
            logger.error(
              `Command execution error: ${error.stderr || error.message}`,
            );
            return {
              content: [
                {
                  type: "text",
                  text: error.stderr || error.stdout || error.message,
                },
              ],
              isError: true,
            };
          }
        } catch (error) {
          // Other error handling
          logger.error("Unexpected error:", error);
          return {
            content: [
              {
                type: "text",
                text: `Error: ${error instanceof Error ? error.message : String(error)}`,
              },
            ],
            isError: true,
          };
        }
      },
    );
  • Zod schema defining the input parameters for shell_exec: required 'command' string and conditional 'workingDir' string (optional if global workingDir set).
    {
      command: z
        .string()
        .min(1)
        .describe(
          "The shell command to execute in the configured shell environment",
        ),
      workingDir: workingDir
        ? z
            .string()
            .optional()
            .describe(
              "Optional working directory to execute the command in (must be under $HOME for security)",
            )
        : z
            .string()
            .describe(
              "Working directory to execute the command in (must be under $HOME for security)",
            ),
    },
  • Registers the 'shell_exec' tool on the MCP server, providing name, description, input schema using Zod, and the execution handler function.
    server.tool(
      "shell_exec",
      "Executes commands in the specified shell with detailed error handling and output capture",
      {
        command: z
          .string()
          .min(1)
          .describe(
            "The shell command to execute in the configured shell environment",
          ),
        workingDir: workingDir
          ? z
              .string()
              .optional()
              .describe(
                "Optional working directory to execute the command in (must be under $HOME for security)",
              )
          : z
              .string()
              .describe(
                "Working directory to execute the command in (must be under $HOME for security)",
              ),
      },
      async ({ command, workingDir: cmdWorkingDir }) => {
        try {
          logger.info(`Executing command: ${command}`);
    
          // Use command-specific working directory or fall back to global setting
          const execWorkingDir = cmdWorkingDir || workingDir;
    
          if (execWorkingDir && !isUnderHome(execWorkingDir)) {
            logger.error(
              `Working directory must be under $HOME: ${execWorkingDir}`,
            );
            return {
              content: [
                {
                  type: "text",
                  text: `Error: Working directory must be under $HOME: ${execWorkingDir}`,
                },
              ],
              isError: true,
            };
          }
    
          try {
            // Execute command using zx
            // Pass the command to the shell with -c option
            if (execWorkingDir) {
              $.cwd = execWorkingDir;
            }
            const result = await $`${shell} -c ${command}`;
    
            if (result.stderr) {
              logger.info(`Command warning: ${result.stderr}`);
            }
    
            // Return successful execution result
            return {
              content: [
                {
                  type: "text",
                  text:
                    result.stdout ||
                    "(Command executed successfully but produced no output)",
                },
              ],
            };
          } catch (execError) {
            // Command execution error (non-zero exit code)
            const error = execError as ProcessOutput;
            logger.error(
              `Command execution error: ${error.stderr || error.message}`,
            );
            return {
              content: [
                {
                  type: "text",
                  text: error.stderr || error.stdout || error.message,
                },
              ],
              isError: true,
            };
          }
        } catch (error) {
          // Other error handling
          logger.error("Unexpected error:", error);
          return {
            content: [
              {
                type: "text",
                text: `Error: ${error instanceof Error ? error.message : String(error)}`,
              },
            ],
            isError: true,
          };
        }
      },
    );
  • Utility function to verify if a given directory path is safely under the user's home directory, used for security in shell_exec working directory validation.
    export const isUnderHome = (dirPath: string): boolean => {
      const homePath = os.homedir();
    
      const absoluteDirPath = path.resolve(dirPath);
      const absoluteHomePath = path.resolve(homePath);
    
      const relativePath = path.relative(absoluteHomePath, absoluteDirPath);
    
      return !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
    };
  • Determines the shell to use for command execution, prioritizing env SHELL, CLI --shell option, or OS default (/bin/bash or cmd.exe). Exported as default and used in shell_exec.
    const getShell = (): string => {
      if (process.env.SHELL) {
        return process.env.SHELL;
      }
    
      const shellProgram = new Command();
      shellProgram
        .name("mcp-shell")
        .description("MCP Shell Server - A server for executing shell commands")
        .version("0.1.0")
        .option("-s, --shell <shell>", "Specify the path to the shell to use");
    
      shellProgram.parse(process.argv);
    
      const options = shellProgram.opts();
    
      if (options.shell) {
        return options.shell;
      }
    
      // Set default shell based on OS
      return os.platform() === "win32" ? "cmd.exe" : "/bin/bash";
    };
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions 'detailed error handling and output capture' which adds some context beyond basic execution, but fails to address critical aspects like security implications, permission requirements, rate limits, or what happens when commands fail. For a shell execution tool with zero annotation coverage, this leaves significant gaps.

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

Conciseness5/5

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

The description is a single, efficient sentence that front-loads the core purpose ('Executes commands in the specified shell') and adds value with secondary capabilities ('with detailed error handling and output capture'). Every word earns its place with zero waste.

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?

Given the complexity of shell execution (security risks, variable outputs) and the absence of both annotations and an output schema, the description is insufficient. It doesn't explain return values, error formats, or security constraints beyond the schema's workingDir note. For a potentially dangerous tool with no structured safety indicators, more descriptive context is needed.

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 description coverage is 100%, so the schema already documents both parameters thoroughly. The description adds no additional parameter semantics beyond what's in the schema (e.g., no examples of command syntax, working directory constraints beyond security). The baseline score of 3 reflects adequate schema coverage without description enhancement.

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?

The description clearly states the tool's purpose: 'Executes commands in the specified shell' with additional capabilities for 'detailed error handling and output capture'. It uses specific verbs ('executes', 'capture') and identifies the resource ('shell commands'). However, there are no sibling tools mentioned, so differentiation from alternatives cannot be evaluated.

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?

The description provides no guidance on when to use this tool versus alternatives, prerequisites, or security considerations. It mentions 'detailed error handling and output capture' which implies some context, but offers no explicit when/when-not instructions or named alternatives.

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

Related 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/mkusaka/mcp-shell-server'

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