Skip to content

fix(brainbar): compact tools list for Claude MCPB#275

Merged
EtanHey merged 3 commits into
mainfrom
fix/brainbar-mcpb-tools-list-size
May 3, 2026
Merged

fix(brainbar): compact tools list for Claude MCPB#275
EtanHey merged 3 commits into
mainfrom
fix/brainbar-mcpb-tools-list-size

Conversation

@EtanHey
Copy link
Copy Markdown
Owner

@EtanHey EtanHey commented May 3, 2026

Summary

  • Fixes the real Claude Desktop boot failure after PR fix(brainbar): stabilize json-rpc envelope order #274: the BrainLayer MCPB extension path is a Node utility-process bridge, not the Python stdio adapter.
  • Keeps BrainBar's public tools/list response below Claude Desktop MCPB's observed 8192-byte raw stdout parse boundary by omitting optional tool annotations from the response.
  • Keeps internal annotation taxonomy coverage on MCPRouter.toolDefinitions, so tool safety metadata remains documented and tested internally.

Root Cause

Claude Desktop config shows BrainLayer Memory is managed by the installed MCPB extension:

node /Users/etanheyman/Library/Application Support/Claude/Claude Extensions/local.mcpb.etan-heyman.brainlayer/server/index.js

with BRAINBAR_SOCKET=/tmp/brainbar.sock.

Claude Desktop logs show the utility process attempts to parse the raw stdout stream in 8192-byte chunks. The previous tools/list response was 8995 bytes, so Claude parsed the first chunk as an unterminated JSON string and then parsed the second chunk as a separate JSON-RPC message.

Raw bytes captured from the deployed Node extension path before this fix:

NODE_EXTENSION_TOTAL_BYTES=9199
NODE_EXTENSION_LINE_LENGTHS=202,8995
RAW_BYTES_8192_SLICE=b'e or all tag subscriptions for an agent.","annotations":{"destructiveHint":false,"readOnlyHint":false,"idempotentHint":true,"openWorldHint":false}},{"name":"brain_ack","inputSchema":{"required":["agent_id","seq"],"properties":{"seq":{"descr'

Claude's own UI/log error matches the second fragment beginning at agent_id:

Invalid JSON-RPC message: agent_id":{"description":"Stable agent identifier","maxLength":128,"type":"string"}}...

Tests

  • TDD red first: swift test --package-path brain-bar --filter MCPRouterTests/testEncodedToolsListFitsClaudeExtensionRawMessageLimit failed before fix with 8995 bytes and annotations present.
  • swift test --package-path brain-bar --filter MCPRouterTests/testEncodedToolsListFitsClaudeExtensionRawMessageLimit passed after fix.
  • swift test --package-path brain-bar --filter MCPRouterTests passed: 45 tests, 0 failures.
  • swift test --package-path brain-bar --filter MCPFramingTests passed: 8 tests, 0 failures.
  • swift test --package-path brain-bar --filter SocketIntegrationTests/testMCPToolsListOverSocket passed.
  • swift test --package-path brain-bar passed: 340 tests, 0 failures.
  • ./scripts/run_tests.sh passed: pytest unit suite 1823 passed, 9 skipped, 75 deselected, 1 xfailed; MCP registration 3 passed; isolated eval/hook routing 32 passed; bun suite 1 pass; FTS5 regression PASS.
  • Pre-push gate reran ./scripts/run_tests.sh and passed with the same suites.

Deploy Verification Plan

After merge: pull main, pause enrichment, rebuild/reinstall BrainBar, restart BrainBar, then launch the MCPB Node extension bridge and verify the raw tools/list line is below 8192 bytes and Claude logs no longer show Unterminated string in JSON at position 8192 or Invalid JSON-RPC message: agent_id.


Note

Medium Risk
Changes JSON-RPC output for newline-delimited transport by conditionally stripping annotations, which could affect clients relying on that metadata or any large raw responses near the size threshold.

Overview
Fixes Claude Desktop MCPB newline-delimited JSON parsing failures by conditionally compacting oversized raw JSON-RPC responses.

