# DesktopCommanderMCP File Handler Factory Architecture: Text, Binary, Image and Document Processing

> Explore the DesktopCommanderMCP file handler factory architecture. Discover how it processes text, binary, image, and document files using a priority-based extension and content detection system.

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

---

**DesktopCommanderMCP implements a centralized factory pattern in [`src/utils/files/factory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/factory.ts) that lazily instantiates specialized file handlers and selects them via a priority-based extension and content detection system.**

DesktopCommanderMCP is a Model Context Protocol (MCP) server that provides secure file system access for AI assistants. At its core, the **file handler factory** architecture enables the server to process diverse formats—from plain text to complex Office documents—through a unified interface while maintaining format-specific capabilities.

## Factory Pattern Implementation and Singleton Handlers

The factory module manages handler instances using a **singleton pattern** with lazy initialization. Rather than creating handlers upfront, the factory declares nullable references and instantiates each handler only upon first request.

In [`src/utils/files/factory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/factory.ts), the factory maintains private references to each handler type:

```typescript
let textHandler: TextFileHandler | null = null;
let imageHandler: ImageFileHandler | null = null;
let binaryHandler: BinaryFileHandler | null = null;
let excelHandler: ExcelFileHandler | null = null;
let pdfHandler: PdfFileHandler | null = null;
let docxHandler: DocxFileHandler | null = null;

```

Dedicated getter functions like `getTextHandler()`, `getImageHandler()`, and `getBinaryHandler()` check for existing instances before creating new ones. This approach minimizes memory overhead and startup latency, ensuring handlers exist only when actively needed.

## Handler Selection Priority and Detection Strategy

The `getFileHandler()` function determines the appropriate processor by evaluating candidates in a **fixed priority sequence**. When you request a handler for a specific path, the factory checks each candidate in order until it finds a match:

1. **DOCX** (`DocxFileHandler`) – Matches `.docx` extensions
2. **PDF** (`PdfFileHandler`) – Matches `.pdf` extensions  
3. **Excel** (`ExcelFileHandler`) – Matches `.xlsx`, `.xls`, `.xlsm` extensions
4. **Image** (`ImageFileHandler`) – Matches image extensions (PNG, JPEG, GIF, WebP)
5. **Binary** (`BinaryFileHandler`) – Detects binary content via the `isBinaryFile` library
6. **Text** (`TextFileHandler`) – Default fallback for all remaining files

This hierarchy ensures specialized handlers capture their formats before the generic binary or text handlers process them.

### Extension-Based vs. Content-Based Detection

The factory employs two distinct detection strategies. **Extension-based handlers** (`DocxFileHandler`, `PdfFileHandler`, `ExcelFileHandler`, `ImageFileHandler`) expose a synchronous `canHandle(path)` method that performs simple string matching on file extensions.

**Content-based detection** handles ambiguous cases where extensions are missing or unreliable. The `BinaryFileHandler.canHandle()` method operates asynchronously, calling the third-party **`isBinaryFile`** library to inspect file headers and determine if content is binary rather than text. This check occurs in [`src/utils/files/binary.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/binary.ts) before the factory falls back to `TextFileHandler`.

## The FileHandler Interface Contract

All concrete handlers implement the common `FileHandler` interface defined in [`src/utils/files/base.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/base.ts). This contract ensures consistent behavior across file types while allowing specialized implementations.

The interface requires four core methods:

- **`canHandle(path: string): boolean | Promise<boolean>`** – Determines if the handler can process the given file
- **`read(path, options?)`** – Returns a `FileResult` containing content, MIME type, and optional metadata
- **`write(path, content, mode?)`** – Persists changes to the file system
- **`getInfo(path)`** – Returns a `FileInfo` object with size, timestamps, type, and handler-specific metadata

Each handler imports this base type (`import { FileHandler } from './base.js'`), ensuring type safety and polymorphic usage throughout the codebase.

## Specialized Handler Implementations

The architecture supports six distinct file processors, each optimized for specific format requirements:

### TextFileHandler

