From f710c893dc83ab9b57c95faed1102f71f2fd0c73 Mon Sep 17 00:00:00 2001 From: hungran <26101787+hungran@users.noreply.github.com> Date: Thu, 10 Jul 2025 19:20:01 +0700 Subject: [PATCH 1/4] feat: tool prefix name Signed-off-by: hungran <26101787+hungran@users.noreply.github.com> --- cmd/github-mcp-server/main.go | 3 +++ internal/ghmcp/server.go | 11 +++++++++-- pkg/toolsets/toolsets.go | 36 ++++++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/cmd/github-mcp-server/main.go b/cmd/github-mcp-server/main.go index 0a4545835..f8c86fe02 100644 --- a/cmd/github-mcp-server/main.go +++ b/cmd/github-mcp-server/main.go @@ -52,6 +52,7 @@ var ( EnabledToolsets: enabledToolsets, DynamicToolsets: viper.GetBool("dynamic_toolsets"), ReadOnly: viper.GetBool("read-only"), + ToolPrefix: viper.GetString("tool-prefix"), ExportTranslations: viper.GetBool("export-translations"), EnableCommandLogging: viper.GetBool("enable-command-logging"), LogFilePath: viper.GetString("log-file"), @@ -72,6 +73,7 @@ func init() { rootCmd.PersistentFlags().StringSlice("toolsets", github.DefaultTools, "An optional comma separated list of groups of tools to allow, defaults to enabling all") rootCmd.PersistentFlags().Bool("dynamic-toolsets", false, "Enable dynamic toolsets") rootCmd.PersistentFlags().Bool("read-only", false, "Restrict the server to read-only operations") + rootCmd.PersistentFlags().String("tool-prefix", "", "Optional prefix to add to all tool names (e.g. 'github_')") rootCmd.PersistentFlags().String("log-file", "", "Path to log file") rootCmd.PersistentFlags().Bool("enable-command-logging", false, "When enabled, the server will log all command requests and responses to the log file") rootCmd.PersistentFlags().Bool("export-translations", false, "Save translations to a JSON file") @@ -82,6 +84,7 @@ func init() { _ = viper.BindPFlag("toolsets", rootCmd.PersistentFlags().Lookup("toolsets")) _ = viper.BindPFlag("dynamic_toolsets", rootCmd.PersistentFlags().Lookup("dynamic-toolsets")) _ = viper.BindPFlag("read-only", rootCmd.PersistentFlags().Lookup("read-only")) + _ = viper.BindPFlag("tool-prefix", rootCmd.PersistentFlags().Lookup("tool-prefix")) _ = viper.BindPFlag("log-file", rootCmd.PersistentFlags().Lookup("log-file")) _ = viper.BindPFlag("enable-command-logging", rootCmd.PersistentFlags().Lookup("enable-command-logging")) _ = viper.BindPFlag("export-translations", rootCmd.PersistentFlags().Lookup("export-translations")) diff --git a/internal/ghmcp/server.go b/internal/ghmcp/server.go index 7ad71532f..f1303d02e 100644 --- a/internal/ghmcp/server.go +++ b/internal/ghmcp/server.go @@ -45,6 +45,9 @@ type MCPServerConfig struct { // ReadOnly indicates if we should only offer read-only tools ReadOnly bool + // ToolPrefix is an optional prefix to add to all tool names (e.g. "github_") + ToolPrefix string + // Translator provides translated text for the server tooling Translator translations.TranslationHelperFunc @@ -143,11 +146,11 @@ func NewMCPServer(cfg MCPServerConfig) (*server.MCPServer, error) { } // Register all mcp functionality with the server - tsg.RegisterAll(ghServer) + tsg.RegisterAllWithPrefix(ghServer, cfg.ToolPrefix) if cfg.DynamicToolsets { dynamic := github.InitDynamicToolset(ghServer, tsg, cfg.Translator) - dynamic.RegisterTools(ghServer) + dynamic.RegisterToolsWithPrefix(ghServer, cfg.ToolPrefix) } return ghServer, nil @@ -174,6 +177,9 @@ type StdioServerConfig struct { // ReadOnly indicates if we should only register read-only tools ReadOnly bool + // ToolPrefix is an optional prefix to add to all tool names (e.g. "github_") + ToolPrefix string + // ExportTranslations indicates if we should export translations // See: https://github.com/github/github-mcp-server?tab=readme-ov-file#i18n--overriding-descriptions ExportTranslations bool @@ -203,6 +209,7 @@ func RunStdioServer(cfg StdioServerConfig) error { EnabledToolsets: cfg.EnabledToolsets, DynamicToolsets: cfg.DynamicToolsets, ReadOnly: cfg.ReadOnly, + ToolPrefix: cfg.ToolPrefix, Translator: t, ContentWindowSize: cfg.ContentWindowSize, }) diff --git a/pkg/toolsets/toolsets.go b/pkg/toolsets/toolsets.go index 85cd5d841..16df5c0ef 100644 --- a/pkg/toolsets/toolsets.go +++ b/pkg/toolsets/toolsets.go @@ -29,6 +29,18 @@ func NewToolsetDoesNotExistError(name string) *ToolsetDoesNotExistError { return &ToolsetDoesNotExistError{Name: name} } +// createToolWithPrefixedName creates a new tool with the same properties as the original but with a prefixed name +func createToolWithPrefixedName(original mcp.Tool, prefix string) mcp.Tool { + // Create a new tool with the prefixed name and copy all properties + newTool := mcp.Tool{ + Name: prefix + original.Name, + Description: original.Description, + InputSchema: original.InputSchema, + Annotations: original.Annotations, + } + return newTool +} + func NewServerTool(tool mcp.Tool, handler server.ToolHandlerFunc) server.ServerTool { return server.ServerTool{Tool: tool, Handler: handler} } @@ -80,15 +92,29 @@ func (t *Toolset) GetAvailableTools() []server.ServerTool { } func (t *Toolset) RegisterTools(s *server.MCPServer) { + t.RegisterToolsWithPrefix(s, "") +} + +func (t *Toolset) RegisterToolsWithPrefix(s *server.MCPServer, prefix string) { if !t.Enabled { return } for _, tool := range t.readTools { - s.AddTool(tool.Tool, tool.Handler) + toolToRegister := tool.Tool + if prefix != "" { + // Create a new tool with the prefixed name + toolToRegister = createToolWithPrefixedName(tool.Tool, prefix) + } + s.AddTool(toolToRegister, tool.Handler) } if !t.readOnly { for _, tool := range t.writeTools { - s.AddTool(tool.Tool, tool.Handler) + toolToRegister := tool.Tool + if prefix != "" { + // Create a new tool with the prefixed name + toolToRegister = createToolWithPrefixedName(tool.Tool, prefix) + } + s.AddTool(toolToRegister, tool.Handler) } } } @@ -239,8 +265,12 @@ func (tg *ToolsetGroup) EnableToolset(name string) error { } func (tg *ToolsetGroup) RegisterAll(s *server.MCPServer) { + tg.RegisterAllWithPrefix(s, "") +} + +func (tg *ToolsetGroup) RegisterAllWithPrefix(s *server.MCPServer, prefix string) { for _, toolset := range tg.Toolsets { - toolset.RegisterTools(s) + toolset.RegisterToolsWithPrefix(s, prefix) toolset.RegisterResourcesTemplates(s) toolset.RegisterPrompts(s) } From cf1dc0730343d1394212c6d95472974655331924 Mon Sep 17 00:00:00 2001 From: hungran <26101787+hungran@users.noreply.github.com> Date: Fri, 11 Jul 2025 13:02:24 +0700 Subject: [PATCH 2/4] keep scope minial Signed-off-by: hungran <26101787+hungran@users.noreply.github.com> --- internal/ghmcp/server.go | 4 ++-- pkg/toolsets/toolsets.go | 14 +++----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/internal/ghmcp/server.go b/internal/ghmcp/server.go index f1303d02e..3a277020e 100644 --- a/internal/ghmcp/server.go +++ b/internal/ghmcp/server.go @@ -146,11 +146,11 @@ func NewMCPServer(cfg MCPServerConfig) (*server.MCPServer, error) { } // Register all mcp functionality with the server - tsg.RegisterAllWithPrefix(ghServer, cfg.ToolPrefix) + tsg.RegisterAll(ghServer, cfg.ToolPrefix) if cfg.DynamicToolsets { dynamic := github.InitDynamicToolset(ghServer, tsg, cfg.Translator) - dynamic.RegisterToolsWithPrefix(ghServer, cfg.ToolPrefix) + dynamic.RegisterTools(ghServer, cfg.ToolPrefix) } return ghServer, nil diff --git a/pkg/toolsets/toolsets.go b/pkg/toolsets/toolsets.go index 16df5c0ef..c20047960 100644 --- a/pkg/toolsets/toolsets.go +++ b/pkg/toolsets/toolsets.go @@ -91,11 +91,7 @@ func (t *Toolset) GetAvailableTools() []server.ServerTool { return append(t.readTools, t.writeTools...) } -func (t *Toolset) RegisterTools(s *server.MCPServer) { - t.RegisterToolsWithPrefix(s, "") -} - -func (t *Toolset) RegisterToolsWithPrefix(s *server.MCPServer, prefix string) { +func (t *Toolset) RegisterTools(s *server.MCPServer, prefix string) { if !t.Enabled { return } @@ -264,13 +260,9 @@ func (tg *ToolsetGroup) EnableToolset(name string) error { return nil } -func (tg *ToolsetGroup) RegisterAll(s *server.MCPServer) { - tg.RegisterAllWithPrefix(s, "") -} - -func (tg *ToolsetGroup) RegisterAllWithPrefix(s *server.MCPServer, prefix string) { +func (tg *ToolsetGroup) RegisterAll(s *server.MCPServer, prefix string) { for _, toolset := range tg.Toolsets { - toolset.RegisterToolsWithPrefix(s, prefix) + toolset.RegisterTools(s, prefix) toolset.RegisterResourcesTemplates(s) toolset.RegisterPrompts(s) } From 609907aea880bb03765502b3b6918d1b48ad6927 Mon Sep 17 00:00:00 2001 From: hungran <26101787+hungran@users.noreply.github.com> Date: Fri, 11 Jul 2025 13:10:21 +0700 Subject: [PATCH 3/4] reduce duplicate read write tool loops Signed-off-by: hungran <26101787+hungran@users.noreply.github.com> --- pkg/toolsets/toolsets.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pkg/toolsets/toolsets.go b/pkg/toolsets/toolsets.go index c20047960..9a43ec07d 100644 --- a/pkg/toolsets/toolsets.go +++ b/pkg/toolsets/toolsets.go @@ -95,7 +95,7 @@ func (t *Toolset) RegisterTools(s *server.MCPServer, prefix string) { if !t.Enabled { return } - for _, tool := range t.readTools { + registerToolWithPrefix := func(tool server.ServerTool) { toolToRegister := tool.Tool if prefix != "" { // Create a new tool with the prefixed name @@ -103,14 +103,13 @@ func (t *Toolset) RegisterTools(s *server.MCPServer, prefix string) { } s.AddTool(toolToRegister, tool.Handler) } + + for _, tool := range t.readTools { + registerToolWithPrefix(tool) + } if !t.readOnly { for _, tool := range t.writeTools { - toolToRegister := tool.Tool - if prefix != "" { - // Create a new tool with the prefixed name - toolToRegister = createToolWithPrefixedName(tool.Tool, prefix) - } - s.AddTool(toolToRegister, tool.Handler) + registerToolWithPrefix(tool) } } } From c60428eb278e0cf03d94f22bbaf5343102b2c902 Mon Sep 17 00:00:00 2001 From: hungran <26101787+hungran@users.noreply.github.com> Date: Fri, 11 Jul 2025 13:30:52 +0700 Subject: [PATCH 4/4] simpler Signed-off-by: hungran <26101787+hungran@users.noreply.github.com> --- pkg/toolsets/toolsets.go | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/pkg/toolsets/toolsets.go b/pkg/toolsets/toolsets.go index 9a43ec07d..449e12d51 100644 --- a/pkg/toolsets/toolsets.go +++ b/pkg/toolsets/toolsets.go @@ -29,18 +29,6 @@ func NewToolsetDoesNotExistError(name string) *ToolsetDoesNotExistError { return &ToolsetDoesNotExistError{Name: name} } -// createToolWithPrefixedName creates a new tool with the same properties as the original but with a prefixed name -func createToolWithPrefixedName(original mcp.Tool, prefix string) mcp.Tool { - // Create a new tool with the prefixed name and copy all properties - newTool := mcp.Tool{ - Name: prefix + original.Name, - Description: original.Description, - InputSchema: original.InputSchema, - Annotations: original.Annotations, - } - return newTool -} - func NewServerTool(tool mcp.Tool, handler server.ToolHandlerFunc) server.ServerTool { return server.ServerTool{Tool: tool, Handler: handler} } @@ -96,12 +84,11 @@ func (t *Toolset) RegisterTools(s *server.MCPServer, prefix string) { return } registerToolWithPrefix := func(tool server.ServerTool) { - toolToRegister := tool.Tool if prefix != "" { // Create a new tool with the prefixed name - toolToRegister = createToolWithPrefixedName(tool.Tool, prefix) + tool.Tool.Name = prefix + tool.Tool.Name } - s.AddTool(toolToRegister, tool.Handler) + s.AddTool(tool.Tool, tool.Handler) } for _, tool := range t.readTools {