Skip to main content
Glama

Self-Hosted Supabase MCP Server

by abushadab
utils.ts3 kB
import { z } from 'zod'; import type { SqlExecutionResult, SqlErrorResponse } from '../types/index.js'; import { exec } from 'node:child_process'; import { promisify } from 'node:util'; import type { SelfhostedSupabaseClient } from '../client/index.js'; const execAsync = promisify(exec); /** * Type guard to check if a SQL execution result is an error response. */ export function isSqlErrorResponse(result: SqlExecutionResult): result is SqlErrorResponse { return (result as SqlErrorResponse).error !== undefined; } /** * Handles SQL execution results and validates them against the expected schema. * Throws an error if the result contains an error or doesn't match the schema. */ export function handleSqlResponse<T>(result: SqlExecutionResult, schema: z.ZodSchema<T>): T { // Check if the result contains an error if ('error' in result) { throw new Error(`SQL Error (${result.error.code}): ${result.error.message}`); } // Validate the result against the schema try { return schema.parse(result); } catch (validationError) { if (validationError instanceof z.ZodError) { throw new Error(`Schema validation failed: ${validationError.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ')}`); } throw new Error(`Unexpected validation error: ${validationError}`); } } /** * Executes an external shell command asynchronously. * Returns stdout, stderr, and any execution error. */ export async function runExternalCommand(command: string): Promise<{ stdout: string; stderr: string; error: Error | null; }> { try { const { stdout, stderr } = await execAsync(command); return { stdout, stderr, error: null }; } catch (error: unknown) { // execAsync throws on non-zero exit code, includes stdout/stderr in the error object const execError = error as Error & { stdout?: string; stderr?: string }; return { stdout: execError.stdout || '', stderr: execError.stderr || execError.message, // Use message if stderr is empty error: execError, }; } } /** * Executes SQL using the best available method: direct database connection first, then RPC fallback. * This bypasses JWT authentication issues when direct database access is available. */ export async function executeSqlWithFallback( client: SelfhostedSupabaseClient, sql: string, readOnly: boolean = true ): Promise<SqlExecutionResult> { // Try direct database connection first (bypasses JWT authentication) if (client.isPgAvailable()) { console.info('Using direct database connection (bypassing JWT)...'); return await client.executeSqlWithPg(sql); } // Fallback to RPC if direct connection not available console.info('Falling back to RPC method...'); return await client.executeSqlViaRpc(sql, readOnly); }

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/abushadab/selfhosted-supabase-mcp-basic-auth'

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