Skip to main content
Glama
dj-pearson

Supabase Coolify MCP Server

by dj-pearson
index.ts23.5 kB
#!/usr/bin/env node /** * Supabase Coolify MCP Server * Manages self-hosted Supabase on Coolify with full deployment support */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import dotenv from 'dotenv'; import { CoolifyClient } from './coolify-client.js'; import { SupabaseManager } from './supabase-client.js'; import { SupabaseCLI } from './supabase-cli.js'; import { registerSupabaseTools } from './tools/supabase-tools.js'; import { registerSupabaseCLITools } from './tools/supabase-cli-tools.js'; import { registerCoolifyTools } from './tools/coolify-tools.js'; import { registerDeploymentTools } from './tools/deployment-tools.js'; import { registerResources } from './resources.js'; import { runStartupHealthCheck, createVerificationReport } from './health-check.js'; // Load environment variables with priority: // 1. MCP config env vars (HIGHEST - if provided by MCP client) - Already in process.env // 2. System environment variables (MEDIUM) - Already in process.env // 3. .env file in CURRENT WORKING DIRECTORY (LOWEST - fallback for development) // // IMPORTANT: dotenv.config() only sets variables that DON'T already exist in process.env, // so MCP config and system env vars will NEVER be overridden by a .env file. // // Note: If running the MCP server from within a project directory that has its own .env, // those values will only be used for variables NOT already set by MCP config or system env. // This is intentional and allows project-specific optional variables (like SUPABASE_PROJECT_REF). dotenv.config(); // Validate required environment variables const requiredEnvVars = [ 'COOLIFY_API_URL', 'COOLIFY_API_TOKEN', 'SUPABASE_URL', 'SUPABASE_SERVICE_ROLE_KEY', ]; const missingEnvVars = requiredEnvVars.filter((varName) => !process.env[varName]); if (missingEnvVars.length > 0) { console.error(`Error: Missing required environment variables: ${missingEnvVars.join(', ')}`); console.error(''); console.error('Environment variables can be provided in 3 ways (in priority order):'); console.error(' 1. MCP config env section (recommended for MCP usage)'); console.error(' 2. System environment variables'); console.error(' 3. .env file (for development)'); console.error(''); console.error('See MCP_CONFIGURATION.md for setup instructions.'); process.exit(1); } // Initialize clients const coolifyClient = new CoolifyClient({ apiUrl: process.env.COOLIFY_API_URL!, apiToken: process.env.COOLIFY_API_TOKEN!, teamId: process.env.COOLIFY_TEAM_ID, }); const supabaseManager = new SupabaseManager( { url: process.env.SUPABASE_URL!, anonKey: process.env.SUPABASE_ANON_KEY || '', serviceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY!, projectId: process.env.SUPABASE_PROJECT_ID, projectRef: process.env.SUPABASE_PROJECT_REF, functionsUrl: process.env.SUPABASE_FUNCTIONS_URL, }, process.env.SUPABASE_DB_HOST ? { host: process.env.SUPABASE_DB_HOST, port: parseInt(process.env.SUPABASE_DB_PORT || '5432'), database: process.env.SUPABASE_DB_NAME || 'postgres', user: process.env.SUPABASE_DB_USER || 'postgres', password: process.env.SUPABASE_DB_PASSWORD!, } : undefined ); const supabaseCLI = new SupabaseCLI({ projectRef: process.env.SUPABASE_PROJECT_REF, projectId: process.env.SUPABASE_PROJECT_ID, accessToken: process.env.SUPABASE_ACCESS_TOKEN, dbUrl: process.env.SUPABASE_DB_URL, }); // Create MCP server const server = new Server( { name: 'supabase-coolify-mcp-server', version: '1.2.4', }, { capabilities: { tools: {}, resources: {}, }, } ); // Register all tools and resources const toolHandlers = new Map<string, (args: any) => Promise<any>>(); registerSupabaseTools(server, supabaseManager, toolHandlers); registerSupabaseCLITools(server, supabaseCLI, toolHandlers); registerCoolifyTools(server, coolifyClient, toolHandlers); registerDeploymentTools(server, coolifyClient, supabaseManager, toolHandlers); registerResources(server, coolifyClient, supabaseManager); // Register verification tool toolHandlers.set('verify_setup', async () => { return await createVerificationReport(coolifyClient, supabaseManager, supabaseCLI); }); // Handle tool list requests server.setRequestHandler(ListToolsRequestSchema, async () => { const tools = Array.from(toolHandlers.keys()).map((name) => { // Get tool metadata from the registered tools return getToolMetadata(name); }); return { tools }; }); // Handle tool execution server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; const handler = toolHandlers.get(name); if (!handler) { throw new Error(`Unknown tool: ${name}`); } try { const result = await handler(args || {}); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify( { success: false, error: error instanceof Error ? error.message : 'Unknown error', }, null, 2 ), }, ], isError: true, }; } }); // Helper function to get tool metadata function getToolMetadata(toolName: string) { const toolDescriptions: Record<string, any> = { // Supabase Migration Tools list_migrations: { name: 'list_migrations', description: 'List all database migrations with their status', inputSchema: { type: 'object', properties: {}, }, }, deploy_migration: { name: 'deploy_migration', description: 'Deploy a new database migration. NOTE: For self-hosted Supabase, consider using supabase_migration_new + supabase_db_push instead for better reliability.', inputSchema: { type: 'object', properties: { sql: { type: 'string', description: 'SQL migration code' }, name: { type: 'string', description: 'Migration name' }, }, required: ['sql', 'name'], }, }, execute_sql: { name: 'execute_sql', description: 'Execute raw SQL query on Supabase database. NOTE: For self-hosted Supabase, use supabase_cli_execute with "db execute" for better reliability.', inputSchema: { type: 'object', properties: { sql: { type: 'string', description: 'SQL query to execute' }, }, required: ['sql'], }, }, get_migration_status: { name: 'get_migration_status', description: 'Get status of a specific migration', inputSchema: { type: 'object', properties: { version: { type: 'string', description: 'Migration version' }, }, required: ['version'], }, }, // Migration Rollback Tools rollback_migration: { name: 'rollback_migration', description: 'Rollback a specific migration (optionally with down SQL)', inputSchema: { type: 'object', properties: { version: { type: 'string', description: 'Migration version to rollback' }, down_sql: { type: 'string', description: 'SQL to execute for rollback (optional)' }, }, required: ['version'], }, }, rollback_to_version: { name: 'rollback_to_version', description: 'Rollback all migrations after a specific version', inputSchema: { type: 'object', properties: { version: { type: 'string', description: 'Target version to rollback to' }, }, required: ['version'], }, }, rollback_last_migrations: { name: 'rollback_last_migrations', description: 'Rollback the last N migrations', inputSchema: { type: 'object', properties: { count: { type: 'number', description: 'Number of migrations to rollback', default: 1 }, }, }, }, create_migration_with_rollback: { name: 'create_migration_with_rollback', description: 'Create a migration with both up and down SQL for safe rollbacks', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Migration name' }, up_sql: { type: 'string', description: 'SQL to apply the migration' }, down_sql: { type: 'string', description: 'SQL to rollback the migration' }, }, required: ['name', 'up_sql', 'down_sql'], }, }, rollback_migration_with_down_sql: { name: 'rollback_migration_with_down_sql', description: 'Rollback a migration using its stored down SQL', inputSchema: { type: 'object', properties: { version: { type: 'string', description: 'Migration version' }, }, required: ['version'], }, }, // Edge Functions Tools list_edge_functions: { name: 'list_edge_functions', description: 'List all deployed edge functions', inputSchema: { type: 'object', properties: {}, }, }, deploy_edge_function: { name: 'deploy_edge_function', description: 'Deploy a new edge function', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Function name' }, code: { type: 'string', description: 'Function code' }, verify_jwt: { type: 'boolean', description: 'Verify JWT tokens', default: true }, }, required: ['name', 'code'], }, }, delete_edge_function: { name: 'delete_edge_function', description: 'Delete an edge function', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Function name' }, }, required: ['name'], }, }, get_edge_function_logs: { name: 'get_edge_function_logs', description: 'Get logs for an edge function', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Function name' }, limit: { type: 'number', description: 'Number of log entries', default: 100 }, }, required: ['name'], }, }, invoke_edge_function: { name: 'invoke_edge_function', description: 'Invoke an edge function', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Function name' }, payload: { type: 'object', description: 'Function payload' }, }, required: ['name'], }, }, // Storage Tools list_storage_buckets: { name: 'list_storage_buckets', description: 'List all storage buckets', inputSchema: { type: 'object', properties: {}, }, }, create_storage_bucket: { name: 'create_storage_bucket', description: 'Create a new storage bucket', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Bucket ID' }, public: { type: 'boolean', description: 'Make bucket public', default: false }, file_size_limit: { type: 'number', description: 'Max file size in bytes' }, }, required: ['id'], }, }, delete_storage_bucket: { name: 'delete_storage_bucket', description: 'Delete a storage bucket', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Bucket ID' }, }, required: ['id'], }, }, // Auth Tools get_auth_config: { name: 'get_auth_config', description: 'Get authentication configuration', inputSchema: { type: 'object', properties: {}, }, }, update_auth_config: { name: 'update_auth_config', description: 'Update authentication configuration', inputSchema: { type: 'object', properties: { config: { type: 'object', description: 'Auth configuration' }, }, required: ['config'], }, }, // Health & Status Tools check_supabase_health: { name: 'check_supabase_health', description: 'Check health of all Supabase services', inputSchema: { type: 'object', properties: {}, }, }, get_supabase_version: { name: 'get_supabase_version', description: 'Get Supabase version information', inputSchema: { type: 'object', properties: {}, }, }, // Coolify Tools list_coolify_applications: { name: 'list_coolify_applications', description: 'List all Coolify applications', inputSchema: { type: 'object', properties: {}, }, }, get_coolify_application: { name: 'get_coolify_application', description: 'Get details of a specific Coolify application', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Application UUID' }, }, required: ['uuid'], }, }, update_coolify_application_env: { name: 'update_coolify_application_env', description: 'Update application environment variables', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Application UUID' }, env: { type: 'object', description: 'Environment variables' }, }, required: ['uuid', 'env'], }, }, deploy_coolify_application: { name: 'deploy_coolify_application', description: 'Deploy a Coolify application', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Application UUID' }, }, required: ['uuid'], }, }, start_coolify_application: { name: 'start_coolify_application', description: 'Start a Coolify application', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Application UUID' }, }, required: ['uuid'], }, }, stop_coolify_application: { name: 'stop_coolify_application', description: 'Stop a Coolify application', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Application UUID' }, }, required: ['uuid'], }, }, restart_coolify_application: { name: 'restart_coolify_application', description: 'Restart a Coolify application', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Application UUID' }, }, required: ['uuid'], }, }, list_coolify_services: { name: 'list_coolify_services', description: 'List all Coolify services', inputSchema: { type: 'object', properties: {}, }, }, get_coolify_service: { name: 'get_coolify_service', description: 'Get details of a specific Coolify service', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Service UUID' }, }, required: ['uuid'], }, }, start_coolify_service: { name: 'start_coolify_service', description: 'Start a Coolify service', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Service UUID' }, }, required: ['uuid'], }, }, stop_coolify_service: { name: 'stop_coolify_service', description: 'Stop a Coolify service', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Service UUID' }, }, required: ['uuid'], }, }, get_coolify_logs: { name: 'get_coolify_logs', description: 'Get application logs from Coolify', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Application UUID' }, lines: { type: 'number', description: 'Number of log lines', default: 100 }, }, required: ['uuid'], }, }, // Supabase CLI Tools check_cli_installed: { name: 'check_cli_installed', description: 'Check if Supabase CLI is installed and get version', inputSchema: { type: 'object', properties: {}, }, }, supabase_init: { name: 'supabase_init', description: 'Initialize a new Supabase project', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Project path', default: '.' }, }, }, }, supabase_link: { name: 'supabase_link', description: 'Link to a remote Supabase project', inputSchema: { type: 'object', properties: { project_ref: { type: 'string', description: 'Project reference ID' }, password: { type: 'string', description: 'Database password (optional)' }, }, required: ['project_ref'], }, }, supabase_start: { name: 'supabase_start', description: 'Start local Supabase development environment', inputSchema: { type: 'object', properties: {}, }, }, supabase_stop: { name: 'supabase_stop', description: 'Stop local Supabase development environment', inputSchema: { type: 'object', properties: {}, }, }, supabase_status: { name: 'supabase_status', description: 'Get status of local Supabase services', inputSchema: { type: 'object', properties: {}, }, }, supabase_db_diff: { name: 'supabase_db_diff', description: 'Generate migration from database schema changes', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Migration name' }, }, required: ['name'], }, }, supabase_db_push: { name: 'supabase_db_push', description: 'Push local migrations to remote database', inputSchema: { type: 'object', properties: {}, }, }, supabase_db_reset: { name: 'supabase_db_reset', description: 'Reset local database to initial state', inputSchema: { type: 'object', properties: {}, }, }, supabase_migration_new: { name: 'supabase_migration_new', description: 'Create a new migration file', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Migration name' }, }, required: ['name'], }, }, supabase_migration_list: { name: 'supabase_migration_list', description: 'List all migrations (CLI)', inputSchema: { type: 'object', properties: {}, }, }, supabase_migration_repair: { name: 'supabase_migration_repair', description: 'Repair migration history', inputSchema: { type: 'object', properties: {}, }, }, supabase_functions_deploy: { name: 'supabase_functions_deploy', description: 'Deploy edge functions using Supabase CLI', inputSchema: { type: 'object', properties: { function_name: { type: 'string', description: 'Function name (optional, deploys all if omitted)' }, }, }, }, supabase_functions_serve: { name: 'supabase_functions_serve', description: 'Serve edge functions locally', inputSchema: { type: 'object', properties: { function_name: { type: 'string', description: 'Function name (optional)' }, }, }, }, supabase_gen_types: { name: 'supabase_gen_types', description: 'Generate TypeScript types from database schema', inputSchema: { type: 'object', properties: { output: { type: 'string', description: 'Output file path', default: 'types/supabase.ts' }, }, }, }, supabase_cli_execute: { name: 'supabase_cli_execute', description: 'Execute arbitrary Supabase CLI command', inputSchema: { type: 'object', properties: { command: { type: 'string', description: 'CLI command (without "supabase" prefix)' }, }, required: ['command'], }, }, // Deployment Tools deploy_supabase_to_coolify: { name: 'deploy_supabase_to_coolify', description: 'Deploy a complete Supabase instance on Coolify', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Deployment name' }, config: { type: 'object', description: 'Deployment configuration' }, }, required: ['name'], }, }, update_supabase_deployment: { name: 'update_supabase_deployment', description: 'Update an existing Supabase deployment', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Application UUID' }, config: { type: 'object', description: 'Updated configuration' }, }, required: ['uuid', 'config'], }, }, get_deployment_status: { name: 'get_deployment_status', description: 'Get status of Supabase deployment on Coolify', inputSchema: { type: 'object', properties: { uuid: { type: 'string', description: 'Application UUID' }, }, required: ['uuid'], }, }, // System Tools verify_setup: { name: 'verify_setup', description: 'Verify system setup and check health of all services (Coolify, Supabase, CLI)', inputSchema: { type: 'object', properties: {}, }, }, }; return toolDescriptions[toolName] || { name: toolName, description: `Execute ${toolName}`, inputSchema: { type: 'object', properties: {} }, }; } // Start server async function main() { // Run startup health checks await runStartupHealthCheck(coolifyClient, supabaseManager, supabaseCLI); const transport = new StdioServerTransport(); await server.connect(transport); console.error('✅ Supabase Coolify MCP Server running on stdio'); console.error(''); console.error('📊 Configuration:'); console.error(` Coolify API: ${process.env.COOLIFY_API_URL}`); console.error(` Supabase URL: ${process.env.SUPABASE_URL}`); console.error(''); console.error('🛠️ Available: 52 tools, 8 resources'); console.error(' • Supabase: Migrations, Rollback, Edge Functions, Storage, Auth'); console.error(' • Coolify: Applications, Services, Deployment'); console.error(' • CLI: Local dev, Type generation, Testing'); console.error(''); console.error('💡 Run "verify_setup" tool for detailed system diagnostics'); console.error(''); } main().catch((error) => { console.error('Fatal error:', error); process.exit(1); });

Latest Blog Posts

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/dj-pearson/supabase-coolify-mcp-server'

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