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
create_or_update_file has no way to write a genuine binary file (e.g. a PNG) without corruption, even when the caller follows the tool's own current description exactly.
The content parameter description says:
"Content of the file, exactly as it should appear once written. Do not base64-encode it; this server does that before calling the REST API."
This reads as a fix for #2981 (models pre-encoding out of confusion with the REST API docs). But it doesn't address the deeper problem: content is a JSON string, and JSON strings must be valid UTF-8. Raw binary bytes (arbitrary byte sequences, e.g. PNG magic bytes 89 50 4E 47 ...) are frequently not valid UTF-8, so there is no way to place them into this parameter at all — encoded or not:
Pass the raw bytes as-is → most MCP/JSON transports will reject the call outright (invalid UTF-8 in a string field), or the bytes get mangled by whatever text encoding recovery the client/transport applies.
Result: commit succeeds, content.size in the response is 104 (the length of the base64 text), not 77 (the actual PNG size). Fetching the file back with get_file_contents returns the literal base64 string as the file's text content — not a decodable/valid PNG.
There is no parameter on this tool to say "this content is base64" or otherwise indicate a binary-safe encoding, unlike what a content_base64 / encoding field would provide. Every path leads to a corrupted binary file for any client that can only pass JSON string parameters (which is all MCP clients).
Impact
Any MCP client — including AI agents — that needs to commit a binary asset (image, font, icon, PDF, zip, etc.) via create_or_update_file (or the equivalent multi-file push_files, which has the identical content: string shape per-file) cannot do so reliably. The only safe workaround currently is bypassing this tool entirely (e.g. driving the GitHub web upload UI in a browser, or using a real git client locally), which defeats the purpose of having this tool.
Suggested fix
Add an explicit binary-safe path, e.g.:
An optional encoding (or content_encoding) parameter on create_or_update_file and each file entry in push_files, with values like "utf-8" (default, current behavior) and "base64" — when "base64", the server decodes the given base64 string once and writes the resulting raw bytes, instead of writing the base64 text (or double-encoding it).
Reproduced via the hosted GitHub MCP Server connector, 2026-09-19, through an Anthropic Claude MCP connector session. Not version-specific — the tool's content parameter has always been a plain JSON string with no encoding flag.
Describe the bug
create_or_update_filehas no way to write a genuine binary file (e.g. a PNG) without corruption, even when the caller follows the tool's own current description exactly.The
contentparameter description says:This reads as a fix for #2981 (models pre-encoding out of confusion with the REST API docs). But it doesn't address the deeper problem:
contentis a JSON string, and JSON strings must be valid UTF-8. Raw binary bytes (arbitrary byte sequences, e.g. PNG magic bytes89 50 4E 47 ...) are frequently not valid UTF-8, so there is no way to place them into this parameter at all — encoded or not:create_or_update_filecontent description doesn't specify plaintext, leading models to double-encode #2981's own reproduction did) → per the current server behavior, the base64 text is stored literally as the file's bytes. The tool reports success; the resulting file is corrupt (its content is the ASCII base64 string, not the decoded image).Minimal reproduction
Created a 77-byte, 10×10 solid-color PNG, base64-encoded it (104 chars), and called
create_or_update_filewith that base64 string ascontent:content: "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAFElEQVR4nGP8n2XJgBsw4ZEbwdIABR4Btgm0KTcAAAAASUVORK5CYII="
Result: commit succeeds,
content.sizein the response is 104 (the length of the base64 text), not 77 (the actual PNG size). Fetching the file back withget_file_contentsreturns the literal base64 string as the file's text content — not a decodable/valid PNG.There is no parameter on this tool to say "this content is base64" or otherwise indicate a binary-safe encoding, unlike what a
content_base64/encodingfield would provide. Every path leads to a corrupted binary file for any client that can only pass JSON string parameters (which is all MCP clients).Impact
Any MCP client — including AI agents — that needs to commit a binary asset (image, font, icon, PDF, zip, etc.) via
create_or_update_file(or the equivalent multi-filepush_files, which has the identicalcontent: stringshape per-file) cannot do so reliably. The only safe workaround currently is bypassing this tool entirely (e.g. driving the GitHub web upload UI in a browser, or using a realgitclient locally), which defeats the purpose of having this tool.Suggested fix
Add an explicit binary-safe path, e.g.:
encoding(orcontent_encoding) parameter oncreate_or_update_fileand each file entry inpush_files, with values like"utf-8"(default, current behavior) and"base64"— when"base64", the server decodes the given base64 string once and writes the resulting raw bytes, instead of writing the base64 text (or double-encoding it).create_or_update_filecontent description doesn't specify plaintext, leading models to double-encode #2981 tried (and, per this report, failed) to close.Related
create_or_update_filecontent description doesn't specify plaintext, leading models to double-encode #2981 — addressed the ambiguity around double-encoding of text-ish content, but this report shows the description fix alone does not make binary uploads possible; there is still no valid way to submit non-UTF-8 bytes.get_file_contentsdouble-base64-encoding binaries), already fixed.Environment
Reproduced via the hosted GitHub MCP Server connector, 2026-09-19, through an Anthropic Claude MCP connector session. Not version-specific — the tool's
contentparameter has always been a plain JSON string with no encoding flag.