Skip to main content
Glama

axom_mcp_exec

Destructive

Execute file operations and shell commands with chain-reaction support for automated workflows. Read files, write data, or run commands while maintaining security restrictions on allowed directories.

Instructions

Execute file operations and shell commands with chain-reaction support.

Operations:

  • read: Read file contents from allowed directories

  • write: Write data to files (unless AXOM_READ_ONLY=true)

  • shell: Execute shell commands (unless AXOM_READ_ONLY=true)

Chain Reactions: Chain multiple operations together using the chain parameter. Each step can reference the previous result using ${_result} variable substitution.

Example: { "operation": "read", "target": "/file.txt", "chain": [ { "tool": "axom_mcp_transform", "args": {"input": "${_result.content}", "output_format": "json"} } ] }

Security:

  • File operations restricted to allowed directories (cwd, ~/)

  • Shell/write operations enabled by default (set AXOM_READ_ONLY=true to disable)

  • Input size limits: 10MB max for files

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
operationYesOperation type
targetYesFile path or command
dataNoData to write (for write operation)
chainNoChain of subsequent operations

Implementation Reference

  • Main handler function handle_exec that routes axom_mcp_exec tool calls to appropriate operation handlers (read, write, shell) with input validation using ExecInput schema
    async def handle_exec(arguments: Dict[str, Any]) -> str:
        """Handle axom_mcp_exec tool calls.
        
        Args:
            arguments: Tool arguments containing operation and parameters
            
        Returns:
            JSON string with operation result
        """
        # Validate input
        input_data = ExecInput(**arguments)
        operation = input_data.operation
        target = input_data.target
        
        try:
            if operation == "read":
                return await _handle_read(target)
            elif operation == "write":
                return await _handle_write(target, input_data.data)
            elif operation == "shell":
                return await _handle_shell(target)
            else:
                return json.dumps({"error": f"Unknown operation: {operation}"})
        except Exception as e:
            logger.error(f"Exec operation failed: {e}")
            return json.dumps({"error": str(e)})
  • Operation-specific handler functions: _handle_read (lines 85-116), _handle_write (lines 119-150), and _handle_shell (lines 153-195) that implement file operations and shell command execution with security validations
    async def _handle_read(target: str) -> str:
        """Read file contents."""
        try:
            path = _validate_path(target)
            
            if not path.exists():
                return json.dumps({"error": f"File not found: {target}"})
            
            if not path.is_file():
                return json.dumps({"error": f"Not a file: {target}"})
            
            # Check file size
            if path.stat().st_size > MAX_FILE_SIZE:
                return json.dumps({
                    "error": f"File too large: {target} (max {MAX_FILE_SIZE} bytes)"
                })
            
            # Read file content
            content = path.read_text(encoding="utf-8", errors="replace")
            
            return json.dumps({
                "success": True,
                "operation": "read",
                "target": str(path),
                "content": content,
                "size": len(content),
            })
        except ValueError as e:
            return json.dumps({"error": str(e)})
        except Exception as e:
            logger.error(f"Failed to read file: {e}")
            return json.dumps({"error": str(e)})
    
    
    async def _handle_write(target: str, data: Optional[str]) -> str:
        """Write data to file."""
        # Check if write operations are allowed (AXOM_READ_ONLY defaults to False)
        if _env_flag_enabled("AXOM_READ_ONLY", default=False):
            return json.dumps({
                "error": "Write operations disabled. AXOM_READ_ONLY is enabled."
            })
        
        if data is None:
            return json.dumps({"error": "data is required for write operation"})
        
        try:
            path = _validate_path(target)
            
            # Create parent directories if needed
            path.parent.mkdir(parents=True, exist_ok=True)
            
            # Write file
            path.write_text(data, encoding="utf-8")
            
            return json.dumps({
                "success": True,
                "operation": "write",
                "target": str(path),
                "size": len(data),
                "message": f"Successfully wrote {len(data)} bytes to {path}",
            })
        except ValueError as e:
            return json.dumps({"error": str(e)})
        except Exception as e:
            logger.error(f"Failed to write file: {e}")
            return json.dumps({"error": str(e)})
    
    
    async def _handle_shell(command: str) -> str:
        """Execute shell command."""
        # Check if shell operations are allowed (AXOM_READ_ONLY defaults to False)
        if _env_flag_enabled("AXOM_READ_ONLY", default=False):
            return json.dumps({
                "error": "Shell operations disabled. AXOM_READ_ONLY is enabled."
            })
        
        try:
            # Execute command with timeout
            process = await asyncio.create_subprocess_shell(
                command,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
            )
            
            try:
                stdout, stderr = await asyncio.wait_for(
                    process.communicate(),
                    timeout=60.0  # 60 second timeout
                )
            except asyncio.TimeoutError:
                process.kill()
                return json.dumps({
                    "error": "Command timed out after 60 seconds",
                    "command": command,
                })
            
            # Decode output
            stdout_str = stdout.decode("utf-8", errors="replace") if stdout else ""
            stderr_str = stderr.decode("utf-8", errors="replace") if stderr else ""
            
            return json.dumps({
                "success": process.returncode == 0,
                "operation": "shell",
                "command": command,
                "exit_code": process.returncode,
                "stdout": stdout_str,
                "stderr": stderr_str,
            })
        except Exception as e:
            logger.error(f"Failed to execute shell command: {e}")
            return json.dumps({"error": str(e)})
  • ExecInput Pydantic schema defining the input validation for axom_mcp_exec tool with operation (read/write/shell), target (file path or command), data (for writes), and optional chain parameter
    class ExecInput(BaseModel):
        """Input schema for axom_mcp_exec tool."""
    
        model_config = {"extra": "forbid"}
    
        operation: str = Field(
            ...,
            pattern="^(read|write|shell)$",
            description="Operation type: read, write, or shell",
        )
        target: str = Field(
            ...,
            min_length=1,
            max_length=4096,
            description="File path for read/write, or command for shell",
        )
        data: Optional[str] = Field(
            default=None,
            max_length=10_000_000,
            description="Data to write (for write operation)",
        )
        chain: Optional[List[Dict[str, Any]]] = Field(
            default=None, max_length=10, description="Chain of subsequent operations"
        )
  • Tool registration in TOOLS list defining axom_mcp_exec with name, description, inputSchema, and annotations for MCP protocol
            name="axom_mcp_exec",
            description="""Execute file operations and shell commands with chain-reaction support.
    
    Operations:
    - read: Read file contents from allowed directories
    - write: Write data to files (unless AXOM_READ_ONLY=true)
    - shell: Execute shell commands (unless AXOM_READ_ONLY=true)
    
    Chain Reactions:
    Chain multiple operations together using the chain parameter. Each step can reference
    the previous result using ${_result} variable substitution.
    
    Example:
    {
      "operation": "read",
      "target": "/file.txt",
      "chain": [
        {
          "tool": "axom_mcp_transform",
          "args": {"input": "${_result.content}", "output_format": "json"}
        }
      ]
    }
    
    Security:
    - File operations restricted to allowed directories (cwd, ~/)
    - Shell/write operations enabled by default (set AXOM_READ_ONLY=true to disable)
    - Input size limits: 10MB max for files""",
            inputSchema={
                "type": "object",
                "properties": {
                    "operation": {
                        "type": "string",
                        "enum": ["read", "write", "shell"],
                        "description": "Operation type",
                    },
                    "target": {"type": "string", "description": "File path or command"},
                    "data": {
                        "type": "string",
                        "description": "Data to write (for write operation)",
                    },
                    "chain": {
                        "type": "array",
                        "items": {"type": "object"},
                        "description": "Chain of subsequent operations",
                    },
                },
                "required": ["operation", "target"],
            },
            annotations=TOOL_ANNOTATIONS["exec"],
        ),
  • call_tool function that routes incoming tool requests, specifically line 492-493 where axom_mcp_exec calls are forwarded to handle_exec handler
    @server.call_tool()
    async def call_tool(name: str, arguments: Dict[str, Any]) -> List[TextContent]:
        """Handle tool calls."""
        try:
            if name == "axom_mcp_memory":
                result = await handle_memory(arguments)
            elif name == "axom_mcp_exec":
                result = await handle_exec(arguments)
            elif name == "axom_mcp_analyze":
                result = await handle_analyze(arguments)
            elif name == "axom_mcp_discover":
                result = await handle_discover(arguments)
            elif name == "axom_mcp_transform":
                result = await handle_transform(arguments)
            else:
                return [TextContent(type="text", text=f"Unknown tool: {name}")]
    
            return [TextContent(type="text", text=result)]
        except Exception as e:
            logger.error(f"Tool call failed: {name} - {e}")
            return [TextContent(type="text", text=f"Error: {str(e)}")]
