@@ -13,16 +13,21 @@ import (
1313 "github.com/github/github-mcp-server/pkg/inventory"
1414 "github.com/github/github-mcp-server/pkg/scopes"
1515 "github.com/github/github-mcp-server/pkg/utils"
16- "github.com/google/jsonschema-go/jsonschema"
1716)
1817
1918// RemoteMCPExperimental is a long-lived feature flag for experimental remote MCP features.
2019// This flag enables experimental behaviors in tools that are being tested for remote server deployment.
2120const RemoteMCPEnthusiasticGreeting = "remote_mcp_enthusiastic_greeting"
2221
22+ // FeatureChecker is an interface for checking if a feature flag is enabled.
23+ type FeatureChecker interface {
24+ // IsFeatureEnabled checks if a feature flag is enabled.
25+ IsFeatureEnabled (ctx context.Context , flagName string ) bool
26+ }
27+
2328// HelloWorld returns a simple greeting tool that demonstrates feature flag conditional behavior.
2429// This tool is for testing and demonstration purposes only.
25- func HelloWorld (t translations.TranslationHelperFunc ) inventory.ServerTool {
30+ func HelloWorldTool (t translations.TranslationHelperFunc ) inventory.ServerTool {
2631 return NewTool (
2732 ToolsetMetadataContext , // Use existing "context" toolset
2833 mcp.Tool {
@@ -32,39 +37,22 @@ func HelloWorld(t translations.TranslationHelperFunc) inventory.ServerTool {
3237 Title : t ("TOOL_HELLO_WORLD_TITLE" , "Hello World" ),
3338 ReadOnlyHint : true ,
3439 },
35- InputSchema : & jsonschema.Schema {
36- Type : "object" ,
37- Properties : map [string ]* jsonschema.Schema {
38- "name" : {
39- Type : "string" ,
40- Description : "Name to greet (optional, defaults to 'World')" ,
41- },
42- },
43- },
4440 },
4541 []scopes.Scope {},
46- func (ctx context.Context , deps ToolDependencies , _ * mcp.CallToolRequest , args map [string ]any ) (* mcp.CallToolResult , any , error ) {
47- // Extract name parameter (optional)
48- name := "World"
49- if nameArg , ok := args ["name" ].(string ); ok && nameArg != "" {
50- name = nameArg
51- }
42+ func (ctx context.Context , deps ToolDependencies , _ * mcp.CallToolRequest , _ map [string ]any ) (* mcp.CallToolResult , any , error ) {
5243
5344 // Check feature flag to determine greeting style
54- var greeting string
45+ greeting := "Hello, world!"
5546 if deps .IsFeatureEnabled (ctx , RemoteMCPEnthusiasticGreeting ) {
56- // Experimental: More enthusiastic greeting
57- greeting = "🚀 Hello, " + name + "! Welcome to the EXPERIMENTAL future of MCP! 🎉"
58- } else {
59- // Default: Simple greeting
60- greeting = "Hello, " + name + "!"
47+ greeting = greeting + " Welcome to the future of MCP! 🎉"
48+ }
49+ if deps .GetFlags ().Experimental {
50+ greeting = greeting + " Experimental features are enabled! 🚀"
6151 }
6252
6353 // Build response
6454 response := map [string ]any {
65- "greeting" : greeting ,
66- "experimental_mode" : deps .IsFeatureEnabled (ctx , RemoteMCPEnthusiasticGreeting ),
67- "timestamp" : "2026-01-12" , // Static for demonstration
55+ "greeting" : greeting ,
6856 }
6957
7058 jsonBytes , err := json .Marshal (response )
@@ -77,53 +65,24 @@ func HelloWorld(t translations.TranslationHelperFunc) inventory.ServerTool {
7765 )
7866}
7967
80- func TestHelloWorld_ToolDefinition (t * testing.T ) {
81- t .Parallel ()
82-
83- // Create tool
84- tool := HelloWorld (translations .NullTranslationHelper )
85-
86- // Verify tool definition
87- assert .Equal (t , "hello_world" , tool .Tool .Name )
88- assert .NotEmpty (t , tool .Tool .Description )
89- assert .True (t , tool .Tool .Annotations .ReadOnlyHint , "hello_world should be read-only" )
90- assert .NotNil (t , tool .Tool .InputSchema )
91- assert .NotNil (t , tool .HandlerFunc , "Tool must have a handler" )
92-
93- // Verify it's in the context toolset
94- assert .Equal (t , "context" , string (tool .Toolset .ID ))
95-
96- // Verify no scopes required
97- assert .Empty (t , tool .RequiredScopes )
98-
99- // Verify no feature flags set (tool itself isn't gated by flags)
100- assert .Empty (t , tool .FeatureFlagEnable )
101- assert .Empty (t , tool .FeatureFlagDisable )
102- }
103-
104- func TestHelloWorld_ConditionalBehavior (t * testing.T ) {
68+ func TestHelloWorld_ConditionalBehavior_Featureflag (t * testing.T ) {
10569 t .Parallel ()
10670
10771 tests := []struct {
108- name string
109- featureFlagEnabled bool
110- inputName string
111- expectedGreeting string
112- expectedExperimentalMode bool
72+ name string
73+ featureFlagEnabled bool
74+ inputName string
75+ expectedGreeting string
11376 }{
11477 {
115- name : "Feature flag disabled - default greeting" ,
116- featureFlagEnabled : false ,
117- inputName : "Alice" ,
118- expectedGreeting : "Hello, Alice!" ,
119- expectedExperimentalMode : false ,
78+ name : "Feature flag disabled - default greeting" ,
79+ featureFlagEnabled : false ,
80+ expectedGreeting : "Hello, world!" ,
12081 },
12182 {
122- name : "Feature flag enabled - experimental greeting" ,
123- featureFlagEnabled : true ,
124- inputName : "Alice" ,
125- expectedGreeting : "🚀 Hello, Alice! Welcome to the EXPERIMENTAL future of MCP! 🎉" ,
126- expectedExperimentalMode : true ,
83+ name : "Feature flag enabled - enthusiastic greeting" ,
84+ featureFlagEnabled : true ,
85+ expectedGreeting : "Hello, world! Welcome to the future of MCP! 🎉" ,
12786 },
12887 }
12988
@@ -149,26 +108,78 @@ func TestHelloWorld_ConditionalBehavior(t *testing.T) {
149108 )
150109
151110 // Get the tool and its handler
152- tool := HelloWorld (translations .NullTranslationHelper )
111+ tool := HelloWorldTool (translations .NullTranslationHelper )
153112 handler := tool .Handler (deps )
154113
155- // Create request
156- args := map [string ]any {}
157- if tt .inputName != "" {
158- args ["name" ] = tt .inputName
159- }
160- argsJSON , err := json .Marshal (args )
114+ // Call the handler with deps in context
115+ ctx := ContextWithDeps (context .Background (), deps )
116+ result , err := handler (ctx , & mcp.CallToolRequest {
117+ Params : & mcp.CallToolParamsRaw {
118+ Arguments : json .RawMessage (`{}` ),
119+ },
120+ })
161121 require .NoError (t , err )
122+ require .NotNil (t , result )
123+ require .Len (t , result .Content , 1 )
162124
163- request := mcp.CallToolRequest {
164- Params : & mcp.CallToolParamsRaw {
165- Arguments : json .RawMessage (argsJSON ),
166- },
167- }
125+ // Parse the response - should be TextContent
126+ textContent , ok := result .Content [0 ].(* mcp.TextContent )
127+ require .True (t , ok , "expected content to be TextContent" )
128+
129+ var response map [string ]any
130+ err = json .Unmarshal ([]byte (textContent .Text ), & response )
131+ require .NoError (t , err )
132+
133+ // Verify the greeting matches expected based on feature flag
134+ assert .Equal (t , tt .expectedGreeting , response ["greeting" ])
135+ })
136+ }
137+ }
138+
139+ func TestHelloWorld_ConditionalBehavior_Config (t * testing.T ) {
140+ t .Parallel ()
141+
142+ tests := []struct {
143+ name string
144+ experimental bool
145+ expectedGreeting string
146+ }{
147+ {
148+ name : "Experimental disabled - default greeting" ,
149+ experimental : false ,
150+ expectedGreeting : "Hello, world!" ,
151+ },
152+ {
153+ name : "Experimental enabled - experimental greeting" ,
154+ experimental : true ,
155+ expectedGreeting : "Hello, world! Experimental features are enabled! 🚀" ,
156+ },
157+ }
158+
159+ for _ , tt := range tests {
160+ t .Run (tt .name , func (t * testing.T ) {
161+ t .Parallel ()
162+
163+ // Create deps with the checker
164+ deps := NewBaseDeps (
165+ nil , nil , nil , nil ,
166+ translations .NullTranslationHelper ,
167+ FeatureFlags {Experimental : tt .experimental },
168+ 0 ,
169+ nil ,
170+ )
171+
172+ // Get the tool and its handler
173+ tool := HelloWorldTool (translations .NullTranslationHelper )
174+ handler := tool .Handler (deps )
168175
169176 // Call the handler with deps in context
170177 ctx := ContextWithDeps (context .Background (), deps )
171- result , err := handler (ctx , & request )
178+ result , err := handler (ctx , & mcp.CallToolRequest {
179+ Params : & mcp.CallToolParamsRaw {
180+ Arguments : json .RawMessage (`{}` ),
181+ },
182+ })
172183 require .NoError (t , err )
173184 require .NotNil (t , result )
174185 require .Len (t , result .Content , 1 )
@@ -183,7 +194,6 @@ func TestHelloWorld_ConditionalBehavior(t *testing.T) {
183194
184195 // Verify the greeting matches expected based on feature flag
185196 assert .Equal (t , tt .expectedGreeting , response ["greeting" ])
186- assert .Equal (t , tt .expectedExperimentalMode , response ["experimental_mode" ])
187197 })
188198 }
189199}
0 commit comments