# How Desktop Commander MCP Implements Audit Logging for Tool Calls: Inside `claude_tool_call.log`

> Explore how Desktop Commander MCP implements audit logging for tool calls in claude_tool_call.log. Learn about structured JSON recording and automatic log rotation.

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

---

**Desktop Commander MCP records every AI tool invocation as structured JSON in `~/.claude-server-commander/claude_tool_call.log`, automatically rotating the file at 10 MiB to prevent unbounded growth.**

Desktop Commander MCP is a Model Context Protocol server that exposes system-level tools to Claude Desktop and other MCP clients. To provide transparency and security, the server implements comprehensive **audit logging for tool calls**, writing a detailed record of every operation to a local log file. Understanding this mechanism helps administrators monitor AI activity, debug issues, and maintain compliance.

## Where Audit Logs Are Configured and Stored

The log destination is defined in [`src/config.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config.ts). The constant `CONFIG_DIR` resolves to `~/.claude-server-commander`, and `TOOL_CALL_FILE` concatenates this path with the filename `claude_tool_call.log`.

```typescript
// src/config.ts
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');

```

This ensures the audit trail is stored in a consistent, user-specific location across macOS, Linux, and Windows systems.

## How Tool Calls Are Recorded

The actual write operation is handled by [`src/utils/toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/toolHistory.ts). Every request handler in `src/handlers/*` invokes the `logToolCall` function before executing the requested operation, creating an append-only stream of JSON Lines.

### Anatomy of a Log Entry

Each line is a self-contained JSON object containing:

- **ts**: ISO 8601 timestamp of the invocation
- **client**: Identifier for the MCP client (e.g., `claude-desktop`, `claude-code`)
- **tool**: The exact tool name being invoked (e.g., `read_file`, `execute_command`)
- **args**: The deserialized arguments object passed to the tool
- **result**: Status flag (`ok` or `error`)
- **error**: Optional error message when result is `error`

A successful call looks like this:

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

```

A failed permission denial appears as:

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

```

This structured format allows precise filtering using standard UNIX tools or JSON processors like `jq`.

## Automatic Log Rotation

To prevent the log from consuming excessive disk space, [`src/utils/toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/toolHistory.ts) implements automatic rotation. The logic, shared with [`src/utils/fuzzySearchLogger.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/fuzzySearchLogger.ts), checks the file size before each write.

When `claude_tool_call.log` exceeds **10 MiB**, the current file is renamed to `claude_tool_call.log.old`, and a fresh log file is started. Only one generation of backup is retained, meaning the `.old` file is overwritten during the next rotation cycle.

## Reading and Filtering Audit Logs

Because the log uses the **JSON Lines** format (one JSON object per line), you can stream-process it without loading the entire file into memory.

### Viewing Recent Activity

```bash

# Print the last 10 tool calls with pretty formatting

tail -n 10 ~/.claude-server-commander/claude_tool_call.log | jq .

```

### Filtering by Tool Name

```bash

# Show only file read operations

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

```

### Reconstructing Full History

If rotation has occurred, concatenate the current and archived logs to analyze a complete session:

```bash
cat ~/.claude-server-commander/claude_tool_call.log* | jq -s 'sort_by(.ts)' > full_audit.json

```

### Programmatic Access

You can also read the log from within Node.js scripts:

```typescript
import { readFileSync } from 'fs';
import { TOOL_CALL_FILE } from './src/config.js';

const entries = readFileSync(TOOL_CALL_FILE, 'utf8')
  .trim()
  .split('\n')
  .map(line => JSON.parse(line));

console.table(entries.slice(-5));

```

## Disabling Audit Logging

For privacy-sensitive environments or temporary debugging sessions, Desktop Commander respects the `DISABLE_AUDIT_LOG` environment variable. When set to any non-empty value, the server bypasses the `logToolCall` write entirely:

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

```

Note that disabling logs removes the audit trail and should only be used when the session activity does not require compliance tracking.

## Summary

- **Audit logging** is implemented in [`src/utils/toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/toolHistory.ts), which writes structured JSON to `~/.claude-server-commander/claude_tool_call.log` as defined in [`src/config.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config.ts).
- Each log entry captures the **timestamp**, **client identifier**, **tool name**, **arguments**, and **outcome** of the invocation.
- **Log rotation** occurs automatically when the file reaches 10 MiB, archiving the previous content to `.old`.
- The **JSON Lines** format enables efficient streaming analysis using tools like `jq`, `grep`, or custom Node.js scripts.
- Logging can be **disabled** via the `DISABLE_AUDIT_LOG` environment variable for privacy-sensitive use cases.

## Frequently Asked Questions

### What data is stored in each `claude_tool_call.log` entry?

Each entry is a JSON object containing an ISO timestamp (`ts`), the MCP client name (`client`), the specific tool invoked (`tool`), the full arguments object (`args`), and a result status (`result`). If the tool fails, an `error` field containing the error message is included. This provides a complete, tamper-evident record of what the AI requested and whether it succeeded.

### Where is the audit log file located on my system?

The log resides in your user's home directory under `.claude-server-commander/claude_tool_call.log`. The exact path is constructed in [`src/config.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config.ts) using `path.join(os.homedir(), '.claude-server-commander', 'claude_tool_call.log')`. On Windows, this resolves to `%USERPROFILE%\.claude-server-commander\claude_tool_call.log`.

### How do I prevent the log file from growing too large?

The server handles this automatically. When the log exceeds 10 MiB, [`src/utils/toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/toolHistory.ts) renames the current file to `claude_tool_call.log.old` and starts a fresh log. Only one backup generation is kept. If you need longer retention, you should configure a system-level log rotation daemon (like `logrotate` on Linux) to archive the `.old` file before it is overwritten.

### Can I disable audit logging entirely?

Yes. Set the environment variable `DISABLE_AUDIT_LOG` to any non-empty value before starting the server. This causes the `logToolCall` function in [`src/utils/toolHistory.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/toolHistory.ts) to skip writing entries, effectively running the server without an audit trail. Use this option with caution in production environments where tool call accountability is required.