mcpcompat drops entire tool/prompt result when it contains an embedded resource

未关闭
#170 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

  • #171 来自 @jhrozek —— 已关闭,未合并

评估

难度
3/5
预计耗时
1-2 天
新手友好度
76/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
冷清
技术栈
go
领域
api

调研方向

从 EmbeddedResource 和 UnmarshalContent 开始,然后跟踪 CallToolResult.UnmarshalJSON 以及 issue 中描述的 convertResult 路径。使用提供的 wire payload 重现失败,并验证仅包含 resource 的内容和混合 tool 内容都能成功解码,且不会丢失同级项;同时检查 prompts/get 路径。

由索引模型根据 Issue 内容生成。

描述

needs-triage

Summary

mcpcompat.EmbeddedResource has a Resource ResourceContents field where ResourceContents is a non-empty interface, and EmbeddedResource has no custom UnmarshalJSON. So json.Unmarshal of any "type":"resource" content item errors:

json: cannot unmarshal object into Go struct field EmbeddedResource.resource of type mcp.ResourceContents

Because CallToolResult.UnmarshalJSON (and the client's convertResult) propagate that error, any tool result — or prompt message — containing an embedded resource is lost in its entirety, including any sibling text/image parts in the same content array.

Impact

Discovered from a ToolHive vMCP MCP-conformance run (the mcp-go → mcpcompat swap). Two conformance scenarios regressed:

  • tools-call-embedded-resource → "No resource content found"
  • tools-call-mixed-content → "Expected multiple content items; Missing image content; Missing resource content"

The prompts/get path is affected too, since convertGetPromptResult also decodes content via mcp.UnmarshalContent.

Call chain

  1. client.CallTool converts the go-sdk result via the generic convertResult → jsonConvert.
  2. That runs CallToolResult.UnmarshalJSON, which calls UnmarshalContent per item.
  3. UnmarshalContent, case ContentTypeResource, does json.Unmarshal(data, &EmbeddedResource{}) — stdlib cannot populate the ResourceContents interface field → error.
  4. The error aborts the whole decode; convertResult discards the partially-decoded result.

ReadResource and GetPrompt were hand-written to avoid this exact trap (convertReadResourceResult maps concrete text/blob types explicitly); CallTool was left on the generic path.

Fix

Add a custom UnmarshalJSON to EmbeddedResource that resolves the polymorphic Resource field to a concrete TextResourceContents/BlobResourceContents (blob-precedence, mirroring convertReadResourceResult). UnmarshalContent is the single chokepoint backing both tools/call and prompts/get.

Repro

wire := []byte(`{"type":"resource","resource":{"uri":"file:///x.txt","mimeType":"text/plain","text":"body"}}`)
_, err := mcp.UnmarshalContent(wire)
// err: json: cannot unmarshal object into Go struct field EmbeddedResource.resource of type mcp.ResourceContents
主要语言
Go
星标
2
派生
6
平均合并
23 小时 44 分钟
30 天内合并 PR
133

环境准备

这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

stacklok/toolhive-core 的其他 Issue

查看 stacklok/toolhive-core 的全部 Issue

相似的 Issue

更多 Go Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。