Skip to content
Merged
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
26 changes: 26 additions & 0 deletions mcp/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,32 @@ func TestResourceNotFoundErrorCode(t *testing.T) {
}
}

// TestReadResourceNilResult verifies that a resource handler returning
// (nil, nil) yields a clean error to the client instead of a nil pointer
// panic that crashes the server. The sibling handlers callTool and getPrompt
// already tolerate a (nil, nil) return; readResource must do the same.
func TestReadResourceNilResult(t *testing.T) {
ctx := context.Background()

cs, _, cleanup := basicConnection(t, func(s *Server) {
s.AddResource(
&Resource{URI: "file:///nil.txt", Name: "nil", MIMEType: "text/plain"},
func(ctx context.Context, req *ReadResourceRequest) (*ReadResourceResult, error) {
return nil, nil
},
)
})
defer cleanup()

_, err := cs.ReadResource(ctx, &ReadResourceParams{URI: "file:///nil.txt"})
if err == nil {
t.Fatal("got nil error, want non-nil error for nil resource result")
}
if !strings.Contains(err.Error(), "nil information") {
t.Errorf("got error %q, want it to mention 'nil information'", err.Error())
}
}

// TestInputValidationToolError validates that input validation errors (missing
// required params, wrong types) are returned as tool results with IsError=true,
// not as JSON-RPC errors. This allows LLMs to see the error and self-correct.
Expand Down
5 changes: 4 additions & 1 deletion mcp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1035,14 +1035,17 @@ func (s *Server) readResource(ctx context.Context, req *ReadResourceRequest) (*R
if err != nil {
return nil, err
}
if res == nil {
return nil, fmt.Errorf("reading resource %s: read handler returned nil information", uri)
}
if err := handleMultiRoundTripResult(req.Session, s.opts.Logger, res); err != nil {
return nil, err
}
res.setDefaultCacheableValues()
if res.resultType == resultTypeInputRequired {
return res, nil
}
if res == nil || res.Contents == nil {
if res.Contents == nil {
return nil, fmt.Errorf("reading resource %s: read handler returned nil information", uri)
}
// As a convenience, populate some fields.
Expand Down
Loading