@@ -62,9 +62,7 @@ func (b *baseClient) InstallInstructions() string {
6262var clientRegistry = []Client {
6363 newClaudeCodeClient (),
6464 newCursorClient (),
65- // Add new clients here in the future:
66- // newVSCodeClient(),
67- // newClaudeDesktopClient(),
65+ newVSCodeClient (),
6866}
6967
7068func Run (ctx context.Context , fsys afero.Fs , clientFlag string ) error {
@@ -301,6 +299,114 @@ func (c *cursorClient) Configure(ctx context.Context, fsys afero.Fs) error {
301299 return nil
302300}
303301
302+ // vscodeClient implements the Client interface for VS Code
303+ type vscodeClient struct {
304+ baseClient
305+ }
306+
307+ func newVSCodeClient () * vscodeClient {
308+ return & vscodeClient {
309+ baseClient : baseClient {
310+ name : "vscode" ,
311+ displayName : "VS Code" ,
312+ installInstructions : "Download from https://code.visualstudio.com" ,
313+ checkInstalled : func () bool {
314+ return commandExists ("code" )
315+ },
316+ },
317+ }
318+ }
319+
320+ func (c * vscodeClient ) Configure (ctx context.Context , fsys afero.Fs ) error {
321+ fmt .Println ("Configuring VS Code..." )
322+ fmt .Println ()
323+
324+ // Prompt for config scope
325+ fmt .Println ("Where would you like to add the configuration?" )
326+ fmt .Println (" 1. Project-local (in .vscode/mcp.json)" )
327+ fmt .Println (" 2. Global (in your home directory)" )
328+ fmt .Print ("Choice [1]: " )
329+
330+ var choice string
331+ if _ , err := fmt .Scanln (& choice ); err != nil && err .Error () != "unexpected newline" {
332+ return fmt .Errorf ("failed to read choice: %w" , err )
333+ }
334+ if choice == "" {
335+ choice = "1"
336+ }
337+
338+ var configPath string
339+ if choice == "2" {
340+ // Global config
341+ homeDir , _ := os .UserHomeDir ()
342+ configPath = filepath .Join (homeDir , ".vscode" , "mcp.json" )
343+ } else {
344+ // Project-local config
345+ cwd , _ := os .Getwd ()
346+ configPath = filepath .Join (cwd , ".vscode" , "mcp.json" )
347+ }
348+
349+ // Prepare the Supabase MCP server config
350+ supabaseConfig := map [string ]interface {}{
351+ "type" : "http" ,
352+ "url" : "https://mcp.supabase.com/mcp" ,
353+ }
354+
355+ // Read existing config if it exists
356+ var config map [string ]interface {}
357+ existingData , err := afero .ReadFile (fsys , configPath )
358+ if err == nil && len (existingData ) > 0 {
359+ if err := json .Unmarshal (existingData , & config ); err != nil {
360+ // If existing file is invalid JSON, start fresh
361+ config = make (map [string ]interface {})
362+ }
363+ } else {
364+ config = make (map [string ]interface {})
365+ }
366+
367+ // Ensure mcpServers exists
368+ mcpServers , ok := config ["mcpServers" ].(map [string ]interface {})
369+ if ! ok {
370+ mcpServers = make (map [string ]interface {})
371+ config ["mcpServers" ] = mcpServers
372+ }
373+
374+ // Add or update Supabase server
375+ mcpServers ["supabase" ] = supabaseConfig
376+
377+ // Ensure directory exists
378+ configDir := filepath .Dir (configPath )
379+ if err := fsys .MkdirAll (configDir , 0755 ); err != nil {
380+ return fmt .Errorf ("failed to create config directory: %w" , err )
381+ }
382+
383+ // Write config
384+ configJSON , err := json .MarshalIndent (config , "" , " " )
385+ if err != nil {
386+ return fmt .Errorf ("failed to marshal config: %w" , err )
387+ }
388+
389+ if err := afero .WriteFile (fsys , configPath , configJSON , 0644 ); err != nil {
390+ return fmt .Errorf ("failed to write config file: %w" , err )
391+ }
392+
393+ fmt .Println ()
394+ fmt .Printf ("✓ Successfully configured VS Code at: %s\n " , configPath )
395+ fmt .Println ()
396+ fmt .Println ("Configuration added:" )
397+ fmt .Println (`{
398+ "mcpServers": {
399+ "supabase": {
400+ "type": "http",
401+ "url": "https://mcp.supabase.com/mcp"
402+ }
403+ }
404+ }` )
405+ fmt .Println ()
406+ fmt .Println ("The Supabase MCP server is now available in VS Code!" )
407+ return nil
408+ }
409+
304410// appExists checks if a macOS application is installed
305411func appExists (appName string ) bool {
306412 if runtime .GOOS == "darwin" {
@@ -316,44 +422,3 @@ func appExists(appName string) bool {
316422 }
317423 return false
318424}
319-
320- // Example: Adding a new client
321- //
322- // 1. Create a struct that embeds baseClient:
323- //
324- // type myNewClient struct {
325- // baseClient
326- // }
327- //
328- // 2. Create a constructor function:
329- //
330- // func newMyNewClient() *myNewClient {
331- // return &myNewClient{
332- // baseClient: baseClient{
333- // name: "my-client",
334- // displayName: "My Client",
335- // installInstructions: "Installation command or URL",
336- // checkInstalled: func() bool {
337- // return commandExists("my-cli") || appExists("MyApp")
338- // },
339- // },
340- // }
341- // }
342- //
343- // 3. Implement the Configure method:
344- //
345- // func (c *myNewClient) Configure(ctx context.Context, fsys afero.Fs) error {
346- // // Your configuration logic here
347- // // See claudeCodeClient or cursorClient for examples
348- // return nil
349- // }
350- //
351- // 4. Add to clientRegistry:
352- //
353- // var clientRegistry = []Client{
354- // newClaudeCodeClient(),
355- // newCursorClient(),
356- // newMyNewClient(), // Add here
357- // }
358-
359-
0 commit comments