@@ -491,6 +491,122 @@ func TestToolIndex_ToolsetBitmap(t *testing.T) {
491491 assert .True (t , bmX .IsEmpty ())
492492}
493493
494+ func TestToolIndex_UniqueFeatureFlags (t * testing.T ) {
495+ t .Parallel ()
496+
497+ testTools := []ServerTool {
498+ mockServerToolInToolset ("basic_tool" , "tools" , true ),
499+ mockServerToolWithFeatureFlag ("advanced_tool" , "tools" , "feature_a" , "" ),
500+ mockServerToolWithFeatureFlag ("experimental_tool" , "tools" , "feature_b" , "" ),
501+ mockServerToolWithFeatureFlag ("legacy_tool" , "tools" , "" , "feature_c" ),
502+ mockServerToolWithFeatureFlag ("complex_tool" , "tools" , "feature_a" , "feature_d" ), // reuses feature_a
503+ }
504+
505+ index := BuildToolIndex (testTools )
506+
507+ flags := index .UniqueFeatureFlags ()
508+
509+ // Should have 4 unique flags: feature_a, feature_b, feature_c, feature_d
510+ assert .Len (t , flags , 4 )
511+ assert .Contains (t , flags , "feature_a" )
512+ assert .Contains (t , flags , "feature_b" )
513+ assert .Contains (t , flags , "feature_c" )
514+ assert .Contains (t , flags , "feature_d" )
515+ }
516+
517+ func TestToolIndex_QueryWithFeatureChecker (t * testing.T ) {
518+ t .Parallel ()
519+
520+ testTools := []ServerTool {
521+ mockServerToolInToolset ("basic_tool" , "tools" , true ),
522+ mockServerToolWithFeatureFlag ("needs_feature_a" , "tools" , "feature_a" , "" ),
523+ mockServerToolWithFeatureFlag ("needs_feature_b" , "tools" , "feature_b" , "" ),
524+ mockServerToolWithFeatureFlag ("disabled_by_feature_c" , "tools" , "" , "feature_c" ),
525+ }
526+
527+ index := BuildToolIndex (testTools )
528+
529+ // Track which flags were checked
530+ checkedFlags := make (map [string ]int )
531+
532+ checker := func (_ context.Context , flag string ) (bool , error ) {
533+ checkedFlags [flag ]++
534+ // Enable feature_a, disable feature_b, enable feature_c
535+ switch flag {
536+ case "feature_a" :
537+ return true , nil
538+ case "feature_b" :
539+ return false , nil
540+ case "feature_c" :
541+ return true , nil // This will disable "disabled_by_feature_c"
542+ default :
543+ return false , nil
544+ }
545+ }
546+
547+ ctx := context .Background ()
548+ result := index .QueryWithFeatureChecker (ctx , QueryConfigWithChecker {
549+ EnabledToolsets : []ToolsetID {"tools" },
550+ ReadOnly : false ,
551+ FeatureChecker : checker ,
552+ })
553+
554+ // Each flag should be checked exactly once
555+ assert .Equal (t , 1 , checkedFlags ["feature_a" ], "feature_a should be checked once" )
556+ assert .Equal (t , 1 , checkedFlags ["feature_b" ], "feature_b should be checked once" )
557+ assert .Equal (t , 1 , checkedFlags ["feature_c" ], "feature_c should be checked once" )
558+
559+ // Materialize and verify results
560+ tools := index .Materialize (ctx , result )
561+ names := make ([]string , len (tools ))
562+ for i , tool := range tools {
563+ names [i ] = tool .Tool .Name
564+ }
565+
566+ // basic_tool: no flags, included
567+ // needs_feature_a: feature_a enabled, included
568+ // needs_feature_b: feature_b disabled, excluded
569+ // disabled_by_feature_c: feature_c enabled, excluded
570+ assert .Len (t , tools , 2 )
571+ assert .Contains (t , names , "basic_tool" )
572+ assert .Contains (t , names , "needs_feature_a" )
573+ assert .NotContains (t , names , "needs_feature_b" )
574+ assert .NotContains (t , names , "disabled_by_feature_c" )
575+ }
576+
577+ func TestToolIndex_QueryWithFeatureChecker_MinimizesChecks (t * testing.T ) {
578+ t .Parallel ()
579+
580+ // Create 50 tools that all use the same 3 feature flags
581+ testTools := make ([]ServerTool , 50 )
582+ for i := 0 ; i < 50 ; i ++ {
583+ flag := []string {"flag_a" , "flag_b" , "flag_c" }[i % 3 ]
584+ testTools [i ] = mockServerToolWithFeatureFlag (
585+ "tool_" + string (rune ('a' + i % 26 )),
586+ "tools" ,
587+ flag , // All tools require one of 3 flags
588+ "" ,
589+ )
590+ }
591+
592+ index := BuildToolIndex (testTools )
593+
594+ checkCount := 0
595+ checker := func (_ context.Context , _ string ) (bool , error ) {
596+ checkCount ++
597+ return true , nil
598+ }
599+
600+ ctx := context .Background ()
601+ _ = index .QueryWithFeatureChecker (ctx , QueryConfigWithChecker {
602+ EnabledToolsets : []ToolsetID {"tools" },
603+ FeatureChecker : checker ,
604+ })
605+
606+ // Should only check 3 unique flags, not 50 tools
607+ assert .Equal (t , 3 , checkCount , "Should check each unique flag exactly once" )
608+ }
609+
494610func BenchmarkBuildToolIndex_130Tools (b * testing.B ) {
495611 // Create realistic toolset distribution
496612 toolsets := []ToolsetID {"repos" , "issues" , "pull_requests" , "users" , "actions" , "code_security" , "projects" , "notifications" , "discussions" , "experiments" }
0 commit comments