Design Patterns Used in Desktop Commander MCP: Architectural Deep Dive

Desktop Commander MCP implements six core design patterns—Singleton, Factory, Facade, Pub/Sub, Strategy, and Template Method—to manage global state, handle diverse file types, abstract complex network operations, and enable flexible runtime behaviors.

The Desktop Commander MCP repository demonstrates sophisticated software architecture through strategic design pattern implementation. These patterns provide the foundation for reliable command execution, configuration management, and remote device communication while keeping the codebase modular and testable.

Singleton Pattern: Global State Management

The Singleton pattern ensures that exactly one instance exists for critical managers throughout the application lifecycle. This prevents duplicated state and race conditions when handling commands and configuration.

In src/config-manager.ts, the ConfigManager class uses a private constructor and static instance accessor:

// src/config-manager.ts
class ConfigManager {
  private static _instance: ConfigManager | null = null;

  private constructor() { /* ... */ }
  
  static get instance() {
    return ConfigManager._instance ??= new ConfigManager();
  }
}

export const configManager = ConfigManager.instance;

Similarly, src/command-manager.ts exports commandManager as a singleton instance, ensuring that command parsing state remains consistent across the application. Access these instances directly without instantiation:

import { configManager } from './config-manager.js';
await configManager.setValue('telemetryEnabled', false);

Factory Pattern: Dynamic File Handler Creation

The Factory pattern in src/utils/files/factory.ts encapsulates the logic for selecting appropriate file handlers based on content type or extension. This allows the rest of the codebase to work with a generic FileHandler interface without knowing concrete implementation details.

The getFileHandler function evaluates file characteristics and returns the correct handler:

// src/utils/files/factory.ts
export async function getFileHandler(filePath: string): Promise<FileHandler> {
  if (getDocxHandler().canHandle(filePath)) return getDocxHandler();
  if (getPdfHandler().canHandle(filePath))  return getPdfHandler();
  // ... additional handlers
  return getTextHandler(); // default fallback
}

Client code remains decoupled from specific handler implementations:

import { getFileHandler } from './utils/files/factory.js';
const handler = await getFileHandler('report.pdf');
await handler.read(); // Executes PDF-specific logic transparently

Facade Pattern: Simplifying Remote Communication

The Facade pattern appears in src/remote-device/remote-channel.ts, where the RemoteChannel class presents a simplified API that hides the complexity of Supabase realtime channels, reconnection back-off, heartbeat handling, and NUL-byte sanitization.

The class exposes straightforward methods while managing intricate internals:

// src/remote-device/remote-channel.ts
export class RemoteChannel {
  initialize(url: string, key: string) { /* ... */ }
  async setSession(session: AuthSession) { /* ... */ }
  async registerDevice(capabilities, deviceId, deviceName, onToolCall) { /* ... */ }
  async notifyResult(callId: string) { /* ... */ }
  // Reconnection logic and heartbeat management remain hidden
}

This abstraction allows high-level usage without worrying about network layer details:

import { RemoteChannel } from './remote-device/remote-channel.js';

const channel = new RemoteChannel();
channel.initialize('https://supabase.example', 'public-anon-key');
await channel.setSession({ access_token: token, refresh_token: refresh });
await channel.registerDevice({audio: true}, 'dev-123', 'my-laptop', payload => {
  // Process incoming tool calls
});

Pub/Sub Pattern: Decoupled Event Communication

The Publish-Subscribe pattern enables loose coupling between components through asynchronous event broadcasting. The implementation leverages Supabase Realtime in RemoteChannel and a lightweight event tracker in src/ui/shared/ui-event-tracker.ts.

The createUiEventTracker function returns a closure that publishes events without blocking the UI flow:

// src/ui/shared/ui-event-tracker.ts
export function createUiEventTracker(callTool, { component, baseParams }) {
  return (event, params = {}) => {
    void callTool('track_ui_event', {
      event,
      component,
      params: { ...baseParams, ...normalizeUiEventParams(params) },
    });
  };
}

Usage demonstrates the decoupled nature:

const track = createUiEventTracker(toolCall, { component: 'file-preview' });
track('open', { fileType: 'pdf' });

Strategy Pattern: Runtime Behavior Selection

The Strategy pattern allows the system to swap algorithms at runtime without modifying caller code. This appears in two key areas within Desktop Commander MCP.

First, ConfigManager selects between immediate and background persistence strategies:

// src/config-manager.ts
private async saveConfig() { /* immediate write */ }

scheduleSave() { // background, coalesced write
  if (!this.saveScheduled) {
    this.saveScheduled = true;
    this.writeChain = this.writeChain.then(this.writeConfigToDisk);
  }
}

Second, RemoteChannel chooses different heartbeat intervals based on device capabilities, selecting between CAPABLE_HEARTBEAT_INTERVAL and LEGACY_HEARTBEAT_INTERVAL according to capability flags detected during registration.

Template Method Pattern: Command Parsing Skeleton

The Template Method pattern in src/command-manager.ts defines the skeleton of the command extraction algorithm while allowing specific steps to be customized. The extractCommands method establishes the overall parsing flow, with extractBaseCommand serving as a customizable hook:

// Conceptual structure from src/command-manager.ts
class CommandManager {
  extractCommands(input: string): Command[] {
    const base = this.extractBaseCommand(input);
    // Additional parsing steps...
    return this.processCommands(base);
  }
  
  protected extractBaseCommand(input: string): string {
    // Default implementation, overridable by subclasses
  }
}

This structure ensures consistent command parsing across the application while permitting specialized behavior for different command types.

Summary

  • Singleton patterns in src/config-manager.ts and src/command-manager.ts provide global access points for configuration and command parsing while preventing duplicate instances.
  • Factory pattern in src/utils/files/factory.ts abstracts file handler selection, enabling support for diverse file types through a unified interface.
  • Facade pattern in src/remote-device/remote-channel.ts simplifies complex Supabase realtime operations into manageable method calls.
  • Pub/Sub patterns enable asynchronous communication between UI components and remote devices without tight coupling.
  • Strategy patterns allow runtime selection between synchronous and asynchronous configuration persistence, as well as adaptive heartbeat intervals.
  • Template Method pattern structures command parsing algorithms with customizable steps for extensibility.

Frequently Asked Questions

What is the purpose of the Factory pattern in Desktop Commander MCP?

The Factory pattern centralizes file type detection and handler instantiation in src/utils/files/factory.ts. This eliminates scattered conditional logic throughout the codebase, ensuring that adding support for new file formats requires changes only within the factory and the new handler implementation.

How does the Singleton pattern improve reliability in this codebase?

By enforcing single instances of ConfigManager and CommandManager, the Singleton pattern prevents race conditions when multiple parts of the application simultaneously read or write configuration values. It also ensures consistent command parsing state across the entire MCP server lifecycle.

Why does RemoteChannel implement both Facade and Pub/Sub patterns?

The RemoteChannel class combines these patterns to address different architectural concerns. As a Facade, it shields callers from the complexity of Supabase realtime connections, reconnection logic, and heartbeat management. As a Pub/Sub consumer, it enables asynchronous receipt of tool calls from remote devices without blocking the main execution thread.

Where can I find examples of the Strategy pattern for configuration persistence?

The Strategy pattern for configuration persistence resides in src/config-manager.ts. Examine the saveConfig method for immediate writes and scheduleSave method for background writes to understand how the system selects between synchronous and asynchronous persistence strategies based on performance requirements.

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 →