Skip to content

Commit 2f1bb12

Browse files
Handle list tools with no body (#55)
1 parent b6b1dca commit 2f1bb12

File tree

3 files changed

+32
-26
lines changed

3 files changed

+32
-26
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414
github.com/buger/jsonparser v1.1.1 // indirect
1515
github.com/davecgh/go-spew v1.1.1 // indirect
1616
github.com/mailru/easyjson v0.7.7 // indirect
17+
github.com/pkg/errors v0.9.1 // indirect
1718
github.com/pmezard/go-difflib v1.0.0 // indirect
1819
github.com/tidwall/gjson v1.18.0 // indirect
1920
github.com/tidwall/match v1.1.1 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uO
1111
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
1212
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
1313
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
14+
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
15+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
1416
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1517
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1618
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=

server.go

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/metoro-io/mcp-golang/internal/protocol"
1010
"github.com/metoro-io/mcp-golang/internal/tools"
1111
"github.com/metoro-io/mcp-golang/transport"
12+
"github.com/pkg/errors"
1213
"reflect"
1314
"sort"
1415
"strings"
@@ -319,19 +320,19 @@ func createWrappedPromptHandler(userHandler any) func(baseGetPromptRequestParams
319320
// Unmarshal the JSON into the correct type
320321
err := json.Unmarshal(arguments.Arguments, &unmarshaledArguments)
321322
if err != nil {
322-
return newPromptResponseSentError(fmt.Errorf("failed to unmarshal arguments: %w", err))
323+
return newPromptResponseSentError(errors.Wrap(err, "failed to unmarshal arguments"))
323324
}
324325

325326
// Need to dereference the unmarshaled arguments
326327
of := reflect.ValueOf(unmarshaledArguments)
327328
if of.Kind() != reflect.Ptr || !of.Elem().CanInterface() {
328-
return newPromptResponseSentError(fmt.Errorf("arguments must be a struct"))
329+
return newPromptResponseSentError(errors.Wrap(err, "arguments must be a struct"))
329330
}
330331
// Call the handler with the typed arguments
331332
output := handlerValue.Call([]reflect.Value{of.Elem()})
332333

333334
if len(output) != 2 {
334-
return newPromptResponseSentError(fmt.Errorf("handler must return exactly two values, got %d", len(output)))
335+
return newPromptResponseSentError(errors.New(fmt.Sprintf("handler must return exactly two values, got %d", len(output))))
335336
}
336337

337338
if !output[0].CanInterface() {
@@ -437,40 +438,40 @@ func createWrappedToolHandler(userHandler any) func(baseCallToolRequestParams) *
437438
return func(arguments baseCallToolRequestParams) *toolResponseSent {
438439
// Instantiate a struct of the type of the arguments
439440
if !reflect.New(argumentType).CanInterface() {
440-
return newToolResponseSentError(fmt.Errorf("arguments must be a struct"))
441+
return newToolResponseSentError(errors.Wrap(fmt.Errorf("arguments must be a struct"), "failed to create argument struct"))
441442
}
442443
unmarshaledArguments := reflect.New(argumentType).Interface()
443444

444445
// Unmarshal the JSON into the correct type
445446
err := json.Unmarshal(arguments.Arguments, &unmarshaledArguments)
446447
if err != nil {
447-
return newToolResponseSentError(fmt.Errorf("failed to unmarshal arguments: %w", err))
448+
return newToolResponseSentError(errors.Wrap(err, "failed to unmarshal arguments"))
448449
}
449450

450451
// Need to dereference the unmarshaled arguments
451452
of := reflect.ValueOf(unmarshaledArguments)
452453
if of.Kind() != reflect.Ptr || !of.Elem().CanInterface() {
453-
return newToolResponseSentError(fmt.Errorf("arguments must be a struct"))
454+
return newToolResponseSentError(errors.Wrap(fmt.Errorf("arguments must be a struct"), "failed to dereference arguments"))
454455
}
455456
// Call the handler with the typed arguments
456457
output := handlerValue.Call([]reflect.Value{of.Elem()})
457458

458459
if len(output) != 2 {
459-
return newToolResponseSentError(fmt.Errorf("handler must return exactly two values, got %d", len(output)))
460+
return newToolResponseSentError(errors.Wrap(fmt.Errorf("handler must return exactly two values, got %d", len(output)), "invalid handler return"))
460461
}
461462

462463
if !output[0].CanInterface() {
463-
return newToolResponseSentError(fmt.Errorf("handler must return a struct, got %s", output[0].Type().Name()))
464+
return newToolResponseSentError(errors.Wrap(fmt.Errorf("handler must return a struct, got %s", output[0].Type().Name()), "invalid handler return"))
464465
}
465466
tool := output[0].Interface()
466467
if !output[1].CanInterface() {
467-
return newToolResponseSentError(fmt.Errorf("handler must return an error, got %s", output[1].Type().Name()))
468+
return newToolResponseSentError(errors.Wrap(fmt.Errorf("handler must return an error, got %s", output[1].Type().Name()), "invalid handler return"))
468469
}
469470
errorOut := output[1].Interface()
470471
if errorOut == nil {
471472
return newToolResponseSent(tool.(*ToolResponse))
472473
}
473-
return newToolResponseSentError(errorOut.(error))
474+
return newToolResponseSentError(errors.Wrap(errorOut.(error), "handler returned an error"))
474475
}
475476
}
476477

@@ -514,9 +515,13 @@ func (s *Server) handleListTools(request *transport.BaseJSONRPCRequest, _ protoc
514515
Cursor *string `json:"cursor"`
515516
}
516517
var params toolRequestParams
517-
err := json.Unmarshal(request.Params, &params)
518-
if err != nil {
519-
return nil, fmt.Errorf("failed to unmarshal arguments: %w", err)
518+
if request.Params == nil {
519+
params = toolRequestParams{}
520+
} else {
521+
err := json.Unmarshal(request.Params, &params)
522+
if err != nil {
523+
return nil, errors.Wrap(err, "failed to unmarshal arguments")
524+
}
520525
}
521526

522527
// Order by name for pagination
@@ -534,7 +539,7 @@ func (s *Server) handleListTools(request *transport.BaseJSONRPCRequest, _ protoc
534539
// Base64 decode the cursor
535540
c, err := base64.StdEncoding.DecodeString(*params.Cursor)
536541
if err != nil {
537-
return nil, fmt.Errorf("failed to decode cursor: %w", err)
542+
return nil, errors.Wrap(err, "failed to decode cursor")
538543
}
539544
cString := string(c)
540545
// Iterate through the tools until we find an entry > the cursor
@@ -585,7 +590,7 @@ func (s *Server) handleToolCalls(req *transport.BaseJSONRPCRequest, _ protocol.R
585590
// Instantiate a struct of the type of the arguments
586591
err := json.Unmarshal(req.Params, &params)
587592
if err != nil {
588-
return nil, fmt.Errorf("failed to unmarshal arguments: %w", err)
593+
return nil, errors.Wrap(err, "failed to unmarshal arguments")
589594
}
590595

591596
var toolToUse *tool
@@ -598,11 +603,10 @@ func (s *Server) handleToolCalls(req *transport.BaseJSONRPCRequest, _ protocol.R
598603
})
599604

600605
if toolToUse == nil {
601-
return nil, fmt.Errorf("unknown tool: %s", req.Method)
606+
return nil, errors.Wrapf(err, "unknown tool: %s", req.Method)
602607
}
603608
return toolToUse.Handler(params), nil
604609
}
605-
606610
func (s *Server) generateCapabilities() serverCapabilities {
607611
t := false
608612
return serverCapabilities{
@@ -623,15 +627,14 @@ func (s *Server) generateCapabilities() serverCapabilities {
623627
}(),
624628
}
625629
}
626-
627630
func (s *Server) handleListPrompts(request *transport.BaseJSONRPCRequest, extra protocol.RequestHandlerExtra) (transport.JsonRpcBody, error) {
628631
type promptRequestParams struct {
629632
Cursor *string `json:"cursor"`
630633
}
631634
var params promptRequestParams
632635
err := json.Unmarshal(request.Params, &params)
633636
if err != nil {
634-
return nil, fmt.Errorf("failed to unmarshal arguments: %w", err)
637+
return nil, errors.Wrap(err, "failed to unmarshal arguments")
635638
}
636639

637640
// Order by name for pagination
@@ -649,7 +652,7 @@ func (s *Server) handleListPrompts(request *transport.BaseJSONRPCRequest, extra
649652
// Base64 decode the cursor
650653
c, err := base64.StdEncoding.DecodeString(*params.Cursor)
651654
if err != nil {
652-
return nil, fmt.Errorf("failed to decode cursor: %w", err)
655+
return nil, errors.Wrap(err, "failed to decode cursor")
653656
}
654657
cString := string(c)
655658
// Iterate through the prompts until we find an entry > the cursor
@@ -694,7 +697,7 @@ func (s *Server) handleListResources(request *transport.BaseJSONRPCRequest, extr
694697
var params resourceRequestParams
695698
err := json.Unmarshal(request.Params, &params)
696699
if err != nil {
697-
return nil, fmt.Errorf("failed to unmarshal arguments: %w", err)
700+
return nil, errors.Wrap(err, "failed to unmarshal arguments")
698701
}
699702

700703
// Order by URI for pagination
@@ -712,7 +715,7 @@ func (s *Server) handleListResources(request *transport.BaseJSONRPCRequest, extr
712715
// Base64 decode the cursor
713716
c, err := base64.StdEncoding.DecodeString(*params.Cursor)
714717
if err != nil {
715-
return nil, fmt.Errorf("failed to decode cursor: %w", err)
718+
return nil, errors.Wrap(err, "failed to decode cursor")
716719
}
717720
cString := string(c)
718721
// Iterate through the resources until we find an entry > the cursor
@@ -760,7 +763,7 @@ func (s *Server) handlePromptCalls(req *transport.BaseJSONRPCRequest, extra prot
760763
// Instantiate a struct of the type of the arguments
761764
err := json.Unmarshal(req.Params, &params)
762765
if err != nil {
763-
return nil, fmt.Errorf("failed to unmarshal arguments: %w", err)
766+
return nil, errors.Wrap(err, "failed to unmarshal arguments")
764767
}
765768

766769
var promptToUse *prompt
@@ -773,7 +776,7 @@ func (s *Server) handlePromptCalls(req *transport.BaseJSONRPCRequest, extra prot
773776
})
774777

775778
if promptToUse == nil {
776-
return nil, fmt.Errorf("unknown prompt: %s", req.Method)
779+
return nil, errors.Wrapf(err, "unknown prompt: %s", req.Method)
777780
}
778781
return promptToUse.Handler(params), nil
779782
}
@@ -783,7 +786,7 @@ func (s *Server) handleResourceCalls(req *transport.BaseJSONRPCRequest, extra pr
783786
// Instantiate a struct of the type of the arguments
784787
err := json.Unmarshal(req.Params, &params)
785788
if err != nil {
786-
return nil, fmt.Errorf("failed to unmarshal arguments: %w", err)
789+
return nil, errors.Wrap(err, "failed to unmarshal arguments")
787790
}
788791

789792
var resourceToUse *resource
@@ -796,7 +799,7 @@ func (s *Server) handleResourceCalls(req *transport.BaseJSONRPCRequest, extra pr
796799
})
797800

798801
if resourceToUse == nil {
799-
return nil, fmt.Errorf("unknown prompt: %s", req.Method)
802+
return nil, errors.Wrapf(err, "unknown prompt: %s", req.Method)
800803
}
801804
return resourceToUse.Handler(), nil
802805
}

0 commit comments

Comments
 (0)