{{ message }}
Repository navigation
Conversation
A tool annotated `-> bytes` publishes output_schema
{"result": {"type": "string", "format": "binary"}}, but real binary
data crashed the conversion: pydantic decodes bytes as UTF-8 when
serializing to JSON, so the first non-UTF-8 byte raised
PydanticSerializationError and the client only saw a generic
"Error executing tool" with the payload lost. UTF-8-decodable bytes came
back as a raw string, and a bytes field inside an output model hit the
same crash.
Encode bytes as base64 — the encoding every other bytes path in this
package already uses (BlobResourceContents, Image/Audio content) — in
both channels: the structured dump and the unstructured content. A
payload without bytes takes the plain JSON dump, byte for byte.
Fixes modelcontextprotocol#3554
Contributor
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Fixes #3554
Motivation and Context
A tool annotated
-> bytespublishesoutput_schema {"result": {"type": "string", "format": "binary"}}, but real binary data crashed the conversion instead of reaching the client: pydantic decodes bytes as UTF-8 when serializing to JSON, so the first non-UTF-8 byte raisedPydanticSerializationErrorinside_convert_to_content(andUnicodeDecodeErrorfrommodel_dump(mode="json")), and the client only saw a genericError executing tool <name>with the payload lost. UTF-8-decodable bytes came back as a raw string rather than an encoding, and a bytes field inside an output model (e.g.class Thumb(BaseModel): data: bytes) hit the same crash.This encodes bytes leaves as base64 — the encoding every other bytes path in this package already uses (
BlobResourceContentsatserver.py:475, andImage/Audiocontent) — in both channels: the structured dump and the unstructured content. A payload without bytes takes the plain JSON dump, byte for byte.How Has This Been Tested?
uv run --frozen pytest tests/server/mcpserver/test_func_metadata.py tests/server/mcpserver/test_integration.py: 74 passed, including 6 new tests (binary and UTF-8-> bytesin both channels, a bytes field in an output model,list[bytes]/dict[str, bytes], and a no-bytes regression guard) plus an end-to-end in-memoryClient(server)call of a-> bytestool.uv run --frozen pytest): 5966 passed, 2 failed. Both failures reproduce on unpatched main on Windows (verified withgit stash):test_sse_client_closes_all_streams_on_connection_errorandtest_safe_join_rejects_symlink_escape(WinError 1314, symlink privilege) — unrelated to this change.ruff check/ruff format --check: clean.pyright(strict): no new errors (34 before, 34 after; all pre-existing Windows-platform diagnostics).Breaking Changes
None for payloads without bytes. Tools returning bytes now deliver base64 in
structuredContentand in their text content, where binary data previously failed the call and UTF-8 bytes previously arrived as a raw string.Types of changes
Checklist
help wanted, or I'm a maintainer)AI assistance disclosure: the diff was written with the ZCode coding agent; I verified the reproduction on Windows (both failure paths), ran the test suites and linters listed above, and reviewed the serializer behaviour against
server.py:475/ Image/Audio before submitting.