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.
- package/.env.example +9 -0
- package/.gemini/skills/supabase-selfhosted/SKILL.md +58 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +36 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +23 -0
- package/.github/workflows/ci.yml +27 -0
- package/.prettierrc +7 -0
- package/CHANGELOG.md +19 -0
- package/CONTRIBUTING.md +34 -0
- package/Dockerfile +36 -0
- package/LICENSE +21 -0
- package/README.md +104 -0
- package/SECURITY.md +22 -0
- package/dist/config/env.d.ts +5 -0
- package/dist/config/env.js +36 -0
- package/dist/db/postgres.d.ts +9 -0
- package/dist/db/postgres.js +50 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +67 -0
- package/dist/supabase/client.d.ts +5 -0
- package/dist/supabase/client.js +26 -0
- package/dist/tools/index.d.ts +441 -0
- package/dist/tools/index.js +521 -0
- package/docker-compose.yml +14 -0
- package/eslint.config.js +21 -0
- package/package.json +59 -0
- package/smithery.yaml +30 -0
- package/src/config/env.ts +42 -0
- package/src/db/postgres.ts +57 -0
- package/src/index.ts +93 -0
- package/src/supabase/client.ts +34 -0
- package/src/tools/index.ts +566 -0
- package/tests/tools.test.ts +34 -0
- package/tsconfig.json +17 -0
package/.env.example
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# URL de tu instancia Self-Hosted de Supabase (ej. http://localhost:8000 o https://api.midominio.com)
|
|
2
|
+
SUPABASE_URL="http://localhost:8000"
|
|
3
|
+
|
|
4
|
+
# Service Role Key para hacer bypass de RLS (necesario para gestionar usuarios/buckets)
|
|
5
|
+
SUPABASE_SERVICE_ROLE_KEY="tu_service_role_key_aqui"
|
|
6
|
+
|
|
7
|
+
# URL de conexión directa a PostgreSQL (para queries directas y gestión de tablas)
|
|
8
|
+
# Generalmente: postgresql://postgres:postgres@localhost:5432/postgres
|
|
9
|
+
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: supabase-selfhosted
|
|
3
|
+
description: Use when you need to interact with a self-hosted Supabase instance to configure Auth, Storage, manage the database schema, apply RLS policies, or debug performance.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: Supabase Self-Hosted MCP
|
|
7
|
+
|
|
8
|
+
This skill guides the agent on how to correctly and safely utilize the `supabase-selfhosted` MCP server tools to interact with a self-hosted Supabase environment.
|
|
9
|
+
|
|
10
|
+
## 1. When to Use
|
|
11
|
+
Activate this skill whenever the user asks to:
|
|
12
|
+
- "Configurar un usuario de prueba en auth."
|
|
13
|
+
- "Crear un bucket para mis imágenes."
|
|
14
|
+
- "Revisar las políticas de seguridad RLS."
|
|
15
|
+
- "Corregir problemas de rendimiento de la base de datos."
|
|
16
|
+
- "Ver qué columnas tiene una tabla en mi Supabase."
|
|
17
|
+
|
|
18
|
+
## 2. Security and RLS (Row Level Security) Mandates
|
|
19
|
+
**Critical:** Because this MCP uses the `SUPABASE_SERVICE_ROLE_KEY` and direct PostgreSQL connections, **it bypasses Row Level Security (RLS) entirely.**
|
|
20
|
+
- When you create tables or schemas using `execute_sql`, you MUST strongly recommend or automatically apply RLS policies unless explicitly told otherwise.
|
|
21
|
+
- Use `list_rls_policies` to audit existing security rules.
|
|
22
|
+
- If the `get_advisors` tool flags tables without RLS, you should proactively offer to write the SQL to secure them.
|
|
23
|
+
|
|
24
|
+
## 3. Recommended Workflows
|
|
25
|
+
|
|
26
|
+
### A. Exploring the Database
|
|
27
|
+
1. Run `list_tables` to see what exists.
|
|
28
|
+
2. Run `get_schema({ table_name: "X" })` to understand the columns before writing any SQL.
|
|
29
|
+
3. Run `get_advisors()` to check if there are missing indexes or security gaps.
|
|
30
|
+
|
|
31
|
+
### B. Configuring Auth
|
|
32
|
+
1. Use `list_users` to see who is registered.
|
|
33
|
+
2. Use `create_user({ email, password, email_confirm: true })` to bootstrap administrative or test accounts without needing an email SMTP server configured locally.
|
|
34
|
+
3. If asked to clean up, use `delete_user({ user_id })`.
|
|
35
|
+
|
|
36
|
+
### C. Configuring Storage (Buckets)
|
|
37
|
+
1. Use `list_buckets()` to check existing buckets.
|
|
38
|
+
2. Use `create_bucket({ bucket: "name", public: true/false })` to make a new one. Remember: making a bucket public allows read access without auth, but RLS policies are still recommended via `storage.objects` table.
|
|
39
|
+
3. Use `list_files({ bucket: "name" })` to verify uploads.
|
|
40
|
+
|
|
41
|
+
### D. Debugging and Infrastructure
|
|
42
|
+
- If the user complains about "Too many connections" or database hanging, immediately run `get_active_connections()` to identify locked processes or long-running queries.
|
|
43
|
+
- Run `get_advisors()` and report the `cache_health` and `unused_indexes` so the user can optimize their self-hosted VPS resources.
|
|
44
|
+
|
|
45
|
+
## 4. Examples
|
|
46
|
+
|
|
47
|
+
**Creating a Secure Table with RLS:**
|
|
48
|
+
If asked to create a `posts` table, execute:
|
|
49
|
+
```sql
|
|
50
|
+
CREATE TABLE posts (
|
|
51
|
+
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
52
|
+
title text,
|
|
53
|
+
user_id uuid REFERENCES auth.users(id)
|
|
54
|
+
);
|
|
55
|
+
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
|
|
56
|
+
CREATE POLICY "Users can read own posts" ON posts FOR SELECT USING (auth.uid() = user_id);
|
|
57
|
+
```
|
|
58
|
+
*(Always use `execute_sql` with robust SQL strings).*
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Create a report to help us improve
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for taking the time to fill out this bug report!
|
|
9
|
+
- type: textarea
|
|
10
|
+
id: what-happened
|
|
11
|
+
attributes:
|
|
12
|
+
label: What happened?
|
|
13
|
+
description: Also tell us what you expected to happen
|
|
14
|
+
placeholder: Tell us what you see!
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: reproduction-steps
|
|
19
|
+
attributes:
|
|
20
|
+
label: Steps to reproduce
|
|
21
|
+
description: How can we reproduce this?
|
|
22
|
+
placeholder: |
|
|
23
|
+
1. Setup MCP with ...
|
|
24
|
+
2. Run tool ...
|
|
25
|
+
3. See error ...
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
- type: textarea
|
|
29
|
+
id: environment
|
|
30
|
+
attributes:
|
|
31
|
+
label: Environment
|
|
32
|
+
description: Operating System, Node version, Docker version, etc.
|
|
33
|
+
placeholder: |
|
|
34
|
+
- OS: Linux/macOS/Windows
|
|
35
|
+
- Node: v20.x
|
|
36
|
+
- MCP Client: Cursor/Claude Desktop
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an idea for this project
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Is your feature request related to a problem?
|
|
9
|
+
description: A concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: solution
|
|
14
|
+
attributes:
|
|
15
|
+
label: Describe the solution you'd like
|
|
16
|
+
description: A concise description of what you want to happen.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: context
|
|
21
|
+
attributes:
|
|
22
|
+
label: Additional context
|
|
23
|
+
description: Add any other context or screenshots about the feature request here.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
node-version: [18.x, 20.x, 22.x]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
20
|
+
uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: ${{ matrix.node-version }}
|
|
23
|
+
cache: 'npm'
|
|
24
|
+
- run: npm ci
|
|
25
|
+
- run: npm run lint
|
|
26
|
+
- run: npm run build
|
|
27
|
+
- run: npm test
|
package/.prettierrc
ADDED
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2026-06-01
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial release of the Supabase Self-Hosted MCP server.
|
|
12
|
+
- Database tools: `list_tables`, `get_schema`, `execute_sql`.
|
|
13
|
+
- Infrastructure tools: `get_advisors`, `get_active_connections`, `list_rls_policies`.
|
|
14
|
+
- Auth tools: `list_users`, `create_user`, `delete_user`.
|
|
15
|
+
- Storage tools: `list_buckets`, `create_bucket`, `delete_bucket`, `list_files`.
|
|
16
|
+
- Docker support with Multi-stage builds.
|
|
17
|
+
- One-command execution support via `npx`.
|
|
18
|
+
- Initial test suite and linting configuration.
|
|
19
|
+
- MIT License and community health files.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Contributing to Supabase Self-Hosted MCP
|
|
2
|
+
|
|
3
|
+
First off, thank you for considering contributing to this project! It's people like you that make the open-source community such a great place to learn, inspire, and create.
|
|
4
|
+
|
|
5
|
+
## Code of Conduct
|
|
6
|
+
|
|
7
|
+
By participating in this project, you are expected to uphold our Code of Conduct.
|
|
8
|
+
|
|
9
|
+
## How Can I Contribute?
|
|
10
|
+
|
|
11
|
+
### Reporting Bugs
|
|
12
|
+
- Use the [GitHub Bug Report template](.github/ISSUE_TEMPLATE/bug_report.md).
|
|
13
|
+
- Provide a clear and descriptive title.
|
|
14
|
+
- Describe the exact steps which reproduce the problem.
|
|
15
|
+
|
|
16
|
+
### Suggesting Enhancements
|
|
17
|
+
- Use the [GitHub Feature Request template](.github/ISSUE_TEMPLATE/feature_request.md).
|
|
18
|
+
- Explain why this enhancement would be useful to most users.
|
|
19
|
+
|
|
20
|
+
### Pull Requests
|
|
21
|
+
1. Fork the repo and create your branch from `main`.
|
|
22
|
+
2. If you've added code that should be tested, add tests.
|
|
23
|
+
3. Ensure the test suite passes (`npm test`).
|
|
24
|
+
4. Make sure your code lints (`npm run lint`).
|
|
25
|
+
5. Issue that pull request!
|
|
26
|
+
|
|
27
|
+
## Styleguide
|
|
28
|
+
|
|
29
|
+
- Use TypeScript for all logic.
|
|
30
|
+
- Follow the existing Prettier and ESLint configurations.
|
|
31
|
+
- Document new tools in the `README.md` and provide examples in the `SKILL.md` if applicable.
|
|
32
|
+
|
|
33
|
+
## License
|
|
34
|
+
By contributing, you agree that your contributions will be licensed under its MIT License.
|
package/Dockerfile
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Construcción
|
|
2
|
+
FROM node:20-slim AS builder
|
|
3
|
+
|
|
4
|
+
WORKDIR /app
|
|
5
|
+
|
|
6
|
+
# Copiar configuración
|
|
7
|
+
COPY package*.json ./
|
|
8
|
+
COPY tsconfig.json ./
|
|
9
|
+
|
|
10
|
+
# Instalar dependencias
|
|
11
|
+
RUN npm ci
|
|
12
|
+
|
|
13
|
+
# Copiar código fuente
|
|
14
|
+
COPY src/ ./src/
|
|
15
|
+
|
|
16
|
+
# Compilar TypeScript
|
|
17
|
+
RUN npm run build
|
|
18
|
+
|
|
19
|
+
# Producción
|
|
20
|
+
FROM node:20-slim AS runner
|
|
21
|
+
|
|
22
|
+
WORKDIR /app
|
|
23
|
+
|
|
24
|
+
# Copiar archivos compilados y dependencias de producción
|
|
25
|
+
COPY package*.json ./
|
|
26
|
+
RUN npm ci --omit=dev
|
|
27
|
+
|
|
28
|
+
COPY --from=builder /app/dist ./dist
|
|
29
|
+
|
|
30
|
+
# Variables de entorno por defecto
|
|
31
|
+
ENV SUPABASE_URL=""
|
|
32
|
+
ENV SUPABASE_SERVICE_ROLE_KEY=""
|
|
33
|
+
ENV DATABASE_URL=""
|
|
34
|
+
|
|
35
|
+
# Ejecutar usando stdio (por eso no exponemos puertos HTTP)
|
|
36
|
+
ENTRYPOINT ["node", "dist/index.js"]
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Open Source Community
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do action so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Supabase Self-Hosted MCP Server
|
|
2
|
+
|
|
3
|
+
Un servidor [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) diseñado específicamente para instancias **Self-Hosted de Supabase**.
|
|
4
|
+
|
|
5
|
+
A diferencia del servidor MCP oficial que depende en gran medida de las APIs de la nube de Supabase y del `project-ref`, esta versión se conecta directamente a tu base de datos PostgreSQL local y a las APIs locales (Auth/Storage) usando tu `SUPABASE_URL` y tu `SERVICE_ROLE_KEY`.
|
|
6
|
+
|
|
7
|
+
## Características
|
|
8
|
+
|
|
9
|
+
- **Introspección de Base de Datos:** Lista tablas y esquemas de tu Postgres.
|
|
10
|
+
- **Ejecución SQL Raw:** Ejecuta consultas SQL directamente, permitiendo a la IA leer datos o modificar la estructura (bypass de RLS).
|
|
11
|
+
- **Gestión de Autenticación:** Lista usuarios registrados en tu instancia.
|
|
12
|
+
- **Gestión de Storage:** Lista buckets de almacenamiento.
|
|
13
|
+
|
|
14
|
+
## Requisitos
|
|
15
|
+
|
|
16
|
+
- Node.js >= 18
|
|
17
|
+
- Docker (opcional, pero recomendado)
|
|
18
|
+
|
|
19
|
+
## Instalación y Uso (Local)
|
|
20
|
+
|
|
21
|
+
1. Clona el repositorio:
|
|
22
|
+
```bash
|
|
23
|
+
git clone https://github.com/tu-usuario/mcp-supabase-selfhosted.git
|
|
24
|
+
cd mcp-supabase-selfhosted
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
2. Instala las dependencias y compila:
|
|
28
|
+
```bash
|
|
29
|
+
npm install
|
|
30
|
+
npm run build
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. Crea tu archivo de entorno:
|
|
34
|
+
```bash
|
|
35
|
+
cp .env.example .env
|
|
36
|
+
```
|
|
37
|
+
Rellena tus credenciales (asegúrate de usar la **Service Role Key**, ¡nunca la anónima!).
|
|
38
|
+
|
|
39
|
+
## Uso con Docker (Recomendado)
|
|
40
|
+
|
|
41
|
+
La forma más limpia de utilizar este servidor en clientes IA (Cursor, Claude, Gemini) sin ensuciar tu entorno local es usar la imagen de Docker.
|
|
42
|
+
|
|
43
|
+
1. Construye la imagen localmente:
|
|
44
|
+
```bash
|
|
45
|
+
docker build -t supabase-selfhosted-mcp .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Configuración en Claude Desktop / Cursor
|
|
49
|
+
Añade lo siguiente a tu archivo `claude_desktop_config.json` o configuración de Cursor:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"mcpServers": {
|
|
54
|
+
"supabase-selfhosted": {
|
|
55
|
+
"command": "docker",
|
|
56
|
+
"args": [
|
|
57
|
+
"run",
|
|
58
|
+
"-i",
|
|
59
|
+
"--rm",
|
|
60
|
+
"-e", "SUPABASE_URL=http://host.docker.internal:8000",
|
|
61
|
+
"-e", "SUPABASE_SERVICE_ROLE_KEY=tu-clave-aqui",
|
|
62
|
+
"-e", "DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/postgres",
|
|
63
|
+
"supabase-selfhosted-mcp"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
*(Nota: usa `host.docker.internal` en lugar de `localhost` si tu base de datos corre en tu máquina host).*
|
|
70
|
+
|
|
71
|
+
### Configuración en Gemini CLI
|
|
72
|
+
Puedes añadirlo en tu archivo `~/.gemini/settings.json`:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"mcpServers": {
|
|
77
|
+
"supabase-selfhosted": {
|
|
78
|
+
"command": "docker",
|
|
79
|
+
"args": [
|
|
80
|
+
"run",
|
|
81
|
+
"-i",
|
|
82
|
+
"--rm",
|
|
83
|
+
"-e", "SUPABASE_URL=...",
|
|
84
|
+
"-e", "SUPABASE_SERVICE_ROLE_KEY=...",
|
|
85
|
+
"-e", "DATABASE_URL=...",
|
|
86
|
+
"supabase-selfhosted-mcp"
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Seguridad y Buenas Prácticas
|
|
94
|
+
|
|
95
|
+
- **Acceso Directo:** Este MCP utiliza conexiones directas a DB y la `SERVICE_ROLE_KEY`. Esto significa que la IA conectada tendrá acceso **total y sin restricciones (bypassing RLS)** a tu instancia.
|
|
96
|
+
- **Entornos:** Se recomienda encarecidamente utilizar esto **sólo en entornos de desarrollo local**, nunca apuntando a una base de datos de producción con datos reales sensibles.
|
|
97
|
+
- **Transporte:** El servidor usa `stdio` (entrada/salida estándar), lo cual es el protocolo de seguridad predeterminado en aplicaciones de escritorio como Cursor y Claude.
|
|
98
|
+
|
|
99
|
+
## Contribuir
|
|
100
|
+
|
|
101
|
+
¡Las contribuciones son bienvenidas! Sientete libre de abrir Issues o Pull Requests. Si planeas añadir una herramienta nueva, añádela en el directorio `src/tools/`.
|
|
102
|
+
|
|
103
|
+
## Licencia
|
|
104
|
+
MIT
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
Currently, only the latest version of the Supabase Self-Hosted MCP server is supported with security updates.
|
|
6
|
+
|
|
7
|
+
| Version | Supported |
|
|
8
|
+
| ------- | ------------------ |
|
|
9
|
+
| 1.0.x | :white_check_mark: |
|
|
10
|
+
| < 1.0 | :x: |
|
|
11
|
+
|
|
12
|
+
## Reporting a Vulnerability
|
|
13
|
+
|
|
14
|
+
We take security seriously. If you discover a security vulnerability within this project, please **do not open a public issue**. Instead, please report it via GitHub's Private Vulnerability Reporting feature or by contacting the maintainers directly.
|
|
15
|
+
|
|
16
|
+
### Our Commitment
|
|
17
|
+
- We will acknowledge receipt of your report within 48 hours.
|
|
18
|
+
- We will provide an estimated timeframe for a fix.
|
|
19
|
+
- We will notify the community once a patch is available.
|
|
20
|
+
|
|
21
|
+
### Bypassing RLS Note
|
|
22
|
+
Please note that this MCP server is designed for **administrative and development purposes**. By definition, using a `Service Role Key` bypasses Row Level Security. This is an intended feature of the tool and not considered a vulnerability in itself. However, exposures of credentials or remote execution flaws are critical bugs.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
// Cargar variables de entorno del archivo .env si existe
|
|
4
|
+
dotenv.config();
|
|
5
|
+
// Esquema de validación para las variables de entorno
|
|
6
|
+
const envSchema = z
|
|
7
|
+
.object({
|
|
8
|
+
SUPABASE_URL: z.string().url('La URL de Supabase debe ser válida').optional(),
|
|
9
|
+
SUPABASE_SERVICE_ROLE_KEY: z.string().optional(),
|
|
10
|
+
DATABASE_URL: z
|
|
11
|
+
.string()
|
|
12
|
+
.url('La URL de la base de datos (Postgres) debe ser válida')
|
|
13
|
+
.optional(),
|
|
14
|
+
})
|
|
15
|
+
.refine((data) => {
|
|
16
|
+
// Al menos una de las dos formas de conexión debe estar configurada
|
|
17
|
+
const hasSupabaseAPI = !!(data.SUPABASE_URL && data.SUPABASE_SERVICE_ROLE_KEY);
|
|
18
|
+
const hasDBConnection = !!data.DATABASE_URL;
|
|
19
|
+
return hasSupabaseAPI || hasDBConnection;
|
|
20
|
+
}, {
|
|
21
|
+
message: 'Debes configurar al menos DATABASE_URL o (SUPABASE_URL y SUPABASE_SERVICE_ROLE_KEY)',
|
|
22
|
+
});
|
|
23
|
+
export function getConfig() {
|
|
24
|
+
try {
|
|
25
|
+
const config = envSchema.parse(process.env);
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (error instanceof z.ZodError) {
|
|
30
|
+
console.error(' Error de configuración. Faltan variables de entorno o son inválidas:');
|
|
31
|
+
error.issues.forEach((e) => console.error(` - ${e.message}`));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
/**
|
|
3
|
+
* Inicializa y retorna el pool de conexiones de Postgres si DATABASE_URL está configurada.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getDbPool(): Promise<Pool>;
|
|
6
|
+
/**
|
|
7
|
+
* Ejecuta una query segura usando el pool.
|
|
8
|
+
*/
|
|
9
|
+
export declare function query(sql: string, params?: unknown[]): Promise<any[]>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import { getConfig } from '../config/env.js';
|
|
3
|
+
let pgPool = null;
|
|
4
|
+
/**
|
|
5
|
+
* Inicializa y retorna el pool de conexiones de Postgres si DATABASE_URL está configurada.
|
|
6
|
+
*/
|
|
7
|
+
export async function getDbPool() {
|
|
8
|
+
if (pgPool) {
|
|
9
|
+
return pgPool;
|
|
10
|
+
}
|
|
11
|
+
const config = getConfig();
|
|
12
|
+
if (!config.DATABASE_URL) {
|
|
13
|
+
throw new Error('DATABASE_URL no está configurada. Las herramientas de base de datos directa no funcionarán.');
|
|
14
|
+
}
|
|
15
|
+
pgPool = new Pool({
|
|
16
|
+
connectionString: config.DATABASE_URL,
|
|
17
|
+
max: 10, // Límite máximo de conexiones activas para este MCP
|
|
18
|
+
idleTimeoutMillis: 30000, // Cerrar conexiones inactivas después de 30s
|
|
19
|
+
connectionTimeoutMillis: 5000, // Abortar intentos de conexión lentos
|
|
20
|
+
statement_timeout: 10000, // (10s) Abortar consultas pesadas/erróneas generadas por la IA
|
|
21
|
+
});
|
|
22
|
+
try {
|
|
23
|
+
// Verificamos la conexión con una consulta sencilla
|
|
24
|
+
const client = await pgPool.connect();
|
|
25
|
+
client.release();
|
|
26
|
+
console.error(' Conectado exitosamente a PostgreSQL (Pool con timeouts configurados).');
|
|
27
|
+
return pgPool;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
pgPool = null;
|
|
31
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
32
|
+
console.error(' Error conectando a PostgreSQL:', msg);
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Ejecuta una query segura usando el pool.
|
|
38
|
+
*/
|
|
39
|
+
export async function query(sql, params = []) {
|
|
40
|
+
const pool = await getDbPool();
|
|
41
|
+
try {
|
|
42
|
+
const result = await pool.query(sql, params);
|
|
43
|
+
return result.rows;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
47
|
+
console.error(' Error ejecutando query:', msg);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
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 { toolsDefinitions, handleExecuteSql, handleListBuckets, handleCreateBucket, handleDeleteBucket, handleListTables, handleListUsers, handleCreateUser, handleDeleteUser, handleGetSchema, handleGetAdvisors, handleListFiles, handleListRlsPolicies, handleGetActiveConnections, } from './tools/index.js';
|
|
7
|
+
async function main() {
|
|
8
|
+
// 1. Validar la configuración al inicio
|
|
9
|
+
getConfig();
|
|
10
|
+
// 2. Inicializar el servidor MCP
|
|
11
|
+
const server = new Server({
|
|
12
|
+
name: 'supabase-selfhosted-mcp',
|
|
13
|
+
version: '1.0.0',
|
|
14
|
+
}, {
|
|
15
|
+
capabilities: {
|
|
16
|
+
tools: {},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
// 3. Registrar el manejador para listar herramientas (Tools)
|
|
20
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
21
|
+
return {
|
|
22
|
+
tools: toolsDefinitions,
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
// 4. Registrar el manejador para ejecutar herramientas
|
|
26
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
27
|
+
const { name, arguments: params } = request.params;
|
|
28
|
+
switch (name) {
|
|
29
|
+
case 'get_schema':
|
|
30
|
+
return await handleGetSchema(params);
|
|
31
|
+
case 'get_advisors':
|
|
32
|
+
return await handleGetAdvisors();
|
|
33
|
+
case 'list_tables':
|
|
34
|
+
return await handleListTables(params);
|
|
35
|
+
case 'execute_sql':
|
|
36
|
+
return await handleExecuteSql(params);
|
|
37
|
+
case 'list_users':
|
|
38
|
+
return await handleListUsers(params);
|
|
39
|
+
case 'create_user':
|
|
40
|
+
return await handleCreateUser(params);
|
|
41
|
+
case 'delete_user':
|
|
42
|
+
return await handleDeleteUser(params);
|
|
43
|
+
case 'list_buckets':
|
|
44
|
+
return await handleListBuckets();
|
|
45
|
+
case 'create_bucket':
|
|
46
|
+
return await handleCreateBucket(params);
|
|
47
|
+
case 'delete_bucket':
|
|
48
|
+
return await handleDeleteBucket(params);
|
|
49
|
+
case 'list_files':
|
|
50
|
+
return await handleListFiles(params);
|
|
51
|
+
case 'list_rls_policies':
|
|
52
|
+
return await handleListRlsPolicies(params);
|
|
53
|
+
case 'get_active_connections':
|
|
54
|
+
return await handleGetActiveConnections();
|
|
55
|
+
default:
|
|
56
|
+
throw new Error(`Tool not found: ${name}`);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
// 5. Configurar el transporte stdio (entrada/salida estándar)
|
|
60
|
+
const transport = new StdioServerTransport();
|
|
61
|
+
await server.connect(transport);
|
|
62
|
+
console.error(' Servidor MCP de Supabase Self-Hosted iniciado correctamente.');
|
|
63
|
+
}
|
|
64
|
+
main().catch((error) => {
|
|
65
|
+
console.error(' Error fatal al iniciar el servidor MCP:', error);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createClient } from '@supabase/supabase-js';
|
|
2
|
+
import { getConfig } from '../config/env.js';
|
|
3
|
+
let supabaseClient = null;
|
|
4
|
+
/**
|
|
5
|
+
* Inicializa y retorna el cliente de Supabase (usando la Service Role Key para bypassing de RLS).
|
|
6
|
+
*/
|
|
7
|
+
export function getSupabaseClient() {
|
|
8
|
+
if (supabaseClient) {
|
|
9
|
+
return supabaseClient;
|
|
10
|
+
}
|
|
11
|
+
const config = getConfig();
|
|
12
|
+
if (!config.SUPABASE_URL || !config.SUPABASE_SERVICE_ROLE_KEY) {
|
|
13
|
+
throw new Error('SUPABASE_URL y SUPABASE_SERVICE_ROLE_KEY son obligatorias para utilizar las herramientas de Auth y Storage.');
|
|
14
|
+
}
|
|
15
|
+
// Creamos el cliente usando la service role key.
|
|
16
|
+
// IMPORTANTE: En el contexto de un MCP (que actúa como un super admin), es seguro
|
|
17
|
+
// y necesario usar la service role key, pero el usuario debe estar consciente de esto.
|
|
18
|
+
supabaseClient = createClient(config.SUPABASE_URL, config.SUPABASE_SERVICE_ROLE_KEY, {
|
|
19
|
+
auth: {
|
|
20
|
+
autoRefreshToken: false,
|
|
21
|
+
persistSession: false,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
console.error(' Cliente Supabase API inicializado.');
|
|
25
|
+
return supabaseClient;
|
|
26
|
+
}
|