# Line Ending Handling in DesktopCommanderMCP: Cross-Platform File Editing Explained

> DesktopCommanderMCP preserves original line endings during edits to prevent cross-platform corruption and ensure accurate diff previews. Learn how.

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

---

**DesktopCommanderMCP preserves original line endings during AI-driven file edits to prevent cross-platform corruption, ensure accurate diff previews, and maintain token efficiency.**

DesktopCommanderMCP is a Model Context Protocol (MCP) server that enables large language models to read and modify files on the host filesystem. Because Windows, macOS, and Linux use different line ending conventions, robust **line ending handling** is essential to prevent silent file corruption and ensure edits apply cleanly regardless of the platform.

## Why Line Ending Handling Prevents File Corruption

When an AI model edits a file without respecting the original line ending characters (`\r\n`, `\n`, or `\r`), several critical problems emerge:

- **Cross-platform corruption** – Windows tools expect `\r\n` while Unix-based systems use `\n`. Changing these conventions can break scripts, configuration files, and source code compilation.

- **Incorrect diffs** – The edit preview shown in Claude Desktop compares old and new text. Mismatched line endings make the diff appear as if every line changed, obscuring the actual modification.

- **Mixed-ending contamination** – Some files intentionally contain mixed line endings. Without detection, edits can introduce a new style, turning a consistent file into an inconsistent one.

- **Token inefficiency** – The MCP server streams file content line-by-line. Preserving original endings allows the server to reuse the same line-ending tokenization, reducing unnecessary token consumption.

## How DesktopCommanderMCP Detects and Normalizes Line Endings

The implementation relies on a three-stage pipeline: detection, normalization, and preservation. This logic resides primarily in [`src/utils/lineEndingHandler.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/lineEndingHandler.ts) and is orchestrated by [`src/tools/edit.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/edit.ts).

### Detecting the Dominant Line Ending Style

The `detectLineEnding` function in [`src/utils/lineEndingHandler.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/lineEndingHandler.ts) scans the raw file string to identify the dominant convention.

```typescript
import { detectLineEnding } from './utils/lineEndingHandler.js';

const style = detectLineEnding(fileContent);
// Returns: '\r\n', '\n', or '\r'

```

If no line endings are detected, the function falls back to the host operating system’s default. This ensures that new files or single-line documents receive appropriate formatting.

### Normalizing Strings to Match File Conventions

Before performing any replacement, both the **search** and **replace** strings must match the file’s internal representation. The `normalizeLineEndings` function collapses all input to LF (`\n`) first, then rewrites the content to the target style.

```typescript
import { normalizeLineEndings } from './utils/lineEndingHandler.js';

const normalizedSearch = normalizeLineEndings(userSearch, fileLineEnding);
const normalizedReplace = normalizeLineEndings(userReplace, fileLineEnding);

```

This normalization guarantees that user input matches the file’s line ending style, enabling accurate string matching regardless of how the user typed the query.

### The Edit Flow Architecture

The complete edit workflow in [`src/tools/edit.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/edit.ts) implements line ending handling through five precise steps:

1. **Read raw file** – `readFileInternal` returns the file exactly as stored, preserving all line endings.
2. **Detect line ending** – `detectLineEnding(content)` yields the dominant style (`\r\n`, `\n`, or `\r`).
3. **Normalize user strings** – Both `search` and `replace` parameters are processed through `normalizeLineEndings` with the detected file style.
4. **Perform replacement** – The edit logic executes on normalized strings, ensuring matches succeed even with cross-platform input.
5. **Write back** – `writeFile` stores the modified content. Because the content derives from the original string (with only the targeted portion changed), the file’s line ending style remains consistent.

## Practical Implementation Examples

**Detecting a file’s line ending before editing:**

```typescript
import { detectLineEnding } from './utils/lineEndingHandler.js';
import { readFileInternal } from './tools/filesystem.js';

async function checkLineEndings(filePath: string) {
  const content = await readFileInternal(filePath, 0, Number.MAX_SAFE_INTEGER);
  const style = detectLineEnding(content as string);
  console.log(`File uses ${JSON.stringify(style)} line endings`);
}

```

**Preparing edit blocks with normalized line endings:**

```typescript
import { normalizeLineEndings } from './utils/lineEndingHandler.js';

function prepareEdit(
  search: string, 
  replace: string, 
  fileLineEnding: '\r\n' | '\n' | '\r'
) {
  return {
    normSearch: normalizeLineEndings(search, fileLineEnding),
    normReplace: normalizeLineEndings(replace, fileLineEnding)
  };
}

```

**Complete line-ending-aware edit operation:**

```typescript
import { readFileInternal, writeFile } from './tools/filesystem.js';
import { detectLineEnding, normalizeLineEndings } from './utils/lineEndingHandler.js';

async function editFile(
  filePath: string, 
  search: string, 
  replace: string
) {
  const raw = await readFileInternal(filePath, 0, Number.MAX_SAFE_INTEGER) as string;
  const lineEnding = detectLineEnding(raw);
  
  const normalizedSearch = normalizeLineEndings(search, lineEnding);
  const normalizedReplace = normalizeLineEndings(replace, lineEnding);
  
  const newContent = raw.split(normalizedSearch).join(normalizedReplace);
  await writeFile(filePath, newContent);
}

```

## Summary

- **Line ending handling** in DesktopCommanderMCP prevents cross-platform file corruption by preserving original `\r\n`, `\n`, or `\r` conventions.
- The `detectLineEnding` function in [`src/utils/lineEndingHandler.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/lineEndingHandler.ts) identifies the dominant style by scanning raw file content.
- `normalizeLineEndings` converts user input to match the file’s specific line ending format before performing edits.
- The edit workflow in [`src/tools/edit.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/edit.ts) reads raw content, detects line endings, normalizes search/replace strings, and writes back while maintaining consistency.
- This architecture ensures accurate diffs in Claude Desktop, supports mixed-ending files, and optimizes token usage during file streaming.

## Frequently Asked Questions

### What line ending styles does DesktopCommanderMCP support?

DesktopCommanderMCP supports all three standard line ending sequences: CRLF (`\r\n`) used by Windows, LF (`\n`) used by Unix/Linux and macOS, and legacy CR (`\r`) used by classic Mac OS. The `detectLineEnding` utility in [`src/utils/lineEndingHandler.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/lineEndingHandler.ts) recognizes each style and falls back to the host OS default when no line endings are present.

### How does DesktopCommanderMCP handle files with mixed line endings?

When a file contains mixed line endings, the `detectLineEnding` function identifies the dominant style based on frequency. The system then normalizes user input to match this dominant style, ensuring that edits do not introduce additional inconsistency. While the tool preserves the existing mixed state, it prevents further corruption by not converting the entire file to a single style during routine edits.

### Why does line ending handling affect diff previews in Claude Desktop?

Claude Desktop generates edit previews by comparing the original file content against the modified version. If line endings change during the edit process, the diff algorithm interprets every line as modified rather than just the intended changes. By preserving original line endings through the `normalizeLineEndings` workflow, DesktopCommanderMCP ensures that only actual content changes appear in the diff view.

### Where is the line ending detection logic located in the codebase?

The core utilities reside in [`src/utils/lineEndingHandler.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/lineEndingHandler.ts), which exports `detectLineEnding` and `normalizeLineEndings`. The orchestration logic that utilizes these utilities during file edits is implemented in [`src/tools/edit.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/edit.ts) at approximately line 57, where it coordinates with `readFileInternal` and `writeFile` from [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) to execute line-ending-aware modifications.