Skip to main content
Glama

Odoo Claude MCP

Production-grade Model Context Protocol (MCP) server suite for Odoo ERP

Odoo MCP server for Claude Code and Claude.ai — turn any self-hosted Odoo instance (15 → 19) into an AI assistant via the Model Context Protocol. 197+ tools, multi-tenant, Bulgaria localization (НАП, ДДС, ЕИК) included.

Connect Claude, Claude Code, and any MCP-compatible client to Odoo, GitHub, filesystem, Portainer, Teams, and more — through a unified, authenticated gateway.

License: AGPL-3.0 Odoo MCP Docker Made by Terraros Commerce

Quick Start · Why this vs alternatives? · Use Cases · Architecture · MCP Servers · Companion Modules · Deployment

Two tracks. You are on branch 3.0 — the preview track for integrators, current v3.3.8. The stable track is branch 2.0, current v2.31.0. All releases: Releases · details in Two Tracks.

🇧🇬 Български README


See Claude editing a live Odoo sale order — real CRUD, real auto-recalculation

Claude Code editing Odoo sale order in real time

▶ Watch the full 4-minute demo: Running Odoo 18 Entirely Through AI — Claude Code + MCP Server


🎯 What is odoo-claude-mcp?

odoo-claude-mcp is a self-hosted MCP server suite that turns any Odoo instance into a first-class citizen in the Claude ecosystem. It exposes Odoo data and operations through the Model Context Protocol, while bundling complementary MCP servers for everything an Odoo developer, consultant, or business user needs — GitHub, OCA modules, Kubernetes/Portainer, Microsoft Teams, and a full Claude Code terminal running in the browser.

Unlike single-purpose MCP wrappers, this stack is built for real production use:

  • 🔐 Unified authentication across all MCP endpoints via token-based auth

  • 🏢 Multi-connection, multi-tenant — one stack serves dozens of Odoo databases

  • 🌐 Claude.ai connector ready — public HTTPS endpoint with token auth

  • ☸️ K3s / Kubernetes native with Kustomize overlays for dev and prod

  • 🐳 Docker Compose for solo developers and small teams

  • 🖥️ Web-based terminal — xterm.js + tmux + Claude Code in the browser

  • 📦 Odoo module deployment via direct RPC (no filesystem access needed)

  • 🔍 Qdrant vector store integration for semantic search across records

  • 🤖 Ollama integration for local LLMs and privacy-first deployments


Related MCP server: MCP Server for Odoo

🚀 Quick Start

Option 1: Docker Compose (local dev)

git clone https://github.com/rosenvladimirov/odoo-claude-mcp.git
cd odoo-claude-mcp

# Configure
cp .env.example .env
nano .env                    # set ODOO_URL, DB, credentials, tokens

# Create the shared Cloudflare tunnel network (one-time per host)
docker network create cloudflare-net

# Start the stack
docker compose up -d

# Verify
docker compose ps
curl http://localhost:8084/health

No Cloudflare tunnel? If you're deploying locally without a Cloudflare sidecar, use the override file instead of creating the external network:

docker compose -f docker-compose.yml -f docker-compose.local.yml up -d

This turns cloudflare-net into a regular Docker bridge network created on demand.

Optional services (Portainer / Teams). The default docker compose up -d starts only the core stack (Odoo RPC, Filesystem, OCA, EE, GitHub, Qdrant, Ollama, Claude Terminal). To also enable the Portainer MCP or Microsoft Teams MCP, opt in with a Compose profile:

docker compose --profile portainer up -d        # core + Portainer
docker compose --profile teams     up -d        # core + Teams
docker compose --profile full      up -d        # everything

Each optional service has its own required env vars (see .env.example). Without them the service container would crash-loop, so they're skipped by default.

First-run troubleshooting. If docker compose ps shows mcp-odoo-rpc in Restarting state, it means the values in .env (ODOO_URL, ODOO_DB, ODOO_USERNAME, ODOO_API_KEY/ODOO_PASSWORD) don't point to a reachable Odoo instance. Edit .env to match a real Odoo and re-run docker compose up -d. The healthcheck curl http://localhost:8084/health will succeed only after mcp-odoo-rpc is Up.

Option 2: Quick installer script

Linux / macOS:

curl -fsSL https://raw.githubusercontent.com/rosenvladimirov/odoo-claude-mcp/2.0/install.sh | bash

Windows (PowerShell as Administrator):

iwr -useb https://raw.githubusercontent.com/rosenvladimirov/odoo-claude-mcp/2.0/install.ps1 | iex

Option 3: Connect to Claude Code

After the stack is running, add it to Claude Code:

claude mcp add odoo-mcp \
  --url https://your-domain.com/mcp \
  --header "Authorization: Bearer YOUR_TOKEN"

Or use the included .mcp.json:

cp claude-terminal/.mcp.json ~/.config/claude-code/mcp.json

⚖️ Why this vs alternatives?

Capability

Raw XML-RPC

Single-purpose MCP-Odoo wrappers

odoo-claude-mcp

Auth

Per-call password

Single shared token

✅ Bearer + per-user profiles + OAuth

Multi-tenant

❌ One DB per process

⚠️ Single connection

✅ N tenants per stack

Tools available

~6 RPC verbs

20–40

✅ 197+ (92 native + 105 proxied)

Memory / context layer

❌

❌

✅ Qdrant vector + Ollama embeddings, per-user + shared

Skills / orchestration

❌

❌

✅ ai.skill records + memory packs

Web terminal in browser

❌

❌

✅ xterm.js + tmux + Claude Code

GitHub / Portainer / Teams / OCA

❌

❌

✅ 8 federated MCP servers

Bulgaria localization

❌

❌

✅ НАП-ready, fiscal positions, VAT

Production deployment

DIY

Docker only

✅ Docker Compose + K3s/Kustomize

Audit logging / rate limit

❌

⚠️

✅ Per-user logs, Cloudflare AI Gateway

License

LGPL (client lib)

Mixed (some MIT, some commercial)

✅ AGPL-3.0 (open, share-alike)

The shorter version: most other MCP-Odoo bridges are great for "one developer wants to talk to one Odoo." odoo-claude-mcp is for teams, agencies, and SaaS providers that need multi-user, multi-database, audited deployments with a unified AI surface.


🎨 Use Cases

For Odoo Developers

  • Live module development with Claude assisting directly on your running instance

  • RPC-based module deployment — update code, views, data without filesystem access

  • Multi-environment workflows — dev, staging, production from a single Claude session

  • OCA contribution flows — clone, search, test, submit PRs through Claude

For Odoo Consultants

  • Manage multiple client databases from one authenticated session

  • Per-client memory — Claude remembers context for each customer

  • Shared team knowledge — memory_share distributes institutional know-how

  • НАП / Bulgaria localization — built-in tools for fiscal positions, VAT compliance

For Business Users

  • "Ask Claude about our sales data" — natural language queries against real Odoo records

  • Document extraction workflows — vision LLMs parse invoices into account.move

  • Semantic search — find similar records, contracts, tickets across the whole database

  • Email & calendar integration — Claude coordinates work across Odoo, Gmail, Calendar

For Platform Operators (SaaS / MSP)

  • Multi-tenant hosting — each client gets an isolated MCP endpoint

  • Billing integration — usage tracking per tenant via Cloudflare AI Gateway

  • White-label terminals — brand claude-terminal for your customers

  • Kubernetes scaling — scale MCP replicas independently based on load


🏗 Architecture

