How the DesktopCommanderMCP Onboarding System Detects New Users and Triggers Welcome Workflows
The DesktopCommanderMCP onboarding system detects new users by checking for the pendingWelcomeOnboarding flag in 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 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 with remote feature-flag evaluation in 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 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 (lines 86-88), this default configuration explicitly sets two critical flags:
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, 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, the code explicitly awaits:
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 (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:
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:
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:
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
ConfigManagercreatingpendingWelcomeOnboarding: trueinsrc/config-manager.tswhenconfig.jsondoes not exist. - Eligibility validation requires both
welcomeOnboardingEligibleto remaintrueand the client not appearing in exclusion lists checked byisWelcomePageClientExcluded(). - Feature-flag synchronization ensures fresh A/B test data via
waitForFreshFlags()before evaluatinghasFeature('showOnboardingPage'). - Welcome page launch occurs through
openWelcomePage()insrc/utils/welcome-onboarding.ts, which usesopenBrowser()fromsrc/utils/open-browser.tsto open system browsers. - State cleanup sets
sawOnboardingPage: trueand clearspendingWelcomeOnboardingto 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 (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, which appends analytics parameters including utm_source before delegating to openBrowser() in src/utils/open-browser.ts (lines 40-48) to handle the actual browser launch.
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 →