Behavior4/5

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

The description adds significant behavioral context beyond annotations. Annotations indicate destructiveHint=true and readOnlyHint=false, but the description elaborates with security details (allowed directories, input size limits), chain-reaction functionality with variable substitution, and specific conditions for write/shell operations. This provides valuable operational context that annotations alone don't cover.

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?

The description is well-structured with clear sections (Operations, Chain Reactions, Example, Security) and front-loads the core purpose. Most sentences add value, though the example could be slightly more concise. Overall, it efficiently communicates complex functionality without unnecessary verbosity.

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

Completeness4/5

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

For a tool with no output schema and complex functionality (multiple operations, chaining, security constraints), the description provides substantial context. It covers operation types, chaining mechanics, security restrictions, and usage conditions. The main gap is lack of information about return values or error handling, but given the annotations and detailed operational guidance, it's reasonably complete.

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?

With 100% schema description coverage, the baseline is 3. The description adds some value by explaining the 'chain' parameter's purpose and providing an example, and it clarifies that 'target' serves as either a file path or command depending on operation. However, it doesn't significantly enhance understanding of parameters beyond what the schema already documents.

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

Purpose5/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 with specific verbs and resources: 'Execute file operations and shell commands with chain-reaction support.' It explicitly lists the three operation types (read, write, shell) and distinguishes this tool from its siblings by emphasizing its execution capabilities, unlike analyze, discover, memory, or transform tools.

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

Usage Guidelines4/5

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

The description provides clear context for when to use this tool: for file operations and shell commands with chain support. It mentions that write and shell operations are disabled when AXOM_READ_ONLY=true, offering some exclusion guidance. However, it doesn't explicitly compare to sibling tools or provide detailed alternatives for specific scenarios.

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/PugzUI/axom-mcp'

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