DesktopCommanderMCP File Handler Factory Architecture: Text, Binary, Image and Document Processing
DesktopCommanderMCP implements a centralized factory pattern in 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, the factory maintains private references to each handler type:
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:
- DOCX (
DocxFileHandler) – Matches.docxextensions - PDF (
PdfFileHandler) – Matches.pdfextensions - Excel (
ExcelFileHandler) – Matches.xlsx,.xls,.xlsmextensions - Image (
ImageFileHandler) – Matches image extensions (PNG, JPEG, GIF, WebP) - Binary (
BinaryFileHandler) – Detects binary content via theisBinaryFilelibrary - 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 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. 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 fileread(path, options?)– Returns aFileResultcontaining content, MIME type, and optional metadatawrite(path, content, mode?)– Persists changes to the file systemgetInfo(path)– Returns aFileInfoobject 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 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
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:
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:
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.tscentralizes 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
isBinaryFilefor ambiguous files). - All handlers implement the
FileHandlerinterface fromsrc/utils/files/base.ts, guaranteeing consistentread(),write(),getInfo(), andcanHandle()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. 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, add a singleton getter in 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.
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 →