Servicio MCP que actua como proxy seguro para acceder a las bases de datos de Pampling y a integraciones API externas (Odoo) desde Claude Code y aplicaciones externas. Las credenciales nunca salen del servidor.
| Campo | Valor |
|---|---|
| URL publica | https://globaldb.pampl.ing |
| MCP endpoint (publico) | https://globaldb.pampl.ing/mcp |
| MCP endpoint (red interna Docker) | http://pampling-global-database:8000/mcp |
| REST API proxy (publico) | https://globaldb.pampl.ing/api/proxy |
| REST API proxy (red interna) | http://pampling-global-database:8000/api/proxy |
| Repositorio | git@bitbucket.org:pampling/pampling-global-database.git |
| App UUID (Coolify) | q179bkab6m4lsz7ogg31uzn5 |
| DB UUID (Coolify) | cdb2q3yuzinpx46foncf7uhq |
| Base de datos | globaldb (usuario: globaldb_user) |
| Alias de red Docker | pampling-global-database |
El contenedor tiene configurado un alias estable de red Docker: pampling-global-database. Cualquier otra app en la red coolify puede resolver ese hostname al contenedor actual aunque Coolify lo recree.
Configurado en Coolify via custom_network_aliases=pampling-global-database en la app. Esto hace que la URL interna sea estable y no cambie entre deploys.
Desde una app consumidora desplegada en Coolify:
PAMPLING_DB_MCP_CONTAINER_URL=http://pampling-global-database:8000/mcp
PAMPLING_DB_MCP_AUTHORIZATION=Bearer <token>
Ventajas sobre usar el dominio publico:
Detalle del patron y checklist para integrarlo en apps nuevas: guias/consumir-mcp-desde-apps-coolify.
Verificacion del alias:
docker inspect $(docker ps --filter "name=q179bkab6m4ls" --format '{{.Names}}') \
--format '{{json .NetworkSettings.Networks}}' | jq .
En Aliases debe aparecer pampling-global-database.
@modelcontextprotocol/sdk) — Streamable HTTP transportmysql2), PostgreSQL (pg)Claude Code (MCP) --token--> MCP Server --credenciales--> BD MySQL/PG
Dashboard (REST) --token--> | Odoo (JSON-RPC)
+-- REST API (paneles web)
+-- REST Proxy (apps externas)
+-- PostgreSQL interna (config, permisos, logs)
+-- Paneles admin/usuario (HTML/CSS/JS)
El sistema separa conceptualmente dos tipos de fuente de datos:
connections): MySQL, PostgreSQL, MariaDB. Se consultan con SQL (tool query).integrations): Odoo (read-only). Se consultan con tools especificos por tipo (odoo_search_read).Ambos comparten: auth, token, grupos, logs, monitor. Solo cambia el conector y los tools.
Claude y las aplicaciones nunca reciben credenciales. El flujo:
| Rol | Panel web | MCP / API | Permisos |
|---|---|---|---|
| admin | Panel completo | Acceso a todo | CRUD conexiones, integraciones, usuarios, grupos, permisos; logs y monitor |
| user | Sus BD/integraciones y su historial | Solo los destinos asignados | SELECT en BDs, read en integraciones |
Los usuarios se auto-registran en https://globaldb.pampl.ing/ (pestana Registro). Restriccion: solo emails @pampling.com.
Tras el registro, el usuario esta activo pero sin permisos. Un admin debe asignarlo a un grupo o darle permisos individuales.
Tambien se pueden dar permisos directos usuario-destino.
Si un usuario tiene acceso por grupo y directo al mismo destino, gana el nivel mas alto (write > read).
Cada usuario anade esto a su configuracion de Claude Code:
{
"mcpServers": {
"pampling-db": {
"type": "http",
"url": "https://globaldb.pampl.ing/mcp",
"headers": {
"Authorization": "Bearer TOKEN_DEL_USUARIO"
}
}
}
}
El token se obtiene en https://globaldb.pampl.ing/user/.
| Tool | Descripcion |
|---|---|
list_databases |
Lista las BDs accesibles del usuario |
describe_database |
Esquema de una BD: tablas, columnas, tipos |
query |
Ejecuta SQL (read-only por defecto) |
query_history |
Historial de queries del usuario |
| Tool | Descripcion |
|---|---|
odoo_list_integrations |
Lista las integraciones Odoo accesibles |
odoo_list_models |
Lista los modelos Odoo disponibles (res.partner, sale.order, ...) |
odoo_describe_model |
Campos de un modelo (via fields_get) |
odoo_search_read |
Consulta registros con domain + fields + limit + offset + order |
Limites de odoo_search_read: default limit 50, max 500.
Aplicaciones externas pueden consultar BDs e integraciones via REST sin credenciales directas.
Base URL publica: https://globaldb.pampl.ing/api/proxy
Base URL red interna: http://pampling-global-database:8000/api/proxy
Auth: Authorization: Bearer TOKEN_DEL_USUARIO
| Metodo | Path | Descripcion |
|---|---|---|
GET |
/databases |
Lista BDs accesibles |
GET |
/databases/:nombre/schema |
Esquema de una BD |
POST |
/query |
Ejecuta SQL (body: {database, sql}) |
| Metodo | Path | Descripcion |
|---|---|---|
GET |
/integrations |
Lista integraciones accesibles |
GET |
/integrations/:name/models |
Lista modelos Odoo (opcional ?filter=sale.) |
GET |
/integrations/:name/models/:model/fields |
Campos de un modelo |
POST |
/integrations/:name/search |
search_read (body: {model, domain, fields, limit, offset, order}) |
import requests
BASE = "https://globaldb.pampl.ing/api/proxy"
headers = {"Authorization": "Bearer TU_TOKEN"}
# SQL
dbs = requests.get(f"{BASE}/databases", headers=headers).json()
result = requests.post(f"{BASE}/query", headers=headers, json={
"database": "pampling-production",
"sql": "SELECT * FROM orders LIMIT 100"
}).json()
# Odoo
integrations = requests.get(f"{BASE}/integrations", headers=headers).json()
partners = requests.post(f"{BASE}/integrations/pampling-odoo/search", headers=headers, json={
"model": "res.partner",
"domain": [["is_company", "=", True]],
"fields": ["name", "email"],
"limit": 10
}).json()
| Metodo | Path | Descripcion |
|---|---|---|
POST |
/api/auth/login |
Login -> JWT |
POST |
/api/auth/register |
Registro (solo @pampling.com) -> JWT |
GET |
/api/catalog |
Catalogo publico de BDs, integraciones y grupos |
GET |
/api/health |
Health check |
| Metodo | Path | Descripcion |
|---|---|---|
GET/POST/PATCH/DELETE |
/api/admin/users/* |
CRUD usuarios |
GET/POST/PATCH/DELETE |
/api/admin/connections/* |
CRUD conexiones BD |
GET/POST/PATCH/DELETE |
/api/admin/integrations/* |
CRUD integraciones API (Odoo) |
POST |
/api/admin/integrations/:id/test |
Probar conexion (version + uid) |
GET/POST/DELETE |
/api/admin/permissions/* |
Permisos individuales BD |
GET/POST/PATCH/DELETE |
/api/admin/groups/* |
CRUD grupos |
POST/DELETE |
/api/admin/groups/:id/connections |
Conexiones del grupo |
POST/DELETE |
/api/admin/groups/:id/integrations |
Integraciones del grupo |
POST/DELETE |
/api/admin/groups/:id/users |
Usuarios del grupo |
GET |
/api/admin/logs |
Logs unificados (SQL + integraciones) con filtro ?source=sql|integration|all |
GET |
/api/admin/stats/* |
Metricas de monitoreo (agregadas SQL + integraciones) |
| Metodo | Path | Descripcion |
|---|---|---|
GET |
/api/user/profile/me |
Perfil |
GET |
/api/user/profile/me/databases |
BDs accesibles |
GET |
/api/user/profile/me/integrations |
Integraciones accesibles |
GET |
/api/user/profile/me/groups |
Grupos del usuario |
GET |
/api/user/history |
Historial de queries |
| Tabla | Descripcion |
|---|---|
users |
Usuarios |
connections |
Conexiones BD (password_encrypted) |
permissions |
Permisos directos usuario-conexion |
groups |
Grupos de permisos |
group_connections |
Conexiones dentro de un grupo |
user_groups |
Usuarios en un grupo |
query_logs |
Registro de queries SQL |
| Tabla | Descripcion |
|---|---|
integrations |
Integraciones (Odoo, ...), con config JSONB cifrado |
integration_permissions |
Permisos directos usuario-integracion |
group_integrations |
Integraciones dentro de un grupo |
integration_logs |
Registro de llamadas a integraciones |
Todos los secretos (passwords SQL, api_key de Odoo, etc.) se almacenan cifrados con AES-256-GCM usando ENCRYPTION_KEY. Formato iv:tag:ciphertext en base64.
| Panel | URL | Descripcion |
|---|---|---|
| Login / Registro | / |
Acceso y registro @pampling.com |
| Catalogo publico | /catalog |
BDs e integraciones disponibles (sin auth) |
| Admin - Conexiones | /admin/ |
Gestionar conexiones BD SQL |
| Admin - Integraciones | /admin/integrations.html |
Gestionar integraciones API (Odoo) |
| Admin - Usuarios | /admin/users.html |
Usuarios y sus grupos |
| Admin - Grupos | /admin/groups.html |
Grupos, conexiones, integraciones y usuarios |
| Admin - Logs | /admin/logs.html |
Logs unificados (SQL + API) con filtros |
| Admin - Monitor | /admin/monitor.html |
Dashboard en tiempo real (SQL + API) |
| Usuario - Panel | /user/ |
BDs, integraciones, grupos, token, config MCP |
| Usuario - Historial | /user/history.html |
Historial |
El panel de monitoreo (/admin/monitor.html) muestra metricas unificadas de BDs SQL e integraciones API:
Colores:
Auto-refresh cada 30s (con boton para pausar).
src/
index.ts -- Entry point: Express + MCP
config.ts -- Variables de entorno
db/
connection.ts -- Pool PostgreSQL interna
migrate.ts -- Schema + seed admin
models/ -- user, connection, integration, permission, group, *-connection/integration, *-log
auth/
middleware.ts -- JWT (web) + token (MCP/proxy)
password.ts, token.ts
mcp/
server.ts -- MCP server Streamable HTTP
tools/ -- list-databases, describe-database, query, query-history, odoo-*
api/
auth.routes.ts
proxy.routes.ts -- REST proxy (SQL + integraciones)
admin/ -- users, connections, integrations, permissions, groups, logs, stats
user/ -- profile, history
connectors/
factory.ts -- SQL
mysql.ts, postgresql.ts
odoo.ts -- JSON-RPC 2.0
utils/
encryption.ts -- AES-256-GCM
query-validator.ts -- Valida SELECT-only
frontend/ -- HTML/CSS/JS paneles web
| Variable | Descripcion |
|---|---|
DATABASE_URL |
Connection string PostgreSQL interna |
JWT_SECRET |
Secret para JWT |
ENCRYPTION_KEY |
Clave AES-256 (min 32 chars) |
ADMIN_PASSWORD |
Password del admin inicial |
PORT |
Default 8000 |
NODE_ENV |
production o development |
git push origin main
curl -s -X POST -H 'Authorization: Bearer <COOLIFY_TOKEN>' \
http://192.168.1.10:8000/api/v1/deploy?uuid=q179bkab6m4lsz7ogg31uzn5
/user/)"type": "http" (no streamableHttp, sse ni stdio)execution que anade el SDK 1.29+ (fix aplicado)Solo SELECT, SHOW, DESCRIBE, EXPLAIN. No se permiten INSERT/UPDATE/DELETE ni multiples sentencias separadas por ;.
coolifyENCRYPTION_KEY, los passwords cifrados antiguos fallaranEl proxy usa el mismo token que el MCP. Verificar Authorization: Bearer TOKEN.
La app consumidora no esta en la misma red Docker coolify, o el contenedor pampling-global-database se recreo justo antes. Verificar con docker inspect que el alias esta activo, y que la app consumidora use la misma red.