When BrainBarServer sends newline-delimited responses (no Content-Length), it now enforces an 8192-byte safety limit by re-encoding tools/list with per-tool annotations removed if needed; framed (Content-Length) responses keep the canonical payload (including annotations).

Tests are updated/added to assert canonical tools/list keeps annotations, framed socket transport still includes annotations even when >8192 bytes, and raw-line transport returns a sub-8192-byte tools/list with annotations omitted.

Reviewed by Cursor Bugbot for commit 99371eb. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Compact tools/list response for Claude MCP raw newline transport when payload exceeds 8192 bytes

  • When sending over raw newline-delimited JSON-RPC (no Content-Length framing), BrainBarServer now strips the annotations field from each tool in tools/list results if the encoded payload is ≥ 8192 bytes.
  • A new encodeRawJSONResponse(_:) helper handles size detection and delegates to compactRawJSONResponseIfNeeded(_:) for compaction, falling back to the original encoding if compaction fails.
  • New integration test in SocketIntegrationTests.swift verifies raw line responses are under 8192 bytes with annotations omitted, while framed responses retain annotations.
  • Behavioral Change: Claude MCP clients using raw newline transport will no longer receive annotations in tools/list responses when the payload is large.

Macroscope summarized 99371eb.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of tool annotations in JSON-RPC responses based on transport method.
    • Fixed tool list response behavior for newline-delimited JSON transport scenarios.
  • Tests

    • Added comprehensive test coverage for tools/list endpoint responses, including socket integration and annotation handling validation.

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

📝 Walkthrough

Walkthrough

The PR adds response preprocessing for newline-delimited JSON-RPC transport to remove tool annotations before encoding, keeping raw responses under size limits. Content-Length framed responses are unaffected. Tests verify annotations are preserved in standard framing and omitted in raw-line mode.

Changes

Annotation Compaction for Raw-Line Transport

Layer / File(s) Summary
Core Implementation
brain-bar/Sources/BrainBar/BrainBarServer.swift
sendResponse now calls compactRawJSONResponseIfNeeded to remove annotations from tools before encoding newline-delimited responses. Content-Length path unchanged.
Test Helpers
brain-bar/Tests/BrainBarTests/SocketIntegrationTests.swift
New sendRawLineJSON and readRawLineJSONData helpers support writing/reading newline-delimited JSON over sockets with timeout handling.
Test Coverage
brain-bar/Tests/BrainBarTests/MCPRouterTests.swift, brain-bar/Tests/BrainBarTests/SocketIntegrationTests.swift
testToolsListPreservesCanonicalAnnotations verifies standard framing preserves annotations. testRawLineToolsListCompactsForClaudeExtensionLimit confirms raw-line responses omit annotations and stay under 8192 bytes. Updated existing test request IDs for consistency.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Server as BrainBarServer
    participant Framing as MCPFraming
    participant Response as Response

    rect rgba(100, 150, 200, 0.5)
        Note over Client,Response: Content-Length Framing (Preserves Annotations)
        Client->>Server: tools/list request
        Server->>Response: build full response with annotations
        Response->>Framing: encodeJSONResponse(response)
        Framing->>Client: Content-Length framed response (preserves annotations)
    end

    rect rgba(150, 200, 100, 0.5)
        Note over Client,Response: Raw Newline-Delimited (Compacts Annotations)
        Client->>Server: tools/list request (raw line)
        Server->>Response: build full response with annotations
        Server->>Server: compactRawJSONResponseIfNeeded (remove tool annotations)
        Response->>Framing: encodeJSONResponse(compacted response)
        Framing->>Client: newline-delimited response (no annotations, <8192 bytes)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Annotations trimmed for the wire so tight,
Raw lines hop under 8192 bytes in flight,
Content-Length keeps the full tale to tell,
Two transport modes dance—both framing well.
Claude's limits met with a preprocessing spell!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: compacting the tools list response for Claude MCPB to address size constraints, which directly matches the PR's core objective of fixing the 8192-byte limit issue.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/brainbar-mcpb-tools-list-size

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 3, 2026

@coderabbitai review

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 3, 2026

@codex review

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 3, 2026

@cursor @BugBot review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cursor
Copy link
Copy Markdown

cursor Bot commented May 3, 2026

Excellent! Now let me write a comprehensive review of this PR. Based on my analysis:

🔍 Bugbot Review: PR #275 - Fix BrainBar MCPB Tools List Size

Summary

This PR successfully fixes a critical Claude Desktop boot failure by reducing the BrainLayer MCPB tools/list response size from 8,995 bytes to under 8,192 bytes. The fix removes optional annotations fields from the public tools list response while preserving them internally for documentation and testing.


✅ What Works Well

1. Root Cause Analysis is Spot-On
The PR correctly identifies that Claude Desktop's MCPB utility process parses raw stdout in 8192-byte chunks, causing JSON-RPC messages that exceed this boundary to be parsed as separate, malformed messages.

2. Elegant Two-Layer Design

// Public API: compact, fits in 8 KiB
static let compactToolDefinitions: [[String: Any]] = toolDefinitions.map { tool in
    var compact = tool
    compact.removeValue(forKey: "annotations")
    return compact
}

// Internal: full annotations for testing/docs
static let toolDefinitions: [[String: Any]] = [...]

This preserves the annotation taxonomy internally while keeping the wire format lean.

3. Test Coverage is Comprehensive

  • testEncodedToolsListFitsClaudeExtensionRawMessageLimit verifies the size constraint
  • testEachToolHasExpectedAnnotations ensures internal annotations remain intact
  • Tests correctly use MCPRouter.toolDefinitions (internal) vs compactToolDefinitions (public)

4. Performance Impact: Zero
The compaction is computed once at static initialization time. No runtime overhead.


🔬 Technical Correctness

Architecture:

  • ✅ Correctly changes handleToolsList to return Self.compactToolDefinitions
  • ✅ Preserves all 16 tools with full schemas and descriptions
  • ✅ Only removes the optional annotations field (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)
  • ✅ Claude's MCP protocol does not require annotations in the tools/list response

Test Changes:

  • ✅ New test uses MCPFraming.encodeJSONResponse to measure actual wire size
  • ✅ Refactored testEachToolHasExpectedAnnotations to test MCPRouter.toolDefinitions directly
  • ✅ Cleaner separation: public API tests vs internal contract tests

Byte Budget Math:

  • Before: 8,995 bytes (109 bytes over limit)
  • After: < 8,192 bytes (confirmed by test assertion)
  • Savings: ~803 bytes (removing annotations for 16 tools × ~50 bytes each)

⚠️ Potential Issues / Questions

1. Missing Size Verification in Test Output
The test asserts body.count < 8192 but doesn't log the actual size. Consider:

XCTAssertLessThan(
    body.count,
    8192,
    "tools/list response is \(body.count) bytes (must be < 8192)"
)

This helps track the safety margin if tools are added in the future.

2. Future-Proofing: What if we add more tools?
Current tool count: 16 tools
Current size: ~7,389 bytes (estimated, under 8 KiB)
Safety margin: ~803 bytes (~50 bytes per additional tool)

Recommendation: Add a comment warning that adding 15+ more tools might breach the limit again.

3. Are Annotations Actually Optional?
The code assumes annotations are optional in MCP 2024-11-05 protocol. Can you confirm:

  • Claude Desktop doesn't require annotations for tool safety checks?
  • The annotations were only for human-readable metadata?

If annotations are used by Claude for safety decisions, this fix might cause issues.

4. Alternative Approaches Not Discussed
Why not:

  • Gzip the response? (MCPB might not support compression)
  • Paginate tools/list? (Would require protocol change)
  • Send annotations separately via a custom capability?

These seem infeasible, but worth documenting why they were rejected.


🧪 Test Strategy Review

What's Tested:

