Skip to content

Commit ad49026

Browse files
authored
Implement repository detection feature in search-servers command (#30)
* Implement repository detection feature in search-servers command - Added support for automatic detection of npm and PyPI packages in the search-servers command. - Enhanced command description and usage examples to reflect new functionality. - Introduced configuration option `check_server_repo` to enable/disable repository detection. - Updated SearchServers function to accept a limit parameter and a guesser for repository info. - Added comprehensive documentation for the repository detection feature, including configuration and usage examples. * Refactor repository guessing to support only GitHub URLs - Updated GuessRepositoryType to handle only GitHub URLs, removing PyPI support. - Simplified package name extraction for npm packages in the format @author/repo. - Enhanced tests to validate new GitHub URL handling and npm package detection. - Removed unused PyPI-related code and tests to streamline functionality. * Refactor test setup to use temporary database files for compatibility - Updated test setup functions in guesser_test.go and search_test.go to create temporary database files instead of using in-memory databases, ensuring compatibility across platforms. * Implement batch processing for repository guessing in mcpproxy - Introduced batch processing for repository guessing in the GuessRepositoryTypesBatch method, allowing concurrent checks of multiple GitHub URLs. - Enhanced performance by implementing connection pooling and limiting concurrent requests to improve response times. - Updated SearchServers to utilize batch processing for repository guessing, applying it only to filtered results. - Refactored related parsing functions to support new batch processing without impacting existing functionality. - Added comprehensive tests to validate batch processing behavior and performance improvements. * Enhance logging configuration and command handling in mcpproxy - Updated default logging settings to disable file logging and enable console output. - Modified command logger setup to use appropriate log levels based on command type. - Improved logging in search-servers command to provide detailed information on server searches and registry loading. - Adjusted autostart configurations to include logging options for better traceability. * Enhance logging in GuessRepositoryTypesBatch for npm package results - Added detailed logging for npm package detection results, including package name, version, and installation command. - Improved error handling logging for failed repository type guesses, ensuring clarity on the URL and error details. - Streamlined logging for cases with no npm package information. * Refactor logging and error handling in mcpproxy and guesser - Introduced a default log level constant in mcpproxy for improved logging consistency. - Updated listAllRegistries function to remove error return, simplifying its signature. - Enhanced guessRepositoryTypeBatch to eliminate error handling, returning only results. - Streamlined server iteration in search.go for better readability. * Enhance search_servers documentation and update server entry structure - Updated documentation to include repository information and separate MCP endpoints from source code repositories. - Added `source_code_url` field to `ServerEntry` struct for better clarity on source code links. - Modified tests to validate the new `source_code_url` field and ensure correct parsing of server entries. * Enhance OAuth configuration handling and add base URL parsing - Updated CreateOAuthConfig to construct the OAuth server metadata URL from the server URL. - Introduced parseBaseURL function to extract the base URL from a full URL, handling cases without a scheme. - Improved logging for OAuth server metadata URL setting and error handling for URL parsing failures.
1 parent 9dd01ab commit ad49026

File tree

19 files changed

+2357
-228
lines changed

19 files changed

+2357
-228
lines changed

cmd/mcpproxy/main.go

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"go.uber.org/zap"
1414

1515
"mcpproxy-go/internal/config"
16+
"mcpproxy-go/internal/experiments"
1617
"mcpproxy-go/internal/logs"
1718
"mcpproxy-go/internal/registries"
1819
"mcpproxy-go/internal/server"
@@ -39,6 +40,10 @@ var (
3940
version = "v0.1.0" // This will be injected by -ldflags during build
4041
)
4142

43+
const (
44+
defaultLogLevel = "info"
45+
)
46+
4247
// TrayInterface defines the interface for system tray functionality
4348
type TrayInterface interface {
4449
Run(ctx context.Context) error
@@ -59,8 +64,8 @@ func main() {
5964
// Add global flags
6065
rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "Configuration file path")
6166
rootCmd.PersistentFlags().StringVarP(&dataDir, "data-dir", "d", "", "Data directory path (default: ~/.mcpproxy)")
62-
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level (debug, info, warn, error)")
63-
rootCmd.PersistentFlags().BoolVar(&logToFile, "log-to-file", true, "Enable logging to file in standard OS location")
67+
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "", "Log level (debug, info, warn, error) - defaults: server=info, other commands=warn")
68+
rootCmd.PersistentFlags().BoolVar(&logToFile, "log-to-file", false, "Enable logging to file in standard OS location (default: console only)")
6469
rootCmd.PersistentFlags().StringVar(&logDir, "log-dir", "", "Custom log directory path (overrides standard OS location)")
6570

6671
// Add server command
@@ -101,38 +106,81 @@ func main() {
101106
func createSearchServersCommand() *cobra.Command {
102107
var registryFlag, searchFlag, tagFlag string
103108
var listRegistries bool
109+
var limitFlag int
104110

105111
cmd := &cobra.Command{
106112
Use: "search-servers",
107-
Short: "Search MCP registries for available servers",
113+
Short: "Search MCP registries for available servers with repository detection",
108114
Long: `Search known MCP registries for available servers that can be added as upstreams.
109-
This tool queries embedded registries to discover MCP servers and returns results
110-
that can be directly used with the 'upstream_servers add' command.
115+
This tool queries embedded registries to discover MCP servers and includes automatic
116+
npm/PyPI package detection to enhance results with install commands.
117+
Results can be directly used with the 'upstream_servers add' command.
111118
112119
Examples:
113120
# List all known registries
114121
mcpproxy search-servers --list-registries
115122
116-
# Search for weather-related servers in the Smithery registry
117-
mcpproxy search-servers --registry smithery --search weather
123+
# Search for weather-related servers in the Smithery registry (limit 10 results)
124+
mcpproxy search-servers --registry smithery --search weather --limit 10
118125
119126
# Search for servers tagged as "finance" in the Pulse registry
120127
mcpproxy search-servers --registry pulse --tag finance`,
121-
RunE: func(_ *cobra.Command, _ []string) error {
128+
RunE: func(cmd *cobra.Command, _ []string) error {
129+
// Setup logger for search command (non-server command = WARN level by default)
130+
cmdLogLevel, _ := cmd.Flags().GetString("log-level")
131+
cmdLogToFile, _ := cmd.Flags().GetBool("log-to-file")
132+
cmdLogDir, _ := cmd.Flags().GetString("log-dir")
133+
134+
logger, err := logs.SetupCommandLogger(false, cmdLogLevel, cmdLogToFile, cmdLogDir)
135+
if err != nil {
136+
return fmt.Errorf("failed to setup logger: %w", err)
137+
}
138+
defer func() {
139+
_ = logger.Sync()
140+
}()
141+
122142
if listRegistries {
123-
return listAllRegistries()
143+
listAllRegistries(logger)
144+
return nil
124145
}
125146

126147
if registryFlag == "" {
127148
return fmt.Errorf("--registry is required (use --list-registries to see available options)")
128149
}
129150

130151
ctx := context.Background()
131-
servers, err := registries.SearchServers(ctx, registryFlag, tagFlag, searchFlag)
152+
153+
// Create config to check if repository guessing is enabled
154+
cfg, err := config.LoadFromFile("")
132155
if err != nil {
156+
// Use default config if loading fails
157+
cfg = config.DefaultConfig()
158+
}
159+
160+
// Initialize registries from config
161+
registries.SetRegistriesFromConfig(cfg)
162+
163+
// Create experiments guesser if repository checking is enabled
164+
var guesser *experiments.Guesser
165+
if cfg.CheckServerRepo {
166+
// Use the proper logger instead of no-op
167+
guesser = experiments.NewGuesser(nil, logger)
168+
}
169+
170+
logger.Info("Searching servers",
171+
zap.String("registry", registryFlag),
172+
zap.String("search", searchFlag),
173+
zap.String("tag", tagFlag),
174+
zap.Int("limit", limitFlag))
175+
176+
servers, err := registries.SearchServers(ctx, registryFlag, tagFlag, searchFlag, limitFlag, guesser)
177+
if err != nil {
178+
logger.Error("Search failed", zap.Error(err))
133179
return fmt.Errorf("search failed: %w", err)
134180
}
135181

182+
logger.Info("Search completed", zap.Int("results_count", len(servers)))
183+
136184
// Print results as JSON
137185
output, err := json.MarshalIndent(servers, "", " ")
138186
if err != nil {
@@ -147,14 +195,29 @@ Examples:
147195
cmd.Flags().StringVarP(&registryFlag, "registry", "r", "", "Registry ID or name to search (exact match)")
148196
cmd.Flags().StringVarP(&searchFlag, "search", "s", "", "Search term for server name/description")
149197
cmd.Flags().StringVarP(&tagFlag, "tag", "t", "", "Filter servers by tag/category")
198+
cmd.Flags().IntVarP(&limitFlag, "limit", "l", 10, "Maximum number of results to return (default: 10, max: 50)")
150199
cmd.Flags().BoolVar(&listRegistries, "list-registries", false, "List all known registries")
151200

152201
return cmd
153202
}
154203

155-
func listAllRegistries() error {
204+
func listAllRegistries(logger *zap.Logger) {
205+
// Load config and initialize registries
206+
cfg, err := config.LoadFromFile("")
207+
if err != nil {
208+
// Use default config if loading fails
209+
cfg = config.DefaultConfig()
210+
}
211+
212+
logger.Info("Loading registries configuration")
213+
214+
// Initialize registries from config
215+
registries.SetRegistriesFromConfig(cfg)
216+
156217
registryList := registries.ListRegistries()
157218

219+
logger.Info("Found registries", zap.Int("count", len(registryList)))
220+
158221
// Format as a simple table for CLI display
159222
fmt.Printf("%-20s %-30s %s\n", "ID", "NAME", "DESCRIPTION")
160223
fmt.Printf("%-20s %-30s %s\n", "==", "====", "===========")
@@ -165,7 +228,6 @@ func listAllRegistries() error {
165228
}
166229

167230
fmt.Printf("\nUse --registry <ID> to search a specific registry\n")
168-
return nil
169231
}
170232

171233
func runServer(cmd *cobra.Command, _ []string) error {
@@ -190,8 +252,14 @@ func runServer(cmd *cobra.Command, _ []string) error {
190252

191253
// Override logging settings from command line
192254
if cfg.Logging == nil {
255+
// Use command-specific default level (INFO for server command)
256+
defaultLevel := cmdLogLevel
257+
if defaultLevel == "" {
258+
defaultLevel = defaultLogLevel // Server command defaults to INFO
259+
}
260+
193261
cfg.Logging = &config.LogConfig{
194-
Level: cmdLogLevel,
262+
Level: defaultLevel,
195263
EnableFile: cmdLogToFile,
196264
EnableConsole: true,
197265
Filename: "main.log",
@@ -203,7 +271,11 @@ func runServer(cmd *cobra.Command, _ []string) error {
203271
}
204272
} else {
205273
// Override specific fields from command line
206-
cfg.Logging.Level = cmdLogLevel
274+
if cmdLogLevel != "" {
275+
cfg.Logging.Level = cmdLogLevel
276+
} else if cfg.Logging.Level == "" {
277+
cfg.Logging.Level = defaultLogLevel // Server command defaults to INFO
278+
}
207279
cfg.Logging.EnableFile = cmdLogToFile
208280
if cfg.Logging.Filename == "" || cfg.Logging.Filename == "mcpproxy.log" {
209281
cfg.Logging.Filename = "main.log"

0 commit comments

Comments
 (0)