How Desktop Commander MCP Tracks Command Usage Statistics: A Deep Dive into the UsageTracker Implementation
Desktop Commander MCP tracks command usage statistics through the UsageTracker class in src/utils/usageTracker.ts, which records every tool invocation via trackSuccess() and trackFailure() methods, aggregates data by category and individual tool, manages session timeouts, and persists statistics non-blocking to the usageStats config key.
Desktop Commander MCP implements a lightweight telemetry system to monitor how users interact with its filesystem, terminal, and editing tools. The system captures every command execution, categorizes usage patterns, and maintains persistent statistics across process restarts. Understanding how this MCP server tracks command usage statistics reveals a sophisticated yet efficient approach to analytics that avoids blocking the event loop while providing detailed operational insights.
The UsageTracker Architecture
The statistics engine centers around the UsageTracker class located in [src/utils/usageTracker.ts](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/usageTracker.ts). This singleton maintains an in-memory representation of the current session while delegating persistent storage to the configuration manager.
The tracker organizes data into a hierarchical structure:
- Global counters:
totalToolCalls,successfulCalls, andfailedCalls - Category aggregations: Grouped by filesystem, terminal, edit, search, config, and process operations
- Per-tool histograms: Individual counters for each specific tool name stored in
stats.toolCounts - Session metadata: Tracks
totalSessionsand timestamps for calculating usage duration
How Statistics Are Collected During Tool Execution
The collection workflow follows a deterministic hook-based pattern implemented in [src/server.ts](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts):
- Tool invocation: The server executes a requested tool (e.g.,
read_file,execute_command) - Resolution hook: Immediately after the tool resolves (around line 1550), the server calls either
usageTracker.trackSuccess(toolName)orusageTracker.trackFailure(toolName)depending on the exit status - Category mapping: The tool name is mapped to a high-level category via the internal
TOOL_CATEGORIESmap - Counter incrementation: The system updates the specific category counter (e.g.,
stats.terminalOperations++), the per-tool counter (stats.toolCounts[toolName]++), and the appropriate success/failure global counter
This approach ensures that every command invocation contributes to the statistical model regardless of whether it completes successfully or throws an error.
Session Management and Timeout Logic
The tracker implements intelligent session handling to distinguish between continuous usage patterns and separate work periods. A new session starts automatically after 30 minutes of inactivity, defined by the SESSION_TIMEOUT constant.
When trackSuccess or trackFailure detects that the elapsed time since the last command exceeds the threshold, it increments totalSessions and resets the session timer. This mechanism allows the system to report both the total number of discrete work sessions and the cumulative days of active usage, which feeds into the feedback prompting logic.
Non-Blocking Persistence Strategy
After updating in-memory statistics, the tracker invokes the private saveStats method to persist data without impacting performance. Rather than writing directly to disk or using blocking I/O, the implementation leverages configManager.setValueNonBlocking (defined in [src/config-manager.js](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config-manager.js)) to serialize the statistics object to JSON and store it under the usageStats configuration key.
This non-blocking approach preserves the responsiveness of heavy-traffic command pipelines by ensuring the libuv thread pool remains available for concurrent operations.
Retrieving Usage Data and Feedback Triggers
The tracker exposes methods for consuming the collected statistics. The getUsageSummary() method returns a human-readable report including total calls, success rates, session counts, and most-used tools.
Additionally, the system uses usage patterns to drive engagement through the shouldPromptForFeedback() method, which returns true when the user has accumulated at least 3 days of usage and 10 or more tool calls. When these thresholds are met, getFeedbackPromptMessage() generates contextual messaging to solicit user input.
Practical Code Examples
Recording a Successful Command
// Inside src/server.ts after a tool finishes without error
await usageTracker.trackSuccess('read_file'); // increments filesystem counters, updates session
Recording a Failed Command
// Inside src/server.ts inside a catch block
await usageTracker.trackFailure('write_file'); // increments failure counters, same category aggregation
Retrieving a Usage Summary
import { usageTracker } from './utils/usageTracker.js';
async function displayUsageReport() {
const summary = await usageTracker.getUsageSummary();
console.log(summary);
}
Example output:
📊 **Usage Summary**
• Total calls: 124 (115 successful, 9 failed)
• Success rate: 93%
• Days using: 7
• Sessions: 4
• Unique tools: 12
• Most used: read_file: 48, list_directory: 30, execute_command: 22
Checking Feedback Eligibility
if (await usageTracker.shouldPromptForFeedback()) {
const { variant, message } = await usageTracker.getFeedbackPromptMessage();
// Surface message to the UI based on the variant logic
}
Summary
- Central tracking: The
UsageTrackerclass insrc/utils/usageTracker.tsmaintains all command usage statistics in-memory and persists them via the configuration manager. - Hook-based collection:
src/server.tscallstrackSuccess()ortrackFailure()immediately after each tool execution, ensuring comprehensive coverage of both successful and failed operations. - Categorical aggregation: Tools are mapped to six categories (filesystem, terminal, edit, search, config, process) via
TOOL_CATEGORIES, enabling high-level usage pattern analysis. - Session awareness: A 30-minute inactivity timeout (
SESSION_TIMEOUT) delineates separate work sessions, tracked separately from total tool calls. - Non-blocking I/O: Statistics persist to the
usageStatsconfig key usingsetValueNonBlockingto prevent event-loop blockage during high-frequency operations. - Integrated feedback: The system automatically triggers feedback prompts after 3 days of usage and 10+ tool calls, using the same statistical foundation.
Frequently Asked Questions
Where are command usage statistics stored in Desktop Commander MCP?
All statistics persist to the usageStats configuration key managed by configManager in src/config-manager.js. The data is stored as a JSON blob that survives process restarts, making it available for diagnostics and telemetry across multiple sessions.
How does the system define a "session" for usage tracking?
A session represents a continuous period of activity. The tracker starts a new session whenever more than 30 minutes elapse between consecutive commands (the SESSION_TIMEOUT constant). This threshold distinguishes between continuous workflow and separate work periods, incrementing totalSessions only when the timeout is breached.
Does tracking command usage impact performance?
No. The implementation uses non-blocking persistence via configManager.setValueNonBlocking, which serializes and writes statistics asynchronously without blocking the libuv thread pool. All counter updates occur in-memory, ensuring that even high-frequency command pipelines maintain responsiveness.
Can users access their own usage statistics?
Yes. The repository exposes a dedicated usage tool defined in src/tools/usage.ts that returns a formatted usage summary including total calls, success rates, session counts, and the most frequently used tools. This allows users to query their own statistical data through the same interface they use for other MCP operations.
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 →