How Desktop Commander MCP Configuration Persistence Works and Where config.json Is Stored

Desktop Commander MCP stores user settings in config.json inside the platform-specific user data directory, managed by the ConfigManager class in src/config-manager.ts which handles automatic loading, merging with defaults, and saving.

The Desktop Commander MCP application provides a robust configuration persistence system that ensures user preferences survive across application restarts and updates. According to the wonderwhy-er/DesktopCommanderMCP source code, this system centers on a single JSON file (config.json) and a dedicated manager class that abstracts all read and write operations.

Where config.json Is Stored on Each Platform

The configuration file location varies by operating system. The getConfigPath() helper in src/config-manager.ts resolves this path using Electron's app.getPath('userData') (or os.homedir() when running outside Electron).

Platform Full Path to config.json
Windows %APPDATA%\DesktopCommanderMCP\config.json
macOS $HOME/Library/Application Support/DesktopCommanderMCP/config.json
Linux $HOME/.config/DesktopCommanderMCP/config.json

This directory choice follows platform conventions: %APPDATA% on Windows, Application Support on macOS, and .config on Linux. The file persists across application updates because it lives outside the application bundle.

How ConfigManager Handles Persistence

The ConfigManager class in src/config-manager.ts implements the complete persistence lifecycle. It never exposes raw file operations; instead, it provides typed getters/setters and emits events when values change.

Initialization and Loading

When instantiated, ConfigManager immediately loads existing settings or creates config.json with defaults:

// src/config-manager.ts – core loading logic
import { app } from 'electron';
import * as fs from 'fs';
import * as path from 'path';
import { defaultConfig } from './config-field-definitions';

const CONFIG_PATH = path.join(app.getPath('userData'), 'config.json');

export class ConfigManager {
  private config = { ...defaultConfig };

  constructor() {
    this.loadConfig();
  }

  private loadConfig() {
    if (fs.existsSync(CONFIG_PATH)) {
      const raw = fs.readFileSync(CONFIG_PATH, 'utf-8');
      this.config = { ...defaultConfig, ...JSON.parse(raw) };
    } else {
      this.saveConfig(); // creates file with defaults on first run
    }
  }
}

Key behaviors during initialization:

  • Default merging: Missing fields in the existing file are filled from src/config-field-definitions.ts, ensuring forward compatibility when new settings are added.
  • Automatic creation: If config.json does not exist, it is created immediately with all default values.

Saving Configuration Changes

The saveConfig() method handles serialization and write operations:

// src/config-manager.ts – persistence method
public saveConfig() {
  const data = JSON.stringify(this.config, null, 2);
  fs.writeFileSync(CONFIG_PATH, data, 'utf-8');
  this.emit('config-updated', this.config);
}

This method:

  1. Formats JSON with 2-space indentation for human readability
  2. Performs a synchronous write to ensure durability before returning
  3. Emits config-updated so other modules can react to changes immediately

Configuration Data Model

The configuration structure is defined in two files that work together:

File Purpose
src/config.ts TypeScript interface Config describing all available settings
src/config-field-definitions.ts Runtime default values and field metadata

This separation allows the ConfigManager to validate loaded data against the interface while using concrete default values for missing fields.

How the UI Triggers Persistence

The Config Editor component in src/ui/config-editor/ provides the user-facing interface. When users modify settings, the UI updates the ConfigManager instance and explicitly calls saveConfig():

// src/ui/config-editor/src/app.ts – UI integration
import { ConfigManager } from '../../../../../config-manager';

const mgr = new ConfigManager();

function onToggleCaffeinate(enabled: boolean) {
  mgr.config.caffeinateWhenInactive = enabled;
  mgr.saveConfig(); // immediate persistence
}

The synchronous saveConfig() call ensures that users can quit the application immediately after changing settings without data loss.

Reading Configuration in Other Modules

Tools and features access configuration through the same ConfigManager class:

// src/tools/usage.ts – example consumer
import { ConfigManager } from '../config-manager';

export function isFeatureEnabled(flag: keyof Config) {
  const mgr = new ConfigManager();
  return Boolean(mgr.config[flag]);
}

Modules like src/terminal-manager.ts also read terminal-specific settings (font size, shell path) from this central source.

Summary

  • config.json lives in the platform-specific user data directory (%APPDATA%, ~/Library/Application Support/, or ~/.config/)
  • ConfigManager in src/config-manager.ts provides the exclusive API for all configuration operations
  • Default merging ensures backward and forward compatibility when the schema evolves
  • Synchronous file I/O guarantees immediate persistence; the config-updated event enables reactive UI updates
  • Human-readable JSON with 2-space indentation allows manual editing when needed

Frequently Asked Questions

How do I manually edit Desktop Commander MCP configuration?

Close the application, then open config.json in your platform's user data directory using any text editor. Modify values as needed—the configuration will be validated and merged with defaults on next launch. Invalid JSON will be replaced with default values.

Will my settings persist when updating Desktop Commander MCP?

Yes. Because config.json resides in the user data directory outside the application bundle, it survives updates, reinstalls, and application version changes. Only deleting the user data directory will remove your settings.

What happens if I delete config.json?

The application will regenerate config.json with all default values from src/config-field-definitions.ts on the next start. No error is thrown; the ConfigManager treats missing files as a first-run scenario.

Can multiple Desktop Commander MCP instances share configuration?

On the same user account, yes—all instances read from and write to the same CONFIG_PATH. Simultaneous modifications from different processes could cause race conditions, though typical single-user usage avoids this. fs.writeFileSync provides atomic writes at the system call level for individual save operations.

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 →