Skip to main content
Glama
zouyingcao

AgentSkills MCP

by zouyingcao

run_shell_command

Execute shell commands within specific skill directories to run scripts and manage processes directly from the AgentSkills MCP server.

Instructions

run shell command in a subprocess. Here you need to fill in skill_name. This skill_name parameter allows you to navigate directly to the folder corresponding to skill_name, making it more convenient to use the scripts within that folder to execute commands. If you want to know the exact path, you can use pwd to get the absolute path.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
skill_nameYesskill name
commandYesshell command

Implementation Reference

  • Implements the core execution logic for the 'run_shell_command' tool: parses input, optionally installs Python dependencies using pipreqs, executes the command in the skill's directory via subprocess, captures and combines stdout/stderr as output.
    async def async_execute(self):
        """Execute the shell command operation.
    
        Executes a shell command in the specified skill's directory. For Python
        commands, the method attempts to automatically detect and install
        dependencies using pipreqs before executing the command.
    
        The method:
        1. Extracts skill_name and command from input_dict
        2. Looks up the skill directory from skill_metadata_dict
        3. For Python commands (containing "py"), checks if pipreqs is available
        4. If pipreqs is available, generates requirements.txt and installs dependencies
        5. Constructs the full command as `cd {skill_dir} && {command}`
        6. Executes the command in a subprocess with the current environment
        7. Captures stdout and stderr output
        8. Returns the combined output (stdout + stderr)
    
        Returns:
            None: The result is set via `self.set_output()` with the combined
                stdout and stderr output from the command execution. The output
                is decoded as UTF-8 and formatted as: "{stdout}\n{stderr}"
    
        Raises:
            KeyError: If skill_name is not found in skill_metadata_dict.
                This should be handled by ensuring LoadSkillMetadataOp is
                called before RunShellCommandOp.
    
        Note:
            - Dependency auto-installation only occurs for commands containing "py"
              and when the auto_install_deps parameter is enabled
            - If pipreqs is not available, a warning is logged but execution continues
            - If dependency installation fails, a warning is logged but the command
              is still executed
            - The command runs in the skill's directory, allowing access to
              skill-specific files and resources
            - Environment variables from the current process are passed to the subprocess
        """
        # Extract skill name and command from input parameters
        skill_name = self.input_dict["skill_name"]
        command: str = self.input_dict["command"]
        # Look up the skill directory from the metadata dictionary
        # This dictionary should be populated by LoadSkillMetadataOp
        # skill_dir = Path(self.context.skill_metadata_dict[skill_name]["skill_dir"])
        skill_dir = Path(C.service_config.metadata["skill_dir"])
        logger.info(f"🔧 run shell command: skill_name={skill_name} skill_dir={skill_dir} command={command}")
    
        # Auto-install dependencies for Python scripts if pipreqs is available
        # This helps ensure that Python scripts have their required dependencies
        # Only install if auto_install_deps parameter is enabled
        if self.auto_install_deps:
            if "py" in command:
                pipreqs_available = shutil.which("pipreqs") is not None
                if pipreqs_available:
                    install_cmd = f"cd {skill_dir}/{skill_name} && pipreqs . --force && pip install -r requirements.txt"
                    proc = await asyncio.create_subprocess_shell(
                        install_cmd,
                        stdout=asyncio.subprocess.PIPE,
                        stderr=asyncio.subprocess.PIPE,
                    )
                    stdout, stderr = await proc.communicate()
                    if proc.returncode != 0:
                        logger.warning(f"⚠️ Failed to install dependencies:\n{stdout.decode()}\n{stderr.decode()}")
                    else:
                        logger.info(f"✅ Dependencies installed successfully.\n{stdout.decode()}\n{stderr.decode()}")
                else:
                    logger.info("❗️ pipreqs not found, skipping dependency auto-install.")
    
        # Construct the full command to execute in the skill directory
        # This ensures the command runs in the correct context
        full_command = f"cd {skill_dir}/{skill_name} && {command}"
        proc = await asyncio.create_subprocess_shell(
            full_command,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
            env=os.environ.copy(),
        )
    
        # Wait for the command to complete and capture output
        stdout, stderr = await proc.communicate()
        # Combine stdout and stderr output, decoded as UTF-8
        output = stdout.decode().strip() + "\n" + stderr.decode().strip()
        logger.info(f"✅ Command executed: skill_name={skill_name} output={output}")
        self.set_output(output)
  • Defines the ToolCall schema for the 'run_shell_command' tool, including name, description, and required input parameters 'skill_name' (string) and 'command' (string).
    return ToolCall(
        **{
            "name": "run_shell_command",
            "description": self.get_prompt("tool_desc"),
            "input_schema": {
                "skill_name": {
                    "type": "string",
                    "description": "skill name",
                    "required": True,
                },
                "command": {
                    "type": "string",
                    "description": "shell command",
                    "required": True,
                },
            },
        },
    )
  • Registers the RunShellCommandOp class as an operation using the @C.register_op() decorator from FlowLLM, which exposes it as the 'run_shell_command' tool in the MCP server.
    @C.register_op()
    class RunShellCommandOp(BaseAsyncToolOp):
  • Imports RunShellCommandOp into the tools package __init__.py, making it available for use in the broader application.
    from .run_shell_command_op import RunShellCommandOp
Behavior2/5

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

No annotations are provided, so the description carries the full burden. It mentions running commands in a subprocess and navigating folders, but fails to disclose critical behavioral traits such as security implications, error handling, output format, or execution environment. This leaves significant gaps for a tool that executes shell commands.

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

Conciseness3/5

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

The description is moderately concise but includes redundant advice (e.g., using 'pwd' to get the path) that may not be necessary. It is front-loaded with the main purpose, but the structure could be improved by eliminating less critical details to focus on core functionality.

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 executing shell commands, no annotations, and no output schema, the description is incomplete. It lacks information on safety, permissions, error responses, and how results are returned, which are essential for proper tool usage in this context.

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. The description adds some context for 'skill_name' (navigating to a folder) but does not provide additional meaning beyond the schema, such as examples or constraints. This meets the baseline for high schema coverage.

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

Purpose3/5

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

The description states the tool 'run shell command in a subprocess,' which provides a clear verb+resource (run + shell command). However, it does not differentiate from sibling tools like 'load_skill' or 'read_reference_file,' leaving the specific role ambiguous. The purpose is clear but lacks sibling distinction.

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 mentions that 'skill_name' allows navigation to a folder for convenience, but it does not provide explicit guidance on when to use this tool versus alternatives. No context on prerequisites, exclusions, or comparisons to sibling tools is given, offering minimal usage direction.

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/zouyingcao/agentskills-mcp'

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