# Desktop Commander MCP Error Handling Strategy for Uncaught Exceptions and Unhandled Rejections

> Desktop Commander MCP uses a fail-fast error handling strategy for uncaught exceptions and unhandled rejections. Learn how it captures, suppresses, records telemetry, and terminates for critical failures.

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

---

**Desktop Commander MCP implements a layered, fail‑fast error handling strategy that captures uncaught exceptions and unhandled promise rejections through process‑level listeners, suppresses benign JSON‑parsing errors, records telemetry, and terminates the process for non‑recoverable failures.**

The error handling approach in wonderwhy‑er/DesktopCommanderMCP balances operational resilience with strict failure boundaries. Rather than allowing silent failures or zombie processes, the codebase actively monitors for runtime errors and makes deliberate decisions about recovery versus termination. This pattern is particularly important for Model Context Protocol (MCP) servers, where stability directly impacts client experience.

## Process-Level Exception and Rejection Listeners

The foundation of Desktop Commander MCP error handling sits in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts), where the `runServer()` function registers two critical `process` event handlers around line 77.

```typescript
// src/index.ts (lines 77-110)
process.on('uncaughtException', async (error) => { … });
process.on('unhandledRejection', async (reason) => { … });

```

These listeners intercept:

- **Synchronous errors** thrown from any execution context
- **Asynchronous promise rejections** that lack `.catch()` handlers

Both handlers follow identical logic paths: classification, logging, telemetry capture, and conditional termination.

## Selective Suppression for JSON-Parsing Errors

Not all errors warrant process termination. Desktop Commander MCP specifically exempts **malformed JSON payloads** from fatal handling.

The detection logic checks error messages for `"JSON"` and `"Unexpected token"`. When matched:

- The error flows through `logger.error` for visibility
- Telemetry is captured via `capture('run_server_uncaught_exception', …)`
- **The process continues running**

This prevents transient configuration issues from crashing long‑lived server instances.

```typescript
// Pseudocode representation of the selective suppression logic
if (error.message.includes('JSON') && error.message.includes('Unexpected token')) {
  logger.error('Non-fatal JSON parse error', { error });
  capture('run_server_uncaught_exception', { error: error.message, fatal: false });
  return; // Skip process.exit(1)
}

```

## Telemetry and Observability Integration

Every intercepted error triggers **structured telemetry collection**. The `capture` utility—imported and invoked within the exception handlers—records:

- Error type and message
- Stack traces when available
- Contextual metadata (timestamp, server state)

```typescript
// From src/index.ts exception handler
capture('run_server_uncaught_exception', {
  error: error.message,
  stack: error.stack,
  fatal: isFatalError(error)
});

```

```typescript
// From src/index.ts rejection handler
capture('run_server_unhandled_rejection', {
  reason: String(reason),
  fatal: true
});

```

This data feeds into production analytics pipelines, enabling proactive issue detection without relying solely on log aggregation.

## Centralized Logging Architecture

