Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

2.2.0: binary content blocks (ImageContentBlock, BlobResourceContents) serialize invalid base64 - client-side CallToolResult deserialization throws (regression of #1340)

オープン
#1,835 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 2 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
55/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
csharp
領域
api, backend

調査の方向性

McpJsonUtilities.DefaultOptions を使用して、まず提供されたコンソールでの再現から始めます。次に、ContentBlock と ResourceContents のポリモーフィックなシリアライゼーションパスを追跡し、BlobResourceContents の直接シリアライゼーションと比較します。ImageContentBlock データと BlobResourceContents の blob が有効な base64 として出力され、CallToolResult が JsonException なしでラウンドトリップできれば、修正は完了です。

索引モデルが issue の本文から書いたものです。

説明

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)
主要言語
C#
スター
4.5k
フォーク
814
平均マージ
8日 7時間
マージ済み PR(30日)
3

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

modelcontextprotocol/csharp-sdk のほかの issue

modelcontextprotocol/csharp-sdk の issue をすべて見る

似ている issue

C# の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。