Skip to content

Handle message.Contents named type in agentResultToMCPCallToolResult - #721

Merged
George Adams (gdams) merged 1 commit into
microsoft:mainfrom
PratikDhanaveFork:mcp-handle-named-contents-type
Jul 29, 2026
Merged

Handle message.Contents named type in agentResultToMCPCallToolResult#721
George Adams (gdams) merged 1 commit into
microsoft:mainfrom
PratikDhanaveFork:mcp-handle-named-contents-type

Conversation

@PratikDhanave

Copy link
Copy Markdown
Contributor

What

agentResultToMCPCallToolResult in tool/mcptool/mcp.go type-switched on case message.Content: and case []message.Content: but had no case for message.Contents — the named slice type (type Contents []Content) that Message.Contents is actually declared as.

A Go type switch matches on dynamic type identity, so a message.Contents value does not match case []message.Content:, nor does it satisfy the Content interface. It fell through to default -> structuredResultToMCPCallToolResult, which json.Marshaled the whole slice into a single TextContent. That:

  • collapsed multiple content blocks into one,
  • encoded image/audio DataContent as base64 JSON strings instead of mcp.ImageContent/mcp.AudioContent, and
  • never set IsError for *message.ErrorContent blocks.

The same defect affected the FunctionResultContent.Result path via functionResultToMCPCallToolResult.

Fix

Add case message.Contents: that converts to []message.Content and delegates to the existing correct branch. That branch already iterates each block, calls agentContentToMCPContent per item (mapping image/audio/resource types), and sets IsError for error content. Minimal and surgical.

Parity

This restores the .NET/Python semantics of surfacing each content block individually to MCP (distinct image/audio/text blocks and an error flag), rather than one opaque JSON text block.

Testing

Added TestAddToolReturnsNamedContentsSlice in tool/mcptool/mcp_test.go: a stub tool returns message.Contents{TextContent, image DataContent, ErrorContent} and the test asserts the resulting mcp.CallToolResult has three blocks — distinct *mcp.TextContent and *mcp.ImageContent (not one JSON text) — with IsError == true. The test fails before the fix (one collapsed block) and passes after. go build ./..., go vet ./tool/mcptool/..., and go test ./tool/mcptool/... are green.

@PratikDhanave
PratikDhanave (PratikDhanave) requested a review from a team as a code owner July 24, 2026 03:18
Copilot AI review requested due to automatic review settings July 24, 2026 03:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes MCP tool-result conversion so message.Contents (the named slice type used by Message.Contents) is handled explicitly in agentResultToMCPCallToolResult, preserving per-block content semantics (text/image/audio blocks) and proper error signaling.

Changes:

  • Add a case message.Contents: branch that converts to []message.Content and reuses the existing multi-content handling.
  • Add a regression test ensuring a tool returning message.Contents yields multiple MCP content blocks and sets IsError when an error block is present.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
tool/mcptool/mcp.go Adds explicit handling for message.Contents so type-switching doesn’t fall back to JSON collapsing behavior.
tool/mcptool/mcp_test.go Adds a regression test covering named-slice (message.Contents) tool results, including image conversion and error-flag propagation.

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

@github-actions

This comment has been minimized.

@github-actions github-actions Bot added the parity-approved Go API consistency review found no parity issues label Jul 24, 2026
A tool may return message.Contents (type Contents []Content), the named
slice type Message.Contents is declared as. The type switch in
agentResultToMCPCallToolResult only matched []message.Content, so a
message.Contents value fell to the default branch and was JSON-marshaled
into a single TextContent, collapsing multiple blocks, encoding image and
audio DataContent as base64 JSON strings, and never setting IsError for
error blocks. Add a case that delegates to the existing []message.Content
branch, which iterates each block, converts image/audio to
mcp.ImageContent/mcp.AudioContent, and sets IsError for error content.
This also fixes the FunctionResultContent.Result path.
@github-actions

Copy link
Copy Markdown
Contributor

Parity Review — Approved

This PR fixes a bug in the unexported agentResultToMCPCallToolResult function where message.Contents (the named slice type type Contents []Content) fell through to the default branch instead of matching case []message.Content:. No exported Go APIs were added or changed.

Cross-repo parity: The fix aligns Go with .NET and Python semantics — surfacing each content block individually as distinct TextContent, ImageContent/AudioContent, and ErrorContent (with IsError set) rather than collapsing them into a single opaque JSON text block.

Labels: public-api-change label is not needed; no exported API surface changed. The existing parity-approved label is correct.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

Generated by Go API Consistency Review Agent · 26 AIC · ⌖ 5.53 AIC · ⊞ 5.9K ·

@gdams
George Adams (gdams) added this pull request to the merge queue Jul 29, 2026
Merged via the queue into microsoft:main with commit 7529bb2 Jul 29, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parity-approved Go API consistency review found no parity issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants