# How to view MCP server logs for debugging

- Tool: MCP
- Difficulty: Beginner
- Time required: 5 min
- Compatibility: Claude Desktop, Cursor, all MCP servers
- Last updated: March 2026

## TL;DR

MCP server logs are captured from the server's stderr output by the host application. Claude Desktop on macOS stores them at ~/Library/Logs/Claude/mcp*.log, and on Windows at %APPDATA%\Claude\logs\. Cursor shows logs in the Output panel under the MCP channel. Use tail -n 20 -F ~/Library/Logs/Claude/mcp*.log to watch logs in real time while debugging connection or runtime errors.

## Viewing MCP Server Logs

When an MCP server fails to start, crashes during operation, or produces unexpected results, the logs are your primary debugging tool. MCP hosts capture everything the server writes to stderr and store it in log files. This tutorial shows you exactly where to find these logs on every platform and how to interpret them.

## Before you start

- An MCP host (Claude Desktop or Cursor) with at least one server configured
- Terminal access on your machine

## Step-by-step guide

### 1. Find Claude Desktop logs on macOS

Claude Desktop on macOS writes MCP server logs to the ~/Library/Logs/Claude/ directory. Each server gets its own log file named with a pattern like mcp-server-{name}.log or mcp*.log. These files contain everything the server writes to stderr, including startup messages, runtime errors, and debug information.

```
# List all MCP log files
ls -la ~/Library/Logs/Claude/mcp*.log

# View the last 20 lines of all MCP logs
tail -n 20 ~/Library/Logs/Claude/mcp*.log

# Watch logs in real time (most useful for debugging)
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log

# Search for errors in logs
grep -i error ~/Library/Logs/Claude/mcp*.log | tail -20
```

**Expected result:** You see the MCP server's stderr output including startup messages and any errors.

### 2. Find Claude Desktop logs on Windows

On Windows, Claude Desktop stores MCP logs in the %APPDATA%\Claude\logs\ directory. Open this folder in File Explorer or use PowerShell to read the log files. The file names follow the same pattern as macOS.

```
# PowerShell — list MCP log files
Get-ChildItem "$env:APPDATA\Claude\logs\mcp*"

# View last 20 lines
Get-Content -Tail 20 "$env:APPDATA\Claude\logs\mcp*.log"

# Watch in real time
Get-Content -Tail 20 -Wait "$env:APPDATA\Claude\logs\mcp*.log"

# Or open the folder in File Explorer
explorer "$env:APPDATA\Claude\logs"
```

**Expected result:** You can see MCP server log files on Windows and read their contents.

### 3. View MCP logs in Cursor

Cursor shows MCP server output in its Output panel. Open the Output panel with View > Output (or Cmd+Shift+U on macOS, Ctrl+Shift+U on Windows), then select 'MCP' or your specific server name from the dropdown in the top-right of the panel. This shows the server's stderr output in real time.

```
# Steps to view MCP logs in Cursor:
# 1. Open Output panel: View → Output (Cmd+Shift+U)
# 2. Click the dropdown in the top-right of the Output panel
# 3. Select 'MCP' or your specific server name
# 4. Logs appear in real time as the server runs

# You can also check the Developer Tools console:
# Help → Toggle Developer Tools → Console tab
# Filter for 'mcp' to see MCP-related messages
```

**Expected result:** Cursor's Output panel shows real-time MCP server logs.

### 4. Add useful logging to your own MCP server

When building your own MCP server, add structured logging that helps with debugging. Log server startup, tool call invocations (with timing), errors with full context, and environment variable status. Always use console.error (Node.js) or print(..., file=sys.stderr) (Python) since stdout is reserved for JSON-RPC protocol messages.

```
// Useful logging patterns for MCP servers

// Startup logging
console.error(`[${new Date().toISOString()}] Server starting...`);
console.error(`  Name: my-mcp-server`);
console.error(`  Version: 1.0.0`);
console.error(`  Node.js: ${process.version}`);
console.error(`  API_KEY: ${process.env.API_KEY ? "SET" : "MISSING"}`);

// Tool call logging (inside tool handler)
console.error(`[${new Date().toISOString()}] Tool call: search`);
console.error(`  Input: ${JSON.stringify(params)}`);
const startTime = Date.now();
// ... tool logic ...
console.error(`  Duration: ${Date.now() - startTime}ms`);

// Error logging
console.error(`[${new Date().toISOString()}] ERROR in tool 'search':`);
console.error(`  Message: ${error.message}`);
console.error(`  Stack: ${error.stack}`);
```

**Expected result:** Your server produces structured, timestamped log output that makes debugging straightforward.

### 5. Interpret common log patterns

