mcpcompat drops entire tool/prompt result when it contains an embedded resource
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
- #171 @jhrozek による — マージされずにクローズ
評価
調査の方向性
EmbeddedResource と UnmarshalContent から始め、次に CallToolResult.UnmarshalJSON と issue に記載されている convertResult パスを追跡します。提供された wire payload で失敗を再現し、リソースのみのコンテンツと混在したツールコンテンツが、兄弟項目を失わずに正常にデコードされることを確認します。prompts/get パスも確認してください。
索引モデルが issue の本文から書いたものです。
説明
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
client.CallToolconverts the go-sdk result via the genericconvertResult→jsonConvert.- That runs
CallToolResult.UnmarshalJSON, which callsUnmarshalContentper item. UnmarshalContent, caseContentTypeResource, doesjson.Unmarshal(data, &EmbeddedResource{})— stdlib cannot populate theResourceContentsinterface field → error.- The error aborts the whole decode;
convertResultdiscards 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分
- マージ済み PR(30日)
- 133
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
stacklok/toolhive-core のほかの issue
-
needs-triage
難易度 4/5 3〜5日 初心者へのやさしさ 54/100
stacklok/toolhive-core#466 ·
メンテナーはふだん 1 日以内に返信
-
needs-triage
難易度 3/5 1〜2日 初心者へのやさしさ 66/100
stacklok/toolhive-core#426 ·
メンテナーはふだん 1 日以内に返信
-
mcpcompat/server: refuse dispatch of a request whose per-request context is gone対応中かも @jhrozek が 15 日前に担当しました。 オープンneeds-triage
難易度 4/5 3〜5日 初心者へのやさしさ 54/100
stacklok/toolhive-core#414 ·
メンテナーはふだん 1 日以内に返信
-
needs-triage
難易度 5/5 1週間以上 初心者へのやさしさ 8/100
stacklok/toolhive-core#343 ·
メンテナーはふだん 1 日以内に返信
-
needs-triage
難易度 5/5 1週間以上 初心者へのやさしさ 12/100
stacklok/toolhive-core#342 ·
メンテナーはふだん 1 日以内に返信
stacklok/toolhive-core の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 73/100
-
[BUG] EphemeralJob matches every pod in the namespace when spec.selector is empty対応中かも @vishnums2k5 が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
openkruise/kruise#2656 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
rancher/rancher-ai-mcp#206 ·
メンテナーはふだん 1 日以内に返信
-
test: make command and stdio startup tests portable対応中かも @dajiaohuang が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 73/100
mark3labs/mcp-go#1220 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信