Skip to content

Commit c78d455

Browse files
authored
Mcp destroy (#4380)
* app destroy * forgot a file * make fly mcp proxy client mcp aware * go mod tidy * latest inspector * split out inspect command * fly mcp launch += secrets * fly mcp launch += secrets, files, vm-sizes, ...
1 parent e0b56bf commit c78d455

File tree

7 files changed

+578
-109
lines changed

7 files changed

+578
-109
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ require (
127127
github.com/alexflint/go-arg v1.5.1 // indirect
128128
github.com/alexflint/go-scalar v1.2.0 // indirect
129129
github.com/andybalholm/brotli v1.1.0 // indirect
130-
github.com/apex/log v1.9.0 // indirect
130+
github.com/apex/log v1.9.0
131131
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
132132
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect
133133
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect

internal/command/mcp/config.go

Lines changed: 140 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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
388415
func 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

Comments
 (0)