The `TextFileHandler` in [`src/utils/files/text.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/text.ts) manages plain-text files with full read/write capabilities and line-count metadata. This handler assumes the factory has already filtered out binary files, operating exclusively on text-encoded content.

### ImageFileHandler

`ImageFileHandler` processes PNG, JPEG, GIF, and WebP formats using the `sharp` image processing library. Like other extension-based handlers, it validates files by extension before attempting processing.

### BinaryFileHandler

When `isBinaryFile` detects binary content, `BinaryFileHandler` takes over. Rather than attempting to display binary data, this handler returns an instructional message directing users to invoke `start_process` with appropriate external tools. This safety mechanism prevents corrupting binary files or overwhelming the context window with encoded data.

### ExcelFileHandler

`ExcelFileHandler` manages spreadsheet formats (`.xlsx`, `.xls`, `.xlsm`) using the `exceljs` library. It provides structured access to cell data, worksheets, and formatting while abstracting the underlying Excel binary format complexity.

### PdfFileHandler

The PDF handler leverages `pdfjs-dist` to parse document structure and extract text or embedded images. It handles the asynchronous nature of PDF parsing while presenting a synchronous interface to the factory consumer.

### DocxFileHandler

`DocxFileHandler` provides the richest functionality among document processors. In addition to reading DOCX files, it generates document outlines, pretty-prints XML structures, and supports advanced editing via the `editRange()` method. This handler can perform find-and-replace operations within specific XML ranges, enabling surgical document modifications without rewriting entire files.

## Usage Flow and Code Examples

The factory exposes a clean async API that resolves the correct handler regardless of file type. Because `getFileHandler()` returns a **`Promise<FileHandler>`**, callers await resolution and then work with a uniform interface.

### Resolving and Reading Files

```typescript
import { getFileHandler } from './utils/files/factory';

async function preview(path: string) {
  const handler = await getFileHandler(path);
  const { content, mimeType } = await handler.read(path, { offset: 0, length: 20 });
  console.log(`MIME: ${mimeType}\n${content}`);
}

```

### Detecting Specific File Types

The factory exports predicate functions for type checking without full handler resolution:

```typescript
import { isImageFile, isExcelFile } from './utils/files/factory';

const path = '/tmp/report.xlsx';
if (isExcelFile(path)) {
  console.log('Excel file – will be processed by ExcelFileHandler');
}
if (isImageFile(path)) {
  console.log('Image file – will be processed by ImageFileHandler');
}

```

### Editing DOCX Documents

Advanced handlers like `DocxFileHandler` expose format-specific methods beyond the base interface:

```typescript
import { getFileHandler } from './utils/files/factory';

async function replaceInDocx(docxPath: string) {
  const handler = await getFileHandler(docxPath);   // resolves to DocxFileHandler
  const editResult = await handler.editRange(docxPath, '', {
    old_string: '<w:t>old text</w:t>',
    new_string: '<w:t>new text</w:t>',
    expected_replacements: 1,
  });
  console.log(editResult);
}

```

## Summary

- The **file handler factory** in [`src/utils/files/factory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/factory.ts) centralizes file type detection and handler instantiation using a singleton pattern with lazy initialization.
- Handler selection follows a strict priority order: DOCX → PDF → Excel → Image → Binary → Text, ensuring specialized processors take precedence over generic handlers.
- Detection strategies vary between **extension-based matching** (for known formats) and **content-based analysis** (using `isBinaryFile` for ambiguous files).
- All handlers implement the `FileHandler` interface from [`src/utils/files/base.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/base.ts), guaranteeing consistent `read()`, `write()`, `getInfo()`, and `canHandle()` methods.
- The architecture supports extensible, format-specific capabilities—such as `DocxFileHandler.editRange()`—while maintaining a uniform consumption API for the rest of the application.

## Frequently Asked Questions

### How does the factory decide which handler to use for a given file?

The `getFileHandler()` function evaluates candidates in a fixed priority sequence defined in [`src/utils/files/factory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/factory.ts). It first checks for document types (DOCX, PDF, Excel), then images, then performs binary content detection, and finally falls back to text. The first handler whose `canHandle()` method returns `true` wins.

### What is the difference between extension-based and content-based detection?

Extension-based handlers like `PdfFileHandler` and `ImageFileHandler` simply check file extensions (`.pdf`, `.png`) synchronously. Content-based detection occurs in `BinaryFileHandler.canHandle()`, which asynchronously calls the `isBinaryFile` library to inspect file headers when extensions are absent or unreliable.

### Can I extend the factory to support additional file formats?

Yes. Create a new handler class implementing the `FileHandler` interface from [`src/utils/files/base.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/base.ts), add a singleton getter in [`src/utils/files/factory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/factory.ts), and insert it into the priority chain within `getFileHandler()`. The factory's design accommodates new handlers without modifying existing code.

### Why does the BinaryFileHandler return instructions instead of file content?

`BinaryFileHandler` detects executable or encoded binary data that could corrupt the context window or be meaningless as text. Instead of returning raw bytes, it provides instructions to use `start_process` with external tools. This safety mechanism prevents accidental data corruption and keeps the AI assistant's context focused on processable information.