# How DesktopCommanderMCP Stores and Retrieves Recent Tool Calls: JSON-Lines Architecture Explained

> Discover how DesktopCommanderMCP stores and retrieves recent tool calls using its JSON-Lines architecture. Learn about its efficient append-only file system and filtered retrieval.

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

---

**DesktopCommanderMCP maintains a per-user, append-only JSON-Lines file at `~/.claude-server-commander/tool-history.jsonl` that caps memory at 1000 entries and disk usage at approximately 5 MiB while providing filtered retrieval via the `ToolHistory` class.**

DesktopCommanderMCP, an open-source Model Context Protocol (MCP) server for desktop automation, implements a robust tool history system to track every invocation for debugging and auditing. The system uses a bounded, append-only storage mechanism that balances durability with strict resource constraints, ensuring that long-running sessions do not exhaust disk or memory.

## Storage Architecture and File Location

The history system persists data in a hidden directory within the user's home folder, using a format that supports atomic appends and easy truncation.

### The JSON-Lines Persistence Layer

All tool invocations are recorded in **`tool-history.jsonl`**, a JSON-Lines file where each line represents a single `ToolCallRecord`. This format allows the system to append new entries without rewriting the entire file, and enables efficient tail-reading when trimming old data. The file resides in:

```text
~/.claude-server-commander/

```

### Bounded Resource Guarantees

The implementation enforces hard limits to prevent resource exhaustion:

- **Memory bound**: Only the most recent **1000** entries are retained in RAM
- **Disk bound**: The JSON-Lines file never exceeds approximately **5 MiB**; older lines are discarded when the threshold is crossed
- **Output capping**: Individual entry outputs are truncated to **4 KiB** to prevent runaway JSON size

## Core Implementation in src/utils/toolHistory.ts

The **`ToolHistory`** class in [`src/utils/toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/toolHistory.ts) manages the entire lifecycle of history records, from initial load to batched disk writes.

### Initialization and Memory Management

When the application starts, the constructor performs three critical operations:

1. Creates the `~/.claude-server-commander/` directory if it does not exist
2. Loads existing records from `tool-history.jsonl` into memory
3. Starts an asynchronous write processor to batch disk operations

This initialization ensures that history persists across server restarts while maintaining the 1000-entry memory ceiling.

### Recording Tool Calls with addCall

The **`addCall(toolName, args, output, duration?)`** method creates a `ToolCallRecord` and stages it for persistence. The method implements several safety mechanisms:

```typescript
import { toolHistory } from './utils/toolHistory';

async function executeTool() {
  const result = await performOperation();
  // Records the call with automatic output capping
  toolHistory.addCall('file_search', { pattern: '*.ts' }, result, 145);
}

```

Before queuing, the method invokes **`capOutput`** to truncate any output exceeding 4 KiB, replacing oversized content with a placeholder message. The record is then pushed onto the in-memory array and queued for the next batch write.

### Asynchronous Disk Persistence

Rather than writing on every call, the system uses **`startWriteProcessor`** to manage a periodic timer that flushes queued records via **`flushToDisk`**. This batching strategy reduces I/O overhead during high-frequency tool usage.

### Automatic File Trimming

When the write processor detects that the file has grown past the 5 MiB threshold, **`trimHistoryFileIfTooLarge`** rewrites only the most recent tail of the file before appending new entries. This operation preserves the newest history while reclaiming disk space from obsolete records.

## Retrieving Recent Tool Calls

The history system provides two primary APIs for accessing stored invocations, both supporting optional filtering by tool name or timestamp.

### Querying with getRecentCalls

The **`getRecentCalls({ maxResults, toolName, since })`** method returns the last N entries (default 50, maximum 1000) from the in-memory buffer. The method signature supports precise filtering:

```typescript
const recent = toolHistory.getRecentCalls({
  maxResults: 20,                    // Return up to 20 entries
  toolName: 'execute_command',       // Filter by specific tool
  since: '2026-08-01T00:00:00Z'     // Only entries after this timestamp
});

```

This approach returns raw `ToolCallRecord` objects containing the tool name, arguments, truncated output, duration, and ISO timestamp.

### Formatted Output via getRecentCallsFormatted

For display purposes, **`getRecentCallsFormatted`** maps raw timestamps to localized strings using **`formatLocalTimestamp`**, converting UTC storage times to the user's local timezone:

```typescript
const formatted = toolHistory.getRecentCallsFormatted({ maxResults: 10 });

formatted.forEach(record => {
  console.log(`${record.timestamp} – ${record.toolName}`);
  console.log(`Duration: ${record.duration}ms`);
  console.log(record.output);
});

```

## RPC Exposure Through history-handlers.ts

The history functionality is exposed to clients via an HTTP/WebSocket handler defined in **[`src/handlers/history-handlers.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/handlers/history-handlers.ts)**. This handler registers the **`get_recent_tool_calls`** RPC endpoint, which maps incoming requests to the `ToolHistory` retrieval methods.

