index.ts•20.3 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { execSync } from "child_process";
import { platform } from "os";
// Detect operating system
const isWindows = platform() === 'win32';
// Create server instance
const server = new McpServer({
  name: "windows-command-line",
  version: "0.3.0",
});
// Helper function to handle command execution based on platform
function executeCommand(command: string, options: any = {}) {
  if (isWindows) {
    return execSync(command, options);
  } else {
    // Log warning for non-Windows environments
    console.error(`Warning: Running in a non-Windows environment (${platform()}). Windows commands may not work.`);
    
    // For testing purposes on non-Windows platforms
    try {
      // For Linux/MacOS, we'll strip cmd.exe and powershell.exe references
      let modifiedCmd = command;
      
      // Replace cmd.exe /c with empty string
      modifiedCmd = modifiedCmd.replace(/cmd\.exe\s+\/c\s+/i, '');
      
      // Replace powershell.exe -Command with empty string or a compatible command
      modifiedCmd = modifiedCmd.replace(/powershell\.exe\s+-Command\s+("|')/i, '');
      
      // Remove trailing quotes if we removed powershell -Command
      if (modifiedCmd !== command) {
        modifiedCmd = modifiedCmd.replace(/("|')$/, '');
      }
      
      console.error(`Attempting to execute modified command: ${modifiedCmd}`);
      return execSync(modifiedCmd, options);
    } catch (error) {
      console.error(`Error executing modified command: ${error}`);
      return Buffer.from(`This tool requires a Windows environment. Current platform: ${platform()}`);
    }
  }
}
// Register the list_running_processes tool
server.tool(
  "list_running_processes",
  "List all running processes on the system. Can be filtered by providing an optional filter string that will match against process names.",
  {
    filter: z.string().optional().describe("Optional filter string to match against process names"),
  },
  async ({ filter }) => {
    try {
      let cmd;
      
      if (isWindows) {
        cmd = "powershell.exe -Command \"Get-Process";
        
        if (filter) {
          // Add filter if provided
          cmd += ` | Where-Object { $_.ProcessName -like '*${filter}*' }`;
        }
        
        cmd += " | Select-Object Id, ProcessName, CPU, WorkingSet, Description | Format-Table -AutoSize | Out-String\"";
      } else {
        // Fallback for Unix systems
        cmd = "ps aux";
        
        if (filter) {
          cmd += ` | grep -i ${filter}`;
        }
      }
      
      const stdout = executeCommand(cmd);
      
      return {
        content: [
          {
            type: "text",
            text: stdout.toString(),
          },
        ],
      };
    } catch (error) {
      return {
        isError: true,
        content: [
          {
            type: "text",
            text: `Error listing processes: ${error}`,
          },
        ],
      };
    }
  }
);
// Register the get_system_info tool
server.tool(
  "get_system_info",
  "Retrieve system information including OS, hardware, and user details. Can provide basic or full details.",
  {
    detail: z.enum(["basic", "full"]).default("basic").describe("Level of detail"),
  },
  async ({ detail }) => {
    try {
      let cmd;
      
      if (isWindows) {
        cmd = "powershell.exe -Command \"";
        
        if (detail === "basic") {
          cmd += "$OS = Get-CimInstance Win32_OperatingSystem; " +
                "$CS = Get-CimInstance Win32_ComputerSystem; " +
                "$Processor = Get-CimInstance Win32_Processor; " +
                "Write-Output 'OS: ' $OS.Caption $OS.Version; " +
                "Write-Output 'Computer: ' $CS.Manufacturer $CS.Model; " +
                "Write-Output 'CPU: ' $Processor.Name; " +
                "Write-Output 'Memory: ' [math]::Round($OS.TotalVisibleMemorySize/1MB, 2) 'GB'";
        } else {
          cmd += "$OS = Get-CimInstance Win32_OperatingSystem; " +
                "$CS = Get-CimInstance Win32_ComputerSystem; " +
                "$Processor = Get-CimInstance Win32_Processor; " +
                "$Disk = Get-CimInstance Win32_LogicalDisk -Filter 'DriveType=3'; " +
                "$Network = Get-CimInstance Win32_NetworkAdapterConfiguration | Where-Object {$_.IPAddress -ne $null}; " +
                "Write-Output '=== OPERATING SYSTEM ==='; " +
                "Write-Output ('OS: ' + $OS.Caption + ' ' + $OS.Version); " +
                "Write-Output ('Architecture: ' + $OS.OSArchitecture); " +
                "Write-Output ('Install Date: ' + $OS.InstallDate); " +
                "Write-Output ('Last Boot: ' + $OS.LastBootUpTime); " +
                "Write-Output (''; '=== HARDWARE ==='); " +
                "Write-Output ('Manufacturer: ' + $CS.Manufacturer); " +
                "Write-Output ('Model: ' + $CS.Model); " +
                "Write-Output ('Serial Number: ' + (Get-CimInstance Win32_BIOS).SerialNumber); " +
                "Write-Output ('Processor: ' + $Processor.Name); " +
                "Write-Output ('Cores: ' + $Processor.NumberOfCores); " +
                "Write-Output ('Logical Processors: ' + $Processor.NumberOfLogicalProcessors); " +
                "Write-Output ('Memory: ' + [math]::Round($OS.TotalVisibleMemorySize/1MB, 2) + ' GB'); " +
                "Write-Output (''; '=== STORAGE ==='); " +
                "foreach($drive in $Disk) { " +
                "Write-Output ('Drive ' + $drive.DeviceID + ' - ' + [math]::Round($drive.Size/1GB, 2) + ' GB (Free: ' + [math]::Round($drive.FreeSpace/1GB, 2) + ' GB)') " +
                "}; " +
                "Write-Output (''; '=== NETWORK ==='); " +
                "foreach($adapter in $Network) { " +
                "Write-Output ('Adapter: ' + $adapter.Description); " +
                "Write-Output ('  IP Address: ' + ($adapter.IPAddress[0])); " +
                "Write-Output ('  MAC Address: ' + $adapter.MACAddress); " +
                "Write-Output ('  Gateway: ' + ($adapter.DefaultIPGateway -join ', ')); " +
                "}";
        }
        
        cmd += "\"";
      } else {
        // Fallback for Unix systems
        if (detail === "basic") {
          cmd = "uname -a && lscpu | grep 'Model name' && free -h | head -n 2";
        } else {
          cmd = "uname -a && lscpu && free -h && df -h && ip addr";
        }
      }
      
      const stdout = executeCommand(cmd);
      
      return {
        content: [
          {
            type: "text",
            text: stdout.toString(),
          },
        ],
      };
    } catch (error) {
      return {
        isError: true,
        content: [
          {
            type: "text",
            text: `Error retrieving system info: ${error}`,
          },
        ],
      };
    }
  }
);
// Register the get_network_info tool
server.tool(
  "get_network_info",
  "Retrieve network configuration information including IP addresses, adapters, and DNS settings. Can be filtered to a specific interface.",
  {
    networkInterface: z.string().optional().describe("Optional interface name to filter results"),
  },
  async ({ networkInterface }) => {
    try {
      let cmd;
      
      if (isWindows) {
        cmd = "powershell.exe -Command \"";
        
        if (networkInterface) {
          cmd += "$adapters = Get-NetAdapter | Where-Object { $_.Name -like '*" + networkInterface + "*' }; ";
        } else {
          cmd += "$adapters = Get-NetAdapter; ";
        }
        
        cmd += "foreach($adapter in $adapters) { " +
              "Write-Output ('======== ' + $adapter.Name + ' (' + $adapter.Status + ') ========'); " +
              "Write-Output ('Interface Description: ' + $adapter.InterfaceDescription); " +
              "Write-Output ('MAC Address: ' + $adapter.MacAddress); " +
              "Write-Output ('Link Speed: ' + $adapter.LinkSpeed); " +
              "$ipconfig = Get-NetIPConfiguration -InterfaceIndex $adapter.ifIndex; " +
              "Write-Output ('IP Address: ' + ($ipconfig.IPv4Address.IPAddress -join ', ')); " +
              "Write-Output ('Subnet: ' + ($ipconfig.IPv4Address.PrefixLength -join ', ')); " +
              "Write-Output ('Gateway: ' + ($ipconfig.IPv4DefaultGateway.NextHop -join ', ')); " +
              "Write-Output ('DNS Servers: ' + ($ipconfig.DNSServer.ServerAddresses -join ', ')); " +
              "Write-Output ''; " +
              "}\"";
      } else {
        // Fallback for Unix systems
        if (networkInterface) {
          cmd = `ip addr show ${networkInterface}`;
        } else {
          cmd = "ip addr";
        }
      }
      
      const stdout = executeCommand(cmd);
      
      return {
        content: [
          {
            type: "text",
            text: stdout.toString(),
          },
        ],
      };
    } catch (error) {
      return {
        isError: true,
        content: [
          {
            type: "text",
            text: `Error retrieving network info: ${error}`,
          },
        ],
      };
    }
  }
);
// Register the get_scheduled_tasks tool
server.tool(
  "get_scheduled_tasks",
  "Retrieve information about scheduled tasks on the system. Can query all tasks or get detailed status of a specific task.",
  {
    action: z.enum(["query", "status"]).default("query").describe("Action to perform"),
    taskName: z.string().optional().describe("Name of the specific task (optional)"),
  },
  async ({ action, taskName }) => {
    if (!isWindows) {
      return {
        content: [
          {
            type: "text",
            text: "The scheduled tasks tool is only available on Windows. Current platform: " + platform(),
          },
        ],
      };
    }
    
    try {
      let cmd = "powershell.exe -Command \"";
      
      if (action === "query") {
        if (taskName) {
          cmd += "Get-ScheduledTask -TaskName '" + taskName + "' | Format-List TaskName, State, Description, Author, LastRunTime, NextRunTime, LastTaskResult";
        } else {
          cmd += "Get-ScheduledTask | Select-Object TaskName, State, Description | Format-Table -AutoSize | Out-String";
        }
      } else if (action === "status" && taskName) {
        cmd += "Get-ScheduledTask -TaskName '" + taskName + "' | Format-List *; " +
              "Get-ScheduledTaskInfo -TaskName '" + taskName + "' | Format-List *";
      } else {
        return {
          isError: true,
          content: [
            {
              type: "text",
              text: "For 'status' action, taskName parameter is required",
            },
          ],
        };
      }
      
      cmd += "\"";
      
      const stdout = executeCommand(cmd);
      
      return {
        content: [
          {
            type: "text",
            text: stdout.toString(),
          },
        ],
      };
    } catch (error) {
      return {
        isError: true,
        content: [
          {
            type: "text",
            text: `Error retrieving scheduled tasks: ${error}`,
          },
        ],
      };
    }
  }
);
// Register the get_service_info tool
server.tool(
  "get_service_info",
  "Retrieve information about Windows services. Can query all services or get detailed status of a specific service.",
  {
    action: z.enum(["query", "status"]).default("query").describe("Action to perform"),
    serviceName: z.string().optional().describe("Service name to get info about (optional)"),
  },
  async ({ action, serviceName }) => {
    if (!isWindows) {
      return {
        content: [
          {
            type: "text",
            text: "The service info tool is only available on Windows. Current platform: " + platform(),
          },
        ],
      };
    }
    
    try {
      let cmd = "powershell.exe -Command \"";
      
      if (action === "query") {
        if (serviceName) {
          cmd += "Get-Service -Name '" + serviceName + "' | Format-List Name, DisplayName, Status, StartType, Description";
        } else {
          cmd += "Get-Service | Select-Object Name, DisplayName, Status, StartType | Format-Table -AutoSize | Out-String";
        }
      } else if (action === "status" && serviceName) {
        cmd += "Get-Service -Name '" + serviceName + "' | Format-List *; " +
              "Get-CimInstance -ClassName Win32_Service -Filter \"Name='" + serviceName + "'\" | Format-List *";
      } else {
        return {
          isError: true,
          content: [
            {
              type: "text",
              text: "For 'status' action, serviceName parameter is required",
            },
          ],
        };
      }
      
      cmd += "\"";
      
      const stdout = executeCommand(cmd);
      
      return {
        content: [
          {
            type: "text",
            text: stdout.toString(),
          },
        ],
      };
    } catch (error) {
      return {
        isError: true,
        content: [
          {
            type: "text",
            text: `Error retrieving service info: ${error}`,
          },
        ],
      };
    }
  }
);
// Register the list_allowed_commands tool
server.tool(
  "list_allowed_commands",
  "List all commands that are allowed to be executed by this server. This helps understand what operations are permitted.",
  {},
  async () => {
    try {
      if (isWindows) {
        return {
          content: [
            {
              type: "text",
              text: "The following commands are allowed to be executed by this server:\n\n" +
                    "- powershell.exe: Used for most system operations\n" +
                    "- cmd.exe: Used for simple command execution\n\n" +
                    "Note: All commands are executed with the same privileges as the user running this server."
            },
          ],
        };
      } else {
        return {
          content: [
            {
              type: "text",
              text: "Running on non-Windows platform: " + platform() + "\n\n" +
                    "Standard Unix/Linux commands are available, but Windows-specific commands like powershell.exe and cmd.exe are not available in this environment.\n\n" +
                    "The following commands should work:\n" +
                    "- ls: List directory contents\n" +
                    "- ps: List processes\n" +
                    "- uname: Print system information\n" +
                    "- ip: Show network information\n\n" +
                    "Note: All commands are executed with the same privileges as the user running this server."
            },
          ],
        };
      }
    } catch (error) {
      return {
        isError: true,
        content: [
          {
            type: "text",
            text: `Error listing allowed commands: ${error}`,
          },
        ],
      };
    }
  }
);
// Register the execute_command tool
server.tool(
  "execute_command",
  "Execute a Windows command and return its output. Only commands in the allowed list can be executed. This tool should be used for running simple commands like 'dir', 'echo', etc.",
  {
    command: z.string().describe("The command to execute"),
    workingDir: z.string().optional().describe("Working directory for the command"),
    timeout: z.number().default(30000).describe("Timeout in milliseconds"),
  },
  async ({ command, workingDir, timeout }) => {
    try {
      // Security check: Ensure only allowed commands are executed
      const commandLower = command.toLowerCase();
      
      // Block potentially dangerous commands
      const dangerousPatterns = [
        'net user', 'net localgroup', 'netsh', 'format', 'rd /s', 'rmdir /s', 
        'del /f', 'reg delete', 'shutdown', 'taskkill', 'sc delete', 'bcdedit',
        'cacls', 'icacls', 'takeown', 'diskpart', 'cipher /w', 'schtasks /create',
        'rm -rf', 'sudo', 'chmod', 'chown', 'passwd', 'mkfs', 'dd'
      ];
      
      // Check for dangerous patterns
      if (dangerousPatterns.some(pattern => commandLower.includes(pattern.toLowerCase()))) {
        return {
          isError: true,
          content: [
            {
              type: "text",
              text: "Command contains potentially dangerous operations and cannot be executed.",
            },
          ],
        };
      }
      
      const options: any = { timeout };
      if (workingDir) {
        options.cwd = workingDir;
      }
      
      let cmdToExecute;
      if (isWindows) {
        cmdToExecute = `cmd.exe /c ${command}`;
      } else {
        // For non-Windows, try to execute the command directly
        cmdToExecute = command;
      }
      
      const stdout = executeCommand(cmdToExecute, options);
      return {
        content: [
          {
            type: "text",
            text: stdout.toString() || 'Command executed successfully (no output)',
          },
        ],
      };
    } catch (error) {
      return {
        isError: true,
        content: [
          {
            type: "text",
            text: `Error executing command: ${error}`,
          },
        ],
      };
    }
  }
);
// Register the execute_powershell tool
server.tool(
  "execute_powershell",
  "Execute a PowerShell script and return its output. This allows for more complex operations and script execution. PowerShell must be in the allowed commands list.",
  {
    script: z.string().describe("PowerShell script to execute"),
    workingDir: z.string().optional().describe("Working directory for the script"),
    timeout: z.number().default(30000).describe("Timeout in milliseconds"),
  },
  async ({ script, workingDir, timeout }) => {
    if (!isWindows) {
      return {
        content: [
          {
            type: "text",
            text: "The PowerShell execution tool is only available on Windows. Current platform: " + platform(),
          },
        ],
      };
    }
    
    try {
      // Security check: Ensure no dangerous operations
      const scriptLower = script.toLowerCase();
      
      // Block potentially dangerous commands
      const dangerousPatterns = [
        'new-user', 'add-user', 'remove-item -recurse -force', 'format-volume', 
        'reset-computer', 'stop-computer', 'restart-computer', 'stop-process -force',
        'remove-item -force', 'set-executionpolicy', 'invoke-webrequest',
        'start-bitstransfer', 'set-location', 'invoke-expression', 'iex', '& {',
        'invoke-command', 'new-psdrive', 'remove-psdrive', 'enable-psremoting',
        'new-service', 'remove-service', 'set-service'
      ];
      
      // Check for dangerous patterns
      if (dangerousPatterns.some(pattern => scriptLower.includes(pattern.toLowerCase()))) {
        return {
          isError: true,
          content: [
            {
              type: "text",
              text: "Script contains potentially dangerous operations and cannot be executed.",
            },
          ],
        };
      }
      
      const options: any = { timeout };
      if (workingDir) {
        options.cwd = workingDir;
      }
      
      const stdout = executeCommand(`powershell.exe -Command "${script}"`, options);
      return {
        content: [
          {
            type: "text",
            text: stdout.toString() || 'PowerShell script executed successfully (no output)',
          },
        ],
      };
    } catch (error) {
      return {
        isError: true,
        content: [
          {
            type: "text",
            text: `Error executing PowerShell script: ${error}`,
          },
        ],
      };
    }
  }
);
// Start the server
async function main() {
  // Log platform information on startup
  console.error(`Starting Windows Command Line MCP Server on platform: ${platform()}`);
  
  if (!isWindows) {
    console.error("Warning: This server is designed for Windows environments. Some features may not work on " + platform());
  }
  
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Windows Command Line MCP Server running on stdio");
}
main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});