Skip to content

Map text DataContent to an MCP text resource, not a binary blob#541

Merged
qmuntal merged 3 commits into
microsoft:mainfrom
PratikDhanave:fix-mcptool-text-resource
Jul 18, 2026
Merged

Map text DataContent to an MCP text resource, not a binary blob#541
qmuntal merged 3 commits into
microsoft:mainfrom
PratikDhanave:fix-mcptool-text-resource

Conversation

@PratikDhanave

Copy link
Copy Markdown
Contributor

Problem

When exposing an agent as an MCP tool, agentContentToMCPContent converts a message.DataContent into an mcp.EmbeddedResource. Image and audio media types get dedicated content types, but every other media type — including text/* — fell through to the default case and was written to Resource.Blob as base64 binary:

switch contentValue.TopLevelMediaType() {
case "image": ...
case "audio": ...
default:
    return &mcp.EmbeddedResource{Resource: &mcp.ResourceContents{
        URI: contentValue.Name, MIMEType: contentValue.MediaType, Blob: data, // text ends up here too
    }}
}

mcp.ResourceContents deliberately separates Text (readable) from Blob (base64 binary). The reverse mapping already relies on this — mcpContentToAgentContent branches on Resource.Text != "" to reconstruct a TextContent. So the writer never producing Text is an asymmetry: a text DataContent round-tripped through MCP becomes an unreadable binary blob, and MCP clients reading the resource treat text as binary.

Fix

Add a text case that populates Resource.Text with the decoded string. Binary payloads (e.g. application/octet-stream) still use Blob — unchanged.

Test

TestAddToolReturnsTextDataAsTextResource (black-box) returns a text/plain DataContent from a tool and asserts the resulting EmbeddedResource carries the text in Resource.Text (and not Blob). Fails on main (Text = "", Blob populated), passes with the fix. The existing TestAddToolReturnsBinaryDataAsEmbeddedResource (octet-stream → Blob) is unchanged.

When exposing an agent as an MCP tool, agentContentToMCPContent converts
a DataContent to an mcp.EmbeddedResource. Image and audio media types get
dedicated content types, but every other media type — including text/* —
fell through to the default case and was written to Resource.Blob as
base64 binary.

The reverse mapping (mcpContentToAgentContent) already branches on
Resource.Text to reconstruct text, so the writer never producing Text is
an asymmetry: a text DataContent round-tripped through MCP became an
unreadable binary blob, and MCP clients reading the resource would treat
text as binary.

Add a text case that populates Resource.Text with the decoded string.
Binary payloads (e.g. application/octet-stream) still use Blob.
@PratikDhanave
PratikDhanave requested a review from a team as a code owner July 17, 2026 22:43
Copilot AI review requested due to automatic review settings July 17, 2026 22:43

Copilot AI 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.

Pull request overview

This pull request fixes an MCP content-mapping asymmetry when exposing an agent as an MCP tool: message.DataContent with text/* media types is now emitted as an MCP embedded resource with Resource.Text (readable) instead of Resource.Blob (binary), matching how the reverse mapping already interprets text resources.

Changes:

  • Add a text media-type case in agentContentToMCPContent that sets mcp.ResourceContents.Text instead of Blob.
  • Add a black-box regression test ensuring text/plain DataContent is returned as an embedded text resource (Text set, Blob empty).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
tool/mcptool/mcp.go Emits text/* DataContent as an MCP embedded resource using Resource.Text rather than Resource.Blob.
tool/mcptool/mcp_test.go Adds a regression test covering text DataContent → embedded text resource behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tool/mcptool/mcp.go Outdated
return &mcp.EmbeddedResource{Resource: &mcp.ResourceContents{
URI: contentValue.Name,
MIMEType: contentValue.MediaType,
Text: string(data),
@karianna

Copy link
Copy Markdown
Member

@PratikDhanave merge conflict

Address review feedback: a text-typed DataContent whose decoded bytes are
not valid UTF-8 would be corrupted if placed in ResourceContents.Text
(JSON transport replaces invalid sequences). Emit a binary Blob resource
in that case. Adds a regression test.
# Conflicts:
#	tool/mcptool/mcp.go
@qmuntal
qmuntal added this pull request to the merge queue Jul 18, 2026
Merged via the queue into microsoft:main with commit 8977554 Jul 18, 2026
19 checks passed
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.

4 participants