diff --git a/pkg/inventory/server_tool.go b/pkg/inventory/server_tool.go index 326009b59f..d6e9359968 100644 --- a/pkg/inventory/server_tool.go +++ b/pkg/inventory/server_tool.go @@ -132,8 +132,15 @@ func NewServerToolWithContextHandler[In any, Out any](tool mcp.Tool, toolset Too // HandlerFunc ignores deps - deps are retrieved from context at call time HandlerFunc: func(_ any) mcp.ToolHandler { return func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) { + argumentsRaw := []byte("{}") + if req.Params != nil && len(req.Params.Arguments) > 0 { + argumentsRaw = req.Params.Arguments + } + if string(argumentsRaw) == "null" { + argumentsRaw = []byte("{}") + } var arguments In - if err := json.Unmarshal(req.Params.Arguments, &arguments); err != nil { + if err := json.Unmarshal(argumentsRaw, &arguments); err != nil { return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{Text: fmt.Sprintf("invalid arguments: %s", err)}, diff --git a/pkg/inventory/server_tool_test.go b/pkg/inventory/server_tool_test.go index 69cee94af0..a01cd090ae 100644 --- a/pkg/inventory/server_tool_test.go +++ b/pkg/inventory/server_tool_test.go @@ -78,3 +78,70 @@ func TestNewServerToolWithContextHandler_ValidArguments_Succeeds(t *testing.T) { require.True(t, ok) assert.Equal(t, "success: octocat/hello-world", textContent.Text) } + +func TestNewServerToolWithContextHandler_EmptyArguments_Succeeds(t *testing.T) { + type expectedArgs struct { + Owner string `json:"owner,omitempty"` + Repo string `json:"repo,omitempty"` + } + + tool := NewServerToolWithContextHandler( + mcp.Tool{Name: "test_tool"}, + testToolsetMetadata("test"), + func(_ context.Context, _ *mcp.CallToolRequest, args expectedArgs) (*mcp.CallToolResult, any, error) { + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: "success: " + args.Owner + "/" + args.Repo}, + }, + }, nil, nil + }, + ) + + handler := tool.HandlerFunc(nil) + + testCases := []struct { + name string + arguments json.RawMessage + expected string + }{ + { + name: "nil arguments", + arguments: nil, + expected: "success: /", + }, + { + name: "empty arguments", + arguments: json.RawMessage(``), + expected: "success: /", + }, + { + name: "null arguments", + arguments: json.RawMessage(`null`), + expected: "success: /", + }, + { + name: "empty object arguments", + arguments: json.RawMessage(`{}`), + expected: "success: /", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result, err := handler(context.Background(), &mcp.CallToolRequest{ + Params: &mcp.CallToolParamsRaw{ + Name: "test_tool", + Arguments: tc.arguments, + }, + }) + + require.NoError(t, err) + require.NotNil(t, result) + assert.False(t, result.IsError) + textContent, ok := result.Content[0].(*mcp.TextContent) + require.True(t, ok) + assert.Equal(t, tc.expected, textContent.Text) + }) + } +} +