mcp-stdio-debug
v1.9.2
Published
Debug logging and protocol tracing for stdio-based MCP servers
Maintainers
Readme
mcp-debug
Debug logging and protocol tracing for stdio-based MCP servers.
The problem
Stdio MCP servers use stdout as the JSON-RPC transport. A stray
console.log writes into that same stream and breaks the client's
parser, so the usual way to debug is unavailable.
What it does
mcp-debug wraps your server process. stdout is relayed to the
client byte-for-byte, untouched. Everything useful for a human,
your debug logs and a summary of each JSON-RPC message, goes to
stderr and to a session log file instead.
Install
npm i mcp-stdio-debugUsage
Wrap the command you'd normally point your MCP client at:
mcp-debug run -- node server.jsIn your server code, swap console.log for the logger so output
never touches stdout:
import { debug, info, warn, error } from "mcp-stdio-debug";
info("server.start", { pid: process.pid });
debug("request.received", { method: "ping" });Each request and response is traced with a direction arrow, and each response is tagged with how long the server took to answer it. Slow responses (over 500ms) and JSON-RPC errors are highlighted in red; a response with no matching request, a duplicate request id, or a malformed message is flagged as an anomaly in yellow:
[rpc] → ping id=1
[rpc] ← ping id=1 (55ms)A one-line summary prints when the server exits:
mcp-debug summary: 1 requests, 1 responses, avg 55ms, slowest 55msEach run writes a session file to
.mcp-debug/session-YYYY-MM-DD-00001.jsonl with every log line and
protocol message, in order.
Replay a saved session later. Defaults to the most recent one:
mcp-debug replay
mcp-debug replay .mcp-debug/session-2026-01-01-00001.jsonl
mcp-debug replay --follow # keep printing new lines as another run appends themOlder session files are deleted automatically as new ones are created; see Session file management to change how many are kept.
Or get a summary instead of the full trace:
mcp-debug statsRequests: 12
Responses: 12 (1 errors)
Notifications: 2
Latency: avg 34ms, p95 112ms
Slowest: tools/call id=9 (340ms)
By method:
tools/call: 8 calls, avg 45ms
resources/read: 4 calls, avg 12msFlags
mcp-debug run --verbose -- node server.js # show full request/response payloads
mcp-debug run --level=warn -- node server.js # only show warn/error debug logs
mcp-debug run --no-color -- node server.js # disable ANSI colorsFields that look like secrets (token, apiKey, password,
authorization, ...) are redacted in --verbose payloads and in
data passed to the logger (debug("auth", { token })), both on
screen and in the session file, regardless of --verbose.
Session file management
Session files live in .mcp-debug/ by default, named
session-YYYY-MM-DD-00001.jsonl, session-YYYY-MM-DD-00002.jsonl, and
so on. By default at most 20 are kept; older ones are deleted as new
runs start.
mcp-debug run --max-sessions=50 -- node server.js # keep the 50 most recent session files
mcp-debug run --max-age=7 -- node server.js # also delete session files older than 7 days
mcp-debug run --max-size=10MB -- node server.js # rotate to a new file once one passes 10MB, instead of growing it forever
mcp-debug run --session-dir=/var/log/mcp -- node server.js # write session files somewhere else
mcp-debug run --session-name=myserver -- node server.js # use a custom filename prefixRotating on --max-size never stops logging: a run that produces a
lot of traffic just ends up with several sequentially numbered files
instead of one unbounded one.
Each flag has an equivalent environment variable, which a flag
overrides if both are set: MCP_DEBUG_MAX_SESSIONS,
MCP_DEBUG_MAX_AGE, MCP_DEBUG_MAX_SIZE, MCP_DEBUG_SESSION_DIR,
MCP_DEBUG_SESSION_NAME.
Topics: splitting logs into separate files
debug/info/warn/error take an optional third argument to
route that entry to its own session file instead of the main one,
for example to keep an api log and a chat log apart:
import { info } from "mcp-stdio-debug";
info("request", { ip: "203.0.113.4" }, "api");
info("message", { text: "hi" }, "chat");By default each topic gets its own subfolder under the session
directory (.mcp-debug/api/, .mcp-debug/chat/), created
automatically, with the same rotation and retention rules as the
main log. To send a topic's files somewhere else entirely, set
MCP_DEBUG_TOPIC_DIR_<TOPIC> (uppercased), for example
MCP_DEBUG_TOPIC_DIR_API=/var/log/myserver/api.
Topics are meant for a handful of fixed categories, not one per request: at most 50 distinct topics get their own log file in a single run. Beyond that, further new topics fall back to the main session log instead of opening more files.
Log format
Session files are JSON Lines by default, one {"time": ..., ...}
object per line. Pass --log-format=opensearch (or set
MCP_DEBUG_LOG_FORMAT=opensearch) to write "@timestamp" instead of
"time", the field OpenSearch/Elasticsearch expect for time-based
indices - the rest of each line is unchanged, so it's still plain
JSON Lines a log shipper like Filebeat can read directly.
A single debug/info/warn/error call can also request its own
format, overriding --log-format for just that entry:
import { info } from "mcp-stdio-debug";
info("request", { ip: "203.0.113.4" }, "api", "opensearch");Doctor
Sanity-check the environment before you spend time debugging the
wrong thing: is the command on PATH, is the current directory
writable:
mcp-debug doctor -- node server.js✓ runtime: linux, node v22.15.0
✓ command "node" on PATH: /usr/bin/node
✓ current directory writable: /home/you/projectColors are on automatically in a real terminal and off when piped to a file or another process.
mcp-debug --version
mcp-debug --helpDevelopment
bun install
bun run build
bun run typecheck
bun testLicense
MIT. See LICENSE.
