Skip to content

Commit 15c037a

Browse files
committed
move experimental to seperate config/ff value
1 parent fa0aa8c commit 15c037a

File tree

6 files changed

+89
-83
lines changed

6 files changed

+89
-83
lines changed

cmd/github-mcp-server/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ var (
8383
LogFilePath: viper.GetString("log-file"),
8484
ContentWindowSize: viper.GetInt("content-window-size"),
8585
LockdownMode: viper.GetBool("lockdown-mode"),
86+
Experimental: viper.GetBool("experimental"),
8687
RepoAccessCacheTTL: &ttl,
8788
}
8889
return ghmcp.RunStdioServer(stdioServerConfig)
@@ -108,6 +109,7 @@ func init() {
108109
rootCmd.PersistentFlags().String("gh-host", "", "Specify the GitHub hostname (for GitHub Enterprise etc.)")
109110
rootCmd.PersistentFlags().Int("content-window-size", 5000, "Specify the content window size")
110111
rootCmd.PersistentFlags().Bool("lockdown-mode", false, "Enable lockdown mode")
112+
rootCmd.PersistentFlags().Bool("experimental", false, "Enable experimental features")
111113
rootCmd.PersistentFlags().Duration("repo-access-cache-ttl", 5*time.Minute, "Override the repo access cache TTL (e.g. 1m, 0s to disable)")
112114

113115
// Bind flag to viper
@@ -122,6 +124,7 @@ func init() {
122124
_ = viper.BindPFlag("host", rootCmd.PersistentFlags().Lookup("gh-host"))
123125
_ = viper.BindPFlag("content-window-size", rootCmd.PersistentFlags().Lookup("content-window-size"))
124126
_ = viper.BindPFlag("lockdown-mode", rootCmd.PersistentFlags().Lookup("lockdown-mode"))
127+
_ = viper.BindPFlag("experimental", rootCmd.PersistentFlags().Lookup("experimental"))
125128
_ = viper.BindPFlag("repo-access-cache-ttl", rootCmd.PersistentFlags().Lookup("repo-access-cache-ttl"))
126129

127130
// Add subcommands

internal/ghmcp/server.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ type MCPServerConfig struct {
6464
// LockdownMode indicates if we should enable lockdown mode
6565
LockdownMode bool
6666

67+
// Experimental indicates if we should enable experimental features
68+
Experimental bool
69+
6770
// Logger is used for logging within the server
6871
Logger *slog.Logger
6972
// RepoAccessTTL overrides the default TTL for repository access cache entries.
@@ -208,7 +211,10 @@ func NewMCPServer(cfg MCPServerConfig) (*mcp.Server, error) {
208211
clients.raw,
209212
clients.repoAccess,
210213
cfg.Translator,
211-
github.FeatureFlags{LockdownMode: cfg.LockdownMode},
214+
github.FeatureFlags{
215+
LockdownMode: cfg.LockdownMode,
216+
Experimental: cfg.Experimental,
217+
},
212218
cfg.ContentWindowSize,
213219
featureChecker,
214220
)
@@ -326,6 +332,9 @@ type StdioServerConfig struct {
326332
// LockdownMode indicates if we should enable lockdown mode
327333
LockdownMode bool
328334

335+
// Experimental indicates if we should enable experimental features
336+
Experimental bool
337+
329338
// RepoAccessCacheTTL overrides the default TTL for repository access cache entries.
330339
RepoAccessCacheTTL *time.Duration
331340
}
@@ -382,6 +391,7 @@ func RunStdioServer(cfg StdioServerConfig) error {
382391
Translator: t,
383392
ContentWindowSize: cfg.ContentWindowSize,
384393
LockdownMode: cfg.LockdownMode,
394+
Experimental: cfg.Experimental,
385395
Logger: logger,
386396
RepoAccessTTL: cfg.RepoAccessCacheTTL,
387397
TokenScopes: tokenScopes,

pkg/github/feature_flags.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,5 @@ package github
33
// FeatureFlags defines runtime feature toggles that adjust tool behavior.
44
type FeatureFlags struct {
55
LockdownMode bool
6+
Experimental bool
67
}
7-
8-
// RemoteMCPExperimental is a long-lived feature flag for experimental remote MCP features.
9-
// This flag enables experimental behaviors in tools that are being tested for remote server deployment.
10-
const RemoteMCPExperimental = "remote_mcp_experimental"
Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,87 @@
1-
package github_test
1+
package github
22

33
import (
44
"context"
55
"encoding/json"
66
"testing"
77

8-
"github.com/github/github-mcp-server/pkg/github"
98
"github.com/github/github-mcp-server/pkg/translations"
109
"github.com/modelcontextprotocol/go-sdk/mcp"
1110
"github.com/stretchr/testify/assert"
1211
"github.com/stretchr/testify/require"
12+
13+
"github.com/github/github-mcp-server/pkg/inventory"
14+
"github.com/github/github-mcp-server/pkg/scopes"
15+
"github.com/github/github-mcp-server/pkg/utils"
16+
"github.com/google/jsonschema-go/jsonschema"
1317
)
1418

19+
// RemoteMCPExperimental is a long-lived feature flag for experimental remote MCP features.
20+
// This flag enables experimental behaviors in tools that are being tested for remote server deployment.
21+
const RemoteMCPEnthusiasticGreeting = "remote_mcp_enthusiastic_greeting"
22+
23+
// HelloWorld returns a simple greeting tool that demonstrates feature flag conditional behavior.
24+
// This tool is for testing and demonstration purposes only.
25+
func HelloWorld(t translations.TranslationHelperFunc) inventory.ServerTool {
26+
return NewTool(
27+
ToolsetMetadataContext, // Use existing "context" toolset
28+
mcp.Tool{
29+
Name: "hello_world",
30+
Description: t("TOOL_HELLO_WORLD_DESCRIPTION", "A simple greeting tool that demonstrates feature flag conditional behavior"),
31+
Annotations: &mcp.ToolAnnotations{
32+
Title: t("TOOL_HELLO_WORLD_TITLE", "Hello World"),
33+
ReadOnlyHint: true,
34+
},
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+
},
44+
},
45+
[]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+
}
52+
53+
// Check feature flag to determine greeting style
54+
var greeting string
55+
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 + "!"
61+
}
62+
63+
// Build response
64+
response := map[string]any{
65+
"greeting": greeting,
66+
"experimental_mode": deps.IsFeatureEnabled(ctx, RemoteMCPEnthusiasticGreeting),
67+
"timestamp": "2026-01-12", // Static for demonstration
68+
}
69+
70+
jsonBytes, err := json.Marshal(response)
71+
if err != nil {
72+
return utils.NewToolResultError("failed to marshal response"), nil, nil
73+
}
74+
75+
return utils.NewToolResultText(string(jsonBytes)), nil, nil
76+
},
77+
)
78+
}
79+
1580
func TestHelloWorld_ToolDefinition(t *testing.T) {
1681
t.Parallel()
1782

1883
// Create tool
19-
tool := github.HelloWorld(translations.NullTranslationHelper)
84+
tool := HelloWorld(translations.NullTranslationHelper)
2085

2186
// Verify tool definition
2287
assert.Equal(t, "hello_world", tool.Tool.Name)
@@ -68,23 +133,23 @@ func TestHelloWorld_ConditionalBehavior(t *testing.T) {
68133

69134
// Create feature checker based on test case
70135
checker := func(_ context.Context, flagName string) (bool, error) {
71-
if flagName == github.RemoteMCPExperimental {
136+
if flagName == RemoteMCPEnthusiasticGreeting {
72137
return tt.featureFlagEnabled, nil
73138
}
74139
return false, nil
75140
}
76141

77142
// Create deps with the checker
78-
deps := github.NewBaseDeps(
143+
deps := NewBaseDeps(
79144
nil, nil, nil, nil,
80145
translations.NullTranslationHelper,
81-
github.FeatureFlags{},
146+
FeatureFlags{},
82147
0,
83148
checker,
84149
)
85150

86151
// Get the tool and its handler
87-
tool := github.HelloWorld(translations.NullTranslationHelper)
152+
tool := HelloWorld(translations.NullTranslationHelper)
88153
handler := tool.Handler(deps)
89154

90155
// Create request
@@ -102,7 +167,7 @@ func TestHelloWorld_ConditionalBehavior(t *testing.T) {
102167
}
103168

104169
// Call the handler with deps in context
105-
ctx := github.ContextWithDeps(context.Background(), deps)
170+
ctx := ContextWithDeps(context.Background(), deps)
106171
result, err := handler(ctx, &request)
107172
require.NoError(t, err)
108173
require.NotNil(t, result)

pkg/github/hello.go

Lines changed: 0 additions & 70 deletions
This file was deleted.

pkg/github/server_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func stubRepoAccessCache(client *githubv4.Client, ttl time.Duration) *lockdown.R
8484
func stubFeatureFlags(enabledFlags map[string]bool) FeatureFlags {
8585
return FeatureFlags{
8686
LockdownMode: enabledFlags["lockdown-mode"],
87+
Experimental: enabledFlags["experimental"],
8788
}
8889
}
8990

0 commit comments

Comments
 (0)