How the Remote Feature Flag System Works in Desktop Commander MCP and How to Disable It
Desktop Commander MCP implements a cached remote feature flag system that fetches flag payloads via WebSocket or HTTP long-polling through src/remote-device/remote-channel.ts, stores them in feature-flags.json, and gates functionality via FeatureFlagManager.isEnabled(); you can disable remote fetching entirely by setting the environment variable DC_DISABLE_REMOTE_FLAGS=1 or deleting the local cache file.
Desktop Commander MCP uses a lightweight remote feature flag system that enables dynamic toggling of experimental features without redeploying the application binary. The architecture centers on the FeatureFlagManager class defined in src/utils/feature-flags.ts, which maintains an in-memory flag set synchronized with a remote service while providing a local file cache for offline resilience. Understanding this mechanism is essential for developers operating in air-gapped environments or requiring deterministic feature states.
Architecture of the Remote Feature Flag System
The feature flag architecture consists of three primary components that coordinate to provide synchronous flag evaluation after initial startup.
Core Components
FeatureFlagManager(src/utils/feature-flags.ts): The central singleton that holds the latest flag payload in memory. It exposesisEnabled(name)for synchronous checks,waitForFreshFlags()for async initialization, andupdateFlags(payload)for ingesting remote updates. It persists state to a local JSON file.- Remote Channel (
src/remote-device/remote-channel.ts): Manages the network connection to the feature flag service using WebSocket or HTTP long-polling. It requests the flag payload on application startup and periodically refreshes it, invokingfeatureFlagManager.updateFlags()when new data arrives. - Cache File (
feature-flags.json): Located in the user configuration directory (typically~/.config/desktop-commander-mcp/), this file stores the last known flag set to enable instant cold starts and serves as a fallback when remote services are unreachable.
Data Flow
- Initialization: On startup,
FeatureFlagManagerinstantiates and attempts to loadfeature-flags.jsonfrom the user config directory. - Remote Fetch:
remote-channel.tsestablishes a connection to the central service and requests the current flag payload, including application version metadata. - Update: When the server responds, the channel calls
featureFlagManager.updateFlags(), which updates the in-memory map and overwrites the local cache file. - Evaluation: Application code throughout the codebase calls
featureFlagManager.isEnabled('flag-name')to gate features, onboarding steps, or UI components without blocking the main thread.
All flag checks remain synchronous after the initial load, ensuring zero UI-blocking network calls. If the remote fetch fails due to timeout, network error, or server unavailability, the system falls back to the cached feature-flags.json or a static default-deny set defined in the class constructor.
Evaluating Feature Flags at Runtime
The system prioritizes performance and reliability through synchronous evaluation and robust fallback mechanisms.
Synchronous Flag Checks
Once initialized, feature flag evaluation requires no asynchronous operations. The isEnabled() method performs a simple lookup in the in-memory map:
import { featureFlagManager } from './utils/feature-flags';
if (featureFlagManager.isEnabled('welcome-page')) {
// Render experimental welcome UI
}
This pattern appears throughout the codebase, including in src/utils/welcome-onboarding.ts and the A/B test wrapper (src/utils/ab-test.ts), which delegates to featureFlagManager.isEnabled() under the hood.
Fallback and Default-Deny Behavior
When featureFlagManager cannot retrieve fresh flags and finds no valid cache file, it initializes with an empty flag set {}. Per the implementation in src/utils/feature-flags.ts, the isEnabled() method treats missing flags as disabled (default-deny), ensuring that network failures cannot accidentally enable unstable features.
How to Disable the Remote Feature Flag System
To run Desktop Commander MCP without remote flag evaluation, use one of the following non-destructive configuration methods.
Disable via Environment Variable
Set DC_DISABLE_REMOTE_FLAGS=1 before launching the application. The remote-channel.ts module checks this variable early in its initialization and skips the WebSocket connection entirely:
// In src/remote-device/remote-channel.ts
if (process.env.DC_DISABLE_REMOTE_FLAGS === '1') {
console.log('Remote feature-flag fetching is disabled by env var.');
return;
}
// WebSocket connection logic follows...
Apply this setting in your shell or a .env file at the repository root:
export DC_DISABLE_REMOTE_FLAGS=1
Remove the Local Cache File
Deleting feature-flags.json forces the manager to start with an empty flag set, triggering the default-deny behavior for all flags. This is useful for one-time resets without modifying environment variables:
import { promises as fs } from 'fs';
import path from 'path';
import { appConfigDir } from './utils/system-info';
async function disableFeatureFlags() {
const cachePath = path.join(appConfigDir(), 'feature-flags.json');
await fs.rm(cachePath, { force: true });
console.log('Feature-flag cache removed; all remote flags disabled.');
}
Implementation Examples
The following patterns demonstrate practical interactions with the feature flag system based on the reference implementation.
Checking if a Feature is Enabled
Reference the FeatureFlagManager instance to gate application logic:
import { featureFlagManager } from '../utils/feature-flags';
// Check specific flag
if (featureFlagManager.isEnabled('new-search')) {
activateNewSearch();
}
Disabling Remote Fetch in Source
When debugging or operating offline, you can verify the remote channel respects the disable flag:
// src/remote-device/remote-channel.ts (excerpt)
const remoteFlagsEnabled = process.env.DC_DISABLE_REMOTE_FLAGS !== '1';
if (!remoteFlagsEnabled) {
console.log('Remote feature-flag fetching disabled');
return;
}
Clearing the Feature Flag Cache
Force a clean slate by removing the persisted cache before initialization:
const fs = require('fs').promises;
const path = require('path');
const configDir = require('./utils/system-info').appConfigDir;
async function clearFlagCache() {
const filePath = path.join(configDir(), 'feature-flags.json');
await fs.unlink(filePath).catch(() => {});
}
Summary
- Desktop Commander MCP synchronizes feature flags via
src/remote-device/remote-channel.ts, stores them insrc/utils/feature-flags.ts, and persists tofeature-flags.json. - The
FeatureFlagManagerprovides synchronousisEnabled()checks with a default-deny fallback for missing or stale flags. - Disable remote fetching by setting the environment variable
DC_DISABLE_REMOTE_FLAGS=1before startup. - Clear local state by deleting the
feature-flags.jsoncache file from the user configuration directory. - The system includes test coverage in
test/test-onboarding-injection-flag.jsandtest/test-feature-flags-timeout.jsfor timeout and fallback validation.
Frequently Asked Questions
What happens if the remote feature flag server is unreachable?
If the remote service is unreachable, remote-channel.ts aborts the request after a timeout (tested in test/test-feature-flags-timeout.js). The FeatureFlagManager then falls back to the cached feature-flags.json file or initializes with an empty set, causing isEnabled() to return false for all flags due to the default-deny implementation.
Can I override individual feature flags without disabling the entire system?
Yes. You can manually edit the feature-flags.json file in the user configuration directory to inject specific flag values. The FeatureFlagManager loads this cache on startup, allowing you to force-enable or force-disable specific features while keeping the remote sync active for other flags.
Where is the feature flag cache stored on disk?
The cache file feature-flags.json resides in the Desktop Commander MCP user configuration directory, typically located at ~/.config/desktop-commander-mcp/feature-flags.json on Linux/macOS or the equivalent platform-specific application data directory. The path is resolved via appConfigDir() in src/utils/system-info.
Is the remote feature flag system enabled by default?
Yes. By default, the application attempts to connect to the remote flag service on startup via src/remote-device/remote-channel.ts. Remote fetching only disables if the DC_DISABLE_REMOTE_FLAGS environment variable is set to 1 or if the network connection is unavailable and no cache exists.
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 →