exec-mcp

Yakwilik/exec-mcp

3.1

If you are the rightful owner of exec-mcp and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.

The Model Context Protocol (MCP) server is designed to manage the execution and termination of processes in a structured and efficient manner.

Exec MCP Server

A Model Context Protocol (MCP) server that provides tools for executing and managing processes. This server allows agents to execute processes and stop them by PID, making process management easier than using terminal commands.

Features

  • exec_process: Execute a process and return its PID for later management (background execution)
  • run_command: Execute a command and return its output immediately (synchronous execution)
  • stop_process: Stop a process by its PID using SIGTERM or SIGKILL
  • Non-blocking: Background processes run detached and don't block the MCP server
  • Concurrent: Multiple processes can be managed simultaneously

Installation

Using go install (Recommended)

go install github.com/Yakwilik/exec-mcp/cmd/exec-mcp@latest

This will install the exec-mcp binary to $GOPATH/bin or $HOME/go/bin (make sure it's in your PATH).

Building from source

git clone https://github.com/Yakwilik/exec-mcp.git
cd exec-mcp
go build -o exec-mcp ./cmd/exec-mcp

Testing

Run the comprehensive test suite:

# Run all tests
go test ./... -v

# Run specific tool tests
go test ./internal/tools/exec/ -v
go test ./internal/tools/run/ -v
go test ./internal/tools/stop/ -v

# Run integration tests
go test ./internal/mcp/ -v

Usage

The server uses stdio transport for communication:

./exec-mcp

Connecting to MCP Clients

This MCP server can be connected to any MCP-compatible client, such as:

  • Claude Desktop (Anthropic)
  • Cursor (with MCP support)
  • Other MCP-compatible agents
For Claude Desktop

Add the server to your Claude Desktop configuration file:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json Linux: ~/.config/Claude/claude_desktop_config.json

If installed via go install, use:

{
  "mcpServers": {
    "exec-mcp": {
      "command": "exec-mcp",
      "args": []
    }
  }
}

Or if built manually, use the full path:

{
  "mcpServers": {
    "exec-mcp": {
      "command": "/absolute/path/to/exec-mcp",
      "args": []
    }
  }
}

Note: Make sure exec-mcp is in your PATH if using the first option, or use the full path to the binary.

For Cursor

If Cursor supports MCP servers, add similar configuration in Cursor's settings.

Testing the Connection

After connecting, the client should be able to use these tools:

  • exec_process - Start background processes
  • run_command - Execute commands synchronously
  • stop_process - Stop processes by PID

Tools

exec_process

Execute a process and return its PID.

Parameters:

  • command (string, required): The command to execute
  • args (array of strings, optional): Command line arguments
  • dir (string, optional): Working directory for the process
  • env (array of strings, optional): Environment variables (format: KEY=VALUE)

Example:

{
  "command": "ls",
  "args": ["-l", "/tmp"],
  "dir": "/home/user"
}

Response:

{
  "content": [
    {
      "type": "text",
      "text": "Process started successfully:\n{\n  \"pid\": 12345,\n  \"command\": \"ls\",\n  \"args\": [\"-l\", \"/tmp\"],\n  \"start_time\": \"2024-01-01T12:00:00Z\",\n  \"status\": \"running\"\n}"
    }
  ],
  "structuredContent": {
    "pid": 12345,
    "command": "ls",
    "args": ["-l", "/tmp"],
    "start_time": "2024-01-01T12:00:00Z",
    "status": "running"
  }
}

Note: The structuredContent field contains the structured data that can be directly accessed without parsing JSON text.

run_command

Execute a command and return its output immediately (synchronous execution).

Parameters:

  • command (string, required): The command to execute
  • args (array of strings, optional): Command line arguments
  • dir (string, optional): Working directory for the process
  • env (array of strings, optional): Environment variables (format: KEY=VALUE)
  • timeout (integer, optional): Timeout in seconds (0 means no timeout)

Example:

{
  "command": "ls",
  "args": ["-l", "/tmp"],
  "dir": "/home/user",
  "timeout": 10
}

Response:

{
  "content": [
    {
      "type": "text",
      "text": "Command executed:\n{\n  \"command\": \"ls\",\n  \"args\": [\"-l\", \"/tmp\"],\n  \"exit_code\": 0,\n  \"stdout\": \"total 0\\n-rw-r--r-- 1 user user 0 Jan 1 12:00 file.txt\",\n  \"stderr\": \"\",\n  \"executed_at\": \"2024-01-01T12:00:00Z\",\n  \"duration_seconds\": 0.05,\n  \"success\": true\n}"
    }
  ],
  "structuredContent": {
    "command": "ls",
    "args": ["-l", "/tmp"],
    "exit_code": 0,
    "stdout": "total 0\n-rw-r--r-- 1 user user 0 Jan 1 12:00 file.txt",
    "stderr": "",
    "executed_at": "2024-01-01T12:00:00Z",
    "duration_seconds": 0.05,
    "success": true
  }
}

Note: This tool waits for the command to complete and returns the full output. Use exec_process for background execution.

stop_process

Stop a process by its PID using SIGTERM or SIGKILL.

Parameters:

  • pid (integer, required): The process ID to stop
  • kill (boolean, optional): If true, use SIGKILL instead of SIGTERM (force kill)

Example:

{
  "pid": 12345,
  "kill": false
}

Response:

{
  "content": [
    {
      "type": "text",
      "text": "Signal SIGTERM sent to process 12345"
    }
  ],
  "structuredContent": {
    "pid": 12345,
    "signal": "SIGTERM",
    "status": "signal_sent"
  }
}

Using Structured Data

The MCP server returns both human-readable text and structured JSON data. For programmatic access, use the structuredContent field:

// Example: Extract PID from exec_process response
result, err := clientSession.CallTool(ctx, execParams)
if err != nil {
    log.Fatal(err)
}

// Access structured data directly
if processInfoMap, ok := result.StructuredContent.(map[string]interface{}); ok {
    if pidFloat, exists := processInfoMap["pid"]; exists {
        if pid, ok := pidFloat.(float64); ok {
            processID := int(pid)
            // Use processID for stop_process
        }
    }
}

Architecture

The project is organized into separate packages for maintainability:

  • ./cmd/exec-mcp/main.go: Main entry point
  • ./internal/mcp/server.go: MCP server setup and configuration
  • ./internal/tools/tool.go: Tool interface definition
  • ./internal/tools/exec/: Process execution tool (background, struct-based)
  • ./internal/tools/run/: Command execution tool (synchronous, struct-based)
  • ./internal/tools/stop/: Process termination tool (struct-based)
  • ./internal/mcp/test_helpers.go: Helper functions for extracting structured data

Tool Architecture

Each tool is implemented as a struct that implements the Tool interface:

type Tool interface {
    Name() string
    Description() string
    Handle(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, any, error)
}

This approach provides:

  • No hardcoded tool names: Names are retrieved from tool structs
  • Self-documenting: Each tool provides its own name and description
  • Type safety: Interface ensures consistent tool implementation
  • Easy testing: Tools can be tested independently

Benefits

This MCP server enables agents to:

  • Execute processes and get their PIDs for precise management (background execution)
  • Execute commands and get immediate output (synchronous execution)
  • Stop processes without needing to search for them using terminal commands
  • Manage multiple processes concurrently with their exact process IDs
  • Use proper signal handling (SIGTERM/SIGKILL) for clean process termination
  • Run processes in detached mode without blocking the MCP server
  • Get command output, exit codes, and execution time for synchronous commands

Without this MCP, agents typically need to use terminal commands like ps, grep, and kill to find and manage processes, which is less reliable and more complex.