MCP Hub
Back to servers

@alcyone-labs/simple-mcp-logger

Requires Setup

A specialized logging utility for MCP servers that prevents console output from corrupting protocol communication by automatically suppressing STDOUT while allowing safe STDERR debugging.

Updated
Jul 25, 2025
Validated
Jan 9, 2026

Quick Install

npx -y @alcyone-labs/simple-mcp-logger

SimpleMcpLogger

The logging solution for MCP (Model Context Protocol) servers

SimpleMcpLogger solves a critical problem in MCP development: preventing console output from breaking MCP communication. When building MCP servers, any stray console.log() or logging output to STDOUT can corrupt the JSON-RPC protocol, causing client communication failures.

This library provides a drop-in replacement for console and popular loggers (Winston, Pino) that automatically suppresses output in MCP mode while preserving full logging functionality during development and testing.

The MCP Problem

MCP servers communicate via JSON-RPC over STDOUT/STDIN. Any non-MCP output to STDOUT breaks the protocol, but STDERR is perfectly safe for debugging:

// ❌ This breaks MCP communication (writes to STDOUT)
console.log("Debug info"); // Corrupts STDOUT → Protocol failure
logger.info("Processing request"); // Invalid MCP message → Connection lost

// ✅ This works perfectly (suppressed STDOUT, safe STDERR)
mcpLogger.info("Processing request"); // Suppressed in MCP mode
mcpLogger.mcpError("Debug info", data); // Safe: writes to STDERR

Key insight: STDOUT is reserved for MCP protocol messages, but STDERR is available for debugging and logging without breaking communication.

SimpleMcpLogger ensures your MCP servers work reliably by preventing accidental STDOUT output while providing safe STDERR channels for debugging.

Features

  • MCP-compliant - Automatically suppresses STDOUT output in MCP mode to prevent protocol corruption
  • Drop-in replacement - Compatible with console, Winston, and Pino APIs
  • Protocol protection - Prevents accidental console output from breaking MCP communication
  • File logging - Persistent logging to files with automatic directory creation
  • Development-friendly - Full logging during development, silent in production MCP mode
  • Bundling optimized - Modular design with separate adapter packages
  • TypeScript-first - Complete type safety and IntelliSense support
  • Zero dependencies - Core logger has no external dependencies
  • Adapter ecosystem - Winston and Pino transports for existing codebases
  • Battle-tested - Comprehensive test suite with real-world MCP scenarios

Table of Contents

Installation

npm install @alcyone-labs/simple-mcp-logger

Bundling-Friendly Design

SimpleMcpLogger uses a modular design to keep your bundles small:

  • Main package (@alcyone-labs/simple-mcp-logger) - Core logger with zero external dependencies
  • Adapters (@alcyone-labs/simple-mcp-logger/adapters) - Winston/Pino adapters with peer dependencies

This means you only bundle what you actually use!

// Core logger (no external dependencies bundled)
import { Logger } from "@alcyone-labs/simple-mcp-logger";

// Adapters (requires peer dependencies)
import { SimpleMcpWinstonTransport } from "@alcyone-labs/simple-mcp-logger/adapters";

Quick Start

Basic Usage

import { Logger, logger } from "@alcyone-labs/simple-mcp-logger";

// Use the global logger instance
logger.info("Hello, world!");
logger.error("Something went wrong");

// Create a custom logger
const myLogger = new Logger({
  level: "debug",
  prefix: "MyApp",
  mcpMode: false,
});

myLogger.debug("Debug message");
myLogger.info("Info message");

// Create a logger with file output
const fileLogger = new Logger({
  level: "info",
  prefix: "MyApp",
  logToFile: "./logs/app.log", // Logs to file, directory created automatically
});

fileLogger.info("This goes to both console and file");

// For MCP servers: use mcpError() for debugging (safe STDERR output)
myLogger.mcpError("Debug info visible in client logs");

MCP Server Usage (Primary Use Case)

