How Desktop Commander MCP Tracks Recent Operations for Context Recovery
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 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:
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:
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:
- Creates a
ToolCallRecordwith the current timestamp - Pushes to the in-memory array (and evicts oldest if over limit)
- Appends a JSON-encoded line to disk via
fs.appendFileSync
// 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 (lines 1141-1146):
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) transforms raw records into human-readable JSON:
// 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. - Records are stored in
~/.claude-server-commander/tool-history.jsonlusing 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_callsendpoint enables clients to recover session context after chat transcript loss. - Error handling and formatting logic in
src/handlers/history-handlers.tsensures 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 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.
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 →