Skip to main content
Glama

Supabase MCP Server

Apache 2.0
797
  • Apple
  • Linux
settings.py7.67 kB
import os from pathlib import Path from typing import Literal from pydantic import Field, ValidationInfo, field_validator from pydantic_settings import BaseSettings, SettingsConfigDict from supabase_mcp.logger import logger SUPPORTED_REGIONS = Literal[ "us-west-1", # West US (North California) "us-east-1", # East US (North Virginia) "us-east-2", # East US (Ohio) "ca-central-1", # Canada (Central) "eu-west-1", # West EU (Ireland) "eu-west-2", # West Europe (London) "eu-west-3", # West EU (Paris) "eu-central-1", # Central EU (Frankfurt) "eu-central-2", # Central Europe (Zurich) "eu-north-1", # North EU (Stockholm) "ap-south-1", # South Asia (Mumbai) "ap-southeast-1", # Southeast Asia (Singapore) "ap-northeast-1", # Northeast Asia (Tokyo) "ap-northeast-2", # Northeast Asia (Seoul) "ap-southeast-2", # Oceania (Sydney) "sa-east-1", # South America (São Paulo) ] def find_config_file(env_file: str = ".env") -> str | None: """Find the specified env file in order of precedence: 1. Current working directory (where command is run) 2. Global config: - Windows: %APPDATA%/supabase-mcp/{env_file} - macOS/Linux: ~/.config/supabase-mcp/{env_file} Args: env_file: The name of the environment file to look for (default: ".env") Returns: The path to the found config file, or None if not found """ # 1. Check current directory cwd_config = Path.cwd() / env_file if cwd_config.exists(): return str(cwd_config) # 2. Check global config home = Path.home() if os.name == "nt": # Windows global_config = Path(os.environ.get("APPDATA", "")) / "supabase-mcp" / ".env" else: # macOS/Linux global_config = home / ".config" / "supabase-mcp" / ".env" if global_config.exists(): logger.error( f"DEPRECATED: {global_config} is deprecated and will be removed in a future release. " "Use your IDE's native .json config file to configure access to MCP." ) return str(global_config) return None class Settings(BaseSettings): """Initializes settings for Supabase MCP server.""" supabase_project_ref: str = Field( default="127.0.0.1:54322", # Local Supabase default description="Supabase project ref - Must be 20 chars for remote projects, can be local address for development", alias="SUPABASE_PROJECT_REF", ) supabase_db_password: str | None = Field( default=None, # Will be validated based on project_ref description="Supabase database password - Required for remote projects, defaults to 'postgres' for local", alias="SUPABASE_DB_PASSWORD", ) supabase_region: str = Field( default="us-east-1", # East US (North Virginia) - Supabase's default region description="Supabase region for connection", alias="SUPABASE_REGION", ) supabase_access_token: str | None = Field( default=None, description="Optional personal access token for accessing Supabase Management API", alias="SUPABASE_ACCESS_TOKEN", ) supabase_service_role_key: str | None = Field( default=None, description="Optional service role key for accessing Python SDK", alias="SUPABASE_SERVICE_ROLE_KEY", ) supabase_api_url: str = Field( default="https://api.supabase.com", description="Supabase API URL", ) query_api_key: str = Field( default="test-key", description="TheQuery.dev API key", alias="QUERY_API_KEY", ) query_api_url: str = Field( default="https://api.thequery.dev/v1", description="TheQuery.dev API URL", alias="QUERY_API_URL", ) @field_validator("supabase_region") @classmethod def validate_region(cls, v: str, info: ValidationInfo) -> str: """Validate that the region is supported by Supabase.""" # Get the project_ref from the values values = info.data project_ref = values.get("supabase_project_ref", "") # If this is a remote project and region is the default if not project_ref.startswith("127.0.0.1") and v == "us-east-1" and "SUPABASE_REGION" not in os.environ: logger.warning( "You're connecting to a remote Supabase project but haven't specified a region. " "Using default 'us-east-1', which may cause 'Tenant or user not found' errors if incorrect. " "Please set the correct SUPABASE_REGION in your configuration." ) # Validate that the region is supported if v not in SUPPORTED_REGIONS.__args__: supported = "\n - ".join([""] + list(SUPPORTED_REGIONS.__args__)) raise ValueError(f"Region '{v}' is not supported. Supported regions are:{supported}") return v @field_validator("supabase_project_ref") @classmethod def validate_project_ref(cls, v: str) -> str: """Validate the project ref format.""" if v.startswith("127.0.0.1"): # Local development - allow default format return v # Remote project - must be 20 chars if len(v) != 20: logger.error("Invalid Supabase project ref format") raise ValueError( "Invalid Supabase project ref format. " "Remote project refs must be exactly 20 characters long. " f"Got {len(v)} characters instead." ) return v @field_validator("supabase_db_password") @classmethod def validate_db_password(cls, v: str | None, info: ValidationInfo) -> str: """Validate database password based on project type.""" project_ref = info.data.get("supabase_project_ref", "") # For local development, allow default password if project_ref.startswith("127.0.0.1"): return v or "postgres" # Default to postgres for local # For remote projects, password is required if not v: logger.error("SUPABASE_DB_PASSWORD is required when connecting to a remote instance") raise ValueError( "Database password is required for remote Supabase projects. " "Please set SUPABASE_DB_PASSWORD in your environment variables." ) return v @classmethod def with_config(cls, config_file: str | None = None) -> "Settings": """Create Settings with a specific config file. Args: config_file: Path to .env file to use, or None for no config file """ # Create a new Settings class with the specific config class SettingsWithConfig(cls): model_config = SettingsConfigDict(env_file=config_file, env_file_encoding="utf-8") instance = SettingsWithConfig() # Log configuration source and precedence - simplified to a single clear message env_vars_present = any(var in os.environ for var in ["SUPABASE_PROJECT_REF", "SUPABASE_DB_PASSWORD"]) if env_vars_present and config_file: logger.info(f"Using environment variables (highest precedence) over config file: {config_file}") elif env_vars_present: logger.info("Using environment variables for configuration") elif config_file: logger.info(f"Using settings from config file: {config_file}") else: logger.info("Using default settings (local development)") return instance # Module-level singleton - maintains existing interface settings = Settings.with_config(find_config_file())

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/alexander-zuev/supabase-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server