# MCP Audit Logging Format and Tool Call Log Storage Location in DesktopCommanderMCP

> Discover the MCP audit logging format and tool call log storage location at claude_tool_call.log. Learn about pipe-delimited logs with ISO timestamps and JSON arguments in DesktopCommanderMCP.

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

---

**DesktopCommanderMCP records every tool invocation to a structured plain‑text audit log located at `claude_tool_call.log` in the configuration directory, using a pipe‑delimited format with ISO timestamps and JSON‑encoded arguments.**

DesktopCommanderMCP is a Model Context Protocol (MCP) server that exposes desktop automation tools to AI assistants. Understanding the **MCP audit logging format and tool call log storage location** is essential for debugging tool executions, auditing system usage, and maintaining compliance records.

## Audit Log Entry Format

The audit log entry is constructed in [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/trackTools.ts) using a template literal that concatenates standardized components into a single line per tool invocation.

### Timestamp and Tool Name Structure

Each entry begins with an ISO 8601 timestamp generated by `new Date().toISOString()`, followed by a space, a pipe character, and a space. The tool name is then left‑justified to exactly 20 characters using `padEnd(20, ' ')` to ensure consistent column alignment.

### Arguments Serialization

If arguments are provided, the entry appends a tab character (`\t`), the literal string `| Arguments:`, and the JSON‑serialized argument object via `JSON.stringify(args)`. When no arguments exist, the entry terminates after the padded tool name without additional fields.

Example log line:

```typescript
2026-07-12T14:23:45.678Z | claude               | Arguments: {"prompt":"Explain quantum entanglement"}

```

## Log File Storage Location and Rotation

The physical storage location and rotation logic are defined in [`src/config.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config.ts) and enforced by the tracking utility.

### Configuration Directory Path

`TOOL_CALL_FILE` is exported from [`src/config.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config.ts) as `path.join(CONFIG_DIR, 'claude_tool_call.log')`. The `CONFIG_DIR` variable typically resolves to `~/.claude-server-commander-logs` (or the platform‑equivalent user configuration directory), resulting in a full absolute path such as `/home/user/.claude-server-commander-logs/claude_tool_call.log`.

### Automatic Log Rotation

The system implements size‑based rotation using the constant `TOOL_CALL_FILE_MAX_SIZE` (set to 10 MiB). When the current log file exceeds this limit, the implementation renames the existing file with a millisecond timestamp suffix (e.g., `claude_tool_call.log.1720789425000.old`) and creates a fresh log file to continue recording.

## Practical Code Examples

The following excerpt demonstrates how a log entry is constructed and appended according to the source implementation:

```typescript
// Implementation pattern from src/utils/trackTools.ts
const timestamp = new Date().toISOString();
const toolName = 'claude'.padEnd(20, ' ');
const args = { prompt: "Explain quantum entanglement" };

const logEntry = `${timestamp} | ${toolName}${args ? `\t| Arguments: ${JSON.stringify(args)}` : ''}\n`;

// Append to the file defined in src/config.ts
await fs.promises.appendFile(TOOL_CALL_FILE, logEntry, 'utf8');

```

To parse existing audit logs programmatically:

```typescript
import { readFile } from 'fs/promises';
import { TOOL_CALL_FILE } from './src/config.ts';

const logContent = await readFile(TOOL_CALL_FILE, 'utf8');
const lines = logContent.trim().split('\n');

const entries = lines.map(line => {
  const [head, argsPart] = line.split('\t| ');
  const [timestamp, tool] = head.split(' | ');
  return {
    timestamp,
    tool: tool.trim(),
    args: argsPart ? JSON.parse(argsPart.replace('Arguments: ', '')) : null
  };
});

```

## Summary

- **Log Location:** DesktopCommanderMCP writes audit logs to `claude_tool_call.log` inside the user‑specific configuration directory (`~/.claude-server-commander-logs`), as defined in [`src/config.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config.ts).
- **Entry Format:** Each line follows the pattern `<ISO-timestamp> | <20‑char‑padded‑tool‑name>` followed by an optional `\t| Arguments: <JSON>` segment, implemented in [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/trackTools.ts).
- **Rotation:** Logs rotate automatically when they exceed 10 MiB (`TOOL_CALL_FILE_MAX_SIZE`), preserving the old file with a timestamp suffix.
- **Encoding:** All text is UTF‑8, with arguments serialized via standard `JSON.stringify` for reliable parsing.

## Frequently Asked Questions

### Where does DesktopCommanderMCP store tool call logs?

According to [`src/config.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/config.ts), tool call logs are stored in a file named `claude_tool_call.log` located within the `CONFIG_DIR` directory. This directory typically resolves to `~/.claude-server-commander-logs` on Unix‑like systems and the equivalent user configuration path on Windows.

### What is the exact format of each log entry?

Each log entry consists of an ISO 8601 timestamp, a pipe delimiter, and a tool name padded to 20 characters. If arguments are present, a tab character and the literal string `Arguments:` followed by JSON‑serialized data are appended. The construction logic in [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/trackTools.ts) uses the template: `${timestamp} | ${toolName.padEnd(20)}${args ? \t| Arguments: ${JSON.stringify(args)} : ''}`.

### Does the log file rotate automatically?

Yes. As implemented in the tracking utility, when `claude_tool_call.log` exceeds the `TOOL_CALL_FILE_MAX_SIZE` threshold (10 MiB), the file is renamed with a millisecond timestamp suffix and a new empty log file is created to continue recording subsequent tool calls.

### How can I parse the audit log programmatically?

Read the file as UTF‑8 text, split by newlines, then split each line on the tab‑delimited `| ` boundary. The first segment contains the timestamp and tool name (split by ` | `), while the optional second segment contains the JSON arguments prefixed by `Arguments: `. Use `JSON.parse()` to deserialize the arguments object.