From f52dc2a8d81e9814ae72607679e8e724577ff54d Mon Sep 17 00:00:00 2001 From: guglielmoc Date: Tue, 10 Nov 2026 10:16:03 +0000 Subject: [PATCH] Allow nil params for ListRoots --- mcp/protocol.go | 7 +++++-- mcp/protocol_test.go | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/mcp/protocol.go b/mcp/protocol.go index 8ca96b24e..d78d25061 100644 --- a/mcp/protocol.go +++ b/mcp/protocol.go @@ -128,9 +128,12 @@ func (m *InputRequestMap) UnmarshalJSON(data []byte) error { } result[k] = &p case methodListRoots: + // For a roots/list request, params are optional. var p ListRootsParams - if err := internaljson.Unmarshal(raw.Params, &p); err != nil { - return err + if len(raw.Params) > 0 { + if err := internaljson.Unmarshal(raw.Params, &p); err != nil { + return err + } } result[k] = &p default: diff --git a/mcp/protocol_test.go b/mcp/protocol_test.go index cd2ae94eb..86f869e86 100644 --- a/mcp/protocol_test.go +++ b/mcp/protocol_test.go @@ -1222,6 +1222,21 @@ func TestInputRequestMapJSON(t *testing.T) { t.Error("Unmarshal succeeded, want an error for a null input request") } }) + + // roots/list params are optional, so a request without them must not fail + // decoding the whole result. + for _, params := range []string{``, `,"params":null`} { + t.Run("roots/list without params"+params, func(t *testing.T) { + var got CallToolResult + data := `{"content":[],"inputRequests":{"r1":{"method":"roots/list"` + params + `}}}` + if err := json.Unmarshal([]byte(data), &got); err != nil { + t.Fatalf("Unmarshal(%s) = %v, want nil", data, err) + } + if p, ok := got.InputRequests["r1"].(*ListRootsParams); !ok || p == nil { + t.Errorf("InputRequests[r1] = %#v, want non-nil *ListRootsParams", got.InputRequests["r1"]) + } + }) + } } func TestInputResponseMapJSON(t *testing.T) {