flowchart TD
    A["🧑 Claude.ai · Claude Code · Claude Desktop · IDE"]
    A -->|HTTPS + Bearer token| B
    subgraph GW["odoo-claude-mcp gateway"]
        B["Unified MCP Router · server.py<br/>• Proxies to 7 backend MCP servers<br/>• Per-user profiles &amp; connections<br/>• Shared memory store · audit log"]
    end
    B --> C1["odoo-rpc-mcp<br/>(core, 100+ tools)"]
    B --> C2["ee-mcp<br/>(Odoo EE)"]
    B --> C3["oca-mcp<br/>(OCA repos)"]
    B --> C4["github-mcp"]
    B --> C5["portainer-mcp"]
    B --> C6["filesystem-mcp"]
    B --> C7["teams-mcp"]
    B --> C8["claude-terminal<br/>(xterm.js + tmux)"]
    C1 --> D1["Odoo 15→19<br/>(N tenants)"]
    C1 --> D2["Qdrant<br/>(vector DB)"]
    C1 --> D3["Ollama<br/>(local LLMs)"]

    classDef gw fill:#e0e7ff,stroke:#4338ca,color:#1e1b4b;
    classDef be fill:#f3f4f6,stroke:#6b7280,color:#111827;
    classDef st fill:#fef3c7,stroke:#d97706,color:#451a03;
    class B gw;
    class C1,C2,C3,C4,C5,C6,C7,C8 be;
    class D1,D2,D3 st;

🧰 MCP Servers

Core: odoo-rpc-mcp

The flagship MCP server. 197+ MCP tools (92 native + 105 proxied across Portainer, GitHub, Teams, EE, OCA, filesystem) covering every aspect of Odoo development and operations.

Capabilities:

  • CRUD & Search: odoo_search_read, odoo_create, odoo_write, odoo_unlink, odoo_execute

  • Introspection: odoo_fields_get, odoo_list_models, odoo_module_info

  • Multi-connection: Switch between databases on the fly — odoo_connect, user_connection_activate

  • Web session support: odoo_web_login, odoo_web_call, odoo_web_export, odoo_web_report

  • File operations: odoo_attachment_upload, odoo_attachment_download, public_access_download

  • Reporting: odoo_report, public_access_report_pdf, public_access_report_xlsx

  • Portal access: public_access_portal_orders, public_access_portal_invoices, public_access_portal_tickets

  • Bulgaria l10n: odoo_fp_configure, odoo_fp_list, odoo_fp_details — fiscal positions tailored for НАП compliance

  • Translations ★ 2.10: odoo_list_translatable_fields, odoo_get_field_translations, odoo_translate_field (simple translate=True), odoo_translate_html (html_translate / xml_translate with extract/terms/replace modes). Version-aware (Odoo 16+ native JSONB API, <16 ir.translation fallback). Auto-ZWSP marks identical translations as "kept intentionally" so the website editor stops flagging them as untranslated.

  • Website snippets ★ 2.10: odoo_website_list_snippets, odoo_website_list_page_snippets, odoo_website_add_snippet, odoo_website_update_snippet, odoo_website_remove_snippet. Lxml-based HTML parsing with xpath substitutions — covers blog posts, website pages (via arch_db), product descriptions, mega-menus. Supports background image swaps, CTA insertions, position-relative placement (end/begin/after/before/replace).

  • AI integration: ai_tokenize_record, ai_search_similar, ai_collection_info — Qdrant vector embeddings per Odoo record

  • Memory system: Per-user and shared memory with memory_read, memory_write, memory_share, memory_pull

  • Google services: OAuth, Gmail search/read/send, Calendar CRUD

  • Telegram: MTProto client — send messages, search contacts, read dialogs

  • SSH & Git: Remote command execution, git operations

ee-mcp — Odoo Enterprise Tools

Tools specific to Odoo Enterprise workflows:

  • License validation & status checks

  • EE module repository management

  • Dependency analysis (CE + EE)

  • Selective EE module linking into CE addons paths

  • Conflict detection between Enterprise and OCA modules

oca-mcp — OCA Module Management

Deep integration with the Odoo Community Association ecosystem:

  • Clone individual OCA repos or oca-clone-everything

  • Search across all local OCA repos

  • Generate READMEs, icons, requirements.txt via oca-gen-*

  • Version migration via oca-migrate-branch

  • Changelog generation from newsfragments

claude-terminal — Browser-based Claude Code

A complete xterm.js + tmux + Claude Code setup running in a Docker container:

  • WebSocket gateway (gateway.js) with session isolation

  • Per-user tmux sessions that persist across reconnects

  • Themable terminal (see themes.json — includes Catppuccin, Dracula, Tokyo Night, Gruvbox, etc.)

  • Landing page (landing.html) for public deployments

  • Authenticated via the same token system as other MCP servers

Infrastructure MCPs

  • github-mcp — GitHub API wrapper (search code, issues, PRs, repos)

  • portainer-mcp — Docker/Kubernetes environment management

  • teams-mcp — Microsoft Teams messaging integration

  • filesystem-mcp — Scoped filesystem operations for AI agents


📦 Companion Odoo Modules & Theme

The MCP stack is paired with several Odoo modules and a website theme. Together they turn any Odoo instance into a fully MCP-aware, multi-tenant, billing-ready AI workstation — with an optional editorial website skin on top.

l10n_bg_claude_terminal — Odoo ↔ MCP integration (free / LGPL-3)

Odoo module that exposes MCP + Claude Terminal configuration as user preferences and company settings. Works on Odoo 16, 18 and 19 (each major series has a dedicated branch).

Repos:

🌍 Non-Bulgarian deployments? Use the international fork rosenvladimirov/odoo-mcp-terminal — same module, redistributed without the BG localization dependencies (no НАП fields, no Bulgarian transliteration mixin). Branches 16.0 / 18.0 / 19.0, AGPL-3.0. Recommended for any Odoo instance outside Bulgaria.

