Skip to main content
Glama
MisterSandFR

Supabase MCP Server - Self-Hosted Edition

by MisterSandFR
execute_sql.ts3.64 kB
import { z } from "zod"; import { ToolContext } from "./types.js"; import type { SelfhostedSupabaseClient } from '../client/index.js'; // import type { McpToolDefinition } from '@modelcontextprotocol/sdk'; // Removed incorrect import import { handleSqlResponse, executeSqlWithFallback } from './utils.js'; import { Tool } from "@modelcontextprotocol/sdk/types.js"; import { validateSqlQuery } from '../utils/sql-sanitizer.js'; // Input schema const ExecuteSqlInputSchema = z.object({ sql: z.string().describe('The SQL query to execute.'), read_only: z.boolean().optional().default(false).describe('Hint for the RPC function whether the query is read-only (best effort).'), allow_multiple_statements: z.boolean().optional().default(false).describe('Allow multiple SQL statements separated by semicolons (DDL operations, migrations).'), // Future enhancement: Add option to force direct connection? // use_direct_connection: z.boolean().optional().default(false).describe('Attempt to use direct DB connection instead of RPC.'), }); type ExecuteSqlInput = z.infer<typeof ExecuteSqlInputSchema>; // Output schema - expects an array of results (rows) const ExecuteSqlOutputSchema = z.array(z.unknown()).describe('The array of rows returned by the SQL query.'); // Static JSON Schema for MCP capabilities const mcpInputSchema = { type: 'object', properties: { sql: { type: 'string', description: 'The SQL query to execute.' }, read_only: { type: 'boolean', default: false, description: 'Hint for the RPC function whether the query is read-only (best effort).' }, allow_multiple_statements: { type: 'boolean', default: false, description: 'Allow multiple SQL statements separated by semicolons (DDL operations, migrations).' }, }, required: ['sql'], }; // The tool definition - No explicit McpToolDefinition type needed export const executeSqlTool = { name: 'execute_sql', description: 'Executes an arbitrary SQL query against the database, using direct database connection when available or RPC function as fallback. Supports multi-statement DDL operations for migrations and complex schema changes.', inputSchema: ExecuteSqlInputSchema, mcpInputSchema: mcpInputSchema, outputSchema: ExecuteSqlOutputSchema, execute: async (input: ExecuteSqlInput, context: ToolContext) => { const client = context.selfhostedClient; // Validate SQL query for injection attempts try { validateSqlQuery(input.sql, input.allow_multiple_statements); } catch (error) { throw new Error(`SQL validation failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } console.error(`Executing SQL (readOnly: ${input.read_only}, multiStatement: ${input.allow_multiple_statements}): ${input.sql.substring(0, 100)}...`); // For multi-statement queries, force direct connection if available if (input.allow_multiple_statements && !input.read_only) { if (!client.isPgAvailable()) { throw new Error('Multi-statement DDL operations require direct database connection (DATABASE_URL) but it is not configured or available.'); } console.info('Using direct database connection for multi-statement DDL...'); const result = await client.executeSqlWithPg(input.sql); return handleSqlResponse(result, ExecuteSqlOutputSchema); } const result = await executeSqlWithFallback(client, input.sql, input.read_only); return handleSqlResponse(result, ExecuteSqlOutputSchema); }, };

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/MisterSandFR/Supabase-MCP-SelfHosted'

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