This is why SimpleMcpLogger exists: to prevent console output from corrupting MCP protocol communication.

The Problem

MCP servers communicate via JSON-RPC over STDOUT. Any logging to STDOUT breaks this, but STDERR is safe:

// ❌ BROKEN: These write to STDOUT and corrupt MCP communication
console.log("Processing request"); // STDOUT → Protocol corruption
logger.info("Debug info"); // STDOUT → JSON-RPC breaks

// Client receives: {"jsonrpc":"2.0",...}Processing request{"id":1,...}
// Result: Invalid JSON, connection fails

// ✅ SAFE: STDERR doesn't interfere with MCP protocol
console.error("Debug info"); // STDERR → Safe for debugging
process.stderr.write("Log data"); // STDERR → Visible to client logs

The Solution

SimpleMcpLogger automatically suppresses STDOUT output in MCP mode while preserving STDERR for debugging:

import { createMcpLogger } from "@alcyone-labs/simple-mcp-logger";

// Create MCP-safe logger (automatically detects MCP environment)
const logger = createMcpLogger("MyMcpServer");

// ✅ SAFE: These are suppressed in MCP mode (no STDOUT output)
logger.info("Processing request"); // Silent in MCP mode
logger.debug("User data:", userData); // Silent in MCP mode
logger.warn("Rate limit approaching"); // Silent in MCP mode

// ✅ SAFE: Critical debugging via STDERR (visible to client logs)
logger.mcpError("Database connection failed"); // STDERR → Always visible
logger.mcpError("Request state:", requestData); // STDERR → Safe debugging

// ✅ SAFE: MCP logger with file output (console suppressed, file enabled)
const fileLogger = createMcpLogger("MyMcpServer", "./logs/mcp.log");
fileLogger.info("Processing request"); // Silent in MCP mode, written to file
fileLogger.error("Error occurred"); // Silent in MCP mode, written to file

Enhanced MCP Logger (v1.2.0+)

🚨 Important: The default createMcpLogger() only captures error-level logs. For comprehensive logging in MCP servers, use the new options-based API:

// ❌ DEFAULT: Only captures errors (backward compatible)
const basicLogger = createMcpLogger("MyServer", "./logs/mcp.log");
basicLogger.debug("Not captured"); // Silent - below error level
basicLogger.info("Not captured");  // Silent - below error level
basicLogger.error("Captured");     // ✅ Written to file

// ✅ ENHANCED: Capture ALL log levels with options API
const comprehensiveLogger = createMcpLogger({
  prefix: "MyServer",
  logToFile: "./logs/mcp.log",
  level: "debug",        // Captures debug, info, warn, error
  mcpMode: true          // MCP compliant (default)
});

comprehensiveLogger.debug("✅ Captured"); // Written to file
comprehensiveLogger.info("✅ Captured");  // Written to file
comprehensiveLogger.warn("✅ Captured");  // Written to file
comprehensiveLogger.error("✅ Captured"); // Written to file

Options-Based API (Recommended for new projects):

interface McpLoggerOptions {
  level?: LogLevel;      // 'debug' | 'info' | 'warn' | 'error' | 'silent'
  mcpMode?: boolean;     // Default: true (MCP compliant)
  prefix?: string;       // Optional prefix for all messages
  logToFile?: string;    // Optional file path for persistent logging
}

// Comprehensive MCP server logging
const logger = createMcpLogger({
  prefix: "MCP-Server",
  logToFile: "./logs/server.log",
  level: "info",         // Captures info, warn, error (recommended)
  mcpMode: true          // MCP compliant
});

// Development/debugging with all levels
const debugLogger = createMcpLogger({
  prefix: "Debug",
  logToFile: "./logs/debug.log",
  level: "debug",        // Captures everything
  mcpMode: true
});

// Non-MCP mode for testing
const testLogger = createMcpLogger({
  prefix: "Test",
  level: "debug",
  mcpMode: false         // Enable console output for testing
});

