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.jsondoes 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:
- Formats JSON with 2-space indentation for human readability
- Performs a synchronous write to ensure durability before returning
- Emits
config-updatedso 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.jsonlives in the platform-specific user data directory (%APPDATA%,~/Library/Application Support/, or~/.config/)ConfigManagerinsrc/config-manager.tsprovides 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-updatedevent 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →