1
1
package mcp
2
2
3
3
import (
4
+ "bytes"
4
5
"encoding/json"
5
6
"errors"
6
7
"fmt"
@@ -41,13 +42,13 @@ type VSCodeConfig struct {
41
42
42
43
// VSCodeMCPServerConfig represents the configuration for a VSCode MCP server
43
44
type VSCodeMCPServerConfig struct {
44
- Type string `json:"type"` // Required: "stdio" or "sse"
45
- Command string `json:"command"` // Required for stdio
46
- Args []string `json:"args"` // Required for stdio
47
- URL string `json:"url,omitempty"` // Required for sse
48
- Env map [string ]string `json:"env,omitempty"`
45
+ Args []string `json:"args,omitempty"` // Required for stdio
46
+ Command string `json:"command,omitempty"` // Required for stdio
47
+ Env map [string ]any `json:"env,omitempty"`
49
48
EnvFile string `json:"envFile,omitempty"`
50
49
Headers map [string ]string `json:"headers,omitempty"` // For sse
50
+ Type string `json:"type,omitempty"` // Required: "stdio" or "sse"
51
+ URL string `json:"url,omitempty"` // Required for sse
51
52
}
52
53
53
54
// MCPClient represents the supported MCP clients as an enum
@@ -236,18 +237,32 @@ func getVSCodeDefangMCPConfig() (*VSCodeMCPServerConfig, error) {
236
237
}
237
238
238
239
// getVSCodeServerConfig returns a map with the VSCode-specific MCP server config
239
- func getVSCodeServerConfig () (map [ string ] any , error ) {
240
+ func getVSCodeServerConfig () (* VSCodeMCPServerConfig , error ) {
240
241
config , err := getVSCodeDefangMCPConfig ()
241
242
if err != nil {
242
243
return nil , err
243
244
}
244
- return map [ string ] any {
245
- "type" : config .Type ,
246
- "command" : config .Command ,
247
- "args" : config .Args ,
245
+ return & VSCodeMCPServerConfig {
246
+ Args : config .Args ,
247
+ Command : config .Command ,
248
+ Type : config .Type ,
248
249
}, nil
249
250
}
250
251
252
+ func parseExistingConfig (data []byte , existingData * map [string ]any ) error {
253
+ // Check if file is empty or only contains whitespace
254
+ if len (bytes .TrimSpace (data )) == 0 {
255
+ // File is empty, treat as new config
256
+ * existingData = make (map [string ]any )
257
+ } else {
258
+ // Parse the JSON into a generic map to preserve all settings
259
+ if err := json .Unmarshal (data , & existingData ); err != nil {
260
+ return fmt .Errorf ("failed to unmarshal existing config: %w" , err )
261
+ }
262
+ }
263
+ return nil
264
+ }
265
+
251
266
// handleVSCodeConfig handles the special case for VSCode mcp.json
252
267
func handleVSCodeConfig (configPath string ) error {
253
268
// Create or update the config file
@@ -259,9 +274,8 @@ func handleVSCodeConfig(configPath string) error {
259
274
260
275
// Check if the file exists
261
276
if data , err := os .ReadFile (configPath ); err == nil {
262
- // File exists, parse it
263
- if err := json .Unmarshal (data , & existingData ); err != nil {
264
- return fmt .Errorf ("failed to unmarshal existing vscode config %w" , err )
277
+ if err := parseExistingConfig (data , & existingData ); err != nil {
278
+ return err
265
279
}
266
280
267
281
// Check if "servers" section exists
@@ -310,9 +324,8 @@ func handleStandardConfig(configPath string) error {
310
324
311
325
// Check if the file exists
312
326
if data , err := os .ReadFile (configPath ); err == nil {
313
- // Parse the JSON into a generic map to preserve all settings
314
- if err := json .Unmarshal (data , & existingData ); err != nil {
315
- return fmt .Errorf ("failed to unmarshal existing config: %w" , err )
327
+ if err := parseExistingConfig (data , & existingData ); err != nil {
328
+ return err
316
329
}
317
330
318
331
// Try to extract MCPServers from existing data
@@ -399,7 +412,7 @@ func SetupClient(clientStr string) error {
399
412
}
400
413
}
401
414
402
- term .Infof ("Restart %s for the changes to take effect.\n " , client )
415
+ term .Infof ("Ensure %s is upgraded to the latest version and restarted for mcp settings to take effect.\n " , client )
403
416
404
417
return nil
405
418
}
0 commit comments