Tool Usage Tracking and Telemetry Collection in DesktopCommanderMCP: A Deep Dive into the Source Code
DesktopCommanderMCP implements a dual-layer telemetry system using local file-based logging in src/utils/trackTools.ts and remote analytics via 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, 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:
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 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:
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.
Kill-Switches and User Consent
DesktopCommanderMCP provides two mechanisms for disabling telemetry:
- Environment Variable: Setting
DESKTOP_COMMANDER_DISABLE_TELEMETRYtriggersisTelemetryDisabledByEnv()and immediately halts all transmission attempts. - Configuration Flag: The
telemetryEnabledsetting stored viaconfigManagerallows 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
sanitizeErrorfunction 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 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, andfailedCalls - Tool-specific counters in the
toolCountsobject 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:
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:
- Local Logging: The handler invokes
trackToolCall()fromsrc/utils/trackTools.ts, appending a timestamped entry to the local filesystem log. - Statistics Aggregation: The handler calls
usageTracker.trackSuccess()ortrackFailure(), which updates in-memory counters and persists them asynchronously via the configuration manager. - Telemetry Transmission: For significant events (errors, session starts, or feedback triggers), the system invokes
capture()fromsrc/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
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.
Tracking Success and Failure
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 without blocking the response.
Sending Custom Telemetry Events
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 and applies all privacy filters before transmission.
Checking Feedback Eligibility
if (await usageTracker.shouldPromptForFeedback()) {
const { variant, message } = await usageTracker.getFeedbackPromptMessage();
// Display to user
}
This queries the aggregated statistics in src/utils/usageTracker.ts to determine if the user meets engagement thresholds for feedback requests.
Summary
- Local audit trail:
src/utils/trackTools.tspersists every tool invocation to a rotating log file with configurable size limits. - Privacy-first telemetry:
src/utils/capture.tstransmits anonymized events only after checkingDESKTOP_COMMANDER_DISABLE_TELEMETRYand thetelemetryEnabledconfig flag, with automatic sanitization of paths and error stacks. - Usage analytics:
src/utils/usageTracker.tsaggregates per-user statistics across six categories and manages session detection using 30-minute inactivity windows. - Non-blocking persistence: Both
usageTrackerandcaptureuse asynchronous writes viaconfigManager.setValueNonBlockingto 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 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 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 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.
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 →