npm package: @mcp-logs/mcp-logger
Description: Structured logging library for Model Context Protocol (MCP) applications
Latest version: 0.1.0

# mcp-logger

Structured logging library for [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) applications.

## Why?

MCP applications involve complex request flows: prompts, model calls, tool executions, and error handling. Traditional logging produces noisy, unstructured output that's hard to trace and analyze.

**mcp-logger** provides:

- **Structured JSON logs** optimized for observability pipelines
- **Trace ID propagation** to correlate events across a request lifecycle
- **MCP-aware events** for prompts, model requests/responses, tool calls/results, and errors
- **Safe-by-default behavior** with automatic redaction of sensitive keys and truncation of large payloads
- **Zero dependencies** — just TypeScript

## Installation

```bash
npm install @mcp-logs/mcp-logger
```

## Quick Start

```typescript
import { createMCPLogger } from '@mcp-logs/mcp-logger';

const logger = createMCPLogger({ service: 'my-mcp-server' });

// Start a traced request (auto-generates traceId)
const { traceId, log } = logger.startRequest('User query');

// Log MCP events with automatic trace correlation
log.prompt({ content: 'What is the weather in NYC?' });

log.toolCall({ tool: 'get_weather', input: { city: 'NYC' } });

const timer = log.timer();
// ... execute tool ...
log.toolResult({ tool: 'get_weather', output: '72°F, sunny', durationMs: timer.elapsed() });

log.modelResponse({
  model: 'claude-3',
  content: 'The weather in NYC is 72°F and sunny.',
  tokens: { prompt: 50, completion: 20 },
});

log.complete({ durationMs: timer.elapsed() });
```

## Example Output

Each log is a single JSON line, ideal for log aggregation:

```json
{"timestamp":"2025-01-27T10:30:00.000Z","level":"info","service":"my-mcp-server","event":"request.start","traceId":"m1abc-xyz123"}
{"timestamp":"2025-01-27T10:30:00.010Z","level":"info","service":"my-mcp-server","event":"prompt.received","traceId":"m1abc-xyz123","data":{"content":"What is the weather in NYC?"}}
{"timestamp":"2025-01-27T10:30:00.020Z","level":"info","service":"my-mcp-server","event":"tool.call","traceId":"m1abc-xyz123","data":{"tool":"get_weather","input":{"city":"NYC"}}}
{"timestamp":"2025-01-27T10:30:00.150Z","level":"info","service":"my-mcp-server","event":"tool.result","traceId":"m1abc-xyz123","durationMs":130,"data":{"tool":"get_weather","output":"72°F, sunny"}}
{"timestamp":"2025-01-27T10:30:00.200Z","level":"info","service":"my-mcp-server","event":"request.complete","traceId":"m1abc-xyz123","durationMs":200}
```

## API

### `createMCPLogger(options)`

Creates a logger instance.

```typescript
const logger = createMCPLogger({
  service: 'my-service',        // Required: service name in logs
  level: 'info',                // Optional: 'debug' | 'info' | 'warn' | 'error' (default: 'info')
  redact: ['apiKey', 'secret'], // Optional: keys to redact (default: common sensitive keys)
  truncate: {                   // Optional: truncation limits (set to false to disable)
    prompt: 500,                // default: 500
    response: 1000,             // default: 1000
    toolOutput: 500,            // default: 500
  },
  allowFullPrompts: false,      // Optional: bypass prompt truncation (default: false)
  transport: new ConsoleTransport(), // Optional: custom transport
});
```

### Logger Methods

| Method | Level | Description |
|--------|-------|-------------|
| `startRequest(message?)` | info | Start a new traced request, returns `{ traceId, log }` |
| `prompt({ content })` | info | Log received prompt |
| `modelRequest({ model, messages })` | debug | Log outgoing model request |
| `modelResponse({ model, content, tokens?, durationMs? })` | info | Log model response |
| `toolCall({ tool, input? })` | info | Log tool invocation |
| `toolResult({ tool, output?, durationMs? })` | info | Log tool result |
| `toolError({ tool, error, input? })` | error | Log tool execution error |
| `error({ error, scope? })` | error | Log request-level error |
| `requestComplete(traceId, { message?, durationMs? })` | info | Log request completion |

### Child Logger

The `startRequest()` method returns a child logger with the traceId pre-bound:

```typescript
const { traceId, log } = logger.startRequest();

log.traceId;           // Access the bound traceId
log.prompt({ ... });   // All methods auto-include traceId
log.timer();           // Create a timer for duration tracking
log.complete({ durationMs: timer.elapsed() });
```

### Transports

```typescript
import { ConsoleTransport, PrettyTransport, NoopTransport } from '@mcp-logs/mcp-logger';

// JSON output (default) — for production
new ConsoleTransport()

// Colored, human-readable — for development
new PrettyTransport()

// Disable logging entirely
new NoopTransport()
```

### Utilities

```typescript
import { generateTraceId, startTimer } from '@mcp-logs/mcp-logger';

const traceId = generateTraceId(); // 'm1abc-xyz123'

const timer = startTimer();
// ... do work ...
const elapsed = timer.elapsed(); // milliseconds
```

## Safe by Default

### Redaction

Sensitive keys are automatically redacted (case-insensitive):

```typescript
// Default redacted keys:
// password, secret, token, apiKey, api_key, authorization, credential, private_key, privateKey

log.toolCall({ tool: 'auth', input: { user: 'bob', password: 'secret123' } });
// Logs: { input: { user: 'bob', password: '[REDACTED]' } }
```

Override with your own list:

```typescript
createMCPLogger({ service: 'x', redact: ['ssn', 'creditCard'] });
```

### Truncation

Large strings are automatically truncated to prevent log bloat:

```typescript
log.prompt({ content: 'A'.repeat(1000) });
// Logs first 500 chars + '…[truncated]'
```

Disable truncation:

```typescript
createMCPLogger({ service: 'x', truncate: false });
```

## TypeScript

Full type definitions are included. All payloads are strictly typed:

```typescript
import type {
  MCPLogger,
  ChildLogger,
  MCPLogEvent,
  LogLevel,
  MCPEventType,
  PromptPayload,
  ToolCallPayload,
  // ... etc
} from '@mcp-logs/mcp-logger';
```

## License

MIT