[Bug] MCP Client Corrupts Base64-Encoded Binary Data in Tool Results

Resolved 💬 4 comments Opened Dec 29, 2025 by lbrack Closed Dec 31, 2025

Bug Description
Bug Report: MCP Client Binary Data Corruption
Product: Claude Code (CLI) Component: MCP Client Layer Severity: High Date: 2025-12-29

Summary
Binary data returned from MCP tool calls is corrupted when passing through Claude Code's MCP client layer. The MCP server correctly handles and returns binary data (verified by independent tests), but the data received by the AI agent is corrupted.

Environment
Claude Code CLI (latest version as of 2025-12-29)
Custom MCP Server: metis-mcp v2.2.1
OS: Linux (Ubuntu 24.04)
Node.js: v20.x
Reproduction Steps
Create an MCP server with file download capability that returns base64-encoded binary data
Upload a binary file (e.g., gzip tarball) to Slack
Download the file via MCP tool call from Claude Code
Compare the downloaded data with the original
Expected Result
Downloaded binary data matches original exactly.

Actual Result
Downloaded binary data is corrupted. Common symptoms:

CRC errors when extracting gzip archives
File size may match but content differs
Corruption appears random/intermittent
Evidence
MCP Server Tests Pass
We created file integrity tests that:

Generate random binary data
Upload via slack_upload_file
Download via slack_download_file
Compare byte-by-byte
Result: All tests PASS when running directly against the MCP server.

✓ slack file upload/download - should preserve binary data integrity (4.5s)
✓ slack file upload/download - should preserve gzip tarball integrity (8.3s)

10 passed (17.3s)
Test code excerpt:

// Generate random binary data
const testDataSize = 1024;
const randomBytes = new Uint8Array(testDataSize);
for (let i = 0; i < testDataSize; i++) {
randomBytes[i] = Math.floor(Math.random() * 256);
}
const originalBase64 = Buffer.from(randomBytes).toString('base64');

// Upload
const uploadResponse = await client.callTool('slack_upload_file', {
channel: 'mcp-test',
filename: test-integrity-${Date.now()}.bin,
content: originalBase64,
is_base64: true
});

// Download
const downloadResponse = await client.callTool('slack_download_file', {
file_id: fileId,
as_base64: true
});

// Verify - THIS PASSES
expect(downloadData.content).toBe(originalBase64);
Claude Code Downloads Fail
When the same download is performed through Claude Code's MCP client:

$ tar -xzf downloaded-file.tar.gz
gzip: stdin: invalid compressed data--crc error
tar: Child returned status 1
tar: Error is not recoverable: exiting now
The file downloads successfully (correct size), but the content is corrupted.

Analysis
The corruption occurs in the MCP client layer within Claude Code, not in:

The MCP server (verified by passing tests)
Slack's API (verified by manual download)
Network transport (consistent corruption pattern)
Possible causes:

Character encoding issues when handling base64 strings
Buffer handling in the JSON-RPC transport
String truncation or modification during message parsing
Workaround
For critical binary files, we:

Upload via MCP (works correctly)
Download via filesystem if agents share storage
Or download via curl/wget from a different process
Requested Fix
Please investigate the MCP client's handling of binary data (returned as base64 strings in tool results) and ensure it is not modified during transport.

Test Case
The test file is available at:

Repository: github.com/partsnap/metis-mcp
Test file: tests/slack.spec.ts
Specific tests: "should preserve binary data integrity" and "should preserve gzip tarball integrity"
To reproduce:

git clone https://github.com/partsnap/metis-mcp
cd metis-mcp
npm install
npm run build
npx playwright test tests/slack.spec.ts # PASSES
Then use Claude Code to call the same tools and observe corruption.

Impact
This bug prevents reliable binary file transfer between AI agents using Claude Code with MCP. Agents cannot:

Share compiled assets
Transfer compressed archives
Exchange binary data reliably
Current workaround (filesystem transfer) only works when agents share storage.

Contact
Laurent Brack GitHub: @lbrack

Environment Info

  • Platform: linux
  • Terminal: pycharm
  • Version: 2.0.76
  • Feedback ID: 3fd87764-05ee-4f6c-8289-0d2d77581174

Errors

[{"error":"SyntaxError: Unexpected token '/', \"/home/lbra\"... is not valid JSON\n    at JSON.parse (<anonymous>)\n    at file:///home/lbrack/.nvm/versions/node/v22.18.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:75:715\n    at B (file:///home/lbrack/.nvm/versions/node/v22.18.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:8:6526)\n    at pM0.<anonymous> (file:///home/lbrack/.nvm/versions/node/v22.18.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:4982:272)\n    at pM0.Q [as _actionHandler] (file:///home/lbrack/.nvm/versions/node/v22.18.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:4759:528)\n    at file:///home/lbrack/.nvm/versions/node/v22.18.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:4763:3119\n    at file:///home/lbrack/.nvm/versions/node/v22.18.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:4763:1674\n    at async pM0.parseAsync (file:///home/lbrack/.nvm/versions/node/v22.18.0/lib/node_modules/@anthropic-ai/claude-code/cli.js:4760:4156)\n    at a

Note: Error logs were truncated.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