Hijacking Console for MCP Safety

Replace console globally to catch all logging in your MCP server:

import { createMcpLogger } from "@alcyone-labs/simple-mcp-logger";

// Replace console at startup (before any other code runs)
const mcpLogger = createMcpLogger("MCP-Server");
globalThis.console = mcpLogger as any;

// Now ALL console calls are MCP-safe
console.log("This is safe"); // Suppressed in MCP mode
console.error("This is safe too"); // Suppressed in MCP mode
someLibrary.log("Third-party logs"); // Also safe!

Environment Detection

SimpleMcpLogger automatically detects MCP environments:

// Automatically enables MCP mode when:
// - No TTY detected (typical MCP server environment)
// - MCP_MODE environment variable is set
// - Explicitly configured

const logger = createMcpLogger(); // Auto-detects MCP mode

Console Replacement

import { Logger } from "@alcyone-labs/simple-mcp-logger";

// Replace console globally (do this at application startup)
const logger = new Logger({ level: "info", prefix: "App" });
globalThis.console = logger as any;

// Now all console calls use SimpleMcpLogger
console.log("This uses SimpleMcpLogger");
console.error("This too");

⚠️ Important: Replace console at application startup before any other logging occurs to avoid infinite loops.

General Purpose Logging (Non-MCP)

import { Logger, createCliLogger } from "@alcyone-labs/simple-mcp-logger";

// Perfect for web apps, APIs, CLI tools, etc.
const appLogger = createCliLogger("info", "MyApp");

appLogger.info("Server starting on port 3000");
appLogger.warn("High memory usage detected");
appLogger.error("Database connection failed");

// Use all console methods
appLogger.table([{ user: "john", status: "active" }]);
appLogger.time("API Response");
// ... some operation
appLogger.timeEnd("API Response");

API Reference

Logger Class

Constructor

new Logger(config?: Partial<LoggerConfig>)

Configuration Options

interface LoggerConfig {
  level: LogLevel; // 'debug' | 'info' | 'warn' | 'error' | 'silent'
  mcpMode: boolean; // Suppress output when true
  prefix?: string; // Prefix for all messages
  logToFile?: string; // Optional file path for persistent logging
}

Methods

All standard console methods are supported:

  • debug(message: string, ...args: any[]): void
  • envDebug(message: string, ...args: any[]): void - Environment-aware debug logging (only outputs when DEBUG env var is truthy)
  • info(message: string, ...args: any[]): void
  • warn(message: string, ...args: any[]): void
  • error(message: string, ...args: any[]): void
  • log(message: string, ...args: any[]): void - Alias for info
  • trace(message?: string, ...args: any[]): void
  • table(data: any, columns?: string[]): void
  • group(label?: string): void
  • groupCollapsed(label?: string): void
  • groupEnd(): void
  • time(label?: string): void
  • timeEnd(label?: string): void
  • timeLog(label?: string, ...args: any[]): void
  • count(label?: string): void
  • countReset(label?: string): void
  • assert(condition: boolean, message?: string, ...args: any[]): void
  • clear(): void
  • dir(obj: any, options?: any): void
  • dirxml(obj: any): void

Special Methods

  • mcpError(message: string, ...args: any[]): void - Always logs even in MCP mode
  • child(prefix: string): Logger - Create child logger with combined prefix
  • setMcpMode(enabled: boolean): void - Toggle MCP mode
  • setLevel(level: LogLevel): void - Change log level
  • setPrefix(prefix: string): void - Change prefix
  • setLogFile(filePath: string): Promise<void> - Set or change log file path
  • close(): Promise<void> - Close file stream and flush pending writes

Factory Functions

createMcpLogger

New Options-Based API (v1.2.0+) - Recommended:

interface McpLoggerOptions {
  level?: LogLevel;      // Default: 'error' (for backward compatibility)
  mcpMode?: boolean;     // Default: true
  prefix?: string;       // Optional prefix
  logToFile?: string;    // Optional file path
}

