How Is Everyone Debugging Their MCP Servers?
How Is Everyone Debugging Their MCP Servers?
MCP server debugging is painful because the normal debugging tools do not work. You cannot print to stdout - that is the protocol channel. You cannot attach a debugger easily because the client spawns the process. Breakpoints are useless when you cannot control when the client sends requests.
The answer everyone eventually lands on: log to stderr and tail.
The stderr Pattern
MCP servers communicate over stdout using JSON-RPC. Anything you print to stdout that is not valid JSON-RPC corrupts the connection. But stderr is free. Log everything to stderr, then tail the output in a separate terminal.
node my-mcp-server.js 2>/tmp/mcp-debug.log
# In another terminal:
tail -f /tmp/mcp-debug.log
This is not glamorous, but it works reliably across every MCP implementation.
macOS MCP Server Traversal Debugging
For MCP servers that interact with macOS desktop apps, there is an extra debugging layer: understanding what the accessibility tree actually shows. The agent sees the UI through the accessibility API, and that view often differs from what you see on screen.
Use the Accessibility Inspector (included with Xcode) to see exactly which elements are exposed, what their roles and labels are, and whether they are actionable. Many debugging sessions end with discovering that the button the agent is trying to click is not exposed in the accessibility tree at all.
Common Gotchas
- Forgetting to flush stderr buffers (use unbuffered writes)
- The MCP client disconnecting but your server not detecting it
- JSON-RPC response IDs not matching request IDs
- Tool result schemas that do not match what you declared in capabilities
Start with stderr logging from day one. You will need it.
Fazm is an open source macOS AI agent. Open source on GitHub.