# How the Desktop Commander MCP Feature Flag System Enables and Disables Experimental Functionality

> Learn how Desktop Commander MCPs feature flag system enables or disables experimental features dynamically. Discover its remote JSON fetching and local caching for efficient control.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: internals
- Published: 2026-07-24

---

**Desktop Commander MCP uses a singleton FeatureFlagManager that fetches remote JSON configuration, caches it locally for 30 minutes, and exposes a `get()` method to enable or disable experimental functionality at runtime.**

Desktop Commander MCP implements a lightweight yet robust feature flag system to control experimental functionality without redeploying the application. According to the source code in `wonderwhy-er/DesktopCommanderMCP`, this system uses a singleton manager pattern that loads cached flags immediately on startup while refreshing configuration asynchronously from a remote endpoint. This architecture ensures the UI remains responsive while allowing maintainers to toggle features globally or target specific user segments.

## Core Architecture and Initialization

### Singleton Manager Pattern

The feature flag system centers on [`src/utils/feature-flags.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/feature-flags.ts), which exports a single `featureFlagManager` instance imported wherever a component needs to evaluate experimental functionality. This singleton maintains an in-memory cache and coordinates all network operations and disk persistence.

The manager defaults to fetching configuration from `https://desktopcommander.app/flags/v2/production.json`, but operators can override this by setting the `DC_FLAG_URL` environment variable to point to staging or development endpoints.

### Startup Initialization Flow

During application bootstrap in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts), the system initializes the manager via `await featureFlagManager.initialize();`. The `initialize()` method first invokes `loadFromCache()` to restore previously saved values from [`feature-flags.json`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/feature-flags.json) in the config directory, ensuring immediate availability of last-known states. It then triggers `fetchFlags()` in the background to retrieve fresh configuration without blocking the startup sequence.

## Caching Strategy and Refresh Mechanisms

### Local Cache and TTL

Fetched flags persist locally as [`feature-flags.json`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/feature-flags.json). According to lines 61-66 in [`src/utils/feature-flags.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/feature-flags.ts), the system enforces a **30-minute** cache validity period (`cacheMaxAge`), after which the manager automatically refreshes data from the remote source.

### Manual Refresh

Developers and administrators can force an immediate update by calling `await featureFlagManager.refresh()`, which re-executes the network fetch and updates the local cache. This is particularly useful in testing scenarios or when debugging feature rollouts.

## Runtime Flag Evaluation

### Synchronous Flag Checks

Components query flag states using `featureFlagManager.get(name, defaultValue)`, which returns the cached boolean or object if present, otherwise the supplied default (typically `false`). This synchronous API prevents UI blocking while providing immediate answers for feature gates.

Example usage for a new UI panel:

```typescript
import { featureFlagManager } from './utils/feature-flags.js';

if (featureFlagManager.get('new_panel_enabled', false)) {
  showNewPanel();
}

```

### Asynchronous Fresh Flag Waiting

Experiments requiring the latest remote data before rendering can await `featureFlagManager.waitForFreshFlags()`. According to lines 120-134 in [`src/utils/feature-flags.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/feature-flags.ts), this method returns a Promise that resolves when the background fetch completes, or after a **5-second** safety timeout to prevent startup hangs.

Example for A/B testing:

```typescript
await featureFlagManager.waitForFreshFlags();
const experiment = featureFlagManager.get('experiments', {});
const variant = experiment.myFeature?.variant;
if (variant === 'beta') {
  enableBetaFeature();
}

```

## Production Usage Examples

The feature flag system governs several experimental subsystems throughout the codebase.

### Welcome Page Onboarding

The onboarding controller in [`src/utils/welcome-onboarding.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/welcome-onboarding.ts) checks `welcome_page_enabled` and `welcome_page_excluded_clients` (lines 20-69) to determine whether to display the welcome UI.

### A/B Testing Framework

The testing module in [`src/utils/ab-test.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/ab-test.ts) reads the `experiments` flag object (lines 2-5) to assign variants to users.

### Telemetry and Survey Controls

[`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts) queries `user_surveys` (lines 224-225) to enable or suppress telemetry prompts, and checks `onboarding_injection` (lines 434-435) to decide whether to insert onboarding hints into tool results.

## Summary

- The **FeatureFlagManager** singleton in [`src/utils/feature-flags.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/feature-flags.ts) provides centralized flag management with a simple `get()` interface.
- Configuration fetches from [`desktopcommander.app/flags/v2/production.json`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/desktopcommander.app/flags/v2/production.json) (or via `DC_FLAG_URL` override) with **30-minute** automatic cache refreshing.
- Flags load from local cache immediately on startup via `initialize()`, then refresh asynchronously to keep the UI responsive.
- Use `get(name, default)` for synchronous checks and `waitForFreshFlags()` for experiments requiring the freshest remote data.
- Manual refresh available via `refresh()` for testing or administrative overrides.

## Frequently Asked Questions

### How does the feature flag system handle offline scenarios?

Desktop Commander MCP stores the last successfully fetched configuration in [`feature-flags.json`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/feature-flags.json) within the local config directory. During initialization, `loadFromCache()` restores these values immediately, ensuring experimental features retain their last known states even when the remote endpoint is unreachable. The system attempts background refreshes automatically when connectivity returns.

### Can I use a custom feature flag endpoint instead of the production URL?

Yes. Set the `DC_FLAG_URL` environment variable to point to your own JSON endpoint before starting the application. The `fetchFlags()` method in [`src/utils/feature-flags.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/feature-flags.ts) prioritizes this variable over the default `https://desktopcommander.app/flags/v2/production.json`, allowing seamless testing of experimental flag sets in staging environments.

### What happens if the remote flag server is slow or unresponsive?

The `waitForFreshFlags()` method includes a **5-second** safety timeout that prevents startup hangs if the remote server fails to respond. Synchronous `get()` calls always return the cached value or the provided default immediately, ensuring the application remains functional regardless of network latency or server outages.

### How do I implement a new experimental feature flag in the codebase?

First, add your flag to the remote JSON configuration served at the endpoint. Then import the singleton in your module: `import { featureFlagManager } from './utils/feature-flags.js'`. Use `featureFlagManager.get('your_flag_name', false)` to branch logic safely, defaulting to `false` to keep the feature disabled until explicitly enabled in the remote configuration.