How the File Factory Pattern Works in Desktop Commander MCP

Desktop Commander MCP centralizes file-type detection through a singleton-based factory in src/utils/files/factory.ts that evaluates handlers in priority order—from DOCX to Text—to return the appropriate handler instance for any given file path.

Desktop Commander MCP implements a robust file factory pattern to decouple file-type detection from business logic across the application. This centralized approach eliminates scattered extension checks and ensures consistent handling whether you're editing documents through src/tools/edit.ts or managing filesystem operations in src/tools/filesystem.ts.

Singleton Handler Architecture

The factory maintains singleton instances of all concrete handlers to avoid unnecessary object creation. As defined in lines 17-55 of src/utils/files/factory.ts, the factory lazily instantiates one instance each of DocxFileHandler, PdfFileHandler, ExcelFileHandler, ImageFileHandler, BinaryFileHandler, and TextFileHandler, reusing these instances across the entire application lifecycle.

Each handler implements the abstract FileHandler interface defined in src/utils/files/base.ts, exposing standardized methods like read(), write(), and preview() while implementing type-specific logic internally.

Priority-Based Handler Resolution

When getFileHandler(filePath) is invoked, the factory evaluates candidates in a deterministic priority sequence (lines 65-72). The system checks handlers in this specific order:

  1. DOCX filesDocxFileHandler checks for .docx extensions
  2. PDF documentsPdfFileHandler validates .pdf extensions
  3. Excel spreadsheetsExcelFileHandler detects .xlsx, .xls, and .csv files
  4. Image filesImageFileHandler handles .png, .jpg, .gif, and other image formats
  5. Binary filesBinaryFileHandler performs content analysis
  6. Text filesTextFileHandler serves as the universal fallback

Extension-Based Detection

Most handlers expose a synchronous canHandle(path) method that performs simple string comparisons on file extensions. According to the source code, DocxFileHandler, PdfFileHandler, ExcelFileHandler, and ImageFileHandler all rely on extension-based detection for immediate classification without reading file contents.

Content-Based Binary Detection

The BinaryFileHandler operates differently from other handlers. Its canHandle(path) method is asynchronous because it executes isBinaryFile on the actual file contents (lines 97-100). This allows the factory to correctly identify binary files that lack standard extensions or have misleading names, ensuring accurate handling of executable data, compiled objects, or proprietary formats.

Text Fallback Strategy

If no specialized handler claims the file, the factory returns the TextFileHandler singleton (line 103). This fallback treats the file as plain text, enabling the application to attempt reading and editing operations on unknown file types rather than throwing errors.

Factory Implementation Details

The factory also exports convenience utilities for direct extension checking. Lines 112-124 expose isExcelFile(path) and isImageFile(path) helper functions that other modules can use for quick predicate checks without instantiating full handler objects.

import { getFileHandler, isExcelFile } from '@/utils/files';

// Check if a path represents an Excel file without getting a handler
if (isExcelFile('budget.xlsx')) {
  console.log('Spreadsheet detected');
}

// Get the appropriate handler for processing
async function processDocument(path: string) {
  const handler = await getFileHandler(path);
  
  // Handler type determines available operations
  const content = await handler.read();
  const metadata = await handler.preview?.();
  
  return { type: handler.constructor.name, content, metadata };
}

Practical Usage Examples

The file factory pattern enables polymorphic file operations throughout the codebase. The src/tools/edit.ts module imports getFileHandler to determine whether a file supports line-based editing or requires specialized handling, while src/tools/filesystem.ts uses the factory for generic read operations across diverse file types.

import { getFileHandler } from '@/utils/files';

async function demonstrateFactory() {
  // Each call returns the appropriate singleton handler
  const excel = await getFileHandler('data/report.xlsx');
  console.log(excel.constructor.name); // → ExcelFileHandler
  
  const image = await getFileHandler('assets/photo.png');
  console.log(image.constructor.name); // → ImageFileHandler
  
  const binary = await getFileHandler('temp/compiled.bin');
  console.log(binary.constructor.name); // → BinaryFileHandler
  
  const text = await getFileHandler('notes.txt');
  console.log(text.constructor.name); // → TextFileHandler
}

Summary

  • Centralized logic: All file-type detection resides in src/utils/files/factory.ts, preventing scattered if/else chains across the application.
  • Priority ordering: The factory evaluates DOCX → PDF → Excel → Image → Binary → Text to ensure specialized handlers capture their formats before generic fallbacks.
  • Hybrid detection: Combines fast extension-based checks with accurate content-based binary detection for robust file identification.
  • Singleton efficiency: Reuses handler instances via lazy initialization to minimize memory overhead and construction costs.
  • Universal interface: All handlers implement the FileHandler base contract from src/utils/files/base.ts, enabling polymorphic operations.

Frequently Asked Questions

What is the exact priority order for handler selection?

The factory evaluates handlers in this sequence: first DocxFileHandler, then PdfFileHandler, followed by ExcelFileHandler, ImageFileHandler, BinaryFileHandler, and finally TextFileHandler as the fallback. This ordering ensures that specialized document handlers capture files before the generic binary or text handlers process them.

How does the factory distinguish binary files from text files?

The BinaryFileHandler.canHandle() method performs an asynchronous content check using the isBinaryFile library on the file's actual bytes (lines 97-100). Unlike other handlers that check extensions, this content-based detection identifies binary data regardless of file extension, placing it late in the priority chain to avoid misclassifying structured formats like PDFs or images.

Why does the factory use singleton instances instead of creating new handlers?

The factory implements lazy initialization patterns (lines 17-55) to create one instance of each handler type and reuse it across all file operations. This design reduces memory allocation overhead and maintains consistent internal state, particularly important for handlers that may cache parsing configurations or maintain resource connections.

Which modules consume the file factory pattern?

The primary consumers include src/tools/edit.ts, which uses getFileHandler to determine editing capabilities, and src/tools/filesystem.ts, which relies on the factory for generic file reading operations. The factory's helper functions isExcelFile() and isImageFile() are also utilized throughout the codebase for quick type checks without full handler instantiation.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →