Skip to content

Commit 5b6fa01

Browse files
author
Zheng Li
committed
change to strong ResourceContents type
1 parent 5dab240 commit 5b6fa01

File tree

7 files changed

+109
-57
lines changed

7 files changed

+109
-57
lines changed

client/sse.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -412,12 +412,7 @@ func (c *SSEMCPClient) ReadResource(
412412
return nil, err
413413
}
414414

415-
var result mcp.ReadResourceResult
416-
if err := json.Unmarshal(*response, &result); err != nil {
417-
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
418-
}
419-
420-
return &result, nil
415+
return mcp.ParseReadResourceResult(response)
421416
}
422417

423418
func (c *SSEMCPClient) Subscribe(

client/stdio.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -338,12 +338,7 @@ func (c *StdioMCPClient) ReadResource(
338338
return nil, err
339339
}
340340

341-
var result mcp.ReadResourceResult
342-
if err := json.Unmarshal(*response, &result); err != nil {
343-
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
344-
}
345-
346-
return &result, nil
341+
return mcp.ParseReadResourceResult(response)
347342
}
348343

349344
func (c *StdioMCPClient) Subscribe(

examples/everything/main.go

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -173,29 +173,25 @@ func runUpdateInterval() {
173173
func handleReadResource(
174174
ctx context.Context,
175175
request mcp.ReadResourceRequest,
176-
) ([]interface{}, error) {
177-
return []interface{}{
176+
) ([]mcp.ResourceContents, error) {
177+
return []mcp.ResourceContents{
178178
mcp.TextResourceContents{
179-
ResourceContents: mcp.ResourceContents{
180-
URI: "test://static/resource",
181-
MIMEType: "text/plain",
182-
},
183-
Text: "This is a sample resource",
179+
URI: "test://static/resource",
180+
MIMEType: "text/plain",
181+
Text: "This is a sample resource",
184182
},
185183
}, nil
186184
}
187185

188186
func handleResourceTemplate(
189187
ctx context.Context,
190188
request mcp.ReadResourceRequest,
191-
) ([]interface{}, error) {
192-
return []interface{}{
189+
) ([]mcp.ResourceContents, error) {
190+
return []mcp.ResourceContents{
193191
mcp.TextResourceContents{
194-
ResourceContents: mcp.ResourceContents{
195-
URI: request.Params.URI,
196-
MIMEType: "text/plain",
197-
},
198-
Text: "This is a sample resource",
192+
URI: request.Params.URI,
193+
MIMEType: "text/plain",
194+
Text: "This is a sample resource",
199195
},
200196
}, nil
201197
}

mcp/types.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ type ReadResourceRequest struct {
373373
// from the client.
374374
type ReadResourceResult struct {
375375
Result
376-
Contents []interface{} `json:"contents"` // Can be TextResourceContents or BlobResourceContents
376+
Contents []ResourceContents `json:"contents"` // Can be TextResourceContents or BlobResourceContents
377377
}
378378

379379
// ResourceListChangedNotification is an optional notification from the server
@@ -459,26 +459,33 @@ type ResourceTemplate struct {
459459

460460
// ResourceContents represents the contents of a specific resource or sub-
461461
// resource.
462-
type ResourceContents struct {
462+
type ResourceContents interface {
463+
isResourceContents()
464+
}
465+
466+
type TextResourceContents struct {
463467
// The URI of this resource.
464468
URI string `json:"uri"`
465469
// The MIME type of this resource, if known.
466470
MIMEType string `json:"mimeType,omitempty"`
467-
}
468-
469-
type TextResourceContents struct {
470-
ResourceContents
471471
// The text of the item. This must only be set if the item can actually be
472472
// represented as text (not binary data).
473473
Text string `json:"text"`
474474
}
475475

476+
func (TextResourceContents) isResourceContents() {}
477+
476478
type BlobResourceContents struct {
477-
ResourceContents
479+
// The URI of this resource.
480+
URI string `json:"uri"`
481+
// The MIME type of this resource, if known.
482+
MIMEType string `json:"mimeType,omitempty"`
478483
// A base64-encoded string representing the binary data of the item.
479484
Blob string `json:"blob"`
480485
}
481486

487+
func (BlobResourceContents) isResourceContents() {}
488+
482489
/* Logging */
483490

484491
// SetLevelRequest is a request from the client to the server, to enable or

mcp/utils.go

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ func NewListResourceTemplatesResult(
305305
// NewReadResourceResult creates a new ReadResourceResult with text content
306306
func NewReadResourceResult(text string) *ReadResourceResult {
307307
return &ReadResourceResult{
308-
Contents: []interface{}{
308+
Contents: []ResourceContents{
309309
TextResourceContents{
310310
Text: text,
311311
},
@@ -410,22 +410,12 @@ func ParseContent(contentMap map[string]any) (Content, error) {
410410
return nil, fmt.Errorf("resource is missing")
411411
}
412412

413-
uri := ExtractString(resourceMap, "uri")
414-
mimeType := ExtractString(resourceMap, "mimeType")
415-
text := ExtractString(resourceMap, "text")
416-
417-
if uri == "" || mimeType == "" {
418-
return nil, fmt.Errorf("resource uri or mimeType is missing")
413+
resourceContents, err := ParseResourceContents(resourceMap)
414+
if err != nil {
415+
return nil, err
419416
}
420417

421-
if text != "" {
422-
return NewEmbeddedResource(
423-
ResourceContents{
424-
URI: uri,
425-
MIMEType: mimeType,
426-
},
427-
), nil
428-
}
418+
return NewEmbeddedResource(resourceContents), nil
429419
}
430420

431421
return nil, fmt.Errorf("unsupported content type: %s", contentType)
@@ -543,3 +533,74 @@ func ParseCallToolResult(rawMessage *json.RawMessage) (*CallToolResult, error) {
543533

544534
return &result, nil
545535
}
536+
537+
func ParseResourceContents(contentMap map[string]any) (ResourceContents, error) {
538+
uri := ExtractString(contentMap, "uri")
539+
if uri == "" {
540+
return nil, fmt.Errorf("resource uri is missing")
541+
}
542+
543+
mimeType := ExtractString(contentMap, "mimeType")
544+
545+
if text := ExtractString(contentMap, "text"); text != "" {
546+
return TextResourceContents{
547+
URI: uri,
548+
MIMEType: mimeType,
549+
Text: text,
550+
}, nil
551+
}
552+
553+
if blob := ExtractString(contentMap, "blob"); blob != "" {
554+
return BlobResourceContents{
555+
URI: uri,
556+
MIMEType: mimeType,
557+
Blob: blob,
558+
}, nil
559+
}
560+
561+
return nil, fmt.Errorf("unsupported resource type")
562+
}
563+
564+
func ParseReadResourceResult(rawMessage *json.RawMessage) (*ReadResourceResult, error) {
565+
var jsonContent map[string]any
566+
if err := json.Unmarshal(*rawMessage, &jsonContent); err != nil {
567+
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
568+
}
569+
570+
var result ReadResourceResult
571+
572+
meta, ok := jsonContent["_meta"]
573+
if ok {
574+
if metaMap, ok := meta.(map[string]any); ok {
575+
result.Meta = metaMap
576+
}
577+
}
578+
579+
contents, ok := jsonContent["contents"]
580+
if !ok {
581+
return nil, fmt.Errorf("contents is missing")
582+
}
583+
584+
contentArr, ok := contents.([]any)
585+
if !ok {
586+
return nil, fmt.Errorf("contents is not an array")
587+
}
588+
589+
for _, content := range contentArr {
590+
// Extract content
591+
contentMap, ok := content.(map[string]any)
592+
if !ok {
593+
return nil, fmt.Errorf("content is not an object")
594+
}
595+
596+
// Process content
597+
content, err := ParseResourceContents(contentMap)
598+
if err != nil {
599+
return nil, err
600+
}
601+
602+
result.Contents = append(result.Contents, content)
603+
}
604+
605+
return &result, nil
606+
}

server/server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ type resourceTemplateEntry struct {
2929
type ServerOption func(*MCPServer)
3030

3131
// ResourceHandlerFunc is a function that returns resource contents.
32-
type ResourceHandlerFunc func(ctx context.Context, request mcp.ReadResourceRequest) ([]interface{}, error)
32+
type ResourceHandlerFunc func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error)
3333

3434
// ResourceTemplateHandlerFunc is a function that returns a resource template.
35-
type ResourceTemplateHandlerFunc func(ctx context.Context, request mcp.ReadResourceRequest) ([]interface{}, error)
35+
type ResourceTemplateHandlerFunc func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error)
3636

3737
// PromptHandlerFunc handles prompt requests with given arguments.
3838
type PromptHandlerFunc func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error)

server/server_test.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -674,14 +674,12 @@ func createTestServer() *MCPServer {
674674
URI: "resource://testresource",
675675
Name: "My Resource",
676676
},
677-
func(ctx context.Context, request mcp.ReadResourceRequest) ([]interface{}, error) {
678-
return []interface{}{
677+
func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
678+
return []mcp.ResourceContents{
679679
mcp.TextResourceContents{
680-
ResourceContents: mcp.ResourceContents{
681-
URI: "resource://testresource",
682-
MIMEType: "text/plain",
683-
},
684-
Text: "test content",
680+
URI: "resource://testresource",
681+
MIMEType: "text/plain",
682+
Text: "test content",
685683
},
686684
}, nil
687685
},

0 commit comments

Comments
 (0)