How Desktop Commander MCP Audit Logging Works: Inside `claude_tool_call.log`

Desktop Commander MCP writes a JSON audit record for every tool call to ~/.claude-server-commander/claude_tool_call.log, capturing timestamps, client identity, tool names, arguments, and outcomes—with automatic 10 MiB log rotation.

This audit system lets developers trace exactly what AI agents requested, when, and what happened. The implementation spans configuration constants, a dedicated logging utility, and integration points across all tool handlers.

Core Architecture: Three Components

Configuration Layer (src/config.ts)

The log file location is defined centrally in src/config.ts via TOOL_CALL_FILE. This constant joins CONFIG_DIR (set to ~/.claude-server-commander) with the filename claude_tool_call.log.

// src/config.ts – simplified excerpt
import path from 'path';
import os from 'os';

export const CONFIG_DIR = path.join(os.homedir(), '.claude-server-commander');
export const TOOL_CALL_FILE = path.join(CONFIG_DIR, 'claude_tool_call.log');

See src/config.ts#L6-L10 for the full definition.

Audit Recorder (src/utils/toolHistory.ts)

The logToolCall function in src/utils/toolHistory.ts is the heart of the audit system. Every tool handler imports and calls this function before executing its logic.

Captured fields per record:

  • ts – ISO-8601 timestamp from new Date().toISOString()
  • client – identifying string for the calling client (e.g., claude-desktop, claude-code)
  • tool – the toolId being invoked
  • args – serialized arguments object
  • result"ok" for success, or "error" with accompanying error message

Source: src/utils/toolHistory.ts

Log Rotation (src/utils/fuzzySearchLogger.ts)

To prevent unbounded growth, the logger enforces a 10 MiB size limit. When TOOL_CALL_FILE exceeds this threshold, it is renamed to claude_tool_call.log.old and a fresh file begins. This rotation logic is shared with other logging utilities in the codebase.

// src/utils/fuzzySearchLogger.ts – rotation logic excerpt
const MAX_LOG_SIZE = 10 * 1024 * 1024; // 10 MiB

if (currentSize > MAX_LOG_SIZE) {
  const oldPath = `${logPath}.old`;
  await rename(logPath, oldPath);
  // Continue writing to fresh file
}

Source: src/utils/fuzzySearchLogger.ts#L30-L36

Log Entry Format and Examples

Each tool call produces a single JSON line (newline-delimited JSON), enabling efficient streaming and command-line processing.

Successful tool call

{"ts":"2024-07-19T14:23:11.842Z","client":"claude-desktop","tool":"read_file","args":{"path":"~/projects/app/src/index.ts"},"result":"ok"}

Failed tool call with error details

{"ts":"2024-07-19T14:25:04.113Z","client":"claude-code","tool":"write_file","args":{"path":"/etc/passwd","content":"..."},"result":"error","error":"EACCES: permission denied"}

The newline-delimited format ensures compatibility with standard Unix tools: grep, jq, awk, and log aggregation pipelines.

Working with Audit Logs: Practical Examples

Read recent entries programmatically

import { readFileSync } from 'fs';
import { join } from 'path';
import os from 'os';

const logPath = join(os.homedir(), '.claude-server-commander', 'claude_tool_call.log');

const recent = readFileSync(logPath, 'utf8')
  .trim()
  .split('\n')
  .slice(-10)
  .map(line => JSON.parse(line));

console.table(recent.map(r => ({ tool: r.tool, client: r.client, result: r.result })));

Filter for specific tool usage with jq


# All read_file calls, pretty-printed

jq 'select(.tool == "read_file")' ~/.claude-server-commander/claude_tool_call.log

# Count errors by tool

jq -r 'select(.result == "error") | .tool' ~/.claude-server-commander/claude_tool_call.log | sort | uniq -c

Combine current and rotated logs for full history

cat ~/.claude-server-commander/claude_tool_call.log* > full_audit.jsonl
jq '.' full_audit.jsonl | less

Disable audit logging for sensitive sessions

Set DISABLE_AUDIT_LOG to any non-empty value to skip logToolCall writes entirely:

DISABLE_AUDIT_LOG=1 npx @wonderwhy-er/desktop-commander@latest setup

Integration Across Tool Handlers

Every handler in src/handlers/ imports logToolCall and invokes it at entry. For example, terminal-related handlers in terminal-handlers.ts call the logger before spawning processes or executing shell commands.

See src/handlers/terminal-handlers.ts for representative usage patterns.

Summary

  • Log location: ~/.claude-server-commander/claude_tool_call.log (defined in src/config.ts)
  • Log format: Newline-delimited JSON with ts, client, tool, args, and result fields
  • Rotation trigger: 10 MiB file size, archived to .old suffix
  • Core implementation: src/utils/toolHistory.ts with shared rotation from src/utils/fuzzySearchLogger.ts
  • Opt-out: Set DISABLE_AUDIT_LOG environment variable

Frequently Asked Questions

What happens when claude_tool_call.log reaches 10 MiB?

The current file is renamed to claude_tool_call.log.old and a new empty log begins. Only one archived generation is kept—older .old files are overwritten on subsequent rotations.

Can I change the audit log directory or filename?

Not without modifying the source. The path is hardcoded in src/config.ts as TOOL_CALL_FILE. To relocate logs, fork the repository and adjust the CONFIG_DIR or TOOL_CALL_FILE constants.

Does the audit log capture the full output of tool executions?

No. The audit log records arguments provided and success/failure status, not the complete stdout/stderr or return values. For full execution transcripts, inspect individual tool implementations or enable additional debugging at the client level.

How do I search audit logs for a specific time range?

Use jq with date filtering on the ts field:

jq 'select(.ts >= "2024-07-19T10:00:00Z" and .ts < "2024-07-19T15:00:00Z")' \
  ~/.claude-server-commander/claude_tool_call.log

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →