# How Desktop Commander MCP Tracks Recent Operations for Context Recovery

> Desktop Commander MCP records tool invocations in a size-limited queue and JSON-Lines file. Recover your session context with this history tracking feature.

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

---

**Desktop Commander MCP uses a size-limited in-memory queue backed by a JSON-Lines file to record every tool invocation, enabling users to recover their session context after a lost chat transcript.**

The **tool history system** in Desktop Commander MCP maintains a durable, queryable log of recent operations. This subsystem lives primarily in [`src/utils/toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/toolHistory.ts) and exposes its data through a dedicated API, allowing clients to rebuild state even when the original conversation context is lost.

## Core Architecture of the Tool History System

### In-Memory Record Queue

At runtime, the history manager maintains a private array that stores recent tool calls:

```typescript
private history: ToolCallRecord[] = [];  // toolHistory.ts#L33

```

Each entry is a `ToolCallRecord` containing **timestamp**, **tool name**, **arguments**, and **output**. The queue enforces a ceiling defined by `MAX_ENTRIES`; when exceeded, the oldest record is dropped via `this.history.shift()` (toolHistory.ts#L286).

### Persistent JSON-Lines Storage

To survive process restarts, records are written to a per-user file:

```typescript
const historyDir = path.join(os.homedir(), '.claude-server-commander');  // toolHistory.ts#L65
if (!fs.existsSync(historyDir)) {
  fs.mkdirSync(historyDir, { recursive: true });
}
this.historyFile = path.join(historyDir, 'tool-history.jsonl');  // toolHistory.ts#L74

```

On instantiation, the constructor loads existing entries using `fs.readFileSync` (toolHistory.ts#L76-L84) and trims the dataset to respect `MAX_STORED_OUTPUT_BYTES` (toolHistory.ts#L263).

## How Records Are Added and Maintained

### Appending New Tool Calls

When a tool completes, `addToolCall()` performs three operations:

1. Creates a `ToolCallRecord` with the current timestamp
2. Pushes to the in-memory array (and evicts oldest if over limit)
3. Appends a JSON-encoded line to disk via `fs.appendFileSync`

```typescript
// src/utils/toolHistory.ts#L230-L240 (excerpt)
public addToolCall(name: string, args: any, output: string) {
  const record: ToolCallRecord = {
    timestamp: Date.now(),
    name,
    args,
    output: output.length > this.MAX_STORED_OUTPUT_BYTES
      ? `[output omitted from history: ${output.length}, over the ${this.MAX_STORED_OUTPUT_BYTES}-byte cap]`
      : output,
  };
  this.history.push(record);
  if (this.history.length > this.MAX_ENTRIES) this.history.shift();
  fs.appendFileSync(this.historyFile, JSON.stringify(record) + '\n');
}

```

### Automatic Log Trimming

The system monitors file size using `fs.statSync` (toolHistory.ts#L140-L152). When the on-disk log exceeds the byte limit, it rewrites the file containing only the most recent `MAX_ENTRIES` records via `fs.writeFileSync` (toolHistory.ts#L187-L191).

## Querying Recent Operations

### Server Endpoint for Context Recovery

The Desktop Commander MCP server exposes recent history through a dedicated route in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) (lines 1141-1146):

```typescript
app.get('/get_recent_tool_calls', async (req, res) => {
  try {
    const calls = await toolHistory.getRecentCalls();
    res.json({
      totalEntries: calls.length,
      oldestEntry: calls[0]?.timestamp,
      newestEntry: calls[calls.length - 1]?.timestamp,
      historyFile: this.historyFile,
      calls
    });
  } catch (e) {
    res.status(500).json({ error: `Failed to get tool call history: ${e.message}` });
  }
});

```

### Formatting for Client Consumption

The **history-handlers** module ([`src/handlers/history-handlers.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/handlers/history-handlers.ts)) transforms raw records into human-readable JSON:

```typescript
// src/handlers/history-handlers.ts#L34-L39
const formattedHistory = JSON.stringify(recentCalls, null, 2);
return {
  content: [{
    type: "text",
    text: `## Recent Tool Calls\n\`\`\`json\n${formattedHistory}\n\`\`\``

  }]
};

```

Errors during file reads are caught and surfaced with descriptive messages (`Error getting tool history…`, history-handlers.ts#L46-L48).

## How Context Recovery Works

When a chat transcript is lost—for example, after a browser refresh—the client can request the recent tool-call dump from the server. By replaying the stored **tool name**, **arguments**, and **output**, the UI reconstructs the last several actions without requiring the original conversation history.

| Component | Responsibility | Key Location |
|-----------|---------------|--------------|
| In-memory queue | Fast runtime access to recent calls | `toolHistory.ts#L33` |
| JSON-Lines persistence | Durability across restarts | `~/.claude-server-commander/tool-history.jsonl` |
| Size-based trimming | Prevents unbounded growth | `toolHistory.ts#L140-L191` |
| HTTP endpoint | Exposes data for context recovery | `server.ts#L1141-L1150` |
| Handler formatting | Pretty-prints for UI display | `history-handlers.ts#L34-L39` |

## Summary

- **Desktop Commander MCP** implements **tool history tracking** through a hybrid memory-disk architecture in [`src/utils/toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/toolHistory.ts).
- Records are stored in `~/.claude-server-commander/tool-history.jsonl` using the JSON-Lines format for append-only efficiency.
- **Automatic size limits** protect against unbounded growth through both entry count (`MAX_ENTRIES`) and byte size (`MAX_STORED_OUTPUT_BYTES`) thresholds.
- The **`/get_recent_tool_calls`** endpoint enables clients to recover session context after chat transcript loss.
- Error handling and formatting logic in [`src/handlers/history-handlers.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/handlers/history-handlers.ts) ensures reliable delivery to the UI.

## Frequently Asked Questions

### What format is used to store tool history entries?

Desktop Commander MCP uses **JSON-Lines** (`.jsonl`), where each line is an independent JSON object representing one `ToolCallRecord`. This format allows efficient append operations without rewriting the entire file on every tool invocation.

### How does the system prevent the history file from growing indefinitely?

Two mechanisms enforce limits: an in-memory ceiling (`MAX_ENTRIES`) drops oldest records when exceeded, and a byte-size check (`MAX_STORED_OUTPUT_BYTES`) triggers periodic file rewrites containing only recent entries. Output text itself is truncated if it exceeds the per-record byte cap.

### Can I retrieve tool history after restarting the Desktop Commander MCP server?

Yes. The constructor in [`toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/toolHistory.ts) automatically loads any existing `tool-history.jsonl` file from `~/.claude-server-commander/` on startup (lines 76-84), restoring the previous session's recent operations into memory.

### What happens if the history file becomes corrupted?

The `getRecentCalls()` method and history handlers wrap file operations in try-catch blocks. Errors are captured and returned with descriptive messages like `Error getting tool history`, preventing server crashes while alerting the client to the failure condition.