Skip to main content
Glama
Siana2022

Elementor Gateway MCP

by Siana2022
README.md
# Elementor Gateway MCP

Gateway MCP multi-tenant que conecta Claude con Elementor Pro en los WordPress
de los clientes de Siana Digital, a través del plugin [`msrbuilds/elementor-mcp`](https://github.com/msrbuilds/elementor-mcp)
instalado en cada sitio.

## Estado de este scaffold (versión 2 — corrige los 2 TODOs pendientes de la versión anterior)

- ✅ Validación de `client_secret` implementada (`lib/crypto.ts` → `verifyClientSecret`, comparación en tiempo constante)
- ✅ Sesiones OAuth persistidas en Supabase (`oauth_sessions`), no en memoria — funciona correctamente en el modelo serverless de Vercel
- ⬜ Plugin `msrbuilds/elementor-mcp` — todavía no instalado en ningún WordPress (hazlo primero en un sitio de PRUEBA, no en un cliente real)
- ⬜ Proyecto todavía no desplegado en Vercel

## Arquitectura

```
Claude ──(OAuth 2.1 + PKCE)──> Este Gateway (Vercel) ──> Supabase (sitios, credenciales cifradas, sesiones)
                                     │
                                     └──(Basic Auth / Application Password)──> WordPress del cliente
                                                                                    └── plugin elementor-mcp
```

Tools expuestas a Claude:
- `list_sites` — lista los sitios de clientes conectados
- `list_site_tools` — lista las tools que expone el plugin elementor-mcp en un sitio concreto
- `call_site_tool` — ejecuta una tool concreta (crear página, insertar JSON de Elementor, subir imagen, etc.) en el sitio indicado

## Pasos de despliegue

### 1. Crear el proyecto en Supabase (o usar uno existente)

En el SQL Editor de tu proyecto Supabase, ejecuta el contenido completo de `supabase/schema.sql`.

### 2. Generar la clave de cifrado

```bash
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```

Guarda el resultado — lo necesitas en el paso 4 y para cifrar credenciales de sitios.

### 3. Instalar dependencias localmente (opcional, para probar antes de desplegar)

```bash
npm install
npm run build   # comprueba que compila sin errores de tipos
```

### 4. Desplegar en Vercel

```bash
npm install -g vercel   # si no lo tienes ya
vercel login
vercel link
vercel env add SUPABASE_URL
vercel env add SUPABASE_SERVICE_ROLE_KEY
vercel env add ENCRYPTION_KEY
vercel --prod
```

Mismo patrón que usaste para `mcpseo.vercel.app` con DinoRank.

### 5. Conectar el gateway como conector MCP en Claude — SIN pasos manuales de OAuth

Claude usa **Dynamic Client Registration (DCR)**: se auto-registra la primera vez
que añades el conector, llamando a `/api/oauth/register`. No necesitas crear
ningún cliente OAuth a mano ni generar client_id/client_secret tú mismo.

En Claude, añade un conector personalizado con:
- URL del servidor MCP: `https://<tu-proyecto>.vercel.app/api/mcp`

Claude descubrirá solo el resto (autorización, registro, token) a través de:
- `https://<tu-proyecto>.vercel.app/.well-known/oauth-authorization-server`
- `https://<tu-proyecto>.vercel.app/.well-known/oauth-protected-resource`

Al pulsar "Conectar", Claude te pedirá aprobar el acceso — apruébalo, y ya
debería quedar conectado.

### 6. Instalar el plugin elementor-mcp en UN SITIO DE PRUEBA

No lo instales todavía en un WordPress de cliente real. Instálalo en un WordPress
de pruebas, genera un Application Password para un usuario administrador, y prueba
el flujo completo antes de tocar nada de producción.

### 7. Registrar ese sitio de prueba en Supabase

```bash
ENCRYPTION_KEY=<tu_clave> node scripts/encrypt-key.js "el-application-password-que-generó-wordpress"
```

Copia el resultado y ejecuta en el SQL editor de Supabase:

```sql
insert into public.sites (slug, display_name, site_url, wp_username, wp_app_password_encrypted)
values (
  'sitio-de-prueba',
  'Sitio de Prueba',
  'https://tu-sitio-de-prueba.com',
  'admin',
  '<pega aquí el resultado cifrado>'
);
```

### 8. Conectar el gateway como conector MCP en Claude

En Claude, añade un conector personalizado con:
- URL del servidor MCP: `https://<tu-proyecto>.vercel.app/api/mcp`
- Descubrimiento OAuth: `https://<tu-proyecto>.vercel.app/.well-known/oauth-authorization-server`

### 9. Probar el ciclo completo

Pide a Claude: *"Lista los sitios conectados al gateway"* → debería devolver `sitio-de-prueba`.
Luego: *"Lista las tools disponibles en sitio-de-prueba"* → debería devolver las tools del plugin elementor-mcp.
Si ambos funcionan, ya puedes probar `call_site_tool` para crear una página real de prueba.

## Seguridad — antes de conectar cualquier sitio de cliente real

- Revisa que `SUPABASE_SERVICE_ROLE_KEY` y `ENCRYPTION_KEY` están SOLO en las variables
  de entorno de Vercel (nunca en el repo, nunca en `.env` versionado).
- Las políticas RLS de Supabase están activas pero sin políticas públicas — todo el acceso
  pasa por `service_role` desde las funciones serverless. No añadas políticas públicas
  a estas tablas.
- Considera limitar qué tools del plugin `elementor-mcp` están expuestas por sitio si
  ese plugin permite acciones destructivas (borrar páginas, etc.) — revisa su lista de
  120+ tools y decide si conviene una allowlist antes de dar acceso amplio a un cliente real.

## Estructura del proyecto

```
elementor-gateway-mcp/
├── api/
│   ├── mcp.ts                 # Endpoint MCP principal (tools/list, tools/call)
│   ├── well-known-oauth.ts    # Descubrimiento OAuth
│   └── oauth/
│       ├── authorize.ts       # Paso 1 del flujo OAuth
│       └── token.ts           # Paso 2 del flujo OAuth (con validación de secret)
├── lib/
│   ├── auth.ts                # Verificación de access tokens
│   ├── crypto.ts               # Cifrado AES-256-GCM + hash de secrets
│   ├── supabase.ts             # Cliente Supabase (service_role)
│   └── wp-client.ts            # Cliente hacia el plugin elementor-mcp de cada sitio
├── scripts/
│   ├── encrypt-key.js          # Cifra un Application Password para un sitio nuevo
│   └── create-oauth-client.js  # Genera credenciales OAuth para un client nuevo
├── supabase/
│   └── schema.sql              # Esquema completo de la base de datos
├── .env.example
├── vercel.json
├── package.json
└── tsconfig.json
```