# How Desktop Commander Telemetry Works: Data Collection and Privacy Controls

> Understand Desktop Commander telemetry data collection and privacy controls. Learn how anonymous usage metrics are captured and opt-out options.

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

---

**Desktop Commander MCP captures anonymous usage metrics through a fire-and-forget telemetry layer that POSTs sanitized JSON payloads to a proxy endpoint, with opt-out controls available via both configuration files and environment variables.**

Desktop Commander MCP (Model Context Protocol) records tool interactions and system context through a privacy-focused telemetry system designed to never block user operations. Understanding Desktop Commander telemetry collection helps users and administrators configure appropriate privacy settings while maintaining visibility into how the tool aggregates usage statistics across filesystem, terminal, and editing operations.

## Telemetry Architecture and Entry Points

The telemetry flow originates from three primary entry points in the codebase:

- **`capture(event, props?)`** – General-purpose function located in [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts) that records custom events from any tool implementation.
- **`captureRemote(event, props?)`** – Variant that forces `remote:true` and strips identity fields (`deviceId`, `email`) for calls originating from remote devices.
- **`usageTracker.trackSuccess(toolName)`** and **`trackFailure(toolName)`** – High-level wrappers in [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts) automatically called from tool wrappers to record invocation outcomes.

All paths ultimately delegate through `capture()` → `buildEventProperties()` → `sendToTelemetryProxy()`.

## Data Payload Structure and Automatic Properties

When `buildEventProperties()` executes (lines 13-84 in [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts)), it constructs a JSON payload containing automatically detected system metadata and user-supplied properties.

**Automatically collected fields include:**

- **`timestamp`** – ISO-8601 string from `new Date().toISOString()`.
- **`platform`** – Operating system identifier (`win32`, `darwin`, `linux`) via `os.platform()`.
- **Container detection** – `isContainer`, `containerType` (e.g., `docker`, `kubernetes`), `orchestrator`, `containerName`, and `containerImage` (sanitized to remove long hashes).
- **`runtimeSource`** – Heuristic classification as `smithery-runtime`, `npx-runtime`, or `direct-runtime`.
- **`isDXT`** – Boolean indicating presence of the `MCP_DXT` environment variable.
- **`app_version`** – Version imported from [`src/version.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/version.ts).
- **Client context** – `client_name` and `client_version` from `currentClient` or `currentRemoteClient` in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts).
- **`saw_onboarding_page`** – Config flag indicating onboarding completion.
- **`remote`** – Flag indicating remote device invocation via `currentCallIsRemote`.

User-supplied properties passed to `capture()` are deep-cloned and subject to sanitization before transmission.

## Data Sanitization and Privacy Protection

Before any payload leaves the process, Desktop Commander applies aggressive sanitization to prevent leakage of sensitive information:

1. **Path stripping** – The sanitizer removes any property keys containing `path`, `filePath`, or `directory`, ensuring filesystem locations never exit the local machine.
2. **Error cleaning** – `sanitizeError` strips stack traces and path information from error objects.
3. **Identity separation** – `captureRemote()` explicitly removes `deviceId`, `email`, and `userId` fields, leaving only the anonymous `client_id`.

All network operations use a 3-second timeout, and failures are silently ignored to guarantee telemetry never blocks tool execution.

## Transmission Pipeline and Kill Switches

The `sendToTelemetryProxy()` function (lines 25-44 in [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts)) manages the actual network transmission:

1. **Kill-switch verification** – Checks `DESKTOP_COMMANDER_DISABLE_TELEMETRY` environment variable and `telemetryEnabled` config value via `isTelemetryDisabledByEnv` and `isTelemetryDisabledValue`.
2. **Payload construction** – Creates minimal JSON with `client_id` (a per-machine UUID from `configManager.getOrCreateClientId()`), `timestamp_micros`, and event parameters.
3. **Dual endpoint strategy** – Attempts primary endpoint `https://telemetry.desktopcommander.app/mp/collect`, falling back to `https://dc-telemetry-proxy-83847352264.europe-west1.run.app/mp/collect` on failure.
4. **Fire-and-forget** – Asynchronous POST with timeout; errors are caught and discarded.

The `client_id` is the only persistent identifier, stored in `~/.config/desktop-commander/config.json` and created lazily on first telemetry use.

## Usage Statistics and Feedback Prompts

[`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts) maintains aggregated counters in the user config under the `usageStats` key:

- **Category counters** – `filesystemOperations`, `terminalOperations`, `editOperations`, `searchOperations`, `configOperations`, `processOperations`.
- **Outcome tracking** – `totalToolCalls`, `successfulCalls`, `failedCalls`, and per-tool frequency counts (`toolCounts`).
- **Session metrics** – `firstUsed`, `lastUsed`, and `totalSessions` (session resets after 30 minutes inactivity).
- **Feedback state** – `feedbackAttempts` and `lastFeedbackPromptDate`.

The `shouldPromptForFeedback()` and `shouldPromptForErrorFeedback()` methods use these statistics to determine when to request user surveys.

## Practical Code Examples

### Recording a Custom Event

```typescript
import { capture } from './utils/capture.js';

await capture('tool_call', {
  tool: 'read_file',
  filePath: '/Users/alice/project/README.md',   // sanitized and removed
  sizeBytes: 3421,
});

```

*Note: The `filePath` property is automatically stripped before transmission.*

### Automatic Tool Tracking

```typescript
import { usageTracker } from './utils/usageTracker.js';

await usageTracker.trackSuccess('read_file');
// Increments filesystemOperations, successfulCalls, 
// toolCounts['read_file'], and session counters

```

### Disabling Telemetry in CI

```bash
export DESKTOP_COMMANDER_DISABLE_TELEMETRY=1
npm test   # All capture() calls become no-ops

```

### Checking Feedback Eligibility

```typescript
if (await usageTracker.shouldPromptForFeedback()) {
  const { message } = await usageTracker.getFeedbackPromptMessage();
  // Present survey to user
}

```

## Summary

- Desktop Commander telemetry operates through **[`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts)**, which builds sanitized payloads and POSTs them to BigQuery-backed endpoints.
- **Automatic data collection** includes OS platform, container status, runtime source, client version, and session timing—**never** file paths or personal identifiers.
- **Privacy controls** include the `telemetryEnabled` config flag and the `DESKTOP_COMMANDER_DISABLE_TELEMETRY` environment kill-switch.
- **Usage aggregation** in [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts) tracks tool categories and success rates to inform development priorities and user feedback timing.
- All transmissions use a fire-and-forget model with 3-second timeouts to ensure zero impact on tool performance.

## Frequently Asked Questions

### What data does Desktop Commander telemetry capture?

Desktop Commander captures anonymous system metadata including OS platform, container detection flags, runtime source identification (`smithery-runtime`, `npx-runtime`, or `direct-runtime`), client version, and aggregated tool usage statistics. According to the [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts) source code, all file paths and potential identifiers are stripped before transmission, leaving only operational metrics and a per-machine UUID.

### How do I completely disable Desktop Commander telemetry?

Set the environment variable `DESKTOP_COMMANDER_DISABLE_TELEMETRY=1`, `true`, `yes`, or `on` before starting the process. Alternatively, edit `~/.config/desktop-commander/config.json` and set `telemetryEnabled` to `false`. The environment variable functions as a kill-switch that prevents telemetry initialization even before config loading, making it ideal for CI environments and containers.

### Where is the telemetry data sent?

The system attempts to POST JSON payloads to `https://telemetry.desktopcommander.app/mp/collect`, falling back to `https://dc-telemetry-proxy-83847352264.europe-west1.run.app/mp/collect` if the primary endpoint fails. Both endpoints receive sanitized, anonymous data ultimately stored in BigQuery for analysis of tool usage patterns and error rates.

### Why does Desktop Commander need a client ID?

The `client_id` is a randomly generated UUID created once per machine via `configManager.getOrCreateClientId()` and stored locally in the config file. This identifier allows the telemetry system to aggregate sessions and usage patterns without collecting personal information, enabling accurate statistics about unique active users while maintaining complete anonymity.