Understanding what log entries mean speeds up debugging significantly. Startup errors usually indicate missing dependencies or environment variables. Connection errors point to transport issues. Tool execution errors show problems in your tool handler code. If you encounter persistent log patterns you cannot interpret, the RapidDev team has experience debugging complex MCP server configurations.

```
# Common log patterns and what they mean:

# GOOD — Server started successfully:
# "Server starting..."
# "API_KEY: SET"
# "MCP server connected and ready."

# BAD — Missing dependency:
# "Error: Cannot find module 'some-package'"
# Fix: npm install some-package

# BAD — Missing environment variable:
# "FATAL: API_KEY environment variable is required"
# Fix: Add API_KEY to your host config env block

# BAD — Port already in use (HTTP transport):
# "Error: listen EADDRINUSE :::3000"
# Fix: Kill the other process on port 3000 or use a different port

# BAD — Permission denied:
# "Error: EACCES: permission denied, open '/path/to/file'"
# Fix: Check file permissions or use a different path
```

**Expected result:** You can quickly identify the type of error from log patterns and know the appropriate fix.

## Complete code example

File: `src/well-logged-server.ts`

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

function log(level: string, message: string, meta?: Record<string, unknown>) {
  const timestamp = new Date().toISOString();
  const metaStr = meta ? ` ${JSON.stringify(meta)}` : "";
  console.error(`[${timestamp}] [${level}] ${message}${metaStr}`);
}

log("INFO", "Server starting", {
  name: "well-logged-server",
  version: "1.0.0",
  nodeVersion: process.version,
  apiKeySet: !!process.env.API_KEY,
});

const server = new McpServer({
  name: "well-logged-server",
  version: "1.0.0",
});

server.tool(
  "example",
  "An example tool with good logging",
  { input: z.string() },
  async ({ input }) => {
    const start = Date.now();
    log("INFO", "Tool called: example", { input });

    try {
      const result = input.toUpperCase();
      log("INFO", "Tool completed: example", {
        durationMs: Date.now() - start,
      });
      return { content: [{ type: "text", text: result }] };
    } catch (error) {
      log("ERROR", "Tool failed: example", {
        error: (error as Error).message,
        durationMs: Date.now() - start,
      });
      return {
        content: [{ type: "text", text: `Error: ${(error as Error).message}` }],
        isError: true,
      };
    }
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);
log("INFO", "Server connected and ready");
```

## Common mistakes

- **Looking for logs in the wrong location** — undefined Fix: macOS Claude Desktop: ~/Library/Logs/Claude/. Windows: %APPDATA%\Claude\logs\. Cursor: Output panel → MCP dropdown.
- **Not using real-time log tailing when debugging** — undefined Fix: Use tail -F to watch logs in real time. Start the tail before restarting the host so you catch startup errors.
- **Logging to stdout instead of stderr** — undefined Fix: Use console.error() in Node.js and print(..., file=sys.stderr) in Python. Stdout is reserved for JSON-RPC messages.
- **Not including timestamps in log messages** — undefined Fix: Add ISO timestamps to every log line. Without them, you cannot correlate events or measure timing.

## Best practices

- Use tail -n 20 -F ~/Library/Logs/Claude/mcp*.log during all debugging sessions
- Include timestamps, log levels, and context in every log message
- Log tool call names and durations to identify slow operations
- Log environment variable presence (not values) at startup for configuration verification
- Log errors with full stack traces for faster debugging
- Keep a terminal window open with log tailing while developing MCP servers

## Frequently asked questions

### Do MCP logs contain sensitive information?

They can, depending on what the server logs. Well-designed servers should never log full API keys, tokens, or user data. If your server handles sensitive information, review your logging code to ensure secrets are not exposed.

### How large do MCP log files get?

Log files grow continuously while the server runs. Claude Desktop typically rotates logs, but they can reach several megabytes during heavy use. Delete old log files periodically if disk space is a concern.

### Can I redirect MCP logs to a custom file?

Not through the host configuration. The host captures stderr and writes it to its own log location. However, your server can write to a custom log file in addition to stderr using a logging library with multiple transports.

### Why are my logs empty?

If the log files exist but are empty, the server may be crashing before it produces any output, or it may be writing all output to stdout (which goes to the protocol stream, not logs). Check that you are using console.error, not console.log.

### Can I view logs from a remote MCP server?

For remote servers using Streamable HTTP, logs are on the remote machine. Check your hosting platform's log viewer (Railway dashboard, Render dashboard, Vercel function logs). Stderr output from the server process appears in the platform's log stream.

---

Source: https://www.rapidevelopers.com/mcp-tutorial/how-to-view-mcp-server-logs
© RapidDev — https://www.rapidevelopers.com/mcp-tutorial/how-to-view-mcp-server-logs
