Desktop Commander MCP Error Handling Strategy: 5 Layers of Safe, Consistent Failure Management
Desktop Commander MCP uses a five-layer error handling strategy that captures errors centrally, sanitizes sensitive data for telemetry, and returns uniform ServerResult objects to all consumers.
The wonderwhy-er/DesktopCommanderMCP repository implements a defensive, privacy-first error handling strategy designed for an AI-powered desktop automation server. Every failure follows a predictable path: capture for diagnostics, sanitize for privacy, and standardize for API consistency. This article breaks down exactly how the codebase handles runtime errors without leaking sensitive information.
Layer 1: Central Capture and Sanitization in capture.ts
All errors flow through src/utils/capture.ts, the telemetry gateway. The capture() function records failures for monitoring while sanitizeError() strips personally identifiable information before data leaves the process.
// src/utils/capture.ts – simplified sanitization logic
export function sanitizeError(error: any): { message: string; code?: string } {
if (typeof error === 'string') {
return { message: error };
}
if (error && typeof error.message === 'string') {
// Strip file paths and credential fragments
const clean = error.message.replace(/([A-Za-z]:\\|\/)[^\s]*/g, '[REDACTED]');
return { message: clean, code: error.code };
}
return { message: 'Unknown error' };
}
The sanitization applies only to telemetry payloads. The original error remains intact for internal debugging, ensuring accurate diagnostics without privacy violations. As noted in the source: "Don't sanitize operation name for logs – only telemetry will sanitize if needed."
Layer 2: Uniform ServerResult API Contract
Every public function returns a ServerResult object. Errors set isError: true and provide a plain-text description in the content array. This structure guarantees that UI components, CLI clients, and remote MCP consumers parse responses identically.
The createErrorResponse() helper in src/error-handlers.ts constructs these objects:
// src/error-handlers.ts – central error response builder
export function createErrorResponse(message: string): ServerResult {
// Record for telemetry (sanitized inside capture)
capture('server_request_error', { error: message });
// Return standardized shape
return {
content: [{ type: 'text', text: `Error: ${message}` }],
isError: true,
};
}
This single function eliminates inconsistent error shapes across the codebase.
Layer 3: Defensive Try/Catch Wrappers
Core tools wrap operations in try { … } catch (e) { … } blocks. The catch handler forwards errors to capture() for telemetry, then transforms them into safe user-facing messages via createErrorResponse().
Real-world example from file system operations:
import { capture } from './utils/capture.js';
import { createErrorResponse } from './error-handlers.js';
import { readFile } from 'fs/promises';
export async function readUserFile(path: string): Promise<ServerResult> {
try {
const data = await readFile(path, 'utf8');
return { content: [{ type: 'text', text: data }], isError: false };
} catch (e) {
// Telemetry: recorded and sanitized automatically
capture('file_read_error', { error: e });
// User response: safe, uniform message
const safeMessage = typeof e === 'object' && e?.message
? e.message
: String(e);
return createErrorResponse(safeMessage);
}
}
This pattern appears throughout src/tools/filesystem.ts, src/utils/withTimeout.ts, and src/utils/trackTools.ts.
Layer 4: Controlled Logging with logger.ts
The lightweight logger in src/utils/logger.ts writes concise console messages when DEBUG mode is enabled. It never prints raw error objects, preventing accidental data exposure in production logs.
Usage pattern:
import { logger } from './utils/logger.js';
logger.error('File read operation failed');
// Output (DEBUG=1): "ERROR: File read operation failed"
// Output (DEBUG=0): silent
Layer 5: Telemetry-Only Data Flow
The Desktop Commander MCP error handling strategy maintains separation between diagnostics and user feedback:
| Path | Data Treatment | Destination |
|---|---|---|
| Telemetry | Sanitized via sanitizeError() |
BigQuery / analytics backends |
| User response | Original message (safe context) | ServerResult.content |
| Debug logs | Conditionally enabled, no raw objects | Console (development only) |
This design prevents the common failure mode of "over-sanitization" that strips useful context from user-facing errors.
Complete Error Flow: Step-by-Step
- Operation initiates – async I/O or tool execution begins
- Exception caught –
try/catchblock intercepts the failure - Telemetry recorded –
capture()receives raw error;sanitizeError()cleans PII before external transmission - Response constructed –
createErrorResponse()buildsServerResultwithisError: true - Result returned – calling REPL, UI, or MCP client receives uniform object
Key Files in the Error Handling Architecture
| File | Responsibility |
|---|---|
src/utils/capture.ts |
Central telemetry hook with sanitizeError() |
src/error-handlers.ts |
createErrorResponse() and related helpers |
src/utils/logger.ts |
Conditional debug logging |
src/utils/withTimeout.ts |
Timeout wrapper demonstrating error forwarding |
src/tools/filesystem.ts |
Production tool implementation with full error pipeline |
Summary
Desktop Commander MCP's error handling strategy delivers three core guarantees:
- Consistent API contracts via the
ServerResulttype andcreateErrorResponse()helper - Privacy-preserving telemetry through
capture.tsandsanitizeError() - Clear user feedback with defensive
try/catchpatterns in every tool function
The layered approach separates concerns cleanly: diagnostics happen invisibly, sensitive data stays protected, and every client receives predictable, parseable responses.
Frequently Asked Questions
How does Desktop Commander MCP prevent sensitive data leaks in error messages?
The sanitizeError() function in src/utils/capture.ts uses regex patterns to detect and redact file paths, credentials, and other PII from telemetry payloads. This sanitization applies only to external analytics; user-facing error messages retain original context for debugging assistance.
What is the ServerResult type and why is it important?
ServerResult is a standardized response object with content (text array), isError (boolean), and optional metadata. It ensures that UI layers, CLI tools, and remote MCP clients all parse success and failure states identically, eliminating integration bugs from inconsistent error shapes.
Where should I add error handling for new tools in this codebase?
Wrap your tool's main operation in try/catch, call capture('your_tool_error', { error: e }) for telemetry, and return createErrorResponse(message) on failure. Follow the pattern in src/tools/filesystem.ts for production-ready implementation.
Does the DEBUG flag affect error reporting behavior?
Yes. When DEBUG=1, logger.error() and related methods write to console. However, raw error objects are never printed—only safe, stringified messages—to maintain privacy even in development environments.
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 →