Skip to content

Latest commit

 

History

History
155 lines (104 loc) · 5.45 KB

File metadata and controls

155 lines (104 loc) · 5.45 KB

Debugging MCP REPL

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.

Built-in event logs

Enable per-startup JSONL logs with either:

  • mcp-repl --debug-dir /path/to/debug-root
  • MCP_REPL_DEBUG_DIR=/path/to/debug-root

Each startup creates a fresh session directory under that root. mcp-repl writes:

  • events.jsonl with startup metadata, tool calls, and parsed sandbox metadata events
  • startup.log for server-side startup trace lines
  • worker-startup.log for worker-side startup trace lines
  • sandbox-state.jsonl for 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 r

Startup diagnostics

Use 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 python

MCP and sandbox tracing

These 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-root writes sandbox-state.jsonl inside the session directory
  • MCP_REPL_KEEP_SESSION_TMPDIR=1 keeps the worker session temp directory after exit so you can inspect it
  • macOS only: MCP_REPL_SANDBOX_LOG_DENIALS=1 prints collected sandbox denials when the worker exits

Example:

MCP_REPL_DEBUG_DIR=/tmp/mcp-repl-debug mcp-repl --sandbox inherit

Interactive debug REPL

--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 r

Behavior:

  • Enter multi-line input and finish it with a line ending in END
  • Type INTERRUPT to send an interrupt
  • Type RESTART to restart the worker
  • Type Ctrl-D to exit

Useful environment variables:

  • MCP_REPL_IMAGES=0|1|kitty controls inline image rendering in the debug REPL
  • MCP_REPL_OUTPUT_BUNDLE_MAX_COUNT, MCP_REPL_OUTPUT_BUNDLE_MAX_BYTES, and MCP_REPL_OUTPUT_BUNDLE_MAX_TOTAL_BYTES let you lower bundle quotas when reproducing spill and pruning behavior

External wire trace proxy

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.json log 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_json when 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 r

Client-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-repl interpretation of that traffic

Claude clear-hook worktree

The clean-claude-hook-session-reset worktree adds Claude-specific debugging that is not on main.

Branch-specific surfaces:

  • mcp-repl claude-hook session-start
  • mcp-repl claude-hook session-end
  • CLAUDE_ENV_FILE
  • MCP_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-clear when XDG_STATE_HOME is not set

In that worktree, the JSONL debug log also records:

  • server_name in the startup payload
  • claude_state_prune_begin
  • claude_state_prune_end

Use those only when you are debugging the Claude /clear reset flow on that branch.