Skip to main content
Glama
odoo-readonly

odoo-readonly

by arisnew
README.md
# MCPOdoo — Odoo Read-Only MCP (Docker)

MCP server untuk **cek data Odoo production/staging** via JSON-RPC (read-only).  
Proyek standalone di luar repo addon. **Satu instance MCP** bisa melayani **beberapa server Odoo** (beda URL/DB/versi) lewat **profile**.

## Persiapan

Clone repo, lalu pilih salah satu mode di bawah. File **`profiles.json`** dan **`.env`** bersifat lokal (ada di `.gitignore`) — jangan di-commit.

### Opsi A — banyak server (disarankan)

```bash
cp profiles.example.json profiles.json
# edit url / db / user per profile (tanpa password)

./scripts/keychain-store.sh prod password
./scripts/keychain-store.sh staging password
docker compose build
```

Opsional di `.env`: `MCPO_ODOO_DEFAULT_PROFILE=staging` dan limit RPC.

### Opsi B — satu server (legacy)

```bash
cp .env.example .env
# ODOO_URL, ODOO_DB, ODOO_USER — password di Keychain: ./scripts/keychain-store.sh default password
docker compose build
```

### Uji image (opsional)

MCP memakai stdio — biasanya lewat Cursor:

```bash
docker compose run --rm -T mcp
# menunggu input JSON-RPC dari stdin; Ctrl+C untuk keluar
```

## Cursor IDE

Tambahkan di **Settings → MCP** (atau merge ke `~/.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "odoo-readonly": {
      "command": "/ABSOLUTE/PATH/TO/MCPOdoo/scripts/run-mcp.sh"
    }
  }
}
```

Ganti path dengan lokasi clone Anda. Contoh lengkap: `cursor-mcp.example.json`.

Script `run-mcp.sh` menjalankan:

`docker compose run --rm -T mcp`  
(`-T` = tanpa TTY, cocok untuk protokol MCP stdio.)

**Penting:** Build image dulu (`docker compose build`). Setiap ubah kode Python, build ulang.

### MCP tidak aktif / error di Cursor

Di **Settings → MCP**, server `odoo-readonly` harus hijau. Jika **Error** / tool discovery gagal:

| Penyebab | Perbaikan |
|----------|-----------|
| **Docker Desktop mati** | Buka Docker Desktop; tunggu “Running”. |
| **`docker` tidak ada di PATH Cursor** | `run-mcp.sh` sudah menambah `/usr/local/bin` & path Docker.app; restart Cursor setelah update script. |
| **Image belum di-build** | `cd MCPOdoo && docker compose build` |
| **Password Keychain** | `./scripts/keychain-store.sh <profile> password` (nama profile = key di `profiles.json`); izinkan **Cursor** akses Keychain jika diminta. |
| **Log MCP** | Cursor: **Output** panel → dropdown **MCP** / **odoo-readonly** — lihat stderr (`MCPOdoo: ...`). |

Tes manual (harus tetap jalan, tidak exit 127):

```bash
/path/to/MCPOdoo/scripts/run-mcp.sh
# menunggu stdio; Ctrl+C
env -i HOME="$HOME" PATH="/usr/bin:/bin" /path/to/MCPOdoo/scripts/run-mcp.sh
# setelah fix PATH di script: tidak boleh "docker not found"
```

Nama server di Cursor: **`odoo-readonly`** (bukan “MCPOdoo”). Tool muncul sebagai namespace **`user-odoo-readonly`**.

## Akses Odoo dari container

- Production HTTPS publik: cukup set `ODOO_URL=https://...` di `.env`.
- Odoo di host lokal (macOS): gunakan `ODOO_URL=http://host.docker.internal:8069` (compose sudah menambah `extra_hosts`).

## Keamanan

- Whitelist method ORM di MCP; denylist model sensitif (`ir.config_parameter`, dll.).
- Buat user Odoo khusus **read-only** + API key; jangan pakai admin.
- Jangan commit `.env`, `profiles.json`, atau password/API key. Detail: [SECURITY.md](SECURITY.md).

### Menyimpan password di MacBook (lebih aman dari plain `.env`)

| Cara | Kelebihan |
|------|-----------|
| **macOS Keychain** (disarankan) | Terenkripsi, bisa Touch ID; `.env` hanya URL/DB/user |
| **1Password / Bitwarden CLI** | `op run --env-file=...` atau inject env saat launch |
| **`.env` chmod 600`** | Minimum; tetap plain text di disk (Time Machine, backup) |

**Keychain (per profile):**

```bash
./scripts/keychain-store.sh prod password
./scripts/keychain-store.sh staging password
# legacy single-server: ./scripts/keychain-store.sh default password
```

Account Keychain: `prod.ODOO_PASSWORD`, `staging.ODOO_PASSWORD`, atau `ODOO_PASSWORD` untuk profile `default`. Service: `MCPOdoo`.

## Beberapa server Odoo (1 MCP)

| Konsep | Keterangan |
|--------|------------|
| `profiles.json` | URL, DB, user per server — **tanpa** password |
| `profile` di setiap tool | Contoh: `odoo_search_read(..., profile="staging")` |
| `odoo_list_profiles` | Daftar profile + versi setelah `odoo_session_info` per server |
| Versi Odoo berbeda | JSON-RPC ORM (`search_read`, dll.) umumnya kompatibel 14–18+; cek `server_version` per profile |

Contoh prompt Cursor:

- “Panggil `odoo_list_profiles`, lalu `odoo_session_info` untuk `prod` dan `staging`.”
- “`odoo_search_read` profile `prod`, model `hr.attendance`, domain …”

**1Password (opsional, tanpa simpan di `.env`):**

```bash
op item get "<your-item>" --fields password --reveal
# atau op run -- docker compose run ...
```

Cursor MCP cukup memanggil `run-mcp.sh`; rahasia tidak perlu ada di `mcp.json`.

## Tool MCP

| Tool | Fungsi |
|------|--------|
| `odoo_list_profiles` | Daftar server yang dikonfigurasi |
| `odoo_session_info` | Cek koneksi & versi server (parameter `profile`) |
| `odoo_search_read` | List record |
| `odoo_read` | Baca by id |
| `odoo_search` / `odoo_search_count` | Id / count |
| `odoo_name_search` / `odoo_fields_get` / `odoo_read_group` | Eksplorasi model |
| `odoo_call_readonly` | Method whitelist lain |
| `odoo_list_installed_modules` | Modul terinstall |

## Tanpa Docker (dev)

```bash
python3.12 -m venv .venv && source .venv/bin/activate
pip install -e .
export $(grep -v '^#' .env | xargs)
odoo-readonly-mcp
```

## Struktur

```
MCPOdoo/
  Dockerfile
  docker-compose.yml
  odoo_readonly_mcp/       # server MCP
  scripts/run-mcp.sh       # entry untuk Cursor
  profiles.example.json    # template multi-server (salin → profiles.json)
  .env.example
  cursor-mcp.example.json
  SECURITY.md
  LICENSE
```

## Lisensi

MIT — lihat [LICENSE](LICENSE).