2.2.0: binary content blocks (ImageContentBlock, BlobResourceContents) serialize invalid base64 - client-side CallToolResult deserialization throws (regression of #1340)
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 55/100
Research direction
Start with the provided console reproduction using McpJsonUtilities.DefaultOptions, then trace the polymorphic ContentBlock and ResourceContents serialization path and compare it with direct BlobResourceContents serialization. The fix is complete when ImageContentBlock data and BlobResourceContents blobs are emitted as valid base64 and CallToolResult round-trips without a JsonException.
Written by the indexing model from the issue text.
Description
Description
Binary content blocks (ImageContentBlock, EmbeddedResourceBlock with BlobResourceContents) round-trip incorrectly through McpJsonUtilities.DefaultOptions in 2.2.0: the writer does not emit valid base64 for the binary payload, so deserializing the produced JSON throws
System.Text.Json.JsonException: The JSON value could not be converted to ModelContextProtocol.Protocol.ResourceContents.
---> System.FormatException: Cannot decode JSON text that is not encoded as valid Base64 to bytes.
at System.Text.Json.Utf8JsonReader.GetBytesFromBase64()
at ModelContextProtocol.Protocol.ResourceContents.Converter.Read(...)
In practice this means a tool that returns a PDF via EmbeddedResourceBlock/BlobResourceContents (or an image via ImageContentBlock) over the Streamable HTTP transport breaks the client-side deserialization of the whole CallToolResult — the client (McpClient.CallToolAsync) throws and the result is lost.
This looks like a regression of #1340 / #1064: ImageContentBlock.Data is serialized as the raw bytes reinterpreted as a UTF-16 string (mostly U+FFFD replacement characters and escaped control characters in the JSON), not as base64.
Repro (console app, ModelContextProtocol.Core 2.2.0, net10.0)
using System.Text.Json;
using ModelContextProtocol;
using ModelContextProtocol.Protocol;
var bytes = new byte[900_000];
Random.Shared.NextBytes(bytes);
var result = new CallToolResult
{
Content =
[
new EmbeddedResourceBlock
{
Resource = new BlobResourceContents
{
Uri = "demo://files/1/test.pdf",
MimeType = "application/pdf",
Blob = bytes,
},
},
],
};
var json = JsonSerializer.Serialize(result, McpJsonUtilities.DefaultOptions);
// throws FormatException("Cannot decode JSON text that is not encoded as valid Base64 to bytes."):
var back = JsonSerializer.Deserialize<CallToolResult>(json, McpJsonUtilities.DefaultOptions);
Same shape for images: serializing new ImageContentBlock { Data = bytes, MimeType = "image/png" } as ContentBlock produces a "data" property that is not base64 (raw bytes as string), and deserializing it back throws the same FormatException.
Interestingly, serializing the BlobResourceContents directly (not through the polymorphic CallToolResult/ContentBlock path) produces correct base64 — the asymmetry sits in the polymorphic converter path.
Expected behavior
blob/data are written as base64 strings (per spec) and round-trip through McpJsonUtilities.DefaultOptions.
Environment
- ModelContextProtocol / ModelContextProtocol.Core / ModelContextProtocol.AspNetCore 2.2.0
- .NET 10.0 (net10.0), macOS arm64
- Observed both in the minimal repro above and end-to-end over the Streamable HTTP transport (ASP.NET Core server to McpClient)
- Dominant language
- C#
- Stars
- 4.5k
- Forks
- 814
- Avg merge
- 9d 19h
- Merged PRs (30d)
- 4
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from modelcontextprotocol/csharp-sdk
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
modelcontextprotocol/csharp-sdk#1867 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
modelcontextprotocol/csharp-sdk#1840 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
modelcontextprotocol/csharp-sdk#1836 ·
-
enhancement needs confirmation
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
modelcontextprotocol/csharp-sdk#678 · 1 comment ·
-
enhancement needs confirmation P3 ready for work
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
modelcontextprotocol/csharp-sdk#515 · 6 comments · 3 reactions ·
All issues in modelcontextprotocol/csharp-sdk
Similar issues
-
untriaged
Difficulty 1/5 Under an hour Newbie friendliness 88/100
dotnet/dotnet-api-docs#13095 ·
-
area-deployment area-integrations triage:bot-seen
Difficulty 2/5 Half a day Newbie friendliness 86/100
-
type/automation type/tech-debt
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
bug
Difficulty 1/5 Under an hour Newbie friendliness 90/100
newrelic/newrelic-dotnet-agent#3850 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
LuckyPennySoftware/AutoMapper#4660 ·