@@ -7,10 +7,12 @@ import (
77 "encoding/json"
88 "errors"
99 "fmt"
10+ "net/url"
1011 "os"
1112 "os/exec"
1213 "path/filepath"
1314 "runtime"
15+ "strings"
1416
1517 "github.com/apex/log"
1618 "github.com/spf13/cobra"
@@ -59,6 +61,11 @@ func NewAdd() *cobra.Command {
5961 flag.String {
6062 Name : "name" ,
6163 Description : "Name to use for the MCP server in the MCP client configuration" ,
64+ Hidden : true ,
65+ },
66+ flag.String {
67+ Name : "server" ,
68+ Description : "Name to use for the MCP server in the MCP client configuration" ,
6269 },
6370 flag.String {
6471 Name : "user" ,
@@ -97,7 +104,7 @@ func NewRemove() *cobra.Command {
97104 long = short + "\n "
98105 usage = "remove"
99106 )
100- cmd := command .New (usage , short , long , runRemove , command .RequireAppName )
107+ cmd := command .New (usage , short , long , runRemove , command .LoadAppNameIfPresent )
101108 cmd .Args = cobra .ExactArgs (0 )
102109
103110 flag .Add (cmd ,
@@ -109,6 +116,11 @@ func NewRemove() *cobra.Command {
109116 flag.String {
110117 Name : "name" ,
111118 Description : "Name to use for the MCP server in the MCP client configuration" ,
119+ Hidden : true ,
120+ },
121+ flag.String {
122+ Name : "server" ,
123+ Description : "Name to use for the MCP server in the MCP client configuration" ,
112124 },
113125 )
114126
@@ -198,24 +210,27 @@ func runAdd(ctx context.Context) error {
198210 }
199211 }
200212
201- configPaths , err := listCOnfigPaths (ctx )
213+ configPaths , err := listCOnfigPaths (ctx , true )
202214 if err != nil {
203215 return err
204216 } else if len (configPaths ) == 0 {
205217 return errors .New ("no configuration paths found" )
206218 }
207219
208- name := flag .GetString (ctx , "name" )
209- if name == "" {
210- name = appConfig .AppName
220+ server := flag .GetString (ctx , "server" )
221+ if server == "" {
222+ server = flag .GetString (ctx , "name" )
223+ if server == "" {
224+ server = appConfig .AppName
225+ }
211226 }
212227
213228 for _ , configPath := range configPaths {
214229 if configPath .ConfigName == "" {
215230 configPath .ConfigName = "mcpServers"
216231 }
217232
218- err = updateConfig (ctx , configPath .Path , configPath .ConfigName , name , flyctl , args )
233+ err = updateConfig (ctx , configPath .Path , configPath .ConfigName , server , flyctl , args )
219234 if err != nil {
220235 return fmt .Errorf ("failed to update configuration at %s: %w" , configPath .Path , err )
221236 }
@@ -225,7 +240,7 @@ func runAdd(ctx context.Context) error {
225240}
226241
227242// Build a list of configuration paths to update
228- func listCOnfigPaths (ctx context.Context ) ([]ConfigPath , error ) {
243+ func listCOnfigPaths (ctx context.Context , configIsArray bool ) ([]ConfigPath , error ) {
229244 log := logger .FromContext (ctx )
230245
231246 var paths []ConfigPath
@@ -288,21 +303,33 @@ func listCOnfigPaths(ctx context.Context) ([]ConfigPath, error) {
288303 paths = append (paths , ConfigPath {Path : zedPath , ConfigName : "context_servers" })
289304 }
290305
291- // Add custom configuration paths
292- for _ , path := range flag .GetStringArray (ctx , "config" ) {
293- path , err := filepath .Abs (path )
294- if err != nil {
295- return nil , fmt .Errorf ("failed to get absolute path for %s: %w" , path , err )
306+ if configIsArray {
307+ // Add custom configuration paths
308+ for _ , path := range flag .GetStringArray (ctx , "config" ) {
309+ path , err := filepath .Abs (path )
310+ if err != nil {
311+ return nil , fmt .Errorf ("failed to get absolute path for %s: %w" , path , err )
312+ }
313+ log .Debugf ("Adding custom configuration path: %s" , path )
314+ paths = append (paths , ConfigPath {Path : path })
315+ }
316+ } else {
317+ path := flag .GetString (ctx , "config" )
318+ if path != "" {
319+ path , err := filepath .Abs (path )
320+ if err != nil {
321+ return nil , fmt .Errorf ("failed to get absolute path for %s: %w" , path , err )
322+ }
323+ log .Debugf ("Adding custom configuration path: %s" , path )
324+ paths = append (paths , ConfigPath {Path : path })
296325 }
297- log .Debugf ("Adding custom configuration path: %s" , path )
298- paths = append (paths , ConfigPath {Path : path })
299326 }
300327
301328 return paths , nil
302329}
303330
304331// updateConfig updates the configuration at the specified path with the MCP servers
305- func updateConfig (ctx context.Context , path string , configKey string , name string , command string , args []string ) error {
332+ func updateConfig (ctx context.Context , path string , configKey string , server string , command string , args []string ) error {
306333 log .Debugf ("Updating configuration at %s" , path )
307334
308335 // Create directory if it doesn't exist
@@ -347,10 +374,10 @@ func updateConfig(ctx context.Context, path string, configKey string, name strin
347374 }
348375
349376 // Merge the new MCP server with existing ones
350- if _ , exists := mcpServers [name ]; exists {
351- log .Debugf ("Replacing existing MCP server: %s" , name )
377+ if _ , exists := mcpServers [server ]; exists {
378+ log .Debugf ("Replacing existing MCP server: %s" , server )
352379 } else {
353- log .Debugf ("Adding new MCP server: %s" , name )
380+ log .Debugf ("Adding new MCP server: %s" , server )
354381 }
355382
356383 // Build the server map
@@ -360,7 +387,7 @@ func updateConfig(ctx context.Context, path string, configKey string, name strin
360387 }
361388
362389 // Update the server in the existing map
363- mcpServers [name ] = serverMap
390+ mcpServers [server ] = serverMap
364391
365392 // Update the mcpServers field in the config
366393 configData [configKey ] = mcpServers
@@ -388,37 +415,40 @@ func updateConfig(ctx context.Context, path string, configKey string, name strin
388415func runRemove (ctx context.Context ) error {
389416 var err error
390417
391- appConfig := appconfig .ConfigFromContext (ctx )
392- if appConfig == nil {
393- appName := appconfig .NameFromContext (ctx )
394- if appName == "" {
395- return errors .New ("app name is required" )
396- } else {
397- appConfig , err = appconfig .FromRemoteApp (ctx , appName )
398- if err != nil {
399- return err
400- }
401- }
402- }
403-
404- configPaths , err := listCOnfigPaths (ctx )
418+ configPaths , err := listCOnfigPaths (ctx , true )
405419 if err != nil {
406420 return err
407421 } else if len (configPaths ) == 0 {
408422 return errors .New ("no configuration paths found" )
409423 }
410424
411- name := flag .GetString (ctx , "name" )
412- if name == "" {
413- name = appConfig .AppName
425+ server := flag .GetString (ctx , "server" )
426+ if server == "" {
427+ server = flag .GetString (ctx , "name" )
428+ if server == "" {
429+ appConfig := appconfig .ConfigFromContext (ctx )
430+ if appConfig == nil {
431+ appName := appconfig .NameFromContext (ctx )
432+ if appName == "" {
433+ return errors .New ("app name is required" )
434+ } else {
435+ appConfig , err = appconfig .FromRemoteApp (ctx , appName )
436+ if err != nil {
437+ return err
438+ }
439+ }
440+ }
441+
442+ server = appConfig .AppName
443+ }
414444 }
415445
416446 for _ , configPath := range configPaths {
417447 if configPath .ConfigName == "" {
418448 configPath .ConfigName = "mcpServers"
419449 }
420450
421- err = removeConfig (ctx , configPath .Path , configPath .ConfigName , name )
451+ err = removeConfig (ctx , configPath .Path , configPath .ConfigName , server )
422452 if err != nil {
423453 return fmt .Errorf ("failed to update configuration at %s: %w" , configPath .Path , err )
424454 }
@@ -488,3 +518,76 @@ func removeConfig(ctx context.Context, path string, configKey string, name strin
488518 log .Debugf ("Successfully updated existing configuration at %s" , path )
489519 return nil
490520}
521+
522+ // MCPConfig represents the structure of the JSON file
523+ type MCPConfig struct {
524+ MCPServers map [string ]MCPServer `json:"mcpServers"`
525+ }
526+
527+ // Server represents a server configuration in the JSON file
528+ type MCPServer struct {
529+ Args []string `json:"args"`
530+ Command string `json:"command"`
531+ }
532+
533+ func configExtract (configFile string , server string ) (map [string ]interface {}, error ) {
534+ // Check if the file exists
535+ // Read the configuration file
536+ data , err := os .ReadFile (configFile )
537+ if err != nil {
538+ return nil , fmt .Errorf ("Error reading file: %v" , err )
539+ }
540+
541+ // Parse the JSON data
542+ var config MCPConfig
543+ if err := json .Unmarshal (data , & config ); err != nil {
544+ return nil , fmt .Errorf ("Error parsing JSON: %v" , err )
545+ }
546+
547+ // Check if the server exists in the configuration
548+ mcpServer , exists := config .MCPServers [server ]
549+ if ! exists {
550+ if server == "" {
551+ if len (config .MCPServers ) == 1 {
552+ for _ , server := range config .MCPServers {
553+ mcpServer = server
554+ }
555+ } else {
556+ return nil , fmt .Errorf ("No server name provided and multiple servers found in configuration" )
557+ }
558+ } else {
559+ return nil , fmt .Errorf ("Server %s not found in configuration" , server )
560+ }
561+ }
562+
563+ // Create a map to hold the server configuration
564+ serverConfig := make (map [string ]interface {})
565+ serverConfig ["command" ] = mcpServer .Command
566+ serverConfig ["args" ] = mcpServer .Args
567+
568+ // Look for bearer token and URL in arguments
569+ for i , arg := range mcpServer .Args {
570+ if arg == "--bearer-token" && i + 1 < len (mcpServer .Args ) {
571+ serverConfig ["bearer-token" ] = mcpServer .Args [i + 1 ]
572+ }
573+
574+ if arg == "--url" && i + 1 < len (mcpServer .Args ) {
575+ appUrl := mcpServer .Args [i + 1 ]
576+ serverConfig ["url" ] = appUrl
577+
578+ parsedURL , err := url .Parse (appUrl )
579+ if err == nil {
580+ hostnameParts := strings .Split (parsedURL .Hostname (), "." )
581+ if len (hostnameParts ) > 2 && hostnameParts [len (hostnameParts )- 1 ] == "dev" && hostnameParts [len (hostnameParts )- 2 ] == "fly" {
582+ serverConfig ["app" ] = hostnameParts [len (hostnameParts )- 3 ]
583+ } else if len (hostnameParts ) > 1 && hostnameParts [len (hostnameParts )- 1 ] == "flycast" {
584+ serverConfig ["app" ] = hostnameParts [len (hostnameParts )- 2 ]
585+ } else if len (hostnameParts ) > 1 && hostnameParts [len (hostnameParts )- 1 ] == "internal" {
586+ serverConfig ["app" ] = hostnameParts [len (hostnameParts )- 2 ]
587+ }
588+ }
589+ }
590+ }
591+
592+ return serverConfig , nil
593+ }
0 commit comments