createMcpLogger(options: McpLoggerOptions): Logger

Legacy API (Deprecated, will be removed in v2.0.0):

createMcpLogger(prefix?: string, logToFile?: string): Logger
createMcpLogger(prefix?: string, logToFile?: string, options?: Partial<McpLoggerOptions>): Logger

Examples:

// ✅ NEW: Options-based API (recommended)
const logger = createMcpLogger({
  prefix: "MyServer",
  logToFile: "./logs/mcp.log",
  level: "debug"         // Capture all levels
});

// ⚠️ LEGACY: Still works but only captures errors by default
const legacyLogger = createMcpLogger("MyServer", "./logs/mcp.log");

// ⚠️ LEGACY: With options override
const enhancedLegacy = createMcpLogger("MyServer", "./logs/mcp.log", {
  level: "info"          // Override to capture more levels
});

createCliLogger

// Create logger for CLI mode
createCliLogger(level?: LogLevel, prefix?: string): Logger

Adapters for Existing Codebases

Migrate existing MCP servers to be protocol-safe without changing your logging code.

If you have an existing codebase using Winston or Pino, you can add SimpleMcpLogger as a transport to make it MCP-compliant without refactoring your logging calls.

Bundling-Friendly Design: Adapters are available as a separate import to avoid bundling dependencies you don't need.

Installation

For adapters, you'll need to install the peer dependencies:

# For Winston adapter
npm install winston winston-transport

# For Pino adapter
npm install pino

# Or install both
npm install winston winston-transport pino

Winston Adapter

Make your existing Winston-based MCP server protocol-safe:

// Import adapters separately to avoid bundling unused dependencies
import { createWinstonTransport } from "@alcyone-labs/simple-mcp-logger/adapters";
import winston from "winston";

// Replace your existing Winston transports with MCP-safe transport
const logger = winston.createLogger({
  transports: [
    createWinstonTransport({
      level: "debug",
      mcpMode: true, // Automatically suppresses STDOUT in MCP mode
      prefix: "MCP-Server",
      logToFile: "./logs/mcp-server.log", // Optional: log to file
    }),
  ],
});

// Your existing logging code works unchanged
logger.info("Processing MCP request"); // Safe in MCP mode, written to file
logger.error("Request failed"); // Safe in MCP mode, written to file

Pino Adapter

Make your existing Pino-based MCP server protocol-safe:

// Import adapters separately to avoid bundling unused dependencies
import { createPinoDestination } from "@alcyone-labs/simple-mcp-logger/adapters";
import pino from "pino";

// Replace your existing Pino destination with MCP-safe destination
const destination = createPinoDestination({
  level: "debug",
  mcpMode: true, // Automatically suppresses STDOUT in MCP mode
  prefix: "MCP-Server",
  logToFile: "./logs/mcp-server.log", // Optional: log to file
});

const logger = pino({ level: "debug" }, destination);

// Your existing logging code works unchanged
logger.info("Processing MCP request"); // Safe in MCP mode, written to file
logger.error("Request failed"); // Safe in MCP mode, written to file

MCP Best Practices

🚨 Critical: Initialize Before Any Logging

Replace console immediately at application startup to catch all logging:

// ✅ CORRECT: Do this FIRST, before importing any other modules
import { createMcpLogger } from "@alcyone-labs/simple-mcp-logger";
globalThis.console = createMcpLogger("MCP-Server") as any;

// Now import your application code
import "./my-mcp-server.js";
// ❌ WRONG: Too late, some logging may have already occurred
import "./my-mcp-server.js";
import { createMcpLogger } from "@alcyone-labs/simple-mcp-logger";
globalThis.console = createMcpLogger("MCP-Server") as any;

🔍 Debugging MCP Servers

Use mcpError() for debugging that needs to be visible - it writes to STDERR which is safe for MCP:

