Skip to main content
Glama
ai-zar

odoo-sh-readonly-mcp

by ai-zar
README.md
# odoo-sh-readonly-mcp 🔒

MCP **solo lectura** para Odoo.sh: builds, entornos, logs y estado del sistema — consultable por una AI sin entrar a la web.

**Sin tools de escritura**: no hay `git push`, ni shell arbitrario, ni escritura de archivos. SSH via `execFile` (sin shell → sin command injection) con comandos whitelisted. El smoke test de CI **falla el build** si alguna vez aparece una tool con nombre de escritura o sin `readOnlyHint`.

---

## 📑 Tabla de contenidos

- [Tools](#-tools)
- [Instalación via imagen GHCR](#-instalación-via-imagen-ghcr-recomendado)
- [Instalación local (Node)](#-instalación-local-node)
- [Configuración](#-configuración)
- [Ejemplos de uso](#-ejemplos-de-uso-con-ai)
- [Nota técnica](#-nota-técnica-modelos-paas)
- [Seguridad](#-seguridad)

---

## 🧰 Tools

| Tool | Fuente | Qué da |
|---|---|---|
| `odoo_sh_overview` | Web API | Repos + branches con stage (production/staging/dev) y último build |
| `odoo_sh_list_builds` | Web API | Builds recientes con **status real** (success/failed/testing) |
| `odoo_sh_model_fields` | Web API | Introspección de campos de modelos `paas.*` |
| `odoo_sh_search_read` | Web API | Query genérica read-only (whitelist `paas.*`) |
| `odoo_sh_logs` | SSH | `tail` de odoo.log / install.log / pip.log (+ filtro) |
| `odoo_sh_system_info` | SSH | Hostname, uptime, disco, memoria, versiones |
| `odoo_sh_databases` | SSH | DBs PostgreSQL y tamaños |
| `odoo_sh_status` | — | Diagnóstico de configuración (sin exponer secretos) |

---

## 🐳 Instalación via imagen GHCR (recomendado)

Cada push a `main` publica una imagen multi-arch (amd64/arm64) en GitHub Container Registry:

```
ghcr.io/ai-zar/odoo-sh-readonly-mcp:latest
```

### 1. Autenticarse contra GHCR

El repo es privado, así que la imagen también. Necesitás un PAT con scope `read:packages`:

```bash
echo $GITHUB_PAT | docker login ghcr.io -u TU_USUARIO --password-stdin
docker pull ghcr.io/ai-zar/odoo-sh-readonly-mcp:latest
```

### 2. Configurar el cliente MCP

**Solo builds/entornos** (sin SSH):

```json
{
  "mcpServers": {
    "odoo-sh": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "ODOO_SH_SESSION_ID",
        "-e", "ODOO_SH_PROJECT",
        "ghcr.io/ai-zar/odoo-sh-readonly-mcp:latest"
      ],
      "env": {
        "ODOO_SH_SESSION_ID": "tu_session_id",
        "ODOO_SH_PROJECT": "mi-proyecto"
      }
    }
  }
}
```

**Con SSH** (logs / system / DBs) — montá la clave privada read-only:

```json
{
  "mcpServers": {
    "odoo-sh": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-v", "/home/usuario/.ssh/odoo_sh:/keys/id:ro",
        "-e", "ODOO_SH_SESSION_ID",
        "-e", "ODOO_SH_SSH_HOST",
        "-e", "ODOO_SH_SSH_USER",
        "-e", "ODOO_SH_SSH_KEY_PATH",
        "ghcr.io/ai-zar/odoo-sh-readonly-mcp:latest"
      ],
      "env": {
        "ODOO_SH_SESSION_ID": "tu_session_id",
        "ODOO_SH_SSH_HOST": "mi-proyecto.dev.odoo.com",
        "ODOO_SH_SSH_USER": "BUILD_ID",
        "ODOO_SH_SSH_KEY_PATH": "/keys/id"
      }
    }
  }
}
```

> ⚠️ En Windows usá rutas estilo `C:\\Users\\usuario\\.ssh\\odoo_sh:/keys/id:ro` en el `-v`.
> `ODOO_SH_SSH_KEY_PATH` siempre apunta a la ruta **dentro** del contenedor (`/keys/id`).

### 3. Probar la imagen a mano

```bash
docker run -i --rm -e ODOO_SH_SESSION_ID=xxx \
  ghcr.io/ai-zar/odoo-sh-readonly-mcp:latest
```

Pegá esto en stdin para ver las tools:

```json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"cli","version":"1"}}}
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
```

---

## 💻 Instalación local (Node)

```bash
git clone https://github.com/ai-zar/odoo-sh-readonly-mcp.git
cd odoo-sh-readonly-mcp
npm install
npm run smoke      # verifica que arranca y expone las 8 tools
```

```json
{
  "mcpServers": {
    "odoo-sh": {
      "command": "node",
      "args": ["C:\\ruta\\absoluta\\odoo-sh-readonly-mcp\\index.js"],
      "env": { "ODOO_SH_SESSION_ID": "tu_session_id" }
    }
  }
}
```

---

## ⚙️ Configuración

| Variable | Requerida | Descripción |
|---|---|---|
| `ODOO_SH_SESSION_ID` | ✅ (web) | Cookie `session_id` de www.odoo.sh |
| `ODOO_SH_PROJECT` | ❌ | Repo por defecto para filtrar |
| `ODOO_SH_BASE_URL` | ❌ | Default `https://www.odoo.sh` |
| `ODOO_SH_SSH_HOST` | ✅ (ssh) | `<proyecto>.dev.odoo.com` |
| `ODOO_SH_SSH_USER` | ✅ (ssh) | `BUILD_ID` o nombre de branch |
| `ODOO_SH_SSH_KEY_PATH` | ✅ (ssh) | Ruta a la clave privada |
| `ODOO_SH_SSH_PORT` | ❌ | Default `22` |
| `ODOO_SH_SSH_TIMEOUT_MS` | ❌ | Default `30000` |

### 🍪 Obtener la cookie de sesión

Odoo.sh **no expone API pública**; su panel web es un Odoo estándar. Se usa tu propia sesión:

1. Logueate en <https://www.odoo.sh>
2. F12 → Application → Cookies → `www.odoo.sh` → copiá `session_id`

La cookie expira: cuando las llamadas fallen con error de sesión, repetí el paso. Los permisos son exactamente los de tu usuario — ni más ni menos.

---

## 💬 Ejemplos de uso con AI

- "¿Cómo están los builds de staging?"
- "¿Falló algún build esta semana en main?"
- "Mostrame los últimos errores del log de producción"
- "¿Cuánto pesa la DB de producción?"
- "Listame todos los entornos y en qué commit está cada uno"

---

## 🔬 Nota técnica: modelos `paas.*`

Los modelos internos de Odoo.sh (`paas.build`, `paas.branch`, ...) no están documentados y sus campos pueden cambiar. Por eso:

- **`resilientSearchRead`**: si un campo no existe, reintenta pidiendo todos los campos legibles
- **`odoo_sh_model_fields`**: la AI puede autodescubrir el schema y después consultar con precisión via `odoo_sh_search_read`

Primera vez, pedile a la AI:

> *"Usá `odoo_sh_model_fields` sobre `paas.build` y después listá los builds con los campos correctos"*

---

## 🛡️ Seguridad

| Riesgo | Mitigación |
|---|---|
| Command injection | SSH via `execFile` (argv, sin shell). Comandos remotos son templates fijos; solo enteros validados y un filtro con whitelist de caracteres se interpolan |
| Escritura accidental | No existen tools de escritura. Whitelist de modelos + de métodos (`search_read`, `read`, `search_count`, `fields_get`, `name_search`) |
| Prompt injection → acción destructiva | Superficie de ataque = solo lectura. Lo peor que puede pasar es leer datos a los que ya tenés acceso |
| MITM en SSH | `StrictHostKeyChecking=accept-new` (TOFU) en vez de `no` |
| Secretos en la imagen | Nada hardcodeado; todo por env vars. Clave SSH se monta read-only en runtime |
| Supply chain | Imagen con attestation de provenance (`actions/attest-build-provenance`) firmada por GitHub |

---

MIT — ver [LICENSE](LICENSE).

TDQS

A3.9/5.0

Scored across 8 tools

Disambiguation4/5

Tools are mostly distinct with clear purposes, though overview and list_builds overlap slightly in build-related information. Overall, each tool targets a specific function and confusion is unlikely.

Naming Consistency5/5

All tools use the consistent 'odoo_sh_' prefix followed by snake_case verbs/nouns, creating a uniform and predictable naming pattern.

Tool Count4/5

8 tools is a reasonable number for a read-only Odoo.sh management surface, covering key areas without being excessive or sparse.

Completeness4/5

The set covers critical read-only operations like builds, logs, system info, databases, and model search. It lacks some advanced operations (e.g., deployment history) but for a read-only utility it is well-rounded.

Maintenance

ActivitySlowing
ResponsivenessNo issues