How Shell Selection Works in Desktop Commander MCP: defaultShell Configuration Guide

Desktop Commander MCP determines which shell to use by first detecting a platform-specific default in src/utils/system-info.ts (PowerShell for Windows, Zsh for macOS, Bash for Linux), then allowing users to override this value via the defaultShell configuration field defined in src/config-field-definitions.ts and applied at runtime in src/terminal-manager.ts and src/tools/improved-process-tools.ts.

The Desktop Commander MCP server provides cross-platform command execution through the Model Context Protocol (MCP), requiring robust shell selection to handle Windows, macOS, and Linux environments gracefully. Understanding how defaultShell is configured and resolved ensures your commands execute in the correct interpreter, whether you rely on system defaults or require a specific shell like PowerShell Core or a custom Bash installation.

Platform-Based Shell Detection in system-info.ts

When the application initializes, it detects the operating system and sets an appropriate default shell before any user configuration is loaded.

How the Operating System Determines the Default

In src/utils/system-info.ts, the application gathers OS information and assigns platform-specific defaults:

  • Windows: powershell.exe
  • macOS: zsh
  • Linux and Unix-like systems: bash

This detected value is stored in SystemInfo.defaultShell and surfaced in the system guidance string displayed to users. If no custom configuration exists, this platform-derived value serves as the fallback for all command executions.

import { getSystemInfo } from './utils/system-info';

const sysInfo = await getSystemInfo();
console.log('Platform default shell:', sysInfo.defaultShell); 
// Outputs: "powershell.exe" on Windows, "zsh" on macOS, "bash" on Linux

Configuring defaultShell in Desktop Commander

Users can permanently override the platform default by setting the defaultShell field in the application configuration.

The Configuration Schema

The configurable field is declared in src/config-field-definitions.ts, allowing the application to recognize and validate user-specified shell paths. When set, this value takes precedence over the system detection logic.

UI Selection in the Settings Panel

The configuration interface in src/ui/config-editor/src/app.ts (lines 562-566) provides a dropdown selection of common shells combined with a custom text input:

// From config-editor/src/app.ts - UI component rendering
<select class="setting-inline-select" data-action="shell-select">
  <option value="powershell.exe">powershell.exe</option>
  <option value="pwsh.exe">PowerShell Core</option>
  <option value="cmd.exe">cmd.exe</option>
  <option value="bash">bash</option>
  <option value="zsh">zsh</option>
</select>
<input class="setting-shell-custom" 
       type="text" 
       placeholder="Custom shell path (e.g., /usr/local/bin/fish)" />

When a user selects a value or enters a custom path, the application writes it to the configuration store via src/config-manager.ts.

Applying Shell Selection at Runtime

When executing commands, Desktop Commander MCP resolves the final shell by checking for user configuration first, then falling back to the platform default.

Terminal Manager Implementation

In src/terminal-manager.ts (line 183), the terminal session initialization uses a nullish coalescing pattern to select the appropriate shell:

import { config } from './config-manager';
import { getSystemInfo } from './utils/system-info';

// Runtime shell resolution
const sysInfo = await getSystemInfo();
const shellToUse = config.defaultShell || sysInfo.defaultShell;

// Used to spawn the terminal process
const terminal = spawn(shellToUse, [], { /* options */ });

This ensures that a user-configured defaultShell in config/defaultShell always overrides the automatic OS detection.

Process Tools Integration

The improved process tools in src/tools/improved-process-tools.ts (lines 157-158) implement the same resolution logic when spawning non-interactive command processes:

import { spawn } from 'child_process';
import { config } from '../config-manager.js';
import { getSystemInfo } from '../utils/system-info.js';

async function executeCommand(command: string) {
  const systemInfo = await getSystemInfo();
  
  // Consistent with terminal-manager.ts logic
  const shell = config.defaultShell ?? systemInfo.defaultShell;
  
  const child = spawn(shell, ['-c', command], { 
    stdio: ['pipe', 'pipe', 'pipe'] 
  });
  
  return child;
}

This dual implementation ensures consistency whether the user is opening an interactive terminal session or running background commands through the MCP tools.

Summary

Frequently Asked Questions

What is the default shell on Windows in Desktop Commander?

On Windows systems, Desktop Commander MCP defaults to powershell.exe as detected in src/utils/system-info.ts. This provides modern PowerShell capabilities without requiring additional configuration, though users can override this with cmd.exe, pwsh.exe (PowerShell Core), or any other shell executable through the defaultShell setting.

How do I set a custom shell path in Desktop Commander MCP?

You can specify a custom shell by setting the defaultShell configuration value to the absolute path of your shell executable, such as /opt/homebrew/bin/fish or C:\Program Files\Git\bin\bash.exe. This can be done through the Settings UI in the configuration editor (using the custom text input field) or by directly editing the configuration file stored by src/config-manager.ts.

Where does Desktop Commander store the defaultShell configuration?

The defaultShell value is defined in the configuration schema at src/config-field-definitions.ts and persisted through src/config-manager.ts. The configuration is typically stored in the application's settings directory and loaded at runtime, making it available to both src/terminal-manager.ts and src/tools/improved-process-tools.ts when resolving shell paths.

Does Desktop Commander fall back to system defaults if defaultShell is not set?

Yes. If the defaultShell configuration field is null or undefined, the application falls back to the platform-specific default detected in src/utils/system-info.ts. This fallback is implemented via the logical OR operator (||) in src/terminal-manager.ts (line 183) and the nullish coalescing operator (??) in src/tools/improved-process-tools.ts (lines 157-158), ensuring a valid shell is always available even without explicit user configuration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →