# Tool Usage Tracking and Telemetry Collection in DesktopCommanderMCP: A Deep Dive into the Source Code

> Explore DesktopCommanderMCP's dual-layer telemetry system. Understand tool usage tracking via local logging and remote analytics, plus detailed privacy controls. Dive into the source code.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: deep-dive
- Published: 2026-08-08

---

**DesktopCommanderMCP implements a dual-layer telemetry system using local file-based logging in [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/trackTools.ts) and remote analytics via [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts), with comprehensive privacy controls via environment variables and user configuration flags.**

DesktopCommanderMCP tracks every tool invocation to improve user experience while maintaining strict privacy controls. The system combines local audit logging with anonymized telemetry transmission, allowing developers to monitor usage patterns without exposing sensitive data. This article examines the actual source code implementation in the wonderwhy-er/DesktopCommanderMCP repository to reveal how tool usage tracking and telemetry collection work under the hood.

## Local Tool-Call Logging with trackTools.ts

The foundation of DesktopCommanderMCP's tracking infrastructure resides in [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/trackTools.ts), which provides lightweight, filesystem-based persistence of every tool invocation.

### The trackToolCall Function

Every tool execution flows through the `trackToolCall` function, which generates timestamped log entries:

```typescript
export async function trackToolCall(toolName: string, args?: unknown): Promise<void> {
  const timestamp = new Date().toISOString();
  const logEntry = `${timestamp} | ${toolName.padEnd(20, ' ')}${
    args ? `\t| Arguments: ${JSON.stringify(args)}` : ''
  }\n`;

  await fs.promises.appendFile(TOOL_CALL_FILE, logEntry, 'utf8');
}

```

This function creates a structured text record containing the ISO timestamp, normalized tool name (padded to 20 characters), and optional serialized arguments. The log file remains strictly local unless explicitly forwarded by the telemetry pipeline.

### Log Rotation Mechanism

To prevent unbounded disk usage, the system implements automatic rotation when the log file exceeds `TOOL_CALL_FILE_MAX_SIZE` (approximately 10 MiB). Once the threshold is reached, the current file is renamed with a timestamp suffix, and a new log file is initiated. This rotation logic ensures that long-running DesktopCommanderMCP instances do not exhaust available storage.

## Remote Telemetry Capture and Privacy Controls

While local logging serves debugging purposes, the [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts) module handles remote analytics transmission through a privacy-preserving proxy architecture.

### The captureBase Implementation

The core telemetry dispatcher is `captureBase`, which constructs and transmits anonymized event payloads:

```typescript
export const captureBase = async (captureURL: string, event: string, properties?: any) => {
  if (isTelemetryDisabledByEnv()) return;
  const telemetryEnabled = await configManager.getValue('telemetryEnabled');
  if (isTelemetryDisabledValue(telemetryEnabled) || !captureURL) return;

  if (uniqueUserId === 'unknown') {
    uniqueUserId = await configManager.getOrCreateClientId();
  }

  const effectiveClient = currentCallIsRemote && currentRemoteClient
        ? currentRemoteClient : currentClient;
  const clientContext = effectiveClient
        ? { client_name: effectiveClient.name, client_version: effectiveClient.version }
        : {};

  const payload = {
    event,
    userId: uniqueUserId,
    version: VERSION,
    platform: platform(),
    ...clientContext,
    ...properties,
  };

  // POST to https://telemetry.desktopcommander.app/mp/collect
};

```

The function first validates telemetry permissions, then constructs a context-rich payload including a persistent anonymous user ID, platform information, and client metadata sourced from [`src/server.js`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.js).

### Kill-Switches and User Consent

DesktopCommanderMCP provides two mechanisms for disabling telemetry:

- **Environment Variable**: Setting `DESKTOP_COMMANDER_DISABLE_TELEMETRY` triggers `isTelemetryDisabledByEnv()` and immediately halts all transmission attempts.
- **Configuration Flag**: The `telemetryEnabled` setting stored via `configManager` allows users to toggle analytics through the application's UI or configuration file.

Both checks must pass before any network request executes, ensuring explicit opt-out capabilities.

### Data Sanitization and Privacy Safeguards

Before transmission, the system applies aggressive data redaction:

- **Error Sanitization**: The `sanitizeError` function removes stack traces and file paths from error objects.
- **Property Filtering**: Keys matching sensitive patterns (`path`, `filePath`, etc.) are stripped from payloads.
- **Container ID Redaction**: Container metadata replaces hexadecimal identifiers with `"ID"` and truncates names to 50 characters.

Data is POSTed to `https://telemetry.desktopcommander.app/mp/collect` with a fallback URL for resilience.

## Aggregated Usage Statistics via usageTracker.ts

The `UsageTracker` singleton in [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts) maintains persistent counters for user behavior analysis and feedback campaign management.

### Session Management and Counters

The tracker categorizes activity into six domains: filesystem, terminal, edit, search, config, and process. It maintains:

- **Category counters** for high-level usage patterns
- **Overall counters** including `totalToolCalls`, `successfulCalls`, and `failedCalls`
- **Tool-specific counters** in the `toolCounts` object indexed by tool name
- **Session detection** using a 30-minute inactivity threshold to increment `totalSessions`

The `trackSuccess(toolName)` and `trackFailure(toolName)` methods update these counters asynchronously using `configManager.setValueNonBlocking`, ensuring telemetry collection never blocks the critical path of tool execution.

### Feedback Prompt Logic

The system implements intelligent prompting to avoid survey fatigue:

```typescript
if (await usageTracker.shouldPromptForFeedback()) {
  const { variant, message } = await usageTracker.getFeedbackPromptMessage();
  // Emit to UI
}

```

The `shouldPromptForFeedback()` method returns true only when users have accumulated at least 3 days of usage and 10 total tool calls, respecting maximum attempt limits (3 prompts) and daily caps. This logic ensures feedback requests reach engaged users at appropriate intervals.

## Integration Flow: How the Three Systems Work Together

When a tool executes, the following sequence occurs:

1. **Local Logging**: The handler invokes `trackToolCall()` from [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/trackTools.ts), appending a timestamped entry to the local filesystem log.
2. **Statistics Aggregation**: The handler calls `usageTracker.trackSuccess()` or `trackFailure()`, which updates in-memory counters and persists them asynchronously via the configuration manager.
3. **Telemetry Transmission**: For significant events (errors, session starts, or feedback triggers), the system invokes `capture()` from [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts), which sanitizes the payload and transmits it to the remote collector if privacy controls permit.

All three layers respect the `DESKTOP_COMMANDER_DISABLE_TELEMETRY` environment variable and the `telemetryEnabled` configuration flag.

## Code Examples

### Logging a Tool Invocation

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

await trackToolCall('list_directory', { path: '/home/user' });

```

This appends a structured line to the local tool call log file in [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/trackTools.ts).

### Tracking Success and Failure

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

// After successful execution
await usageTracker.trackSuccess('read_file');

// After catching an error
await usageTracker.trackFailure('execute_command');

```

These methods update the persistent usage statistics in [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts) without blocking the response.

### Sending Custom Telemetry Events

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

await capture('custom_event', {
  tool: 'list_directory',
  durationMs: 42,
  extraInfo: 'performance metric'
});

```

The `capture` function wraps `captureBase` in [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts) and applies all privacy filters before transmission.

### Checking Feedback Eligibility

```typescript
if (await usageTracker.shouldPromptForFeedback()) {
  const { variant, message } = await usageTracker.getFeedbackPromptMessage();
  // Display to user
}

```

This queries the aggregated statistics in [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts) to determine if the user meets engagement thresholds for feedback requests.

## Summary

- **Local audit trail**: [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/trackTools.ts) persists every tool invocation to a rotating log file with configurable size limits.
- **Privacy-first telemetry**: [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts) transmits anonymized events only after checking `DESKTOP_COMMANDER_DISABLE_TELEMETRY` and the `telemetryEnabled` config flag, with automatic sanitization of paths and error stacks.
- **Usage analytics**: [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts) aggregates per-user statistics across six categories and manages session detection using 30-minute inactivity windows.
- **Non-blocking persistence**: Both `usageTracker` and `capture` use asynchronous writes via `configManager.setValueNonBlocking` to prevent latency in tool execution.
- **Smart engagement**: The feedback system uses accumulated usage data (3 days minimum, 10 calls minimum) to target surveys appropriately.

## Frequently Asked Questions

### How do I completely disable telemetry in DesktopCommanderMCP?

Set the environment variable `DESKTOP_COMMANDER_DISABLE_TELEMETRY` to any truthy value, or set the `telemetryEnabled` configuration flag to `false` via the config manager. The environment variable acts as a hard kill-switch that prevents `captureBase` in [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts) from executing any network requests, while the config flag allows runtime toggling through the application interface.

### Where are tool usage logs stored locally?

The `trackToolCall` function in [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/trackTools.ts) writes to a file defined by the constant `TOOL_CALL_FILE`. This file contains timestamped entries for every tool invocation with optional argument serialization, and automatically rotates when exceeding approximately 10 MiB to prevent disk space exhaustion.

### What data is sent to the telemetry endpoint?

The payload sent to `https://telemetry.desktopcommander.app/mp/collect` includes an anonymized user ID, event name, DesktopCommanderMCP version, platform information, client context (name and version), and event-specific properties. Before transmission, the system strips all `path` and `filePath` properties, redacts container identifiers, and removes stack traces from error objects to ensure no sensitive filesystem information leaves the machine.

### How does the feedback prompt system determine when to ask for user input?

The `shouldPromptForFeedback()` method in [`src/utils/usageTracker.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts) checks that the user has at least 3 days of usage history and has executed 10 or more tool calls, while respecting a maximum of 3 lifetime prompts and daily frequency caps. This logic ensures only engaged, experienced users receive feedback requests, reducing survey fatigue while maximizing response quality.