Stdio transport reads stdin, writes stdout, no console.log pollution
Why it matters
When an MCP server uses stdio transport, stdout is the JSON-RPC channel. A single console.log() in a tool handler writes non-JSON text into that channel, corrupting the message stream. Clients receive parse errors or silently drop subsequent messages. This is the most common MCP server defect in production — debug logging left in handlers from development. CWE-116 (improper encoding/escaping) applies directly: the output stream carries protocol data, not freeform text, and mixing the two is a protocol violation that makes the server non-functional.
Severity rationale
Critical because any `console.log()` in a stdio-transport server corrupts the protocol channel, causing immediate and total communication failure with connected clients.
Remediation
Replace every console.log() in server code with console.error(). stderr is safe; stdout is the protocol channel.
// src/tools/search.ts — WRONG and CORRECT
// WRONG — corrupts stdio transport
console.log(`Searching: ${query}`) // do not commit
// CORRECT — stderr is safe for debug output
console.error(`Searching: ${query}`)
For logging libraries (Winston, Pino), set their transport explicitly to process.stderr:
import pino from 'pino'
const logger = pino({ transport: { target: 'pino/file', options: { destination: 2 } } }) // fd 2 = stderr
Run grep -rn 'console\.log' src/ before every release to catch regressions.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the MCP Server Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-116 — Improper Encoding or Escaping of Output (stdout pollution corrupts protocol stream)
- external · mcp-spec-stdio — MCP Specification — Stdio transport
Taxons
History
- 2026-04-18·v1.0.0·Initial import from mcp-server·automated