fix: support newline-delimited JSON-RPC — Claude Code's actual MCP transport#89
Conversation
…sport
ROOT CAUSE: Claude Code v2.1+ (MCP protocol 2025-11-25) sends
newline-delimited JSON-RPC ({json}\n), not Content-Length framing.
BrainBar always responded with Content-Length headers, which Claude
Code's line-delimited reader couldn't parse — causing silent
disconnect after the first initialize.
Fix: auto-detect client framing mode from the first message.
- Content-Length header present → respond with Content-Length framing
- Raw JSON with newline → respond with JSON + newline (no headers)
Per-client tracking via MCPFraming.lastExtractUsedContentLength flag
and ClientState.usesContentLengthFraming.
Also adds file-based debug logging to /tmp/brainbar-debug.log for
future diagnosis.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR enhances the MCP server with per-process debugging infrastructure and implements dual message framing support (content-length and newline-delimited JSON) with runtime detection. The changes introduce verbose logging for client connections and message processing, track framing mode per client, and conditionally encode responses based on detected framing format. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Server as BrainBarServer
participant MCPFraming
Client->>Server: Send raw data packet
Server->>Server: debugLog RECV packet
Server->>MCPFraming: extractMessages()
MCPFraming->>MCPFraming: Attempt Content-Length parse
alt Content-Length succeeds
MCPFraming->>MCPFraming: lastExtractUsedContentLength = true
MCPFraming-->>Server: Return messages
else Falls back to raw JSON
MCPFraming->>MCPFraming: lastExtractUsedContentLength = false
MCPFraming-->>Server: Return messages
end
Server->>Server: Update ClientState.usesContentLengthFraming
Server->>Server: debugLog extracted messages + framing mode
Server->>Server: Process message (method, id)
Server->>Server: Generate response
alt usesContentLengthFraming == true
Server->>Server: Encode with Content-Length framing
else
Server->>Server: JSON encode + append newline
end
Server->>Client: Send response
Server->>Server: debugLog response sent
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
2025-11-25) sends newline-delimited JSON-RPC ({json}\n), NOT Content-Length framing. BrainBar always responded withContent-Length: N\r\n\r\n{json}, which Claude Code's line-delimited reader couldn't parse — causing silent disconnect afterinitialize.MCPFraming.lastExtractUsedContentLengthandClientState.usesContentLengthFraming/tmp/brainbar-debug.logEvidence
Debug log from real Claude Code v2.1.78 session:
No
Content-Length:header — bare JSON with trailing\n.After fix:
Full handshake completes successfully.
Test plan
swift build -c releaseclean🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Improvements