All server instances share the same `~/.claude-server-commander/tool-history.jsonl` file, ensuring a consistent view of recent activity even when multiple clients connect to different server processes. The handler serializes the filtered results and transmits them over the established transport connection.

## Safety Bounds and Performance Characteristics

The DesktopCommanderMCP tool history system is designed for production reliability with three critical safeguards:

- **Atomic appends**: JSON-Lines format allows safe concurrent writes from multiple processes
- **Graceful degradation**: When output exceeds 4 KiB, the system stores a truncation notice rather than failing
- **Automatic cleanup**: The 5 MiB disk limit ensures that logging never fills the user's home directory, even during extended debugging sessions

These constraints make the history system suitable for long-running desktop automation workflows without manual maintenance.

## Summary

- DesktopCommanderMCP stores tool history in **`~/.claude-server-commander/tool-history.jsonl`** using an append-only JSON-Lines format
- The **`ToolHistory`** class in [`src/utils/toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/toolHistory.ts) caps memory usage at **1000 entries** and disk usage at **~5 MiB**
- The **`addCall`** method automatically truncates outputs exceeding **4 KiB** before staging for disk writes
- **Batched writes** via `flushToDisk` minimize I/O overhead while `trimHistoryFileIfTooLarge` prevents unbounded growth
- Retrieval methods **`getRecentCalls`** and **`getRecentCallsFormatted`** support filtering by tool name, timestamp, and result count
- The **`get_recent_tool_calls`** RPC in [`src/handlers/history-handlers.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/handlers/history-handlers.ts) exposes history to remote clients over shared storage

## Frequently Asked Questions

### How does DesktopCommanderMCP prevent the tool history file from growing indefinitely?

The system implements a **5 MiB size cap** enforced by the `trimHistoryFileIfTooLarge` method in [`src/utils/toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/toolHistory.ts). When the JSON-Lines file exceeds this threshold during a write operation, the system reads only the most recent tail of the file, discards older entries, and rewrites the truncated content before appending new records. This ensures that long-running sessions cannot exhaust disk space.

### What happens when a tool returns output larger than 4 KiB?

The `capOutput` helper function truncates any output exceeding **4096 bytes** and replaces the excess with a placeholder message indicating truncation. This prevents individual `ToolCallRecord` entries from becoming bloated, ensuring that the in-memory array of 1000 entries and the JSON-Lines file remain within their bounded size limits.

### Can I query tool history for a specific time range or tool name?

Yes. The `getRecentCalls` method accepts optional parameters for **`toolName`** and **`since`** (ISO timestamp), allowing you to filter results to specific tools or time periods. The method returns entries from the in-memory buffer, which contains the most recent 1000 calls, defaulting to 50 results if no limit is specified.

### Is the tool history shared between multiple DesktopCommanderMCP server instances?

Yes. Because all instances read from and write to the same **`~/.claude-server-commander/tool-history.jsonl`** file, multiple server processes maintain a consistent view of recent activity. The JSON-Lines format supports atomic appends, making it safe for concurrent access from different server instances or client connections.