You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Image content blocks >99 bytes fail with "illegal base64 at byte 0" #3123
Image content blocks returned via _mcp_content_blocks fail client-side base64 decoding when the decoded image bytes exceed 99 bytes, despite the server emitting spec-compliant MCP protocol messages. The issue manifests as "illegal base64 data at input byte 0" errors in the client, while server wire logs confirm correct base64 encoding with proper padding.
Environment
Server:
Python SDK: mcp==1.28.1
Python: 3.12
Transport: stdio (JSON-RPC over stdin/stdout)
OS: Linux (Ubuntu-based)
Client:
Claude Code (Anthropic's MCP client)
Error source: Go encoding/base64 (based on error message format)
Image '<uuid>.webp' could not be processed: illegal base64 data at input byte 0
This error indicates the first character received by the client decoder is not valid base64, despite server logs showing first_char='U' (valid base64).
Root Cause Analysis
The evidence suggests:
Server-side is correct:
Wire logs show proper base64 encoding
First/last characters are valid
Padding is correct (len % 4 == 0)
No unexpected keys or wrapping
Client-side has size threshold:
Exact boundary at 100 decoded bytes
Error message from Go encoding/base64 (not Python)
✅ Root Cause Identified: Entropy-Based Redaction Pre-Decode
After 7 test rounds over 6 days with discriminating experiments, root cause confirmed:
Claude.ai's tool-result pipeline applies high-entropy string redaction to base64 image payloads inside ImageContent and EmbeddedResource blocks BEFORE image decoding, replacing valid data and causing "illegal base64 data at input byte 0" errors.
Discriminating Test Results (2026-07-17)
Built entropy-discriminating test with Shannon entropy calculation:
For reference: typical compressed images (JPEG/WebP/PNG compress_level=6-9) have ~5.5-6.0 bits/char Shannon entropy.
Error Source Attribution
Error phrasing "illegal base64 data at input byte N" is Go's encoding/base64 exact format (not Python binascii, not TypeScript, not MCP SDK error messages).
This points to Anthropic's Claude.ai server-side ingestion layer (Go-based), not the MCP Python SDK.
The bug manifests when:
MCP server emits valid base64 ImageContent/EmbeddedResource block (verified via server-side diagnostics)
Claude.ai ingestion pipeline detects high-entropy string in tool result
Redaction filter replaces base64 blob with "[REDACTED: high_entropy_string]"
Image decoder receives "[" as first character
Decoder fails at byte 0: "illegal base64 data at input byte 0"
This explains all observations across 7 test rounds and matches the known behavior of Claude.ai redacting high-entropy strings in data URIs.
Server-Side Verification
Wire-level logging confirmed server emits perfect, valid base64:
Yet client receives: "illegal base64 data at input byte 0"
Bug is definitively downstream of MCP SDK stdout — in Claude.ai's ingestion/redaction pipeline.
Impact
All compressed images fail (WebP, JPEG, PNG with standard compression)
Only artificially low-entropy images work (solid colors, compress_level=0)
Real-world thumbnails/charts/photos inherently have high entropy when compressed
Defeats the purpose of MCP's image content block feature
Workaround (Being Validated)
Potential: Uncompressed PNG (compress_level=0) of real content if pixel redundancy keeps Shannon entropy <0.7 bits/char.
Testing realistic chart/thumbnail content to validate if workaround is viable for production use.
Recommendation
This is a Claude.ai client-side bug, not an MCP SDK bug. Should be escalated to Anthropic's Claude.ai tool ingestion team:
Redaction filter should NOT run on image data fields inside MCP content blocks. These are already typed as type: "image" with mimeType — there's no ambiguity requiring entropy-based heuristics.
Status: Root cause identified with reproducible test. First successful image deliveries achieved. Awaiting Anthropic fix or workaround validation for real content.
✅ Threshold Measured: 4.52 ± 0.04 bits/char Global Shannon Entropy
After systematic bisection testing, the exact redaction threshold has been determined:
Threshold: 4.52 ± 0.04 bits/char global Shannon entropy over the full payload (consistent with 4.5 exactly)
Filter Mechanism Confirmed
The redaction filter computes global Shannon entropy over the entire base64 payload.
Alternative hypotheses eliminated:
Window-based filtering: ❌ Eliminated
Test payload with sliding-window max 4.65 bits/char but global 0.64 → ✅ Passed
Payload with sliding max 2.25 but global 5.007 → ❌ Failed
Run-based filtering: ❌ Eliminated
Payload with longest run 32 characters but global entropy 5.007 → ❌ Failed
Long repeated runs don't defeat filter if global entropy exceeds threshold
Distinct-character count: ❌ Eliminated
Payloads with identical distinct-character counts split pass/fail based on global entropy alone
36 distinct @ 5.007 entropy → ❌ Failed
49 distinct @ 0.147 entropy → ✅ Passed
Conclusion: Global Shannon entropy is the single determining factor.
Production Workaround: Palette-Mode PNG
Since all standard compression fails (PNG deflate at any level produces 5.24-5.75 bits/char), the optimization lever is representation, not compression.
Solution: Indexed-palette PNG, compress_level=0
Benefits:
Indexed mode: 1 byte/pixel vs 3-4 bytes/pixel for RGB
256×256 thumbnail: ~47 KB base64 (acceptable for MCP protocol)
Supported content:
✅ Charts, infographics, diagrams
✅ UI mockups, wireframes
✅ QR codes, logos, icons
❌ Photos/natural images: 5.77 bits/char even at palette cl=0 (blocked on Anthropic fix)
Test Results Summary
Encoding
Entropy (bits/char)
Result
RGB cl=0
0.147 (chart)
✅ Pass
Palette cl=0
~0.6-0.8 (chart)
✅ Pass
PNG cl=1
5.750
❌ Fail
PNG cl=9
5.236
❌ Fail
WebP lossless
5.393
❌ Fail
Palette cl=0 (photo)
5.77
❌ Fail
Threshold location: Between 4.48 and 4.56 bits/char Best estimate: 4.52 ± 0.04 (consistent with 4.5 exactly)
Scope Limitation
Natural images (photos, AI-generated art) remain blocked even with optimal representation. The inherent pixel variation in natural imagery produces entropy above threshold regardless of encoding.
Recommendation: Anthropic should exempt type: "image" content blocks with mimeType from high-entropy redaction. These are already typed as image data, not potential secrets requiring heuristic detection.
Corroborating from the SDK side — I audited the python-sdk source for anything that could alter content-block data:
There is no entropy-based redaction or sanitization anywhere in this SDK. The only base64-wrapping code (the =?base64?...?= sentinel in src/mcp/shared/inbound.py) applies to HTTP header round-trips, not content blocks.
The Image helper encodes with newline-free base64.b64encode — so the SDK emitting clean base64 matches your wire logs exactly.
One additional fingerprint supporting your diagnosis: your measured threshold of 4.52 ± 0.04 bits/char is a near-exact match for the default base64 entropy limit in detect-secrets (4.5) — the most widely deployed secrets-scanning heuristic. That strongly suggests a stock secrets-redaction pass running over tool results downstream of this SDK, consistent with everything you measured.
+1 to your recommendation: content blocks already typed "type": "image" with a mimeType shouldn't be subject to entropy-based secret heuristics at all. This likely belongs on Anthropic's Claude Code / claude.ai feedback tracker rather than this repo — but leaving the corroboration here so the next reader doesn't re-derive it.
There's no size- or entropy-based redaction in this SDK — ImageContent.data is a plain str written to the transport untouched — so the alteration is downstream in the client's tool-result ingestion; for Claude Code that's https://github.com/anthropics/claude-code. Closing this as part of a wider backlog cleanup following the v2 launch. Feel free to reopen if this is still relevant.
Activity
PeeperFrog commentedon Jul 18, 2026
Minimal Reproduction Server:
Requirements:
Usage:
Then connect with Claude Code and run:
test_image_size(test_variant=0)→ ✅ 48 bytes, renderstest_image_size(test_variant=1)→ ❌ 102 bytes, fails with 'illegal base64 at byte 0'PeeperFrog commentedon Jul 18, 2026
Temporary Workaround Implemented
While awaiting fix, we've deployed a hybrid thumbnail delivery system:
Implementation:
Code:
Results:
This workaround will be removed once SDK fix is deployed.
PeeperFrog commentedon Jul 18, 2026
✅ Root Cause Identified: Entropy-Based Redaction Pre-Decode
After 7 test rounds over 6 days with discriminating experiments, root cause confirmed:
Claude.ai's tool-result pipeline applies high-entropy string redaction to base64 image payloads inside ImageContent and EmbeddedResource blocks BEFORE image decoding, replacing valid data and causing "illegal base64 data at input byte 0" errors.
Discriminating Test Results (2026-07-17)
Built entropy-discriminating test with Shannon entropy calculation:
Key finding: 4,232-char low-entropy (0.27 bits/char) payload renders successfully. 112-char high-entropy (4.89 bits/char) payload fails at byte 0.
Size is irrelevant. Entropy is everything.
Entropy Threshold
For reference: typical compressed images (JPEG/WebP/PNG compress_level=6-9) have ~5.5-6.0 bits/char Shannon entropy.
Error Source Attribution
Error phrasing "illegal base64 data at input byte N" is Go's encoding/base64 exact format (not Python binascii, not TypeScript, not MCP SDK error messages).
This points to Anthropic's Claude.ai server-side ingestion layer (Go-based), not the MCP Python SDK.
The bug manifests when:
"[REDACTED: high_entropy_string]""["as first characterThis explains all observations across 7 test rounds and matches the known behavior of Claude.ai redacting high-entropy strings in data URIs.
Server-Side Verification
Wire-level logging confirmed server emits perfect, valid base64:
Yet client receives:
"illegal base64 data at input byte 0"Bug is definitively downstream of MCP SDK stdout — in Claude.ai's ingestion/redaction pipeline.
Impact
Workaround (Being Validated)
Potential: Uncompressed PNG (compress_level=0) of real content if pixel redundancy keeps Shannon entropy <0.7 bits/char.
Testing realistic chart/thumbnail content to validate if workaround is viable for production use.
Recommendation
This is a Claude.ai client-side bug, not an MCP SDK bug. Should be escalated to Anthropic's Claude.ai tool ingestion team:
Redaction filter should NOT run on image data fields inside MCP content blocks. These are already typed as
type: "image"withmimeType— there's no ambiguity requiring entropy-based heuristics.Test Code
Entropy-discriminating test available at: https://github.com/PeeperFrog/noisk-ai-mcp/blob/18919c7b/src/NOISK_AI_server.py#L14006-14133
Shannon entropy calculation:
Solid pattern (low entropy):
Status: Root cause identified with reproducible test. First successful image deliveries achieved. Awaiting Anthropic fix or workaround validation for real content.
PeeperFrog commentedon Jul 18, 2026
✅ Threshold Measured: 4.52 ± 0.04 bits/char Global Shannon Entropy
After systematic bisection testing, the exact redaction threshold has been determined:
Threshold: 4.52 ± 0.04 bits/char global Shannon entropy over the full payload (consistent with 4.5 exactly)
Filter Mechanism Confirmed
The redaction filter computes global Shannon entropy over the entire base64 payload.
Alternative hypotheses eliminated:
Window-based filtering: ❌ Eliminated
Run-based filtering: ❌ Eliminated
Distinct-character count: ❌ Eliminated
Conclusion: Global Shannon entropy is the single determining factor.
Production Workaround: Palette-Mode PNG
Since all standard compression fails (PNG deflate at any level produces 5.24-5.75 bits/char), the optimization lever is representation, not compression.
Solution: Indexed-palette PNG, compress_level=0
Benefits:
Supported content:
Test Results Summary
Threshold location: Between 4.48 and 4.56 bits/char
Best estimate: 4.52 ± 0.04 (consistent with 4.5 exactly)
Scope Limitation
Natural images (photos, AI-generated art) remain blocked even with optimal representation. The inherent pixel variation in natural imagery produces entropy above threshold regardless of encoding.
Recommendation: Anthropic should exempt
type: "image"content blocks withmimeTypefrom high-entropy redaction. These are already typed as image data, not potential secrets requiring heuristic detection.Implementation Status
Repository: https://github.com/PeeperFrog/noisk-ai-mcp (Test 7 series, commits 3cbf27ef-416dfed9)
earfman commentedon Jul 18, 2026
Corroborating from the SDK side — I audited the python-sdk source for anything that could alter content-block data:
=?base64?...?=sentinel insrc/mcp/shared/inbound.py) applies to HTTP header round-trips, not content blocks.Imagehelper encodes with newline-freebase64.b64encode— so the SDK emitting clean base64 matches your wire logs exactly.One additional fingerprint supporting your diagnosis: your measured threshold of 4.52 ± 0.04 bits/char is a near-exact match for the default base64 entropy limit in
detect-secrets(4.5) — the most widely deployed secrets-scanning heuristic. That strongly suggests a stock secrets-redaction pass running over tool results downstream of this SDK, consistent with everything you measured.+1 to your recommendation: content blocks already typed
"type": "image"with amimeTypeshouldn't be subject to entropy-based secret heuristics at all. This likely belongs on Anthropic's Claude Code / claude.ai feedback tracker rather than this repo — but leaving the corroboration here so the next reader doesn't re-derive it.maxisbey commentedon Aug 10, 2026
There's no size- or entropy-based redaction in this SDK —
ImageContent.datais a plainstrwritten to the transport untouched — so the alteration is downstream in the client's tool-result ingestion; for Claude Code that's https://github.com/anthropics/claude-code. Closing this as part of a wider backlog cleanup following the v2 launch. Feel free to reopen if this is still relevant.AI Disclaimer