const logger = createMcpLogger("MCP-Server");

// Silent in MCP mode (suppressed STDOUT - good for normal operation)
logger.info("Processing request"); // No output in MCP mode
logger.debug("User data:", userData); // No output in MCP mode

// Always visible via STDERR (safe for MCP protocol - good for debugging)
logger.mcpError("Critical error:", error); // STDERR → Visible in client logs
logger.mcpError("Server state:", serverState); // STDERR → Safe debugging
logger.mcpError("Performance metric:", timing); // STDERR → Monitoring data

Why STDERR is safe: MCP protocol only uses STDOUT for JSON-RPC messages. STDERR output appears in client logs without interfering with protocol communication.

🔧 Environment-Aware Debug Logging

The envDebug() method provides controlled debug logging that only outputs when the DEBUG environment variable is set. This allows you to safely add debug information throughout your codebase without worrying about output pollution in production.

import { Logger, createMcpLogger } from "@alcyone-labs/simple-mcp-logger";

const logger = createMcpLogger("MyApp");

// These will only output when DEBUG environment variable is truthy
logger.envDebug("Processing user request", { userId: 123 });
logger.envDebug("Database query", { sql: "SELECT * FROM users" });
logger.envDebug("API response time", { duration: "245ms" });

// Regular debug logging (always respects log level)
logger.debug("This always logs when level allows");

Environment Variable Behavior:

  • DEBUG=true or DEBUG=1 or DEBUG=anything → Logging enabled
  • DEBUG=false or DEBUG=0 or DEBUG="" or unset → Logging disabled

Usage Examples:

# Enable debug logging
DEBUG=1 node my-mcp-server.js

# Disable debug logging (production)
node my-mcp-server.js

# Enable with custom value
DEBUG=verbose node my-mcp-server.js

Benefits:

  • Safe for production: No output pollution when DEBUG is not set
  • Works with all transports: Console, file logging, MCP mode, etc.
  • Respects all logger settings: Log levels, prefixes, MCP mode
  • Clear identification: Debug messages are prefixed with [ENV-DEBUG]

File Logging Example:

// Logs to file only when DEBUG is set
const logger = createMcpLogger("MCP-Server", "./logs/debug.log");

logger.envDebug("Server state", serverState); // Only written when DEBUG=1

📡 Understanding STDOUT vs STDERR in MCP

STDOUT (Protocol Channel):

  • Reserved exclusively for MCP JSON-RPC messages
  • Any non-MCP output breaks protocol communication
  • Must be kept clean for reliable client connections

STDERR (Debugging Channel):

  • Safe for logging, debugging, and monitoring output
  • Visible in client logs without protocol interference
  • Perfect for error reporting and diagnostic information
// ❌ STDOUT - Reserved for MCP protocol
process.stdout.write('{"jsonrpc":"2.0",...}'); // MCP messages only

// ✅ STDERR - Safe for debugging
process.stderr.write("Debug: Processing request\n");
console.error("Server metrics:", metrics);
logger.mcpError("Performance data:", data);

🧪 Testing MCP Servers

Disable MCP mode during testing to see all logs:

// ✅ NEW: Options-based API
const logger = createMcpLogger({
  prefix: "Test-Server",
  level: "debug",
  mcpMode: false         // Enable console output for testing
});

// ⚠️ LEGACY: Still works
const legacyLogger = createMcpLogger("Test-Server", undefined, { mcpMode: false });

// OR use environment variable
process.env.MCP_MODE = "false";
const autoLogger = createMcpLogger({ prefix: "Test-Server" }); // Auto-detects

🔄 Migration to Enhanced API

For New Projects - Use the options-based API:

// ✅ RECOMMENDED: Comprehensive logging
const logger = createMcpLogger({
  prefix: "MyMcpServer",
  logToFile: "./logs/server.log",
  level: "info",         // Captures info, warn, error
  mcpMode: true
});

