diff --git a/mcp/content.go b/mcp/content.go index 84ac60e..668dfb6 100644 --- a/mcp/content.go +++ b/mcp/content.go @@ -6,6 +6,7 @@ package mcp import ( "encoding/json" + "errors" "fmt" ) @@ -23,7 +24,7 @@ type Content struct { Type string `json:"type"` Text string `json:"text,omitempty"` MIMEType string `json:"mimeType,omitempty"` - Data []byte `json:"data,omitzero"` + Data []byte `json:"data,omitempty"` Resource *ResourceContents `json:"resource,omitempty"` Annotations *Annotations `json:"annotations,omitempty"` } @@ -68,8 +69,34 @@ func NewResourceContent(resource ResourceContents) Content { type ResourceContents struct { URI string `json:"uri,"` MIMEType string `json:"mimeType,omitempty"` - Text string `json:"text,omitempty"` - Blob []byte `json:"blob,omitzero"` + Text string `json:"text"` + Blob []byte `json:"blob,omitempty"` +} + +func (r ResourceContents) MarshalJSON() ([]byte, error) { + if r.URI == "" { + return nil, errors.New("ResourceContents missing URI") + } + if r.Blob == nil { + // Text. Marshal normally. + type wireResourceContents ResourceContents + return json.Marshal((wireResourceContents)(r)) + } + // Blob. + if r.Text != "" { + return nil, errors.New("ResourceContents has non-zero Text and Blob fields") + } + // r.Blob may be the empty slice, so marshal with an alternative definition. + br := struct { + URI string `json:"uri,omitempty"` + MIMEType string `json:"mimeType,omitempty"` + Blob []byte `json:"blob"` + }{ + URI: r.URI, + MIMEType: r.MIMEType, + Blob: r.Blob, + } + return json.Marshal(br) } func NewTextResourceContents(uri, mimeType, text string) ResourceContents { diff --git a/mcp/content_test.go b/mcp/content_test.go index 512c7d3..0f43eeb 100644 --- a/mcp/content_test.go +++ b/mcp/content_test.go @@ -57,3 +57,46 @@ func TestContent(t *testing.T) { } } } + +func TestResourceContents(t *testing.T) { + for _, tt := range []struct { + rc mcp.ResourceContents + want string // marshaled JSON + }{ + { + mcp.ResourceContents{URI: "u", Text: "t"}, + `{"uri":"u","text":"t"}`, + }, + { + mcp.ResourceContents{URI: "u", MIMEType: "m", Text: "t"}, + `{"uri":"u","mimeType":"m","text":"t"}`, + }, + { + mcp.ResourceContents{URI: "u", Text: "", Blob: nil}, + `{"uri":"u","text":""}`, + }, + { + mcp.ResourceContents{URI: "u", Blob: []byte{}}, + `{"uri":"u","blob":""}`, + }, + { + mcp.ResourceContents{URI: "u", Blob: []byte{1}}, + `{"uri":"u","blob":"AQ=="}`, + }, + } { + data, err := json.Marshal(tt.rc) + if err != nil { + t.Fatal(err) + } + if got := string(data); got != tt.want { + t.Errorf("%#v:\ngot %s\nwant %s", tt.rc, got, tt.want) + } + var urc mcp.ResourceContents + if err := json.Unmarshal(data, &urc); err != nil { + t.Fatal(err) + } + if diff := cmp.Diff(tt.rc, urc); diff != "" { + t.Errorf("mismatch (-want, +got):\n%s", diff) + } + } +}