Skip to main content
Glama

Supabase MCP Server

Apache 2.0
797
  • Apple
  • Linux
conftest.py11.7 kB
import os from collections.abc import AsyncGenerator, Generator from pathlib import Path from typing import Any from unittest.mock import AsyncMock, MagicMock import pytest import pytest_asyncio from dotenv import load_dotenv from mcp.server.fastmcp import FastMCP from supabase_mcp.clients.management_client import ManagementAPIClient from supabase_mcp.clients.sdk_client import SupabaseSDKClient from supabase_mcp.core.container import ServicesContainer from supabase_mcp.logger import logger from supabase_mcp.services.api.api_manager import SupabaseApiManager from supabase_mcp.services.api.spec_manager import ApiSpecManager from supabase_mcp.services.database.migration_manager import MigrationManager from supabase_mcp.services.database.postgres_client import PostgresClient from supabase_mcp.services.database.query_manager import QueryManager from supabase_mcp.services.database.sql.loader import SQLLoader from supabase_mcp.services.database.sql.validator import SQLValidator from supabase_mcp.services.safety.safety_manager import SafetyManager from supabase_mcp.settings import Settings, find_config_file from supabase_mcp.tools import ToolManager from supabase_mcp.tools.registry import ToolRegistry # ====================== # Environment Fixtures # ====================== @pytest.fixture def clean_environment() -> Generator[None, None, None]: """Fixture to provide a clean environment without any Supabase-related env vars.""" # Save original environment original_env = dict(os.environ) # Remove all Supabase-related environment variables for key in list(os.environ.keys()): if key.startswith("SUPABASE_"): del os.environ[key] yield # Restore original environment os.environ.clear() os.environ.update(original_env) def load_test_env() -> dict[str, str | None]: """Load test environment variables from .env.test file""" env_test_path = Path(__file__).parent.parent / ".env.test" if not env_test_path.exists(): raise FileNotFoundError(f"Test environment file not found at {env_test_path}") load_dotenv(env_test_path) return { "SUPABASE_PROJECT_REF": os.getenv("SUPABASE_PROJECT_REF"), "SUPABASE_DB_PASSWORD": os.getenv("SUPABASE_DB_PASSWORD"), "SUPABASE_SERVICE_ROLE_KEY": os.getenv("SUPABASE_SERVICE_ROLE_KEY"), "SUPABASE_ACCESS_TOKEN": os.getenv("SUPABASE_ACCESS_TOKEN"), } @pytest.fixture(scope="session") def settings_integration() -> Settings: """Fixture providing settings for integration tests. This fixture loads settings from environment variables or .env.test file. Uses session scope since settings don't change during tests. """ return Settings.with_config(find_config_file(".env.test")) @pytest.fixture def mock_validator() -> SQLValidator: """Fixture providing a mock SQLValidator for integration tests.""" return SQLValidator() @pytest.fixture def settings_integration_custom_env() -> Generator[Settings, None, None]: """Fixture that provides Settings instance for integration tests using .env.test""" # Load custom environment variables test_env = load_test_env() original_env = dict(os.environ) # Set up test environment for key, value in test_env.items(): if value is not None: os.environ[key] = value # Create fresh settings instance settings = Settings() logger.info(f"Custom connection settings initialized: {settings}") yield settings # Restore original environment os.environ.clear() os.environ.update(original_env) # ====================== # Service Fixtures # ====================== @pytest_asyncio.fixture(scope="module") async def postgres_client_integration(settings_integration: Settings) -> AsyncGenerator[PostgresClient, None]: # Reset before creation await PostgresClient.reset() # Create a client client = PostgresClient(settings=settings_integration) try: yield client finally: await client.close() @pytest_asyncio.fixture(scope="module") async def spec_manager_integration() -> AsyncGenerator[ApiSpecManager, None]: """Fixture providing an ApiSpecManager instance for tests.""" manager = ApiSpecManager() yield manager @pytest_asyncio.fixture(scope="module") async def api_client_integration(settings_integration: Settings) -> AsyncGenerator[ManagementAPIClient, None]: # We don't need to reset since it's not a singleton client = ManagementAPIClient(settings=settings_integration) try: yield client finally: await client.close() @pytest_asyncio.fixture(scope="module") async def sdk_client_integration(settings_integration: Settings) -> AsyncGenerator[SupabaseSDKClient, None]: """Fixture providing a SupabaseSDKClient instance for tests. Uses function scope to ensure a fresh client for each test. """ client = SupabaseSDKClient.get_instance(settings=settings_integration) try: yield client finally: # Reset the singleton to ensure a fresh client for the next test SupabaseSDKClient.reset() @pytest.fixture(scope="module") def safety_manager_integration() -> SafetyManager: """Fixture providing a safety manager for integration tests.""" # Reset the safety manager singleton SafetyManager.reset() # Create a new safety manager safety_manager = SafetyManager.get_instance() safety_manager.register_safety_configs() return safety_manager @pytest.fixture(scope="module") def tool_manager_integration() -> ToolManager: """Fixture providing a tool manager for integration tests.""" # Reset the tool manager singleton ToolManager.reset() return ToolManager.get_instance() @pytest.fixture(scope="module") def query_manager_integration( postgres_client_integration: PostgresClient, safety_manager_integration: SafetyManager, ) -> QueryManager: """Fixture providing a query manager for integration tests.""" query_manager = QueryManager( postgres_client=postgres_client_integration, safety_manager=safety_manager_integration, ) return query_manager @pytest.fixture(scope="module") def mock_api_manager() -> SupabaseApiManager: """Fixture providing a properly mocked API manager for unit tests.""" # Create mock dependencies mock_client = MagicMock() mock_safety_manager = MagicMock() mock_spec_manager = MagicMock() # Create the API manager with proper constructor arguments api_manager = SupabaseApiManager(api_client=mock_client, safety_manager=mock_safety_manager) # Add the spec_manager attribute api_manager.spec_manager = mock_spec_manager return api_manager @pytest.fixture def mock_query_manager() -> QueryManager: """Fixture providing a properly mocked Query manager for unit tests.""" # Create mock dependencies mock_safety_manager = MagicMock() mock_postgres_client = MagicMock() mock_validator = MagicMock() # Create the Query manager with proper constructor arguments query_manager = QueryManager( postgres_client=mock_postgres_client, safety_manager=mock_safety_manager, ) # Replace the validator with a mock query_manager.validator = mock_validator # Store the postgres client as an attribute for tests to access query_manager.db_client = mock_postgres_client # Make execute_query_async an AsyncMock query_manager.db_client.execute_query_async = AsyncMock() return query_manager @pytest_asyncio.fixture(scope="module") async def api_manager_integration( api_client_integration: ManagementAPIClient, safety_manager_integration: SafetyManager, ) -> AsyncGenerator[SupabaseApiManager, None]: """Fixture providing an API manager for integration tests.""" # Create a new API manager api_manager = SupabaseApiManager.get_instance( api_client=api_client_integration, safety_manager=safety_manager_integration, ) try: yield api_manager finally: # Reset the API manager singleton SupabaseApiManager.reset() # ====================== # Mock MCP Server # ====================== @pytest.fixture def mock_mcp_server() -> Any: """Fixture providing a mock MCP server for integration tests.""" # Create a simple mock MCP server that mimics the FastMCP interface class MockMCP: def __init__(self) -> None: self.tools: dict[str, Any] = {} self.name = "mock_mcp" def register_tool(self, name: str, func: Any, **kwargs: Any) -> None: """Register a tool with the MCP server.""" self.tools[name] = func def run(self) -> None: """Mock run method.""" pass return MockMCP() @pytest.fixture(scope="module") def mock_mcp_server_integration() -> Any: """Fixture providing a mock MCP server for integration tests.""" return FastMCP(name="supabase") # ====================== # Container Fixture # ====================== @pytest.fixture(scope="module") def container_integration( postgres_client_integration: PostgresClient, api_client_integration: ManagementAPIClient, sdk_client_integration: SupabaseSDKClient, api_manager_integration: SupabaseApiManager, safety_manager_integration: SafetyManager, query_manager_integration: QueryManager, tool_manager_integration: ToolManager, mock_mcp_server_integration: FastMCP, ) -> ServicesContainer: """Fixture providing a basic Container for integration tests. This container includes all services needed for integration testing, but is not initialized. """ # Create a new container with all the services container = ServicesContainer( mcp_server=mock_mcp_server_integration, postgres_client=postgres_client_integration, api_client=api_client_integration, sdk_client=sdk_client_integration, api_manager=api_manager_integration, safety_manager=safety_manager_integration, query_manager=query_manager_integration, tool_manager=tool_manager_integration, ) logger.info("✓ Integration container created successfully.") return container @pytest.fixture(scope="module") def initialized_container_integration( container_integration: ServicesContainer, settings_integration: Settings, ) -> ServicesContainer: """Fixture providing a fully initialized Container for integration tests. This container is initialized with all services and ready to use. """ container_integration.initialize_services(settings_integration) logger.info("✓ Integration container initialized successfully.") return container_integration @pytest.fixture(scope="module") def tools_registry_integration( initialized_container_integration: ServicesContainer, ) -> ServicesContainer: """Fixture providing a Container with tools registered for integration tests. This container has all tools registered with the MCP server. """ container = initialized_container_integration mcp_server = container.mcp_server registry = ToolRegistry(mcp_server, container) registry.register_tools() logger.info("✓ Tools registered with MCP server successfully.") return container @pytest.fixture def sql_loader() -> SQLLoader: """Fixture providing a SQLLoader instance for tests.""" return SQLLoader() @pytest.fixture def migration_manager(sql_loader: SQLLoader) -> MigrationManager: """Fixture providing a MigrationManager instance for tests.""" return MigrationManager(loader=sql_loader)

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