# How DesktopCommander MCP Tracks Onboarding Progress and Auto-Disables

> DesktopCommander MCP tracks onboarding progress via a state machine in usageTracker.ts. Discover how it auto-disables after 3 attempts, 10 tool calls, or onboarding prompt interaction.

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

---

**DesktopCommander MCP uses a persistent state machine in [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts) that tracks onboarding attempts, tool usage, and time delays, automatically disabling after three attempts, ten tool calls, or when the user interacts with an onboarding prompt.**

The onboarding system in the `wonderwhy-er/DesktopCommanderMCP` repository guides new users through the MCP server's capabilities while respecting strict limits to avoid overwhelming experienced users. This lightweight implementation persists progress in a JSON configuration and automatically terminates once specific engagement or usage thresholds are met.

## Onboarding State Persistence

The system maintains a durable state object via `getOnboardingState()` in [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts). This function reads an `onboardingState` object from the global config manager or initializes a default structure:

```typescript
{
  promptsUsed: false,
  attemptsShown: 0,
  lastShownAt: 0
}

```

This state survives server restarts because the config manager writes to persistent storage. The `OnboardingState` interface defines three critical tracking fields that drive the entire logic flow.

## Progress Tracking Logic

The `shouldShowOnboarding()` function (line 421 in [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts)) evaluates a cascade of conditions to determine if the onboarding message should inject into the LLM response. This method checks:

- **Remote feature flag** `onboarding_injection` (kill-switch)
- **Local config override** `onboarding_injection`
- **CLI flag** `--no-onboarding` (exposed via global `disableOnboarding` parsed in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts))
- **Client name validation** – disabled entirely for the `desktop-commander` client
- **Usage metrics** – disables after **10 tool calls** or **3 attempts**
- **Time-based rate limiting** – requires a **2-minute delay** between attempts after the first show

Only if all conditions pass does the system proceed to generate the onboarding message.

## Auto-Disable Triggers

The **DesktopCommander MCP onboarding system** auto-disables when any of the following thresholds are met:

1. **Feature flag disabled** – Remote `onboarding_injection` set to `false`
2. **Local config override** – Local `onboarding_injection` explicitly set to `false`
3. **CLI opt-out** – `--no-onboarding` flag present at startup
4. **Client mismatch** – Running under the `desktop-commander` client name
5. **Successful engagement** – User invokes `get_prompts` and triggers `markOnboardingPromptsUsed()`, setting `promptsUsed: true`
6. **Usage threshold** – User makes **10 or more tool calls** (no longer considered "new")
7. **Attempt limit** – `attemptsShown` reaches **3**
8. **Time restriction** – Less than 2 minutes elapsed since `lastShownAt`

These checks execute inside `shouldShowOnboarding()`, ensuring the system silently backs off once the user demonstrates proficiency or ignores the prompts.

## Recording User Engagement

When onboarding displays, `markOnboardingShown(variant)` increments `attemptsShown`, updates `lastShownAt` to the current timestamp, and persists the state. If the user selects any onboarding option (triggering the `get_prompts` tool), `markOnboardingPromptsUsed()` (line 559) immediately sets `promptsUsed: true`, creating a permanent block against future injections.

The server integration in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) (around line 1560) orchestrates this flow:

```typescript
// Server entry point (simplified)
if (await usageTracker.shouldShowOnboarding()) {
  const msg = await usageTracker.getOnboardingMessage();
  // inject msg into LLM response …
  await usageTracker.markOnboardingShown(msg.variant);
}

```

When a user engages with the UI:

```typescript
await usageTracker.markOnboardingPromptsUsed();   // stops future prompts

```

## Implementation Architecture

Key files supporting this system include:

- **[`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts)** – Core state machine with `getOnboardingState`, `shouldShowOnboarding`, `getOnboardingMessage`, `markOnboardingShown`, and `markOnboardingPromptsUsed`
- **[`src/utils/welcome-onboarding.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/welcome-onboarding.ts)** – Manages the separate "welcome page" A/B test while respecting the same feature flags
- **[`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts)** – Parses `--no-onboarding` CLI flag and sets global `disableOnboarding`
- **[`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts)** (~line 1560) – Injection point for onboarding messages into LLM responses

## Summary

- DesktopCommander MCP stores onboarding state in a persistent JSON config via `getOnboardingState()` in [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts)
- The system tracks `attemptsShown`, `lastShownAt`, and `promptsUsed` to determine when to stop showing prompts
- **Auto-disable occurs** after 3 attempts, 10 tool calls, successful prompt usage, or explicit opt-out via flags/config
- A **2-minute cooldown** between attempts prevents spam while allowing legitimate discovery
- The `desktop-commander` client name automatically bypasses onboarding entirely
- State changes persist across server restarts through the config manager

## Frequently Asked Questions

### Where is the onboarding state stored?

The state lives in the global config manager as a JSON object named `onboardingState`, persisted to disk alongside other usage statistics. This ensures durability across server restarts and consistent tracking of `attemptsShown`, `lastShownAt`, and `promptsUsed` fields.

### How many times will the onboarding prompt appear?

The system allows **maximum 3 attempts** spaced by at least **2 minutes** each. If the user never interacts with the prompts after three displays, the system permanently disables itself by incrementing `attemptsShown` to the threshold value.

### Can I disable onboarding manually?

Yes. You can pass the `--no-onboarding` CLI flag when starting the server (parsed in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts)), set the local config value `onboarding_injection` to `false`, or rely on the remote feature flag kill-switch. Additionally, simply using any of the onboarding prompts once will trigger `markOnboardingPromptsUsed()` and permanently disable future injections.

### What client name disables onboarding automatically?

The `desktop-commander` client name triggers an automatic disable in `shouldShowOnboarding()`, preventing the onboarding system from injecting messages when the MCP server runs under this specific client identifier.