mcp-repl has built-in debugging at a few different layers:
- Internal event logs from inside
mcp-repl - Worker startup and sandbox diagnostics
- An external trace proxy that captures the raw stdio traffic between the client and
mcp-repl
Use the built-in logs when you want to understand what mcp-repl thinks happened. Use the external proxy when you need to see the exact bytes that crossed the wire.
Enable per-startup JSONL logs with either:
mcp-repl --debug-dir /path/to/debug-rootMCP_REPL_DEBUG_DIR=/path/to/debug-root
Each startup creates a fresh session directory under that root. mcp-repl writes:
events.jsonlwith startup metadata, tool calls, and parsed sandbox metadata eventsstartup.logfor server-side startup trace linesworker-startup.logfor worker-side startup trace linessandbox-state.jsonlfor the initial effective sandbox policy plus later tool-call sandbox metadata and effective policy updates
Example:
mkdir -p /tmp/mcp-repl-debug
MCP_REPL_DEBUG_DIR=/tmp/mcp-repl-debug mcp-repl --interpreter rUse MCP_REPL_DEBUG_DIR or --debug-dir when the worker fails early or startup feels slow. The startup trace lines go into startup.log and worker-startup.log inside the session directory.
The worker-side MCP_REPL_IPC_* env vars are bootstrap-only. Backends clear them before handing control to user code, so child-process debugging should not rely on those names being visible inside the REPL.
Example:
MCP_REPL_DEBUG_DIR=/tmp/mcp-repl-debug mcp-repl --interpreter pythonThese switches are useful when the client is sending Codex sandbox metadata or when the sandbox policy is the thing you are debugging.
MCP_REPL_DEBUG_DIR=/path/to/debug-rootwritessandbox-state.jsonlinside the session directoryMCP_REPL_KEEP_SESSION_TMPDIR=1keeps the worker session temp directory after exit so you can inspect it- macOS only:
MCP_REPL_SANDBOX_LOG_DENIALS=1prints collected sandbox denials when the worker exits
Example:
MCP_REPL_DEBUG_DIR=/tmp/mcp-repl-debug mcp-repl --sandbox inherit--debug-repl runs mcp-repl as a local interactive driver for the worker instead of as an MCP server. This is the fastest way to reproduce REPL behavior without involving a client.
If you start it with --sandbox inherit, the debug REPL bootstraps one local
inherited sandbox snapshot from the current default sandbox state before the
first worker spawn. That keeps the inherit code path debuggable even though
there is no per-tool-call MCP metadata in local debug mode.
Start it with:
mcp-repl --debug-repl --interpreter rBehavior:
- Enter multi-line input and finish it with a line ending in
END - Type
INTERRUPTto send an interrupt - Type
RESTARTto restart the worker - Type
Ctrl-Dto exit
Useful environment variables:
MCP_REPL_IMAGES=0|1|kittycontrols inline image rendering in the debug REPLMCP_REPL_OUTPUT_BUNDLE_MAX_COUNT,MCP_REPL_OUTPUT_BUNDLE_MAX_BYTES, andMCP_REPL_OUTPUT_BUNDLE_MAX_TOTAL_BYTESlet you lower bundle quotas when reproducing spill and pruning behavior
The built-in event log only sees what reaches mcp-repl after startup. If you need the exact stdio traffic between an MCP client and the server, use the external proxy in scripts/mcp-stdio-trace.py.
What it does:
- Spawns the real stdio MCP server, typically
mcp-repl - Forwards client stdin to server stdin
- Forwards server stdout back to the client
- Captures server stderr into the trace log
- Writes both a raw JSONL log and an indented
.pretty.jsonlog under.mcp-repl-trace/in the current working directory
Each captured chunk includes:
- Timestamp and pid
- Stream name and route
- Raw bytes as base64
- UTF-8 text when the chunk decodes cleanly
- Parsed JSON in
text_as_jsonwhen the chunk is line-delimited JSON
Set MCP_REPL_TRACE_FORWARD_STDERR=1 if you also want the proxied server stderr mirrored to your terminal. If MCP_REPL_DEBUG_DIR is set, the proxy writes wire.jsonl and wire.pretty.json into the same session directory and passes that directory to mcp-repl.
Direct invocation:
scripts/mcp-stdio-trace.py ~/.cargo/bin/mcp-repl --interpreter rClient-config pattern:
{
"command": "/absolute/path/to/scripts/mcp-stdio-trace.py",
"args": [
"/absolute/path/to/mcp-repl",
"--interpreter",
"r",
"--debug-dir",
"/tmp/mcp-repl-debug"
]
}That setup gives you two views at once:
- The proxy log shows the exact client/server traffic
- The session directory shows the internal
mcp-replinterpretation of that traffic
The clean-claude-hook-session-reset worktree adds Claude-specific debugging that is not on main.
Branch-specific surfaces:
mcp-repl claude-hook session-startmcp-repl claude-hook session-endCLAUDE_ENV_FILEMCP_REPL_CLAUDE_SESSION_ID
That worktree also keeps inspectable Claude clear-hook state under:
$XDG_STATE_HOME/mcp-repl/claude-clear~/.local/state/mcp-repl/claude-clearwhenXDG_STATE_HOMEis not set
In that worktree, the JSONL debug log also records:
server_namein the startup payloadclaude_state_prune_beginclaude_state_prune_end
Use those only when you are debugging the Claude /clear reset flow on that branch.