mcp-supabase-selfhosted 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,57 @@
1
+ import { Pool } from 'pg';
2
+ import { getConfig } from '../config/env.js';
3
+
4
+ let pgPool: Pool | null = null;
5
+
6
+ /**
7
+ * Inicializa y retorna el pool de conexiones de Postgres si DATABASE_URL está configurada.
8
+ */
9
+ export async function getDbPool(): Promise<Pool> {
10
+ if (pgPool) {
11
+ return pgPool;
12
+ }
13
+
14
+ const config = getConfig();
15
+
16
+ if (!config.DATABASE_URL) {
17
+ throw new Error(
18
+ 'DATABASE_URL no está configurada. Las herramientas de base de datos directa no funcionarán.',
19
+ );
20
+ }
21
+
22
+ pgPool = new Pool({
23
+ connectionString: config.DATABASE_URL,
24
+ max: 10, // Límite máximo de conexiones activas para este MCP
25
+ idleTimeoutMillis: 30000, // Cerrar conexiones inactivas después de 30s
26
+ connectionTimeoutMillis: 5000, // Abortar intentos de conexión lentos
27
+ statement_timeout: 10000, // (10s) Abortar consultas pesadas/erróneas generadas por la IA
28
+ });
29
+
30
+ try {
31
+ // Verificamos la conexión con una consulta sencilla
32
+ const client = await pgPool.connect();
33
+ client.release();
34
+ console.error(' Conectado exitosamente a PostgreSQL (Pool con timeouts configurados).');
35
+ return pgPool;
36
+ } catch (error: unknown) {
37
+ pgPool = null;
38
+ const msg = error instanceof Error ? error.message : String(error);
39
+ console.error(' Error conectando a PostgreSQL:', msg);
40
+ throw error;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Ejecuta una query segura usando el pool.
46
+ */
47
+ export async function query(sql: string, params: unknown[] = []) {
48
+ const pool = await getDbPool();
49
+ try {
50
+ const result = await pool.query(sql, params);
51
+ return result.rows;
52
+ } catch (error: unknown) {
53
+ const msg = error instanceof Error ? error.message : String(error);
54
+ console.error(' Error ejecutando query:', msg);
55
+ throw error;
56
+ }
57
+ }
package/src/index.ts ADDED
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
5
+ import { getConfig } from './config/env.js';
6
+ import {
7
+ toolsDefinitions,
8
+ handleExecuteSql,
9
+ handleListBuckets,
10
+ handleCreateBucket,
11
+ handleDeleteBucket,
12
+ handleListTables,
13
+ handleListUsers,
14
+ handleCreateUser,
15
+ handleDeleteUser,
16
+ handleGetSchema,
17
+ handleGetAdvisors,
18
+ handleListFiles,
19
+ handleListRlsPolicies,
20
+ handleGetActiveConnections,
21
+ } from './tools/index.js';
22
+
23
+ async function main() {
24
+ // 1. Validar la configuración al inicio
25
+ getConfig();
26
+
27
+ // 2. Inicializar el servidor MCP
28
+ const server = new Server(
29
+ {
30
+ name: 'supabase-selfhosted-mcp',
31
+ version: '1.0.0',
32
+ },
33
+ {
34
+ capabilities: {
35
+ tools: {},
36
+ },
37
+ },
38
+ );
39
+
40
+ // 3. Registrar el manejador para listar herramientas (Tools)
41
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
42
+ return {
43
+ tools: toolsDefinitions,
44
+ };
45
+ });
46
+
47
+ // 4. Registrar el manejador para ejecutar herramientas
48
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
49
+ const { name, arguments: params } = request.params;
50
+
51
+ switch (name) {
52
+ case 'get_schema':
53
+ return await handleGetSchema(params);
54
+ case 'get_advisors':
55
+ return await handleGetAdvisors();
56
+ case 'list_tables':
57
+ return await handleListTables(params);
58
+ case 'execute_sql':
59
+ return await handleExecuteSql(params);
60
+ case 'list_users':
61
+ return await handleListUsers(params);
62
+ case 'create_user':
63
+ return await handleCreateUser(params);
64
+ case 'delete_user':
65
+ return await handleDeleteUser(params);
66
+ case 'list_buckets':
67
+ return await handleListBuckets();
68
+ case 'create_bucket':
69
+ return await handleCreateBucket(params);
70
+ case 'delete_bucket':
71
+ return await handleDeleteBucket(params);
72
+ case 'list_files':
73
+ return await handleListFiles(params);
74
+ case 'list_rls_policies':
75
+ return await handleListRlsPolicies(params);
76
+ case 'get_active_connections':
77
+ return await handleGetActiveConnections();
78
+ default:
79
+ throw new Error(`Tool not found: ${name}`);
80
+ }
81
+ });
82
+
83
+ // 5. Configurar el transporte stdio (entrada/salida estándar)
84
+ const transport = new StdioServerTransport();
85
+ await server.connect(transport);
86
+
87
+ console.error(' Servidor MCP de Supabase Self-Hosted iniciado correctamente.');
88
+ }
89
+
90
+ main().catch((error) => {
91
+ console.error(' Error fatal al iniciar el servidor MCP:', error);
92
+ process.exit(1);
93
+ });
@@ -0,0 +1,34 @@
1
+ import { createClient, SupabaseClient } from '@supabase/supabase-js';
2
+ import { getConfig } from '../config/env.js';
3
+
4
+ let supabaseClient: SupabaseClient | null = null;
5
+
6
+ /**
7
+ * Inicializa y retorna el cliente de Supabase (usando la Service Role Key para bypassing de RLS).
8
+ */
9
+ export function getSupabaseClient(): SupabaseClient {
10
+ if (supabaseClient) {
11
+ return supabaseClient;
12
+ }
13
+
14
+ const config = getConfig();
15
+
16
+ if (!config.SUPABASE_URL || !config.SUPABASE_SERVICE_ROLE_KEY) {
17
+ throw new Error(
18
+ 'SUPABASE_URL y SUPABASE_SERVICE_ROLE_KEY son obligatorias para utilizar las herramientas de Auth y Storage.',
19
+ );
20
+ }
21
+
22
+ // Creamos el cliente usando la service role key.
23
+ // IMPORTANTE: En el contexto de un MCP (que actúa como un super admin), es seguro
24
+ // y necesario usar la service role key, pero el usuario debe estar consciente de esto.
25
+ supabaseClient = createClient(config.SUPABASE_URL, config.SUPABASE_SERVICE_ROLE_KEY, {
26
+ auth: {
27
+ autoRefreshToken: false,
28
+ persistSession: false,
29
+ },
30
+ });
31
+
32
+ console.error(' Cliente Supabase API inicializado.');
33
+ return supabaseClient;
34
+ }