Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions mcp/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,39 @@ type ResourceContents struct {
Meta Meta `json:"_meta,omitempty"`
}

func (r *ResourceContents) MarshalJSON() ([]byte, error) {
// Custom wire format to ensure the required "text" or "blob" field is
// always included, even when empty, so a text resource with empty
// content still matches the TextResourceContents branch of the spec's
// anyOf union instead of matching neither branch.
if r.Blob != nil {
wire := struct {
URI string `json:"uri"`
MIMEType string `json:"mimeType,omitempty"`
Blob []byte `json:"blob"`
Meta Meta `json:"_meta,omitempty"`
}{
URI: r.URI,
MIMEType: r.MIMEType,
Blob: r.Blob,
Meta: r.Meta,
}
return json.Marshal(wire)
}
wire := struct {
URI string `json:"uri"`
MIMEType string `json:"mimeType,omitempty"`
Text string `json:"text"`
Meta Meta `json:"_meta,omitempty"`
}{
URI: r.URI,
MIMEType: r.MIMEType,
Text: r.Text,
Meta: r.Meta,
}
return json.Marshal(wire)
}

// wireContent is the wire format for content.
// It represents the protocol types TextContent, ImageContent, AudioContent,
// ResourceLink, EmbeddedResource, ToolUseContent, and ToolResultContent.
Expand Down
4 changes: 3 additions & 1 deletion mcp/content_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,10 @@ func TestEmbeddedResource(t *testing.T) {
`{"uri":"u","mimeType":"m","text":"t","_meta":{"key":"value"}}`,
},
{
// Text is required by TextResourceContents in the spec, so it must
// always be present, even when empty.
&mcp.ResourceContents{URI: "u"},
`{"uri":"u"}`,
`{"uri":"u","text":""}`,
},
{
&mcp.ResourceContents{URI: "u", Blob: []byte{}},
Expand Down
Loading