# How the DesktopCommanderMCP Onboarding System Detects New Users and Triggers Welcome Workflows

> Learn how the DesktopCommanderMCP onboarding system detects new users by checking the pendingWelcomeOnboarding flag and triggers welcome workflows for a seamless user experience.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: how-to-guide
- Published: 2026-07-19

---

**The DesktopCommanderMCP onboarding system detects new users by checking for the `pendingWelcomeOnboarding` flag in [`config.json`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/config.json), which `ConfigManager` automatically sets to `true` during first-run initialization, then validates eligibility against feature flags and A/B tests before launching the welcome page in the default browser.**

The onboarding flow in the [DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP) repository identifies fresh installations through configuration state rather than external analytics. When the Model Context Protocol (MCP) server starts for the first time, it creates a default configuration that marks the user as eligible for the welcome workflow. This detection mechanism combines local state persistence in [`src/config-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config-manager.ts) with remote feature-flag evaluation in [`src/utils/welcome-onboarding.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/welcome-onboarding.ts) to ensure the onboarding experience reaches only the intended audience.

## Configuration-Based New User Detection

### Default Config Initialization

When the server boots, `ConfigManager` attempts to load the user's [`config.json`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/config.json) from disk. If the file does not exist, `ConfigManager.init()` invokes `getDefaultConfig()` to create a fresh configuration object. According to the source code in [`src/config-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config-manager.ts) (lines 86-88), this default configuration explicitly sets two critical flags:

```ts
pendingWelcomeOnboarding: true,
welcomeOnboardingEligible: true

```

The `pendingWelcomeOnboarding` flag serves as the primary new-user marker, indicating that this installation has never processed the onboarding logic. This boolean persists in local storage until the workflow completes or is explicitly skipped, ensuring the system can differentiate between new and returning users even across server restarts.

## Eligibility Guards and Client Filtering

### The welcomeOnboardingEligible Check

Even when a configuration exists, the onboarding routine validates user eligibility before proceeding. In [`src/utils/welcome-onboarding.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/welcome-onboarding.ts), the `handleWelcomePageOnboarding()` function reads `welcomeOnboardingEligible` at line 43. If this flag is falsy, the function returns immediately (lines 43-46), preventing the welcome page from displaying to ineligible users.

### Excluded Clients and Remote Devices

The system implements client-level exclusions to avoid showing the welcome page in unsuitable contexts. During the `Initialize` request, the server checks against hardcoded exclusions for clients named `desktop-commander-app`, `desktop-commander`, or any remote-device context. Additionally, the function `isWelcomePageClientExcluded()` (lines 19-29) checks the dynamic feature flag `welcome_page_excluded_clients`, allowing runtime customization of excluded client names without code changes.

## Feature Flag Synchronization and A/B Testing

### Waiting for Fresh Feature Flags

New users typically lack a local feature-flag cache, so the onboarding system ensures fresh data before making assignment decisions. At line 63 of [`welcome-onboarding.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/welcome-onboarding.ts), the code explicitly awaits:

```ts
await featureFlagManager.waitForFreshFlags();

```

This synchronization guarantees that the A/B test evaluation uses the latest flag definitions from the remote configuration service, preventing stale or missing flag data from influencing the user experience.

### Treatment Group Evaluation

After flags load, the function `hasFeature('showOnboardingPage')` determines whether the current user belongs to the treatment group. This boolean check (lines 80-87) captures the A/B test decision for analytics purposes while controlling access to the welcome workflow. Only users in the treatment group proceed to the welcome page launch.

## Opening the Welcome Page and State Cleanup

### Browser Launch and URL Construction

When a user passes all eligibility checks and A/B test assignments, `openWelcomePage(clientName)` executes at line 104. This function constructs a URL containing `utm_source` parameters for client-level analytics tracking, then delegates to `openBrowser()` in [`src/utils/open-browser.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/open-browser.ts) (lines 40-48) to launch the default system browser with the welcome page.

### Persisting Onboarding Completion

After attempting to open the welcome page—whether successful or not—the system updates configuration state to prevent duplicate workflows. On success, `sawOnboardingPage` sets to `true` (lines 101-108). Regardless of outcome, `pendingWelcomeOnboarding` clears to `false` (lines 110-113), ensuring the detection logic triggers only once per installation.

## Practical Implementation Examples

### Simulating a Fresh Install

To test the new-user detection logic without deleting production configuration:

```ts
import { configManager } from './config-manager.js';
import { handleWelcomePageOnboarding } from './utils/welcome-onboarding.js';

// Reset the config to force a “first run”
await configManager.resetConfig();   // clears pendingWelcomeOnboarding = true
await handleWelcomePageOnboarding('my‑custom‑client');

```

*Running this snippet triggers the onboarding flow exactly as a real first-run would.*

### Manually Skipping Onboarding

For testing or administrative purposes, bypass the welcome page without launching the browser:

```ts
import { skipWelcomePageOnboarding } from './utils/welcome-onboarding.js';

await skipWelcomePageOnboarding();   // Clears pending flag without opening the page

```

### Checking Dynamic Client Exclusions

Verify if a specific client name would be excluded via feature flags:

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

featureFlagManager.set('welcome_page_excluded_clients', ['my‑client']);
const excluded = featureFlagManager.get('welcome_page_excluded_clients').includes('my‑client');
console.log('Is excluded?', excluded);

```

## Summary

- **First-run detection** relies on `ConfigManager` creating `pendingWelcomeOnboarding: true` in [`src/config-manager.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config-manager.ts) when [`config.json`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/config.json) does not exist.
- **Eligibility validation** requires both `welcomeOnboardingEligible` to remain `true` and the client not appearing in exclusion lists checked by `isWelcomePageClientExcluded()`.
- **Feature-flag synchronization** ensures fresh A/B test data via `waitForFreshFlags()` before evaluating `hasFeature('showOnboardingPage')`.
- **Welcome page launch** occurs through `openWelcomePage()` in [`src/utils/welcome-onboarding.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/welcome-onboarding.ts), which uses `openBrowser()` from [`src/utils/open-browser.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/open-browser.ts) to open system browsers.
- **State cleanup** sets `sawOnboardingPage: true` and clears `pendingWelcomeOnboarding` to prevent workflow repetition.

## Frequently Asked Questions

### How does the system prevent the welcome page from showing on every server restart?

The onboarding system clears the `pendingWelcomeOnboarding` flag immediately after the first execution attempt, regardless of whether the browser successfully opened. This persistence happens in [`src/utils/welcome-onboarding.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/welcome-onboarding.ts) (lines 110-113), ensuring the workflow runs exactly once per installation.

### Can specific client implementations disable the welcome workflow?

Yes. The `isWelcomePageClientExcluded()` function checks against hardcoded client names like `desktop-commander-app` and supports dynamic exclusion via the `welcome_page_excluded_clients` feature flag. Clients can be excluded at runtime without modifying source code by updating this remote configuration value.

### What happens if feature flags fail to load during initialization?

The onboarding code explicitly awaits `featureFlagManager.waitForFreshFlags()` at line 63 before evaluating A/B test assignments. If flags fail to load, this promise rejects or times out, preventing premature treatment group evaluation and ensuring the system does not display the welcome page based on stale or missing configuration data.

### Where is the final welcome page URL constructed?

The URL assembly occurs in `openWelcomePage()` within [`src/utils/welcome-onboarding.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/welcome-onboarding.ts), which appends analytics parameters including `utm_source` before delegating to `openBrowser()` in [`src/utils/open-browser.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/open-browser.ts) (lines 40-48) to handle the actual browser launch.