What it adds to Odoo:

  • Per-user MCP endpoint + Bearer token config (Odoo UI → Preferences)

  • Per-user Odoo RPC connector (URL, DB, API key, protocol, verify_ssl flag with TOFU cert pinning)

  • Per-user Web Session credentials (for MCP's web session support)

  • Per-user Anthropic API key / OAuth token passthrough (billing account or Claude Pro/Teams/Max)

  • Telegram + Viber MTProto / bot token config

  • 18 terminal themes (Catppuccin, Dracula, Tokyo Night, Gruvbox, …)

  • Claude.ai OAuth login button → one-click auth to Claude API

  • Live refresh bus — MCP odoo_create / odoo_write triggers open form / list views to update in real time (no full reload)

  • Test Connections button — smoke-tests Odoo RPC + MCP + Web Session

    • Qdrant + Ollama in one click (sticky notifications)

  • Save to MCP button — register the user's Odoo alias into the MCP connection store without touching /data/connections.json manually

  • Dynamic XML-RPC db list — populates the Database dropdown from the Odoo instance's list_dbs() (multi-tenant friendly)

l10n_bg_ai_billing — SaaS billing module (OPL-1, paid)

Odoo module for hosting providers and reseller tier management. Tracks per-user MCP usage, calculates bills, provisions Portainer stacks per tenant, ships licensed memory packs.

Repo:

What it adds:

  • 8 models: ai.billing.{bundle, tenant, usage.line, invoice.batch, skill.catalog, memory.pack, memory.deployment, tenant.addon}

  • Bundle pricing — Starter €49 / Business €129 / Professional €299 / Enterprise €599 tiers with per-user / per-call / per-skill usage meters

  • Millicents precision ($0.00001) on usage lines — prevents the 30–40% rounding loss common on cent-based billing

  • Portainer client wrapper — portainer.client wizard creates a per-tenant MCP stack with auto-provisioned port, env, and network

  • AES-256 encrypted ZIP export (via pyzipper) of tenant config bundles for offline demos or DR backups

  • Skill catalog — ai.skill records with L1/L2/L3 disclosure tiers

  • Memory packs — versioned markdown playbooks distributable to tenants via MCP /admin/memory/upload endpoint

  • BG Trade Registry integration — fetches EIK / VAT / legal form from portal.registryagency.bg for tenant bootstrap

  • sale.order integration — selling a bundle SKU auto-provisions the tenant + deploys memory + activates skills

  • MCP Terminal addons — extra per-tenant features (dedicated subdomain, white-label branding)

Dependency on the MCP stack: uses the MCP_ADMIN_TOKEN endpoint family (/admin/memory/*) added in odoo-rpc-mcp 2.8.0.

odoo-mcp-theme — Custom Odoo website theme (free / AGPL-3)

Editorial "paper" theme purpose-built for the MCP Works landing site and any Odoo website that wants a clean, content-first presentation.

Repo: rosenvladimirov/odoo-mcp-theme · branch 19.0 · current: 19.0.x

What it ships:

  • OKLCH paper/ink + indigo colour system — perceptually-uniform palette that prints well, scans well, and adapts to dark mode without losing contrast

  • Custom snippets — pricing cards (5-tier layout), feature grids, setup-wizard CTAs, demo-link blocks, MCP architecture diagrams

  • Vertical timeline language switcher — replaces Odoo's default language dropdown with a sidebar timeline (works well for trilingual EN / BG / RU sites)

  • Editorial typography — measured for long-form posts, runs ≤ 70 chars per line, optimised vertical rhythm

  • Fully #wrapwrap-scoped — no leakage into Odoo backend or Website Builder editor (avoids the $o-color-palettes-name global leak that breaks editor UI in older themes)

Installable on any Odoo 19 instance. Drop it into your addons path, install via Apps, then assign in Website → Configuration → Themes.

Installation order

odoo-mcp-theme            ← optional: editorial website skin
l10n_bg_claude_terminal   ← every user of the MCP terminal
       ↓
l10n_bg_ai_billing        ← hosting providers / resellers / BL-tier ops

l10n_bg_ai_billing depends on l10n_bg_claude_terminal — installing the billing module auto-pulls the terminal integration. odoo-mcp-theme is independent and can be used with or without the MCP stack.


☸️ Deployment

Full Kustomize-based deployment in k3s/:

k3s/
├── base/                    # Base manifests
│   ├── namespace.yaml
│   ├── configmaps.yaml
│   ├── secrets.example.yaml
│   ├── pvcs.yaml
│   ├── odoo-rpc-mcp.yaml
│   ├── ee-mcp.yaml
│   ├── oca-mcp.yaml
│   ├── github-mcp.yaml
│   ├── teams-mcp.yaml
│   ├── portainer-mcp.yaml
│   ├── filesystem-mcp.yaml
│   ├── claude-terminal.yaml
│   ├── qdrant.yaml
│   ├── ollama.yaml
│   └── ingress.yaml
└── overlays/
    ├── direct/              # NodePort + cert-manager-example
    └── prod/                # Ingress with TLS for public endpoints

Deploy:

cd k3s/overlays/prod
cp .env.example .env
cp ../../base/secrets.example.yaml secrets.yaml
# edit secrets.yaml with real values

kubectl apply -k .
kubectl -n odoo-claude-mcp get pods

See k3s/README.md for complete deployment guide including cert-manager, Cloudflare tunnels, and horizontal scaling.

Public deployment pattern

For Claude.ai connector access, the recommended production topology is:

Internet → Cloudflare (DNS + WAF) → Nginx reverse proxy → MCP gateway
                                                              │
                                                              ▼
                                                    Backend MCP servers

Token-based authentication on the gateway ensures only authorized Claude sessions connect. Cloudflare's Zero Trust or simple tunnel setup both work.


🔌 Claude.ai Connector

The stack is designed to be registered as a Custom Connector in Claude.ai (Team/Enterprise) or via the API.

Configuration:

  1. Deploy the stack with a public HTTPS endpoint (e.g., https://mcp.yourdomain.com)

  2. Generate a user token (see odoo_connect_cli.py or Qt GUI)

  3. In Claude.ai Settings → Connectors → Add Custom Connector:

    • URL: https://mcp.yourdomain.com/mcp

    • Auth: Bearer token

  4. The gateway will expose all MCP tools to your Claude conversations

Security features:

  • Per-user profile isolation (/data/users/{username}/)

  • Shared memory vs. personal memory separation

  • Connection-level access control (users only see their own Odoo connections)

  • All tool calls logged per user


🛠 Developer Tools

Beyond MCP servers, the repo includes standalone desktop and CLI tools:

Connection Manager

tools/odoo_connect_qt.py — PyQt6 desktop GUI for managing Odoo connections, SSH keys, and MCP endpoints. Cross-platform (Linux/Windows/macOS).

tools/odoo_connect.py — GTK4/Adwaita alternative for Linux/GNOME users.

odoo-rpc-mcp/odoo_connect_cli.py — Terminal CLI for CI/CD and scripting.

Module Analyzer

tools/odoo_module_analyzer.py — Analyzes Odoo module source for:

  • Manifest validation

  • Dependency graph extraction

  • Model relationships

  • View definitions

  • Security rules

GLB Viewer

tools/glb_viewer.py — 3D model inspection tool for the MRP Design Matrix workflows.

Windows Installer

Pre-packaged NSIS installer (packaging/windows/) produced automatically via GitHub Actions (.github/workflows/build-windows.yml).


📚 Documentation


🔐 Security

  • No credentials in code — all secrets via environment variables or Kubernetes secrets

  • Token-based MCP auth — no shared passwords

  • Per-user data isolation — filesystem and memory scoped to authenticated user

  • OAuth for third-party services — Google, GitHub, Telegram all use standard OAuth flows

  • Connection encryption — HTTPS/WSS everywhere in production deployments

  • Rate limiting — via Cloudflare AI Gateway or ingress controller

  • Audit logging — all MCP tool calls logged with user context

  • Admin console behind a second factor — TOTP (RFC 6238) with one-time recovery codes, optional MCP_ADMIN_REQUIRE_TOTP policy, every session-issuing path gated ★ new in 3.3.8 (see below)

Reporting security issues: please email vladimirov.rosen@gmail.com rather than opening a public issue.

Admin console (/admin)

A hidden web console inside odoo-rpc-mcp for the people who operate a stack: per-user Odoo connections, user provisioning with one-time keys, backups and filestore. Optional and off unless configured.

Env

Meaning

MCP_ADMIN_PATH_PREFIX

Mount path, default /admin; empty disables the console

MCP_BOOTSTRAP_ADMIN

Odoo login that becomes admin on first sign-in

MCP_SECRET_TOKEN / MCP_ADMIN_SESSION_SECRET

Signs session cookies. Required — the console refuses to mount without one

MCP_KEY_PEPPER

≥32 chars. Encrypts TOTP secrets at rest (same pepper as identify_totp_*)

MCP_ADMIN_REQUIRE_TOTP

admins or all — hold users in scope on the Security page until they enrol a second factor

MCP_ADMIN_KNOCK_TOKEN, MCP_ADMIN_ALLOWED_IPS

Optional knock token (?k=) and IP/CIDR allowlist

Second factor. Each user enrols TOTP from Security: password → QR → confirming code → eight one-time recovery codes. Once enrolled, every way of obtaining a session (MCP password, Odoo re-auth, one-time key) asks for the code. Secrets live in /data/users/<login>/totp.json; an admin can reset a user's factor from Users, and the last admin recovers by deleting that file on the volume. Everything is written to /data/admin_audit.log — never the secret or a code.


🌍 Bulgaria Localization

This project is maintained by the OCA l10n-bulgaria maintainer. Bulgarian-specific features are first-class:

  • НАП integration — fiscal position tax action maps, VAT reports

  • l10n_bg_* module family support — fiscal positions, VAT reports, payroll, HR

  • Образец 1 — monthly NAP declaration (Наредба №Н-13/2019)

  • Bulgarian partner identification — UIC/ЕИК, legal forms, NACE activity codes

  • Transliteration — BG ⇄ EN ⇄ GR mixin for partner names

  • НАП справка-декларация — SQL-engine based audit reports

See the Bulgaria-specific OCA modules for the complete ecosystem.


❓ FAQ

Does it work with Odoo Enterprise? Yes. Odoo 15→19 (Community + Enterprise) are all supported via XML-RPC + JSON-RPC. EE-specific tools (license check, EE module discovery, dependency analysis) live in the dedicated ee-mcp server. No Odoo SH-specific hooks — works on any self-hosted Odoo (bare metal, Docker, K3s, Odoo SH outbound).

Is this OCA-approved / on the Odoo Apps Store? The companion modules (l10n_bg_claude_terminal, the broader l10n-bulgaria family) are maintained by the OCA l10n-bulgaria maintainer. The MCP server itself is an independent project (not an Odoo app), AGPL-3.0, distributed via Docker Hub + GitHub. Track 3.x will publish a SaaS billing module on the Odoo Apps Store separately.

BYOK (bring your own Anthropic key) — is it safe? Yes. Each authenticated user can configure their own Anthropic API key via the Odoo UI (Preferences → Claude Terminal). Keys are stored encrypted in the per-user profile (/data/users/{username}/) and never leak to other tenants. The server never bundles a shared Anthropic key into multi-tenant deployments.

Can one stack serve multiple Odoo databases? Yes — that's the core design. One MCP server instance proxies to N Odoo connections, each with its own credentials, language, and timezone. odoo_connect / user_connection_activate switch the active database mid-session. Per-user memory namespaces keep context isolated.

Does it require Cloudflare? No. Cloudflare is the recommended production topology (Tunnel + WAF + AI Gateway), but the stack runs fine behind any reverse proxy (Nginx, Traefik, Caddy) or directly on a LAN/VPN. The docker-compose.local.yml override removes the Cloudflare network requirement for local dev.

What's the difference between this and Rutger Klabbers's odoo-mcp-pro? Different scope. odoo-mcp-pro is a focused single-user/single-DB Odoo MCP wrapper. odoo-claude-mcp is a multi-tenant gateway with 7+ federated MCP servers (Odoo + GitHub + OCA + Portainer + filesystem + Teams + claude-terminal), per-user authentication, audit logging, and a companion Odoo billing module for SaaS providers. Both projects are open source — pick the one that matches your deployment shape.

Can I run only the parts I need? Yes. Compose profiles gate optional services: docker compose up -d starts only the core (no Portainer, no Teams). Use --profile portainer / --profile teams / --profile full to add them. K3s overlays are similarly modular.


🛤 Two Tracks — Which Branch Do You Want?

This project ships on two parallel branches, each targeting a different audience. Most users want Track 2.x; the 3.x track is for integrators building hosted offerings on top of the stack.

🧑‍💼 Track 2.x — End Users (current stable, branch 2.0)

Who: Odoo end-users, accountants, Bulgarian SMEs, developers who work with a single Odoo stack, content teams managing website/blog.

What you get:

  • All 188+ MCP tools for day-to-day Odoo work (CRUD, search, RPC, introspection, attachments, reports, web session)

  • Multi-language field management (odoo_translate_field + odoo_translate_html + 2 helpers — covers blog.post, product descriptions, website pages, arch_db) ★ new in 2.10

  • Website snippet management (list / add / update / remove snippets on blog posts and pages, with background image swaps and substitutions) ★ new in 2.10

  • Bulgaria localization (fiscal positions, VAT, НАП integration)

  • AI tokenizer (Qdrant + Ollama embeddings per Odoo record)

  • Memory system (shared + per-user + licensed memory packs)

  • Google / Telegram / Teams integration

  • Claude.ai connector — Bearer-token HTTPS endpoint ready

Docker tags: :latest, :stable, :2.x.y (current: 2.31.0)

Documentation: this README

🔧 Track 3.x — Implementers / Integrators (preview, branch 3.0)

Who: Odoo implementation partners, OCA community contributors, SaaS MSPs running multiple client instances, integrator agencies.

What's planned (development — not production yet):

  • Admin lifecycle tools — odoo_module_install/upgrade/uninstall/ diff, odoo_config_apply, odoo_health_check, odoo_backup_db / restore_db

  • Industry skill packs — Manufacturing, Retail, Services, BG Localization, AI Accounting Assistant. Each pack = modules + ai.skill records + memory packs + pipeline steps.

  • Demo builder — one-command generator of fresh demo environments (mcp demo create --industry=... --seed=...). Tenant + Odoo DB + demo data + skills + memory in < 5 minutes.

  • Module dev + test toolkit — odoo_module_scaffold / lint / test / install_from_path / explain, odoo_xml_validate.

Already shipping on 3.x: self-service provisioning (/provision), supervisor + fleet tools, OAuth hardening with mandatory PKCE (3.3.6), TOTP second factor for MCP name-identify (3.3.0) and for the admin console (3.3.8, see Security above).

Docker tags: :next, :3.x.y (current: 3.3.8)

Documentation: docs/integrator-platform.md (coming soon — see project memory roadmap_integrator_platform.md for the full 4-track spec)

Positioning: the 3.x track shifts buyer persona from the final Odoo user to the integrator / partner / agency — giving them the tools to deploy, configure, and demo Odoo + AI workflows for their own clients at scale.


🗺 Roadmap

  • Billing module — l10n_bg_ai_billing 19.0.1.3.0 shipped (4 tiers, millicents precision, Portainer auto-provisioning)

  • Invoice AI integration — l10n_bg_ai_pipeline + l10n_bg_ai_invoice_glue shipped (98.5% conf EAD OCR, Odoo 18+19, end-to-end tokenize)

  • Self-service tenant provisioning — v3 /provision endpoint LIVE on mcp.odoo-shell.space (Apr 2026)

  • Multi-tenant admin dashboard — admin UI for managing hosted MCP instances

  • Skills marketplace — publish and subscribe to pre-built Odoo workflows (ai.skill records + memory packs)

  • Audit log UI — searchable web UI for MCP tool call history

  • Self-healing connections — automatic retry with token refresh on auth failures


🤝 Contributing

Contributions welcome! This project follows OCA conventions:

  1. Fork the repo

  2. Create a feature branch (git checkout -b feature/amazing-thing)

  3. Follow PEP 8 / Odoo coding guidelines

  4. Add tests where applicable

  5. Submit a PR with a clear description

For large changes, please open an issue first to discuss approach.


📜 License

This project is licensed under the AGPL-3.0 license. See LICENSE for details.


🙏 Credits & Acknowledgements


⭐ Star History

Star History Chart

If this project helps you, please consider starring the repo — it helps others discover the work and motivates further development.


👤 Maintainer

Rosen Vladimirov — Terraros Commerce Ltd. Odoo Silver Partner · OCA l10n-bulgaria maintainer · 10+ years of Odoo specialization

📧 Email: vladimirov.rosen@gmail.com 🐙 GitHub: @rosenvladimirov 🏢 Company: Terraros Комерс ЕООД · Bulgaria


Made with ❤️ and ☕ in Bulgaria 🇧🇬

Available Tools

138 tools
ai_collection_infoB

Return info about the per-database Qdrant collection: vector size, distance metric, point count, indexed-vectors count, plus Odoo-side indexed-document count for cross-check.

Inputs: connection.

ai_invoice_extractA

Extract structured invoice data from an Odoo attachment via Anthropic Vision. Auto-routes to haiku/sonnet/opus based on pages+size. Writes extract_prefill_data back to account.move (if write_back). Logs usage to the billing ledger with token counts + cost in millicents.

Inputs: attachment_id (required), source, move_id, connection, +4 more.

ai_invoice_pipeline_runB

Execute the full registered step pipeline for one move+attachment. Steps: probe_move → guard_already_extracted → extract_vision → log_usage → write_back_move → invoke_posting_skill + any loaded plugins. Returns step-by-step audit trail.

Inputs: move_id (required), source, connection, tenant_code, +3 more.

ai_invoice_pipeline_stepsA

List currently registered pipeline steps with sequence, description, and plugin vs built-in provenance. Useful for debugging which steps will run against a move.

Inputs: no named parameters.

ai_invoice_pipeline_summaryB

Dashboard aggregation: counts of vendor bill moves by next_step across the last 60 days. Use for header KPI cards.

Inputs: connection, tenant_code.

ai_invoice_plugins_reloadA

Reload plugin steps from the plugins directory (default /data/plugins/ai_invoice). Called after uploading a new plugin without restarting the server.

Inputs: plugins_dir.

ai_invoice_scan_pendingA

List vendor-bill drafts that have an attachment and no successful extraction yet. Oldest first (FIFO). Feeds batch processing. Set requested_only=true to return only moves explicitly queued by the l10n_bg_ai_invoice_glue attachment auto-trigger (ai_pipeline_requested=True) — recommended for cron drivers.

Inputs: limit, connection, tenant_code, requested_only.

ai_invoice_stack_inspectA

Cross-layer snapshot for a single account.move: Odoo state + attachments + extraction history + skill status + decided next_step with blockers and hints. Read-only.

Inputs: move_id (required), connection, tenant_code.

ai_list_documentsC

List ai.composite.document records (tokenized records tracked by Odoo). Useful for monitoring tokenization progress / errors.

Inputs: limit, model, state, connection.

ai_pipeline_runA

Execute an Odoo-defined pipeline (ai.pipeline.step records for the given pipeline name, ordered by sequence). Respects skill_id + trigger_domain + on_error. MCP-native steps (model starts with 'mcp') are dispatched to the local registry; other steps are invoked via RPC on the configured Odoo model.method. Writes back last_run_state/message per step.

Inputs: pipeline (required), source_id (required), source_model (required), extra_ctx, +4 more.

ai_pipeline_step_executeA

Execute a single ai.pipeline.step by name via Odoo RPC. Looks up the step in Odoo by name, builds a ctx from the supplied parameters, calls env[step.model].step.method(ctx), and returns the updated ctx (with composite_fields populated by the step). Use ai_pipeline_steps_list to discover available step names.

Inputs: source_id (required), step_name (required), source_model (required), extra_ctx, +2 more.

ai_pipeline_steps_listA

List ai.pipeline.step records in Odoo for a given pipeline name. Shows sequence, model.method, skill_id, on_error, last run state — mirrors the Odoo Settings view.

Inputs: pipeline, connection, include_inactive.

ai_search_similarA

Semantic search across tokenized Odoo records. Embeds the query with the configured provider, searches the per-DB Qdrant collection. Filterable by model, view_type, company. Returns ranked hits with score + snippet.

Inputs: query (required), limit, model, view_type, +3 more.

ai_tokenize_collectionA

Tokenize ALL records of a model via the registry entry. Heavy operation — for large models prefer the nightly cron. Returns count of processed records.

Inputs: model (required), view_type, connection.

ai_tokenize_recordB

Tokenize a single Odoo record: build composite document, embed via configured provider, upsert to Qdrant. Synchronous — returns final state.

Inputs: id (required), model (required), view_type, connection.

ai_usage_budget_statusB

Current month's vision spend vs configured cap. Reads res.company.ai_monthly_budget_eur (requires l10n_bg_ai_invoice_glue) and sums billed ai_usage_log rows. Returns spent, limit, remaining, % used. limit_eur=0 means no cap configured.

Inputs: connection, tenant_code.

ai_usage_log_exportA

Export billing ledger rows as CSV for a tenant + date range. Used for month-end invoice generation and audit trails.

Inputs: date_to, date_from, connection, tenant_code.

ai_usage_log_queryA

Query the AI usage billing ledger. Filter by tenant, state, source, date range. Returns detailed rows for audit + monthly reconciliation.

Inputs: limit, state, offset, source, +5 more.

ai_usage_log_statsA

Dashboard KPIs for the billing ledger: totals, per-model breakdown, 30-day timeseries, recent errors, derived metrics (cache hit rate, avg cost per billed doc, monthly €).

Inputs: period, connection, tenant_code.

github_apiA

Call GitHub REST API directly. Uses the GitHub token from local_profile.json. For operations not covered by the GitHub MCP server, or when it's not running.

Inputs: endpoint (required), body, method, params.

git_remoteB

Run git commands on a remote server via SSH. Shortcut for common git operations (pull, status, log, branch, diff) on remote repositories. Provide the connection alias and repo path.

Inputs: operation (required), repo_path (required), connection (required), args, +2 more.

google_authA

Authenticate with Google OAuth2 for Gmail and Calendar access. Requires credentials.json from Google Cloud Console (Desktop app type). First call opens browser for consent. Token is saved for reuse.

Inputs: credentials_file.

google_auth_statusB

Check Google authentication status.

Inputs: no named parameters.

google_calendar_create_eventC

Create a new calendar event.

Inputs: end (required), start (required), summary (required), location, +4 more.

google_calendar_delete_eventC

Delete a calendar event.

Inputs: event_id (required), calendar_id.

google_calendar_eventsB

List upcoming calendar events. Supports time range and text search.

Inputs: query, time_max, time_min, calendar_id, +1 more.

google_calendar_listA

List all available Google calendars.

Inputs: no named parameters.

google_calendar_update_eventB

Update an existing calendar event. Only provided fields are changed.

Inputs: event_id (required), end, start, summary, +5 more.

google_gmail_labelsA

List all Gmail labels (folders).

Inputs: no named parameters.

google_gmail_readA

Read a specific Gmail message by ID. Returns full body, headers, and labels.

Inputs: message_id (required).

google_gmail_sendB

Send an email or reply to an existing message.

Inputs: to (required), body (required), subject (required), cc, +3 more.

identifyA

Identify yourself to load your personal settings and connections. Call this at the start of a session. Returns your saved connections.

Inputs: name (required).

mcp_terminal_get_configA

Generate a password-protected ZIP archive with the Claude Terminal configuration keys (MCP, Qdrant, Embeddings) for the requesting tenant. Anthropic API key is NOT included by default (set include_anthropic=true to embed it). Returns base64-encoded ZIP + a temporary password (shown ONCE — copy it now). Use the password in the Odoo Setup Wizard (Settings → Technical → Настройка с ZIP конфигурация) to apply the config across res.company + res.users records in 5 guided steps.

Inputs: connection, tenant_code, include_anthropic.

memory_deleteC

Delete a memory file from personal or shared storage.

Inputs: filename (required), scope.

memory_listA

List memory files. Shows personal files (for current user) and shared files. Use scope='personal', 'shared', or 'all' (default).

Inputs: scope.

memory_pullA

Pull shared memory file(s) into your personal storage. Use filename='*' to pull ALL shared files at once. If a file already exists locally, it gets overwritten with the shared version.

Inputs: filename (required).

memory_readA

Read a memory file by filename. Searches personal first, then shared.

Inputs: filename (required), scope.

memory_shareA

Share personal memory file(s) — copies to shared storage so colleagues can pull. Use filename='*' to share ALL personal files.

Inputs: filename (required).

memory_writeA

Write/update a memory file. Saves to personal storage by default. Content should be markdown with YAML frontmatter (name, description, type).

Inputs: content (required), filename (required), scope.

odoo_attachment_downloadA

Download an ir.attachment from Odoo by ID. Returns filename, mimetype, size, and base64-encoded content.

Inputs: attachment_id (required), save_path, connection.

odoo_attachment_uploadA

Upload a file as an ir.attachment on an Odoo record. Returns the attachment ID which can be used with odoo_message_post (attachment_ids parameter) or linked to any record.

Inputs: model (required), res_id (required), filename (required), content_base64 (required), +2 more.

odoo_cert_infoA

Return the pinned SSL certificate details (issuer, subject, notAfter, fingerprint) for a connection. Useful to verify which self-signed cert MCP has trusted. Requires verify_ssl=False on the connection.

Inputs: alias.

odoo_cert_refreshA

Re-fetch the peer SSL certificate for a connection and overwrite the pinned copy. Use after the server's self-signed cert was rotated. Fails if the connection has verify_ssl=True (standard CA verification does not need pinning).

Inputs: alias.

odoo_connectA

Add/update an Odoo connection. Auth via password or API key. Protocol: xmlrpc (Odoo 8+) or jsonrpc (Odoo 14+).

Inputs: db (required), url (required), username (required), alias, +4 more.

odoo_connectionsA

List all configured Odoo connections.

Inputs: no named parameters.

odoo_createB

Create one or more records. Returns list of new IDs.

Inputs: model (required), values (required), connection.

odoo_disconnectC

Remove an Odoo connection.

Inputs: alias.

odoo_executeA

Execute any model method via execute_kw. Use for workflow actions (action_confirm, action_done), custom methods, or anything not covered by CRUD tools.

Inputs: model (required), method (required), args, kwargs, +1 more.

odoo_fields_getB

Get field definitions for an Odoo model. Returns field names, types, labels, and attributes.

Inputs: model (required), attributes, connection.

odoo_fp_configureA

Add or update a tax action map entry for a fiscal position (l10n_bg_tax_admin). Provide action_id to update existing entry, or position_id to create new. Use odoo_fp_types for available selection values.

Inputs: action_id, move_type, account_id, connection, +9 more.

odoo_fp_detailsB

Get detailed fiscal position with all tax action map entries (l10n_bg_tax_admin). Returns position info plus full action mappings: move types, BG move types, VAT types, document types, narrations, replacement rules, etc.

Inputs: position_id (required), connection.

odoo_fp_listA

List fiscal positions with tax action map summary (l10n_bg_tax_admin). Shows position name, auto_apply, country, company, and action mapping count.

Inputs: name, limit, company_id, connection, +1 more.

odoo_fp_remove_actionC

Remove a tax action map entry from a fiscal position (l10n_bg_tax_admin).

Inputs: action_id (required), connection.

odoo_fp_typesA

Get available selection values for fiscal position configuration (l10n_bg_tax_admin). Returns move_types, bg_move_types, doc_types, and type_vat. Use as reference when calling odoo_fp_configure. Set live=true to fetch current values from Odoo instead of cached.

Inputs: live, connection.

odoo_get_field_translationsA

Read current translations for a translatable field on a record. For simple translate=True fields returns {lang: value}. For html_translate/xml_translate fields returns {lang: {term: value}}. Auto-detects the translate type via fields_get. Works on blog.post.content, blog.post.name, product.template.website_description, ir.ui.view.arch_db, any res.partner.name with translate=True, etc.

Inputs: model (required), res_id (required), field_name (required), connection.

odoo_list_modelsC

List available Odoo models (ir.model). Optionally filter by name pattern.

Inputs: limit, pattern, connection.

odoo_list_translatable_fieldsA

List all translatable fields on an Odoo model. Returns per-field: translate type ('simple' for translate=True, 'html' for html_translate, 'xml' for xml_translate, 'callable' for other), field type, label, help. Use this to discover which fields on blog.post, product.template, website.page, res.partner, etc. can be translated.

Inputs: model (required), connection.

odoo_message_postA

Post a message or internal note on any Odoo record (chatter). Body supports Markdown formatting (headers, bold, italic, tables, code blocks) — automatically converted to HTML. Use message_type='note' for internal notes (employees only) or 'comment' for public messages (visible to followers).

Inputs: body (required), model (required), res_id (required), subject, +4 more.

odoo_module_infoA

Get detailed information about an Odoo module: Odoo RPC state + filesystem locations (OCA, EE, custom repos). Shows where the module physically exists, its manifest, dependencies, and installation status.

Inputs: module (required), connection.

odoo_readB

Read specific records by IDs.

Inputs: ids (required), model (required), fields, connection.

odoo_record_backupA

Read full field snapshot of one or more records (any model) and return as a JSON structure. Use BEFORE destructive operations to capture state for possible rollback. Returns a dict with metadata (date, connection alias, model, ids, field count) plus the records themselves. Does NOT write to disk — caller decides what to do with the JSON.

Inputs: ids (required), model (required), connection, include_related.

odoo_refreshA

Send a refresh notification to the user's Odoo browser tab. Call this after creating, updating, or deleting records so the user's list/form/kanban view reloads automatically. Requires l10n_bg_claude_terminal module installed on the Odoo instance.

Inputs: model, res_id, connection.

odoo_reportC

Generate a PDF report for records. Returns base64-encoded PDF.

Inputs: ids (required), report_name (required), connection.

odoo_search_countC

Count records matching a domain.

Inputs: model (required), domain, connection.

odoo_search_readC

Search and read records in one call. Most common operation.

Inputs: model (required), limit, order, domain, +3 more.

odoo_stock_close_unaccounted_valueA

Create an Inventory Valuation journal entry (Dr stock valuation / Cr GRNI/stock-input) for a stocked movement that was valued but not accounted (account_move_id=false), then bind the new account.move back to the record. Version-aware: works on stock.valuation.layer (Odoo 14-18) OR stock.move (Odoo 19+). GRNI account auto-detection order: (a) v14-18 → category.property_stock_account_input_categ_id; (b) v19 with l10n_bg_stock_account → category.l10n_bg_stock_input_account_id; (c) v19 vanilla → category.account_stock_variation_id (fallback). User can override via grni_account_id parameter. Refuses if record is already accounted or category is not real_time. ALWAYS use dry_run=true first.

Inputs: record_id (required), date, dry_run, connection, +2 more.

odoo_stock_initial_deleteA

Delete wrong opening stock balances — cascade-removes stock.move (is_inventory=TRUE) records, their stock.move.line, and (v14-v18) stock.valuation.layer; then zeros out stock.quant on affected (product, location, lot). Bypasses Odoo's ORM guard 'You can not delete product moves if the picking is done' via raw SQL in an ir.actions.server + env.cr.commit(). Version-aware: v14-v18 DELETEs SVL→SML→SM; v19 DELETEs SML→SM (SVL doesn't exist). PRE-FLIGHT: refuses if any affected SVL/stock.move has account_move_id set (orphan journal entries would remain). Caller must reverse those first. ALWAYS writes a full JSON backup to /backups// BEFORE any delete. ALWAYS use dry_run=true first to see the impact scope.

Inputs: tz (required), company_id (required), date_to, dry_run, +3 more.

odoo_stock_initial_importA

Import opening stock balances (initial inventory) via direct SQL INSERT, bypassing ORM overrides (e.g. custom modules that null out stock.move.name). Version-aware: v14-v18 creates stock.move + stock.move.line + stock.valuation.layer + stock.quant; v19 creates stock.move (with value/price_unit/remaining_qty/remaining_value/is_valued=true/is_in=true fields — SVL does not exist) + stock.move.line + stock.quant. All datetimes anchored at 23:59:59 in the caller's timezone, converted to UTC before INSERT. Writes a JSON snapshot to /backups// before execution. ALWAYS use dry_run=true first to preview the plan and catch category/location/product errors. For real_time valuation, follow up with odoo_stock_initial_opening_journal to book the account entry (SQL INSERT does NOT create account.move).

Inputs: tz (required), items (required), company_id (required), accounting_date (required), +3 more.

odoo_stock_initial_opening_journalA

Book the opening-balance journal entry for a previous SQL-inserted initial stock (complements odoo_stock_initial_import — SVL/stock.move written via raw SQL do NOT auto-create account.move even for real_time valuation). Creates ONE account.move (MISC journal, state=posted) with: DR lines grouped by category.property_stock_valuation_account_id (e.g. 302 Materials, 303 Products); CR contra account (default: code '122000' Retained earnings from prior years). Version-aware: v14-v18 reads stock.valuation.layer for the date; v19 reads stock.move (is_inventory=true, is_valued=true) for the same date — totals the 'value' column. DUPLICATE GUARD: before create, scans account.move.line for the same accounts on the same date — if any posted lines found, refuses and returns them (Alpinter lesson: comprehensive opening entries often already include the stock lines). ALWAYS use dry_run=true first.

Inputs: tz (required), company_id (required), accounting_date (required), ref, +5 more.

odoo_stock_mo_delete_draftA

Safely DELETE a draft or cancelled mrp.production with cascade (raw stock.moves, finished stock.moves, procurement.group if orphaned). Bypasses Odoo's ORM 'cannot be deleted' constraint by forcing state='cancel' via raw SQL, then using DELETE statements inside an ir.actions.server. Refuses if MO has any SVL, stock.move with quantity > 0, or an already-done state. ALWAYS use dry_run=true first.

Inputs: mo_id (required), dry_run, connection.

odoo_stock_product_flip_to_storableA

Flip a product from consumable (is_storable=false) to storable (is_storable=true) when the product ALREADY has stock.move records. Bypasses Odoo's ORM constraint 'You can not change the inventory tracking of a product that was already used' via raw SQL in an ir.actions.server. Then inserts a stock.quant DIRECTLY (not through an inventory adjustment wizard) so no duplicate SVL is created — existing SVLs stay intact. Use when a GRN/bill was recorded for a product that was mistakenly set as consu. ALWAYS use dry_run=true first to preview impact. Returns full pre/post snapshot.

Inputs: in_date (required), quantity (required), company_id (required), product_id (required), +3 more.

odoo_translate_context_awareA

Translate Odoo records using Claude with rich domain context for natural, fluent results (not literal). AUTO-DETECTS field kind and handles both: (1) simple char/text fields (e.g. ir.ui.menu.name, account.account.name) → batch translate via update_field_translations; (2) HTML/XML fields (e.g. ir.ui.view.arch_db, website.page, product.template.website_description) → extracts canonical terms via get_field_translations, translates each term preserving inline HTML tags (, , ...), writes back in terms mode. Context to LLM: Odoo model, parent chain for menus, existing translations, user-supplied domain hint, field kind (simple/html/xml). Requires Odoo 16+. Requires ANTHROPIC_API_KEY env var (per-tenant override: ANTHROPIC_API_KEY_). Recommended models: 'claude-haiku-4-5' (menu labels, fast), 'claude-sonnet-4-6' (balanced, website pages), 'claude-opus-4-7' (complex legal/accounting terminology). ALWAYS use dry_run=true first to review proposals.

Inputs: ids (required), model (required), target_lang (required), dry_run, +6 more.

odoo_translate_fieldA

Write translations for a simple translate=True field (Char/Text/Selection). Use for: blog.post.name/subtitle/teaser, product.template.name, res.partner.name, account.account.tag.name — any short/plain field. Format: translations = {lang_code: value, ...}. Pass value=null/'' to remove a language's translation (falls back to source_lang). Errors if field.translate is not True (use odoo_translate_html for HTML). Auto-detects Odoo version: v16+ uses update_field_translations() native API, older falls back to ir.translation.

Inputs: model (required), res_id (required), field_name (required), translations (required), +4 more.

odoo_translate_htmlA

Write/read translations for translate=html_translate / translate=xml_translate fields. Use for: blog.post.content, product.template.website_description, hr.job.description, ir.ui.view.arch_db (covers website.page), website.menu.mega_menu_content, event.track.description, forum.forum.guidelines, res.partner.website_description. Three modes: (a) mode='extract' — READ-ONLY. translations arg ignored. Returns the list of translatable terms that Odoo's html_translate engine extracts from source_lang. Each term is an HTML-serialised translatable block (preserves inline tags like ). Use this to see what must be translated before writing. (b) mode='terms' — translations = {lang: {source_term: translated_term, ...}} Direct term map. Terms must match exactly those from mode='extract'. Calls update_field_translations() with JSONB payload. (c) mode='replace' — translations = {lang: full_html_string}. The tool writes each language's HTML through Odoo's native ORM with {'lang': } context. Odoo's html_translate engine aligns terms automatically — no manual term extraction required. This is what Odoo's Website editor does internally. Errors if field.translate is not callable. Requires Odoo 16+.

Inputs: model (required), res_id (required), field_name (required), mode, +5 more.

odoo_versionC

Get Odoo server version info.

Inputs: connection.

odoo_web_callB

Call any Odoo model method via web session (JSON-RPC /web/dataset/call_kw). Works like odoo_execute but uses cookie session instead of XML-RPC.

Inputs: model (required), method (required), args, kwargs, +1 more.

odoo_web_exportC

Export records to structured data via web session (Odoo export_data).

Inputs: model (required), fields (required), domain, connection, +1 more.

odoo_web_loginA

Login to Odoo web interface with user/password. Creates a persistent cookie session for accessing web controllers, exports, reports, and any frontend URL. Session is reused until logout or expiry.

Inputs: db, url, login, password, +1 more.

odoo_web_logoutC

Destroy web session and logout.

Inputs: connection.

odoo_web_readB

Search and read records via web session (frontend web_search_read format). Supports field specification, domain, limit, offset, order.

Inputs: model (required), fields (required), limit, order, +3 more.

odoo_web_reportC

Download PDF report via web session. Returns base64-encoded PDF.

Inputs: ids (required), report_name (required), save_path, connection.

odoo_web_requestC

Raw HTTP request to any Odoo controller URL via web session. Access frontend pages, custom controllers, website routes, etc.

Inputs: path (required), data, method, params, +1 more.

odoo_website_add_snippetA

Insert a snippet into a target HTML field. Fetches the snippet template from ir.ui.view by key, extracts its root HTML element, applies optional substitutions (text/attr/src changes before insertion), and places it at the specified position relative to an anchor. Positions: 'end' (after last element), 'begin' (before first), 'after' (after anchor_xpath), 'before' (before anchor_xpath), 'replace' (replace anchor_xpath). Substitutions format: {'relative_xpath': value} for text; {'relative_xpath/@attr': value} for attribute; {'relative_xpath/@style:background-image': 'url(...)'} for CSS property; {'relative_xpath/@src': 'https://...'} for image URL.

Inputs: model (required), res_id (required), field_name (required), snippet_key (required), +6 more.

odoo_website_list_page_snippetsA

List snippets currently embedded in a target HTML field. Target can be a blog.post (field=content), website.page (field=arch_db via view_id), product.template (field=website_description), or any HTML field. Parses the HTML with lxml, finds all elements bearing a data-snippet attribute. Returns per-snippet: index, data_snippet, data_name, xpath, text_preview, has_background (detects url() in style), background_url.

Inputs: model (required), res_id (required), field_name (required), lang, +1 more.

odoo_website_list_snippetsA

List available Odoo website snippet templates (ir.ui.view records with key matching 'website.s_*' or similar). Returns per-snippet: key, name, module, category (structure|content|dynamic|effect|unknown), preview. Use this to discover what snippets can be added to a page. Categories inferred from snippet key patterns and modules.

Inputs: limit, module, search, category, +1 more.

odoo_website_remove_snippetB

Remove a snippet block from a target HTML field. Locates via snippet_xpath (absolute). Writes back the reduced HTML.

Inputs: model (required), res_id (required), field_name (required), snippet_xpath (required), +3 more.

odoo_website_update_snippetA

Update an existing snippet on a target HTML field. Locates the snippet via snippet_xpath (absolute in target), applies substitutions to its descendants via relative xpaths, and writes back. Common use cases: swap background image, change H1/H2 text, update CTA button text+href, change card content. Substitution syntax identical to odoo_website_add_snippet.

Inputs: model (required), res_id (required), field_name (required), snippet_xpath (required), +4 more.

odoo_writeD

Update existing records.

Inputs: ids (required), model (required), values (required), connection.

open_connection_managerA

Open the Connection Manager GUI (desktop app). Launches GTK4 version on Linux, Qt6 on Windows/macOS. Use this when the user wants to visually manage connections, configure Portainer/GitHub, manage SSH keys, or see active sessions.

Inputs: no named parameters.

proxy_callA

Forward a tool call to an internal MCP sub-service. Available services: 'portainer' (Docker/K8s management, 38 tools), 'github' (repos/issues/PRs, 20 tools), 'teams' (MS Teams messaging, 6 tools). Use proxy_discover first to see available tools on each service.

Inputs: tool (required), service (required), arguments.

proxy_discoverA

List available tools on an internal MCP sub-service. Call this first to see what tools are available on portainer/github/teams.

Inputs: service (required).

proxy_refreshA

Re-discover tools from all internal MCP sub-services. Use after starting a new sub-service or if tools are missing.

Inputs: no named parameters.

public_access_barcodeC

Generate barcode image via /report/barcode/{type}/{value}.

Inputs: value (required), width, height, save_path, +2 more.

public_access_downloadB

Download attachment/binary content by ID via /web/content/{id}. Public route.

Inputs: content_id (required), save_path, connection.

public_access_export_csvC

Export Odoo list data as CSV via web session.

Inputs: model (required), fields (required), domain, save_path, +2 more.

public_access_export_xlsxC

Export Odoo list data as XLSX file via web session. Returns base64.

Inputs: model (required), fields (required), domain, save_path, +2 more.

public_access_imageB

Download image field from record via /web/image/{model}/{id}/{field}.

Inputs: model (required), record_id (required), field, save_path, +1 more.

public_access_portal_homeC

Get portal home page content via web session (/my/home).

Inputs: connection.

public_access_portal_invoicesC

Get list of portal invoices (/my/invoices). Returns HTML page content.

Inputs: page, connection.

public_access_portal_ordersC

Get list of portal sale orders (/my/orders). Returns HTML page content.

Inputs: page, connection.

public_access_portal_purchasesC

Get list of portal purchase orders (/my/purchase).

Inputs: page, connection.

public_access_portal_ticketsB

Get list of portal helpdesk tickets (/my/tickets).

Inputs: page, connection.

public_access_report_htmlC

Render report as HTML via web session.

Inputs: ids (required), report_name (required), connection.

public_access_report_pdfC

Download PDF report via web session. Route: /report/pdf/{report_name}/{doc_ids}.

Inputs: ids (required), report_name (required), save_path, connection.

public_access_report_xlsxC

Download XLSX report via OCA reporting-engine (/report/xlsx/{name}/{ids}).

Inputs: ids (required), report_name (required), save_path, connection.

public_access_shopC

Get website shop product listing (/shop). Returns HTML.

Inputs: page, search, connection.

public_access_sitemapC

Download sitemap.xml from Odoo website.

Inputs: connection.

session_listA

List MCP session-store rows. Regular callers see their own sessions; admin principals (MCP_ADMIN_PRINCIPALS) see all.

Inputs: principal, include_orphaned.

session_revokeA

Revoke one MCP session (admin, or your own): marks the row revoked and tears down its live resources (connection, web, telegram client when unreferenced).

Inputs: session_key (required).

ssh_executeA

Execute a command on a remote server via SSH. Uses SSH config from connections.json (connection's ssh section). Provide either a connection alias (to use saved SSH config) or explicit host/user.

Inputs: command (required), host, port, user, +3 more.

telegram_agent_create_quoteC

Create a DRAFT sale.order in the scenario's company. Returns a shareable summary. Honors quote_send (approve → confirm before sending; auto → may send).

Inputs: lines (required), chat_id (required), connection, partner_id.

telegram_agent_enrollA

Enroll a Telegram chat for agentic handling with a scenario. mode: auto (self-converse) | advisory (suggest, human sends) | notify. scenario (optional dict): persona, default_toolset, data_scope {models,fields,pricelist}, forbid[], company_id, quote_send (approve|auto), skills[] ({name,toolset,triggers[]}). Confidentiality is enforced by data_scope. Enrolments are per-principal — you never see or change another principal's.

Inputs: chat_id (required), mode, scenario.

telegram_agent_get_scenarioA

Get the full scenario for an enrolled chat.

Inputs: chat_id (required).

telegram_agent_listA

List enrolled chats with their mode/persona/skills.

Inputs: no named parameters.

telegram_agent_product_lookupA

Search products for an enrolled chat, returning ONLY the scenario's allowlisted fields (confidential fields withheld by design). Uses the scenario's company + pricelist.

Inputs: query (required), chat_id (required), limit, connection.

telegram_agent_routeA

Classify the conversation direction for an enrolled chat and return the active TOOLSET to switch to (based on the scenario's skills), plus the data_scope/forbid guardrails and a memory_search_hint. Call this on each incoming message before acting.

Inputs: text (required), chat_id (required).

telegram_agent_set_scenarioB

Replace the scenario for an enrolled chat.

Inputs: chat_id (required), scenario (required).

telegram_agent_unenrollC

Stop agentic handling for a chat.

Inputs: chat_id (required).

telegram_authA

Authenticate with Telegram. Two-step process: 1) Call with phone → code is sent to Telegram. 2) Call with phone + code → authenticated. If 2FA enabled, provide password too.

Inputs: phone (required), code, password.

telegram_auth_statusA

Check Telegram authentication status.

Inputs: no named parameters.

telegram_configureA

Set Telegram API credentials (api_id and api_hash from my.telegram.org).

Inputs: api_id (required), api_hash (required).

telegram_download_mediaA

Download media/document from a Telegram message into the MCP download root (MCP_DOWNLOAD_ROOT, default /data/downloads). Returns the saved path.

Inputs: chat (required), filename (required), message_id (required).

telegram_get_dialogsC

List recent Telegram chats (users, groups, channels).

Inputs: limit.

telegram_get_messagesA

Read messages from a Telegram chat. Chat can be @username, phone, or numeric ID.

Inputs: chat (required), limit, search.

telegram_search_contactsC

Search Telegram contacts by name or username.

Inputs: query (required).

telegram_send_fileA

Send a file/document to a Telegram chat. The file must live under the MCP download root (MCP_DOWNLOAD_ROOT, default /data/downloads) — pass a relative path or an absolute path inside it. Chat can be @username, phone, or numeric ID.

Inputs: chat (required), path (required), caption, reply_to.

telegram_send_messageB

Send a Telegram message. Chat can be @username, phone, or numeric ID.

Inputs: chat (required), message (required), reply_to.

telegram_sub_addA

Subscribe a principal's Telegram listener to a chat (admin allow-list). No subscriptions for a principal = listen to ALL (back-compat). Once a principal has any subscription, only those chats are pushed to its telegram: channel. Use 'principal' to assign for another user.

Inputs: chat_id (required), mode, note, title, +1 more.

telegram_sub_listB

List a principal's Telegram chat subscriptions. allow_all=true means no filter (listens to all).

Inputs: principal.

telegram_sub_removeC

Remove a chat from a principal's Telegram subscription allow-list.

Inputs: chat_id (required), principal.

user_connection_activateA

Activate one of your personal connections as the working connection.

Inputs: alias (required).

user_connection_addB

Add/update a personal Odoo connection (saved per-user). Supports Odoo, SSH, and Portainer settings.

Inputs: db (required), url (required), user (required), alias (required), +8 more.

user_connection_deleteA

Delete a personal connection.

Inputs: alias (required).

user_connection_listB

List your personal connections.

Inputs: no named parameters.

who_am_iA

Show current user identity and active connection.

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.9/5.0

    Scored across 138 tools

    Disambiguation3/5

    Many tools have clear distinct purposes, but there are several overlapping pairs like odoo_search vs odoo_search_read vs odoo_search_count, odoo_report vs odoo_web_report vs public_access_report_pdf, and odoo_execute vs odoo_web_call. The separation between web-session and XML-RPC tools is subtle and could cause misselection. Some AI and stock tools are also highly specialized, but their descriptions help.

    Naming Consistency4/5

    Most tools follow a consistent snake_case prefix_domain_action pattern (e.g., odoo_read, telegram_send_message, google_calendar_list). Some outliers like identify, who_am_i, and open_connection_manager break the pattern but are still readable. Overall the naming is predictable and grouped by domain.

    Tool Count1/5

    138 tools is far beyond any reasonable scope for a single MCP server. Even for a multi-domain personal assistant, this is excessive and will overwhelm an agent's tool selection. The server would benefit from splitting into separate MCP servers per domain (Odoo, Telegram, Google, AI, etc.).

    Completeness4/5

    The tool surface covers a wide range of operations across Odoo (CRUD, web, reports, translations, website snippets, fiscal positions, stock), Telegram, Google (Gmail, Calendar), AI pipelines, and memory. Some minor gaps exist (e.g., no Gmail draft/delete, no Odoo user management), but core workflows are well covered. The sheer number suggests high coverage, though it could be more focused.

    Maintenance

    ActivityMaintained
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      C
      maintenance
      An MCP server implementation that integrates with Odoo ERP systems, enabling AI assistants to interact with Odoo data and functionality through the Model Context Protocol.
      41
      1,602 PyPI
      427
      MIT
    • A
      license
      Not graded
      quality
      A
      maintenance
      An MCP server that enables AI assistants like Claude to interact with Odoo ERP systems through natural language, allowing users to search, create, update, and manage business data in their Odoo instance.
      39,303 PyPI
      413
      Mozilla Public 2.0
    • F
      license
      Not graded
      quality
      D
      maintenance
      MCP server to connect Claude with Odoo 18, enabling CRUD operations on Odoo models via natural language.
      2
      -
    • A
      license
      B
      quality
      C
      maintenance
      Connects MCP clients like Claude to your Odoo ERP, enabling natural language queries, reports, and optional data modifications.
      9
      42 npm
      MIT