@mcp-logs/mcp-logger
v0.1.0
Published
Structured logging library for Model Context Protocol (MCP) applications
Maintainers
Readme
mcp-logger
Structured logging library for Model Context Protocol (MCP) 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
npm install @mcp-logs/mcp-loggerQuick Start
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:
{"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.
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:
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
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
import { generateTraceId, startTimer } from '@mcp-logs/mcp-logger';
const traceId = generateTraceId(); // 'm1abc-xyz123'
const timer = startTimer();
// ... do work ...
const elapsed = timer.elapsed(); // millisecondsSafe by Default
Redaction
Sensitive keys are automatically redacted (case-insensitive):
// 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:
createMCPLogger({ service: 'x', redact: ['ssn', 'creditCard'] });Truncation
Large strings are automatically truncated to prevent log bloat:
log.prompt({ content: 'A'.repeat(1000) });
// Logs first 500 chars + '…[truncated]'Disable truncation:
createMCPLogger({ service: 'x', truncate: false });TypeScript
Full type definitions are included. All payloads are strictly typed:
import type {
MCPLogger,
ChildLogger,
MCPLogEvent,
LogLevel,
MCPEventType,
PromptPayload,
ToolCallPayload,
// ... etc
} from '@mcp-logs/mcp-logger';License
MIT
