-
Notifications
You must be signed in to change notification settings - Fork 309
feat(mcp): add supabase mcp init command to configure MCP clients
#4383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
Rodriguespn
wants to merge
17
commits into
develop
Choose a base branch
from
feat/mcp-init-command
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+819
−1
Draft
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
efefe8f
feat: add supabase mcp init command skeleton
Rodriguespn 6873105
fix: move mcp command to Quick Start group
Rodriguespn 7d1d1cf
feat: add --client flag with MCP client detection and config templates
Rodriguespn f07209b
feat: add interactive auto-configuration for Cursor, VS Code, and Cla…
Rodriguespn 63278ae
feat(mcp): add client installation validation and remote server support
Rodriguespn f1c9eac
feat(mcp): add Codex AI Editor to supported clients
Rodriguespn 33e2250
fix: resolve golangci-lint issues
Rodriguespn 208bd8a
feat: add scalable client registry system for MCP init
Rodriguespn e11bb78
feat: add Cursor support to MCP init
Rodriguespn 6ba1fd2
refactor: use baseClient composition for DRY client implementation
Rodriguespn 71cb136
feat: add VS Code support to MCP init
Rodriguespn 8301537
refactor: split client implementations into separate files
Rodriguespn 6677751
feat(init): add --mcp-client flag to configure MCP during project init
Rodriguespn 1a77952
fix: apply gofmt formatting to cmd/init.go and internal/mcp/init/init.go
Rodriguespn fd00eef
feat: add interactive MCP configuration to supabase init
Rodriguespn 4bc34c6
minor fixes
Rodriguespn 7eafb42
fix: linting and formatting for MCP init command
Rodriguespn File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| var ( | ||
| mcpCmd = &cobra.Command{ | ||
| GroupID: groupQuickStart, | ||
| Use: "mcp", | ||
| Short: "Manage Model Context Protocol (MCP) configuration", | ||
| Long: "Commands for setting up and managing MCP server configurations for AI assistants like Cursor, VS Code Copilot, and Claude Desktop.", | ||
| } | ||
| ) | ||
|
|
||
| func init() { | ||
| rootCmd.AddCommand(mcpCmd) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "github.com/spf13/afero" | ||
| "github.com/spf13/cobra" | ||
| mcpinit "github.com/supabase/cli/internal/mcp/init" | ||
| ) | ||
|
|
||
| var ( | ||
| mcpInitCmd = &cobra.Command{ | ||
| Use: "init", | ||
| Short: "Configure Supabase MCP server for AI assistant clients", | ||
| Long: `Configure the Supabase MCP server for your AI assistant clients. | ||
|
|
||
| This command will detect installed MCP clients and guide you through the setup process. | ||
| Currently supports: Claude Code, Cursor, VS Code (with more clients coming soon). | ||
|
|
||
| The Supabase MCP server allows AI assistants to interact with your Supabase projects, | ||
| providing tools for database operations, edge functions, storage, and more. | ||
|
|
||
| Examples: | ||
| # Auto-detect and configure installed clients | ||
| supabase mcp init | ||
|
|
||
| # Configure a specific client | ||
| supabase mcp init --client claude-code | ||
| supabase mcp init --client cursor | ||
| supabase mcp init --client vscode`, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| client, _ := cmd.Flags().GetString("client") | ||
| return mcpinit.Run(cmd.Context(), afero.NewOsFs(), client) | ||
| }, | ||
| } | ||
| ) | ||
|
|
||
| func init() { | ||
| mcpInitCmd.Flags().StringP("client", "c", "", "Target specific client (e.g., claude-code)") | ||
| mcpCmd.AddCommand(mcpInitCmd) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,219 @@ | ||
| # MCP Init - Client Configuration System | ||
|
|
||
| This package provides a scalable system for configuring the Supabase MCP server with various AI assistant clients. | ||
|
|
||
| ## Architecture | ||
|
|
||
| The system uses a client registry pattern where each client implements the `Client` interface: | ||
|
|
||
| ```go | ||
| type Client interface { | ||
| Name() string // CLI identifier (e.g., "claude-code") | ||
| DisplayName() string // Human-readable name (e.g., "Claude Code") | ||
| IsInstalled() bool // Check if client is installed | ||
| InstallInstructions() string // Installation instructions | ||
| Configure(ctx context.Context, fsys afero.Fs) error // Perform configuration | ||
| } | ||
| ``` | ||
|
|
||
| ## Adding a New Client | ||
|
|
||
| ### Step 1: Implement the Client Interface | ||
|
|
||
| Create a new struct that implements the `Client` interface. Here's a complete example: | ||
|
|
||
| ```go | ||
| // cursorClient implements the Client interface for Cursor | ||
| type cursorClient struct{} | ||
|
|
||
| func (c *cursorClient) Name() string { | ||
| return "cursor" | ||
| } | ||
|
|
||
| func (c *cursorClient) DisplayName() string { | ||
| return "Cursor" | ||
| } | ||
|
|
||
| func (c *cursorClient) IsInstalled() bool { | ||
| // Check if cursor command exists or app is installed | ||
| return commandExists("cursor") || appExists("Cursor") | ||
| } | ||
|
|
||
| func (c *cursorClient) InstallInstructions() string { | ||
| return "Download from https://cursor.sh" | ||
| } | ||
|
|
||
| func (c *cursorClient) Configure(ctx context.Context, fsys afero.Fs) error { | ||
| fmt.Println("Configuring Cursor...") | ||
| fmt.Println() | ||
|
|
||
| // Option 1: Run a CLI command | ||
| cmd := exec.CommandContext(ctx, "cursor", "config", "add", "mcp", "supabase") | ||
| cmd.Stdout = os.Stdout | ||
| cmd.Stderr = os.Stderr | ||
| if err := cmd.Run(); err != nil { | ||
| return fmt.Errorf("failed to configure Cursor: %w", err) | ||
| } | ||
|
|
||
| // Option 2: Write a config file | ||
| // configPath := filepath.Join(os.Getenv("HOME"), ".cursor", "mcp.json") | ||
| // ... write JSON config ... | ||
|
|
||
| // Option 3: Display manual instructions | ||
| // fmt.Println("Manual setup instructions:") | ||
| // fmt.Println("1. Open Cursor settings...") | ||
|
|
||
| fmt.Println("✓ Successfully configured Cursor!") | ||
| return nil | ||
| } | ||
| ``` | ||
|
|
||
| ### Step 2: Register the Client | ||
|
|
||
| Add your new client to the `clientRegistry` slice: | ||
|
|
||
| ```go | ||
| var clientRegistry = []Client{ | ||
| &claudeCodeClient{}, | ||
| &cursorClient{}, // Add your new client here | ||
| &vscodeClient{}, // Add more as needed | ||
| } | ||
| ``` | ||
|
|
||
| ### Step 3: Test | ||
|
|
||
| Test the new client: | ||
|
|
||
| ```bash | ||
| # Auto-detect and configure | ||
| supabase mcp init | ||
|
|
||
| # Or target your specific client | ||
| supabase mcp init --client cursor | ||
| ``` | ||
|
|
||
| ## Configuration Approaches | ||
|
|
||
| Depending on the client, you can use different configuration approaches: | ||
|
|
||
| ### 1. CLI Command Execution | ||
|
|
||
| Best for clients with a CLI that supports adding MCP servers: | ||
|
|
||
| ```go | ||
| cmd := exec.CommandContext(ctx, "client-cli", "mcp", "add", "supabase", "https://mcp.supabase.com/mcp") | ||
| cmd.Stdout = os.Stdout | ||
| cmd.Stderr = os.Stderr | ||
| return cmd.Run() | ||
| ``` | ||
|
|
||
| ### 2. JSON Configuration File | ||
|
|
||
| Best for clients that read MCP config from a JSON file: | ||
|
|
||
| ```go | ||
| import ( | ||
| "encoding/json" | ||
| "path/filepath" | ||
| ) | ||
|
|
||
| func (c *myClient) Configure(ctx context.Context, fsys afero.Fs) error { | ||
| homeDir, _ := os.UserHomeDir() | ||
| configPath := filepath.Join(homeDir, ".client", "mcp.json") | ||
|
|
||
| config := map[string]interface{}{ | ||
| "mcpServers": map[string]interface{}{ | ||
| "supabase": map[string]interface{}{ | ||
| "type": "remote", | ||
| "url": "https://mcp.supabase.com/mcp", | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| // Create directory if needed | ||
| if err := fsys.MkdirAll(filepath.Dir(configPath), 0755); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Read existing config to merge | ||
| existingData, _ := afero.ReadFile(fsys, configPath) | ||
| var existing map[string]interface{} | ||
| if len(existingData) > 0 { | ||
| json.Unmarshal(existingData, &existing) | ||
| // Merge configs... | ||
| } | ||
|
|
||
| // Write config | ||
| configJSON, _ := json.MarshalIndent(config, "", " ") | ||
| return afero.WriteFile(fsys, configPath, configJSON, 0644) | ||
| } | ||
| ``` | ||
|
|
||
| ### 3. Manual Instructions | ||
|
|
||
| Best for clients that require manual setup or don't have automation support: | ||
|
|
||
| ```go | ||
| func (c *myClient) Configure(ctx context.Context, fsys afero.Fs) error { | ||
| fmt.Println("Manual Configuration Required") | ||
| fmt.Println("==============================") | ||
| fmt.Println() | ||
| fmt.Println("1. Open Client Settings") | ||
| fmt.Println("2. Navigate to MCP Servers") | ||
| fmt.Println("3. Add the following configuration:") | ||
| fmt.Println() | ||
| fmt.Println(`{ | ||
| "supabase": { | ||
| "type": "remote", | ||
| "url": "https://mcp.supabase.com/mcp" | ||
| } | ||
| }`) | ||
| fmt.Println() | ||
| fmt.Println("4. Save and restart the client") | ||
| return nil | ||
| } | ||
| ``` | ||
|
|
||
| ## Helper Functions | ||
|
|
||
| ### `commandExists(command string) bool` | ||
|
|
||
| Checks if a command-line tool is available: | ||
|
|
||
| ```go | ||
| if commandExists("cursor") { | ||
| // cursor CLI is available | ||
| } | ||
| ``` | ||
|
|
||
| ### `appExists(appName string) bool` (to be added if needed) | ||
|
|
||
| Checks if a macOS application is installed: | ||
|
|
||
| ```go | ||
| func appExists(appName string) bool { | ||
| if runtime.GOOS == "darwin" { | ||
| locations := []string{ | ||
| fmt.Sprintf("/Applications/%s.app", appName), | ||
| fmt.Sprintf("%s/Applications/%s.app", os.Getenv("HOME"), appName), | ||
| } | ||
| for _, location := range locations { | ||
| if _, err := os.Stat(location); err == nil { | ||
| return true | ||
| } | ||
| } | ||
| } | ||
| return false | ||
| } | ||
| ``` | ||
|
|
||
| ## User Experience Flow | ||
|
|
||
| 1. **No clients installed**: Shows list of available clients with install instructions | ||
| 2. **One client installed**: Auto-configures that client | ||
| 3. **Multiple clients installed**: Shows options and prompts user to choose | ||
| 4. **Specific client requested**: Configures that client if installed, shows install instructions otherwise | ||
|
|
||
| ## Examples | ||
|
|
||
| See `claudeCodeClient` in `init.go` for a complete working example. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| package mcpinit | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "os" | ||
| "os/exec" | ||
|
|
||
| "github.com/spf13/afero" | ||
| "github.com/supabase/cli/internal/utils" | ||
| ) | ||
|
|
||
| // claudeCodeClient implements the Client interface for Claude Code | ||
| type claudeCodeClient struct { | ||
| baseClient | ||
| } | ||
|
|
||
| func newClaudeCodeClient() *claudeCodeClient { | ||
| return &claudeCodeClient{ | ||
| baseClient: baseClient{ | ||
| name: "claude-code", | ||
| displayName: "Claude Code", | ||
| installInstructions: "npm install -g @anthropic-ai/claude-cli", | ||
| checkInstalled: func() bool { | ||
| return commandExists("claude") | ||
| }, | ||
| }, | ||
| } | ||
| } | ||
|
|
||
| func (c *claudeCodeClient) Configure(ctx context.Context, fsys afero.Fs) error { | ||
| fmt.Println("Configuring Claude Code...") | ||
| fmt.Println() | ||
|
|
||
| // Use utils.PromptChoice for dropdown | ||
| choice, err := utils.PromptChoice(ctx, "Where would you like to add the Claude Code MCP server?", []utils.PromptItem{ | ||
| {Summary: "local", Details: "Local (only for you in this project)"}, | ||
| {Summary: "project", Details: "Project (shared via .mcp.json in project root)"}, | ||
| {Summary: "user", Details: "User (available across all projects for your user)"}, | ||
| }) | ||
| if err != nil { | ||
| fmt.Printf("⚠️ Warning: failed to select scope for Claude Code MCP server: %v\n", err) | ||
| fmt.Println("Defaulting to local scope.") | ||
| choice = utils.PromptItem{Summary: "local"} | ||
| } | ||
|
|
||
| cmdArgs := []string{"mcp", "add", "--transport", "http", "supabase", "http://localhost:54321/mcp"} | ||
| if choice.Summary != "local" { | ||
| cmdArgs = append(cmdArgs, "--scope", choice.Summary) | ||
| } | ||
| cmd := exec.CommandContext(ctx, "claude", cmdArgs...) | ||
|
|
||
| cmd.Stdout = os.Stdout | ||
| cmd.Stderr = os.Stderr | ||
|
|
||
| err = cmd.Run() | ||
| if err != nil { | ||
| fmt.Println() | ||
| fmt.Printf("⚠️ Warning: failed to configure Claude Code MCP server: %v\n", err) | ||
| fmt.Println("You may need to configure it manually.") | ||
| } else { | ||
| fmt.Println() | ||
| fmt.Println("✓ Successfully added Supabase MCP server to Claude Code!") | ||
| fmt.Println() | ||
| // Command string display removed (cmdStr no longer exists) | ||
| fmt.Println() | ||
| fmt.Println("The server is now available in your Claude Code environment.") | ||
| } | ||
| return nil | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we plan to add other sub commands under
supabase mcp? If not, I'd probably add new flags tosupabase initinstead.We currently prompt users to create deno config when running
supabase initwhich is logically similar to vscode config for mcp.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have plans to extend the mcp command to a dev env for building mcp servers
https://www.notion.so/supabase/Supabase-CLI-Integration-635fe64201f944c1a97856cf83c565c9?source=copy_link
The Notion page is still under construction so please disregard the exact commands stated but the general idea is there.
But since these plans are for developing mcp servers using Supabase and not to configure the SUpabase MCP server using our CLI, I agree that a flag to
supabase initwould suit this use case better.Something like
supabase init --mcp-client=claude-code?