@@ -322,6 +322,169 @@ func ListConfigPaths(ctx context.Context, configIsArray bool) ([]ConfigPath, err
322
322
return paths , nil
323
323
}
324
324
325
+ func ServerMap (configPaths []ConfigPath ) (map [string ]any , error ) {
326
+ // build a server map from all of the configs
327
+ serverMap := make (map [string ]any )
328
+
329
+ for _ , configPath := range configPaths {
330
+ // if the configuration file doesn't exist, skip it
331
+ if _ , err := os .Stat (configPath .Path ); err != nil {
332
+ if os .IsNotExist (err ) {
333
+ continue
334
+ }
335
+ return nil , err
336
+ }
337
+
338
+ // read the configuration file
339
+ file , err := os .Open (configPath .Path )
340
+ if err != nil {
341
+ return nil , err
342
+ }
343
+ defer file .Close ()
344
+
345
+ // parse the configuration file as JSON
346
+ var data map [string ]any
347
+ decoder := json .NewDecoder (file )
348
+ if err := decoder .Decode (& data ); err != nil {
349
+ return nil , fmt .Errorf ("failed to parse %s: %w" , configPath .Path , err )
350
+ }
351
+
352
+ if mcpServers , ok := data [configPath .ConfigName ].(map [string ]any ); ok {
353
+ // add metadata about the tool
354
+ config := make (map [string ]any )
355
+ config ["mcpServers" ] = mcpServers
356
+ config ["configName" ] = configPath .ConfigName
357
+
358
+ if configPath .ToolName != "" {
359
+ config ["toolName" ] = configPath .ToolName
360
+ }
361
+
362
+ serverMap [configPath .Path ] = config
363
+
364
+ // add metadata about each MCP server
365
+ for name := range mcpServers {
366
+ if serverMap , ok := mcpServers [name ].(map [string ]any ); ok {
367
+ server , err := configExtract (configPath , name )
368
+ if err != nil {
369
+ return nil , fmt .Errorf ("failed to extract config for %s: %w" , name , err )
370
+ }
371
+
372
+ for key , value := range server {
373
+ if key != "command" && key != "args" {
374
+ serverMap [key ] = value
375
+ }
376
+ }
377
+
378
+ mcpServers [name ] = serverMap
379
+ }
380
+ }
381
+ }
382
+ }
383
+
384
+ return serverMap , nil
385
+ }
386
+
387
+ func SelectServerAndConfig (ctx context.Context , configIsArray bool ) (string , []ConfigPath , error ) {
388
+ server := flag .GetString (ctx , "server" )
389
+
390
+ // Check if the user has specified any client flags
391
+ configSelected := false
392
+ for client := range McpClients {
393
+ configSelected = configSelected || flag .GetBool (ctx , client )
394
+ }
395
+
396
+ // if no cllent is selected, select all clients
397
+ if ! configSelected {
398
+ for client := range McpClients {
399
+ flag .SetString (ctx , client , "true" )
400
+ }
401
+ }
402
+
403
+ // Get a list of config paths
404
+ configPaths , err := ListConfigPaths (ctx , true )
405
+ if err != nil {
406
+ return "" , nil , err
407
+ }
408
+
409
+ var serverMap map [string ]any
410
+
411
+ if len (configPaths ) > 1 || server == "" {
412
+ serverMap , err = ServerMap (configPaths )
413
+ if err != nil {
414
+ return "" , nil , fmt .Errorf ("failed to get server map: %w" , err )
415
+ }
416
+ }
417
+
418
+ if len (configPaths ) == 0 {
419
+ return "" , nil , errors .New ("no configuration paths found" )
420
+ } else if len (configPaths ) > 1 && ! configIsArray {
421
+ choices := make ([]string , 0 )
422
+ choiceMap := make (map [int ]int )
423
+ for i , configPath := range configPaths {
424
+ if config , ok := serverMap [configPath .Path ].(map [string ]any ); ok {
425
+ if servers , ok := config ["mcpServers" ].(map [string ]any ); ok && len (servers ) > 0 {
426
+ if toolName , ok := config ["toolName" ].(string ); ok {
427
+ choices = append (choices , toolName )
428
+ } else {
429
+ choices = append (choices , configPath .Path )
430
+ }
431
+ choiceMap [i ] = len (choices ) - 1
432
+ }
433
+ }
434
+ }
435
+
436
+ index := 0
437
+ if len (choices ) == 0 {
438
+ return "" , nil , errors .New ("no MCP servers found in the selected configuration files" )
439
+ } else if len (choices ) > 1 {
440
+ err := prompt .Select (ctx , & index , "Select a configuration file" , "" , choices ... )
441
+ if err != nil {
442
+ return "" , nil , fmt .Errorf ("failed to select configuration file: %w" , err )
443
+ }
444
+ if choiceIndex , ok := choiceMap [index ]; ok {
445
+ index = choiceIndex
446
+ }
447
+
448
+ }
449
+
450
+ configPaths = []ConfigPath {configPaths [index ]}
451
+ }
452
+
453
+ if server == "" {
454
+ if len (serverMap ) == 0 {
455
+ return "" , configPaths , errors .New ("no MCP servers found in the selected configuration files" )
456
+ }
457
+ // Select a server from the server map
458
+ var index int
459
+ choices := make ([]string , 0 )
460
+ for _ , configPath := range serverMap {
461
+ if config , ok := configPath .(map [string ]any ); ok {
462
+ if servers , ok := config ["mcpServers" ].(map [string ]any ); ok {
463
+ for name := range servers {
464
+ choices = append (choices , name )
465
+ }
466
+ }
467
+ }
468
+ }
469
+
470
+ if len (choices ) == 0 {
471
+ return "" , configPaths , errors .New ("no MCP servers found in the selected configuration files" )
472
+ } else if len (choices ) == 1 {
473
+ server = choices [0 ]
474
+ log .Debugf ("Only one MCP server found: %s" , server )
475
+ } else {
476
+ err := prompt .Select (ctx , & index , "Select a MCP server" , "" , choices ... )
477
+ if err != nil {
478
+ return "" , configPaths , fmt .Errorf ("failed to select MCP server: %w" , err )
479
+ }
480
+ server = choices [index ]
481
+ log .Debugf ("Selected MCP server: %s" , server )
482
+ }
483
+ }
484
+
485
+ return server , configPaths , nil
486
+ }
487
+
325
488
// UpdateConfig updates the configuration at the specified path with the MCP servers
326
489
func UpdateConfig (ctx context.Context , path string , configKey string , server string , command string , args []string ) error {
327
490
log .Debugf ("Updating configuration at %s" , path )
@@ -413,32 +576,9 @@ func UpdateConfig(ctx context.Context, path string, configKey string, server str
413
576
func runRemove (ctx context.Context ) error {
414
577
var err error
415
578
416
- configPaths , err := ListConfigPaths (ctx , true )
579
+ server , configPaths , err := SelectServerAndConfig (ctx , false )
417
580
if err != nil {
418
581
return err
419
- } else if len (configPaths ) == 0 {
420
- return errors .New ("no configuration paths found" )
421
- }
422
-
423
- server := flag .GetString (ctx , "server" )
424
- if server == "" {
425
- server = flag .GetString (ctx , "name" )
426
- if server == "" {
427
- appConfig := appconfig .ConfigFromContext (ctx )
428
- if appConfig == nil {
429
- appName := appconfig .NameFromContext (ctx )
430
- if appName == "" {
431
- return errors .New ("app name is required" )
432
- } else {
433
- appConfig , err = appconfig .FromRemoteApp (ctx , appName )
434
- if err != nil {
435
- return err
436
- }
437
- }
438
- }
439
-
440
- server = appConfig .AppName
441
- }
442
582
}
443
583
444
584
for _ , configPath := range configPaths {
0 commit comments