What's NOT Tested:

  • ❓ Actual Claude Desktop boot with the compact response
  • ❓ Whether Claude still respects tool safety (readOnly/destructive hints)
  • ❓ Edge case: adding a 17th tool and verifying size still fits

Deploy Verification Plan (from PR description):

After merge: pull main, pause enrichment, rebuild/reinstall BrainBar, restart BrainBar, then launch the MCPB Node extension bridge and verify the raw tools/list line is below 8192 bytes and Claude logs no longer show Unterminated string in JSON at position 8192.

This is good but manual. Consider adding an integration test that:

  1. Launches the MCPB bridge
  2. Captures raw stdout
  3. Verifies the tools/list line is < 8192 bytes

🎯 Recommendations

High Priority:

  1. Verify with actual Claude Desktop boot before merging
  2. Document the 8 KiB limit in a comment near compactToolDefinitions
  3. Add logging to track actual response size in production

Medium Priority:
4. Add a test that simulates adding many tools and ensures we'd catch a size regression
5. Update PR description to clarify that annotations are optional per MCP spec

Low Priority:
6. Consider a compile-time assertion that fails if the static size exceeds 7900 bytes (leaving a 292-byte buffer)


📊 Risk Assessment

Likelihood of Regression: Low

  • Well-tested change
  • Clear root cause identified
  • Backwards compatible (annotations were optional)

Impact if Annotations Matter: Medium-High

  • If Claude Desktop uses annotations for safety decisions, removing them could allow destructive operations unexpectedly
  • Recommend verifying Claude's annotation usage before merge

Deployment Risk: Low

  • Clean Swift-only change
  • No DB schema changes
  • No Python interop affected

✅ Final Verdict

LGTM with minor recommendations. This is a well-reasoned fix with solid test coverage. The two-layer design is elegant and maintains internal documentation while solving the immediate boot failure.

Before merging:

  1. Confirm annotations are optional in MCP protocol
  2. Test with actual Claude Desktop MCPB extension
  3. Add a comment documenting the 8 KiB limit near compactToolDefinitions

Post-merge:

  • Monitor Claude Desktop logs for any annotation-related warnings
  • Track the actual response size in production telemetry

📝 Code Quality Notes

Strengths:

  • Clear, explanatory comments
  • Test-driven development (RED test first)
  • No premature optimization
  • Follows existing code style

Minor Style Notes:

  • Consider extracting the magic number 8192 to a named constant:
    private static let claudeMCPBChunkSize = 8192

Summary for User

I've completed a thorough review of this PR. The fix is technically sound and solves the Claude Desktop boot failure by removing optional annotations fields from the tools/list response, reducing it from 8,995 bytes to under the 8,192-byte limit.

Key findings:

  • ✅ Root cause correctly identified
  • ✅ Elegant two-layer design preserves internal documentation
  • ✅ Comprehensive test coverage
  • ⚠️ Should verify annotations are optional in MCP spec before merging
  • ⚠️ Recommend adding size tracking comment for future tool additions

The PR is ready to merge after confirming that Claude Desktop doesn't require annotations for tool safety decisions.

Open in Web Open in Cursor 

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a1301690d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread brain-bar/Sources/BrainBar/MCPRouter.swift Outdated
Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 3, 2026

Addressed Codex P1 in 4b1f020: canonical MCPRouter tools/list and Content-Length/framed socket responses now preserve full tool annotations. The sub-8192-byte compaction is scoped only to raw newline transport used by Claude Desktop's MCPB extension bridge, with a regression test covering both paths.

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 3, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b1f020c4e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread brain-bar/Sources/BrainBar/BrainBarServer.swift
@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 3, 2026

Addressed latest Codex P2 in 99371eb: raw newline responses now encode the canonical payload first and preserve annotations whenever the message is below the 8192-byte Claude MCPB chunk limit. Compaction only runs for oversized tools/list responses.

@EtanHey
Copy link
Copy Markdown
Owner Author

EtanHey commented May 3, 2026

@codex review

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@EtanHey EtanHey merged commit 70606e0 into main May 3, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant