Safeguard
Developer Tools•

Why printing to stdout breaks a local MCP server

A stdio MCP server speaks the protocol on stdout, so debug prints corrupt it. Log to stderr instead. Why this happens and how to fix it quickly.

Safeguard Security Team
3 min read

A local MCP server that uses the stdio transport sends its protocol messages over standard output. If your code also prints debug text to standard output, the client reads that text as part of the protocol and the connection fails. Log to standard error instead. The MCP documentation states this directly.

What goes wrong

With stdio, the client starts your server as a child process and talks to it through the process's input and output streams. The messages are JSON-RPC. A stray print statement adds non-JSON text to the same stream. The client cannot parse it, and you see a failed connection, a hang or a confusing parse error.

This is the most common first bug for people writing their first server, because printing is the habit when debugging.

The rule

The official debugging guide says that for servers using the stdio transport, messages logged to stderr are captured by the host application automatically. It warns that local servers should not log to stdout because that interferes with protocol operation.

Quick fixes by language

In Python, set your logging handler to write to the standard error stream, and avoid bare print calls. In Node, use the error method of the console rather than the plain log method. In a shell wrapper, redirect diagnostic output to the error stream.

import logging
import sys

logging.basicConfig(stream=sys.stderr, level=logging.INFO)
logging.info("server starting")

HTTP servers are different

For servers using Streamable HTTP, the guide says stderr is not captured by the client. Use your own log aggregation or OpenTelemetry, and standard HTTP tools to inspect requests. Protocol level log messages sent to the client are marked deprecated as of the 2026-07-28 protocol version, with new implementations told to log to stderr for stdio or use OpenTelemetry.

Other quiet breakers include:

  • Libraries that print banners or progress bars on import.
  • Wrapper scripts that echo a message before launching the real process.
  • Package managers that write status lines to standard output when launched through a tool runner.

Test any wrapper by running it directly and checking that only protocol messages appear on standard output. The Inspector can also reveal where parsing fails. See testing with the Inspector.

While you are fixing logging, check that tokens and personal data are not written to log files. The debugging guide lists sanitising logs and protecting credentials as part of security when debugging.

How to confirm the fix

Run the server by hand and pipe its output to a file, with nothing else attached. The file should contain only protocol messages, not banners or log lines. Then connect through the Inspector, and finally through your real client. If the client still fails, read its log for a parse error, which usually names the first bad character and points to the stray output.

Quick check

Where do my stdio server logs end up?

On stderr, which the host application captures. Clients usually surface it in an MCP log view.

Does this apply to remote servers?

Not in the same way. HTTP servers do not share a stream with the protocol, but the client does not capture their stderr, so use your own logging.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.