For Existing Projects - Gradual migration:

// Step 1: Keep existing code working (no changes needed)
const logger = createMcpLogger("MyServer", "./logs/mcp.log");

// Step 2: Add comprehensive logging where needed
const debugLogger = createMcpLogger({
  prefix: "MyServer-Debug",
  logToFile: "./logs/debug.log",
  level: "debug"         // Capture everything for debugging
});

// Step 3: Eventually migrate to options-based API
const logger = createMcpLogger({
  prefix: "MyServer",
  logToFile: "./logs/mcp.log",
  level: "info"          // Better than error-only default
});

Why Migrate?

  • 🔍 See Everything: Capture debug, info, warn messages (not just errors)
  • 🎛️ Better Control: Fine-tune log levels per logger instance
  • 🚀 Future-Proof: Prepared for v2.0 when legacy API is removed
  • 📖 Clearer Intent: Options object makes configuration explicit

Browser Usage

SimpleMcpLogger works seamlessly in browser environments! The core logger and most adapters are browser-compatible.

Basic Browser Usage

<!DOCTYPE html>
<html>
  <head>
    <script type="module">
      import {
        Logger,
        logger,
        createMcpLogger,
      } from "https://unpkg.com/@alcyone-labs/simple-mcp-logger/dist/index.mjs";

      // Use the global logger
      logger.info("Hello from browser!");

      // Create a custom logger
      const browserLogger = new Logger({
        level: "debug",
        prefix: "Browser",
        mcpMode: false,
      });

      browserLogger.debug("Debug message in browser");
      browserLogger.table([{ name: "John", age: 30 }]);

      // Replace console globally
      globalThis.console = browserLogger;
      console.log("Now using SimpleMcpLogger!");
    </script>
  </head>
  <body>
    <h1>SimpleMcpLogger Browser Demo</h1>
    <p>Check the browser console for log messages!</p>
  </body>
</html>

Browser with Bundlers (Webpack, Vite, etc.)

import { Logger, createMcpLogger } from "@alcyone-labs/simple-mcp-logger";

// Create logger for browser app
const appLogger = new Logger({
  level: "info",
  prefix: "MyApp",
  mcpMode: false,
});

// Use all console methods
appLogger.log("Application started");
appLogger.group("User Actions");
appLogger.info("User clicked button");
appLogger.warn("Form validation warning");
appLogger.groupEnd();

// Time operations
appLogger.time("API Call");
// ... some async operation
appLogger.timeEnd("API Call");

Browser Adapter Support

AdapterBrowser SupportNotes
Core Logger✅ Full supportAll console methods work
Winston Adapter✅ Full supportWorks if Winston is browser-compatible
Pino Transport✅ Full supportUse createPinoDestination()
Pino Logger Factory❌ Node.js onlyUse destination with browser Pino build

Browser + Pino Example

import { createPinoDestination } from "@alcyone-labs/simple-mcp-logger";
// Import browser-compatible Pino build
import pino from "pino/browser";

const destination = createPinoDestination({
  level: "info",
  prefix: "Browser",
});

const logger = pino({ level: "info" }, destination);
logger.info("Hello from Pino in browser!");

File Logging

SimpleMcpLogger supports persistent logging to files with automatic directory creation and proper file stream management.

Basic File Logging

import { Logger, createMcpLogger } from "@alcyone-labs/simple-mcp-logger";

// Create logger with file output
const logger = new Logger({
  level: "info",
  logToFile: "./logs/app.log", // Directory created automatically
});

logger.info("This goes to both console and file");
logger.error("Errors are logged to file too");

// Always close the logger when done to flush pending writes
await logger.close();

MCP Mode with File Logging

Perfect for MCP servers - suppress console output but maintain file logs:

// MCP logger with file output (console suppressed, file enabled)
const mcpLogger = createMcpLogger("MCP-Server", "./logs/mcp.log");

mcpLogger.info("Processing request"); // Silent in MCP mode, written to file
mcpLogger.error("Error occurred"); // Silent in MCP mode, written to file
mcpLogger.mcpError("Debug info"); // Always visible via STDERR + written to file

// Gracefully close when shutting down
await mcpLogger.close();

Dynamic File Path Changes

const logger = new Logger({ level: "info" });

// Start logging to one file
await logger.setLogFile("./logs/startup.log");
logger.info("Application starting");

// Switch to a different file
await logger.setLogFile("./logs/runtime.log");
logger.info("Now logging to runtime file");

// Disable file logging
await logger.setLogFile(""); // Empty string disables file logging

File Logging with Adapters

Both Winston and Pino adapters support file logging:

// Winston with file logging
import { createWinstonTransport } from "@alcyone-labs/simple-mcp-logger/adapters";

const transport = createWinstonTransport({
  logToFile: "./logs/winston.log",
  mcpMode: true,
});

// Pino with file logging
import { createPinoDestination } from "@alcyone-labs/simple-mcp-logger/adapters";

const destination = createPinoDestination({
  logToFile: "./logs/pino.log",
  mcpMode: true,
});

File Logging Best Practices

  1. Always close loggers when your application shuts down:

    process.on("SIGINT", async () => {
      await logger.close();
      process.exit(0);
    });
    
  2. Use absolute paths for production deployments:

    import { resolve } from "node:path";
    
    const logFile = resolve(process.cwd(), "logs", "app.log");
    const logger = new Logger({ logToFile: logFile });
    
  3. Handle file errors gracefully - SimpleMcpLogger automatically handles permission errors and continues logging to console.

Bundle Size

The browser build is optimized and lightweight:

  • ESM build: ~11KB (2.4KB gzipped)
  • Tree-shakeable: Import only what you need
  • Zero dependencies: No external runtime dependencies

Migration Guide

From console

// Before
console.log("Hello");
console.error("Error");

// After
import { logger } from "@alcyone-labs/simple-mcp-logger";
logger.log("Hello");
logger.error("Error");

// Or replace globally
globalThis.console = logger as any;

From Winston

// Before
import winston from "winston";
const logger = winston.createLogger({
  transports: [new winston.transports.Console()],
});

// After
import { createWinstonTransport } from "@alcyone-labs/simple-mcp-logger";
const logger = winston.createLogger({
  transports: [createWinstonTransport()],
});

From Pino

// Before
import pino from "pino";
const logger = pino();

// After
import { createPinoLogger } from "@alcyone-labs/simple-mcp-logger";
const logger = createPinoLogger();

Why This Matters for MCP Development

The Hidden Problem

Many MCP servers fail in production due to STDOUT contamination. Even a single console.log() can break the entire MCP communication channel:

// This innocent debug line breaks everything (writes to STDOUT):
console.log("Debug: processing request");

// MCP client expects: {"jsonrpc":"2.0","id":1,"result":{...}}
// But receives: Debug: processing request{"jsonrpc":"2.0","id":1,"result":{...}}
// Result: JSON parse error, connection terminated

// The fix is simple - use STDERR instead:
console.error("Debug: processing request"); // Safe: goes to STDERR

The Solution Impact

SimpleMcpLogger has prevented countless MCP server failures by:

  • Catching stray console calls before they reach STDOUT
  • Preserving development logging while ensuring production safety
  • Enabling gradual migration of existing codebases to MCP compliance
  • Providing safe STDERR channels for debugging without protocol interference
  • Maintaining visibility into server operations via client-visible STDERR logs

Real-World Success

Teams using SimpleMcpLogger report:

  • Zero MCP protocol corruption issues in production
  • Faster debugging with safe error logging channels
  • Seamless migration of existing Node.js services to MCP servers
  • Confident deployment knowing logging won't break client connections

SimpleMcpLogger isn't just a logger—it's MCP reliability insurance.

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.

Reviews

No reviews yet

Sign in to write a review