Error messages route through [`src/utils/logger.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/logger.ts), which abstracts transport complexity.

The `logger.error` helper chooses between:

- **MCP transport** when the `FilteredStdioServerTransport` is initialized
- **Raw JSON‑RPC notifications** on `stdout` during early startup before transport readiness

```typescript
// src/utils/logger.ts implementation pattern
export function loggerError(level: 'error' | 'warn', message: string, meta?: object) {
  if (transportReady) {
    transport.send({ jsonrpc: '2.0', method: 'log', params: { level, message, ...meta } });
  } else {
    logToStderr(level, message); // Fallback JSON‑RPC notification
  }
}

```

This dual‑mode design ensures **no error is silently dropped**, even during initialization races.

## Process Termination Behavior

For errors **not** classified as benign JSON issues, Desktop Commander MCP enforces strict termination:

1. Log the error with full context
2. Capture telemetry
3. **`process.exit(1)`**

This **fail‑fast philosophy** prevents undefined state propagation. An MCP server in an unknown error condition cannot reliably serve client requests; termination allows orchestration layers (systemd, Docker, process managers) to restart a clean instance.

## Top-Level Fatal Guard for Initialization Failures

The `runServer()` function wraps its entire body in a `try…catch` block. If server initialization itself throws:

- A **structured JSON‑RPC error notification** emits to `stderr`
- Telemetry captures the failure context
- Stack traces are preserved and logged
- The process exits immediately

```typescript
// Pattern from src/index.ts
async function runServer() {
  try {
    // ... server initialization and main loop
  } catch (fatalError) {
    logger.error('Fatal initialization error', { stack: fatalError.stack });
    capture('run_server_fatal_init', { error: fatalError.message });
    process.stderr.write(JSON.stringify({
      jsonrpc: '2.0',
      error: { code: -32603, message: fatalError.message }
    }) + '\n');
    process.exit(1);
  }
}

```

## Catch-All for Asynchronous Post-Startup Failures

The final safety layer attaches to the promise returned by `runServer()`:

```typescript
runServer().catch((err) => {
  console.error('Unhandled error in runServer:', err);
  process.stderr.write(/* JSON‑RPC error */);
  capture('run_server_async_fatal', { error: String(err) });
  process.exit(1);
});

```

This captures **any rejection escaping the main try…catch**, including unanticipated async failures after successful initialization.

## Practical Examples

### Example 1: Custom Error Handler for Extension Code

When building on top of Desktop Commander MCP, register targeted listeners before the server starts:

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

process.once('uncaughtException', (err) => {
  if (err.message.includes('MySpecialError')) {
    logger.error('Gracefully handled extension error', { detail: err });
    // Perform cleanup, then controlled exit
    await gracefulShutdown();
    process.exit(0);
  }
});

```

### Example 2: Triggering Handled Rejection Path

Test the unhandled rejection handler directly:

```typescript
async function simulateFailure() {
  Promise.reject(new Error('Simulated unhandled rejection'));
}
simulateFailure();
// Output: "Unhandled rejection: Simulated unhandled rejection" → telemetry → exit 1

```

### Example 3: Pre-Transport Logging

Emit structured logs before the MCP transport initializes:

```typescript
import { logToStderr } from './src/utils/logger.js';

logToStderr('warning', 'Configuration file not found, using defaults');

```

## Key Source Files

| File | Responsibility |
|------|--------------|
| [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts) | Process-level exception/rejection handlers, fatal guards, telemetry triggers |
| [`src/utils/logger.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/logger.ts) | Centralized logging with transport fallback |
| [`src/custom-stdio.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/custom-stdio.ts) | `FilteredStdioServerTransport` implementation for structured output |
| [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts) | Telemetry collection utility (imported by handlers) |

## Summary

- **Dual process listeners** in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts) catch `uncaughtException` and `unhandledRejection` synchronously
- **JSON-parsing errors are suppressed** to allow recovery from malformed configuration
- **Every error generates telemetry** via the `capture` utility for production observability
- **Centralized logging** in [`src/utils/logger.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/logger.ts) routes through MCP transport or JSON‑RPC fallback
- **Non-recoverable errors trigger `process.exit(1)`** to enforce clean state via external orchestration
- **Multiple defensive layers** (try…catch, promise catch, selective suppression) prevent silent failures

## Frequently Asked Questions

### What happens when Desktop Commander MCP encounters a malformed JSON payload?

The error handler in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts) detects JSON‑parsing failures by matching `"JSON"` and `"Unexpected token"` in the error message. These errors are logged and telemetered but **do not terminate the process**, allowing the server to continue operating despite configuration issues.

### How does Desktop Commander MCP ensure errors are visible during early startup?

The [`logger.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/logger.ts) utility implements a fallback mechanism. Before the `FilteredStdioServerTransport` initializes, errors emit as raw JSON‑RPC notifications on `stderr`. Once the transport is ready, messages flow through the proper MCP channel. This guarantees no error is lost to initialization timing.

### Can Desktop Commander MCP recover from unhandled promise rejections?

No—the current implementation treats unhandled rejections as fatal. The `unhandledRejection` listener captures telemetry, logs the rejection reason, and calls `process.exit(1)`. This aligns with Node.js best practices: unhandled rejections indicate programming errors that invalidate process state.

### Where is telemetry for errors actually sent?

The `capture` function invoked in exception handlers originates from [`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts) (imported into [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts)). While the exact destination depends on build configuration, the integration pattern suggests external analytics services. The telemetry includes error messages, stack traces, and fatality classification.