Skip to content

fix(mcp): return text asset content as UTF-8, not base64 - #211

Merged
getappz merged 5 commits into
masterfrom
fix/asset-get-utf8-content
Jul 16, 2026
Merged

fix(mcp): return text asset content as UTF-8, not base64#211
getappz merged 5 commits into
masterfrom
fix/asset-get-utf8-content

Conversation

@getappz

@getappz getappz commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Problem

MCP asset action=get base64-encoded all asset content unconditionally, regardless of mime type. Reading a text/markdown asset (e.g. a handoff) forced every consumer through a decode step — the asset get -> base64-decode dance — even though the bytes were already valid UTF-8.

Fix

The get handler now returns readable text for textual MIME types whose bytes are valid UTF-8, and reports which encoding it used:

  • textual MIME (text/*, +json/+xml, application/{json,xml,javascript,typescript,toml,yaml}) and valid UTF-8 -> "content" as text with "encoding": "utf8"
  • everything else (binary MIME, or invalid UTF-8) -> "encoding": "base64"

Callers branch on encoding instead of blindly decoding. Gating on MIME (not just UTF-8 validity) prevents binary assets that happen to be valid UTF-8 — e.g. an application/octet-stream of control bytes — from being mislabeled utf8. The over-inline-limit and read-error branches are unchanged.

Tests

  • asset_get_returns_text_content_as_utf8_not_base64 — a text/markdown asset with a non-ASCII codepoint round-trips as encoding: "utf8" with readable content.
  • asset_get_returns_base64_for_binary_with_valid_utf8_bytes — a valid-UTF-8 .bin (octet-stream) asset returns encoding: "base64".

Full cargo test --workspace green.

Compatibility

Breaking change to the tool's output contract: consumers that unconditionally base64-decode content now receive raw text for textual assets. They should switch to checking the encoding field.

Tracked as agentflare item 134 (child of the DX/tooling-friction bucket, item 118) — not a GitHub issue.

Summary by CodeRabbit

  • New Features
    • Inline text assets are now returned as readable UTF-8 content when their type is recognized as textual and the bytes decode cleanly.
    • Inline responses now include an encoding indicator (utf8 for text, base64 otherwise).
  • Bug Fixes
    • Inline handling no longer forces Base64 for text content; non-textual or undecodable bytes are still Base64-encoded.
  • Tests
    • Added unit tests covering UTF-8 vs Base64 behavior for inline assets based on both decode results and asset type.

asset `get` base64-encoded every asset's content unconditionally,
forcing consumers to decode even plain-text markdown/html handoffs
(the get -> Write-Host -> b64decode dance). Now returns valid-UTF-8
bytes as-is with `encoding: "utf8"`, and only base64-encodes true
binary (`encoding: "base64"`). The `encoding` field lets callers
branch on the format instead of blindly decoding.

Test: a text/markdown asset round-trips as encoding=utf8 with readable
content, including a non-ASCII codepoint.
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c6dd74f2-ee97-4799-b09d-4b3b0ad33002

📥 Commits

Reviewing files that changed from the base of the PR and between 6fa528c and 01dd2e2.

📒 Files selected for processing (1)
  • src/mcp_server.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/mcp_server.rs

📝 Walkthrough

Walkthrough

Inline asset retrieval now returns readable UTF-8 for decodable textual assets, reports the encoding, and falls back to Base64 for binary or invalid UTF-8 content. Tests cover both encoding outcomes.

Changes

Inline asset encoding

Layer / File(s) Summary
Encoding selection and validation
src/mcp_server.rs
A MIME classifier identifies textual assets; inline retrieval returns original text with "encoding": "utf8" only when bytes are valid UTF-8 and textual, otherwise Base64 with "encoding": "base64". Tests cover markdown text and binary content containing valid UTF-8 bytes.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: returning textual asset content as UTF-8 instead of base64.
Description check ✅ Passed The description covers the problem, fix, tests, and compatibility, though it doesn't use the exact template headings.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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/asset-get-utf8-content

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mcp_server.rs`:
- Around line 2745-2748: Update the content/encoding selection around
std::str::from_utf8 to first allow text decoding only for MIME types in the
established textual MIME allowlist; return Base64 for binary MIME types even
when their bytes are valid UTF-8. Add a regression test covering a valid-UTF8
.bin asset containing binary bytes and verify it reports "encoding": "base64".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 32e030eb-905b-4766-ad3e-fa97b2671b15

📥 Commits

Reviewing files that changed from the base of the PR and between e9fdea9 and 0f6ea2c.

📒 Files selected for processing (1)
  • src/mcp_server.rs

Comment thread src/mcp_server.rs
getappz added 2 commits July 16, 2026 16:25
Binary assets (e.g. application/octet-stream of control bytes) can be
valid UTF-8, so the from_utf8-only discriminator mislabeled them as
encoding=utf8. Gate on a textual-MIME allowlist (text/*, +json/+xml,
application/{json,xml,javascript,typescript,toml,yaml}) AND UTF-8
validity; everything else stays base64.

Adds a regression test: a valid-UTF-8 .bin (octet-stream) asset returns
encoding=base64. Addresses CodeRabbit review on #211.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mcp_server.rs`:
- Around line 5138-5152: Update the test around the parsed `got` response to
assert that `got["content"]` equals the Base64 string `AAECAw==` for the binary
input `[0, 1, 2, 3]`, while preserving the existing `encoding` assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8f06321c-0142-4da8-911a-b58652a164a3

📥 Commits

Reviewing files that changed from the base of the PR and between 0f6ea2c and 7cd0ce5.

📒 Files selected for processing (1)
  • src/mcp_server.rs

Comment thread src/mcp_server.rs
Per CodeRabbit review: the test asserted only encoding=base64, not the
content, so a correct label with wrong content would still pass. Assert
content == "AAECAw==" (base64 of [0,1,2,3]).
@getappz
getappz enabled auto-merge (squash) July 16, 2026 11:14
@getappz
getappz merged commit 92686a6 into master Jul 16, 2026
15 checks passed
@getappz
getappz deleted the fix/asset-get-utf8-content branch July 16, 2026 11:19
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