Skip to main content
Glama
Transgenia

Odoo 10-19 MCP Server

by Transgenia
README.md
# MCP-Odoo-Tools: CE, EE & online (Odoo 10-19)

> **Where it runs:** the Odoo tools run in Claude Code (terminal, VS Code, JetBrains
> and the **Code** tab of Claude Desktop). In Cowork and Claude chat the plugin
> installs and its skills and commands load, but the Odoo tools do not run: open the
> Code tab, where the plugin is synced to the same Claude account, or ask Transgenia
> for assisted setup (dev@transgenia.org, WhatsApp +52 55 8034 0405). See
> [Where it works](#where-it-works).

[![CI](https://github.com/Transgenia/MCP-Odoo-Tools-CE-EE-and-online/actions/workflows/ci.yml/badge.svg)](https://github.com/Transgenia/MCP-Odoo-Tools-CE-EE-and-online/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-blue)](server/pyproject.toml)
[![MCP Compatible](https://img.shields.io/badge/MCP-Compatible-orange)](https://modelcontextprotocol.io)
[![Claude Code plugin](https://img.shields.io/badge/Claude_Code-plugin-D97757?logo=claude&logoColor=white)](https://claude.com/claude-code)
[![Odoo ERP 10-19](https://img.shields.io/badge/Odoo_ERP-10--19-714B67?logo=odoo&logoColor=white)](https://www.odoo.com)
[![Odoo CE | EE | Online](https://img.shields.io/badge/Odoo-CE_%7C_EE_%7C_Online-714B67?logo=odoo&logoColor=white)](docs/compat-matrix.md)
[![M8ven Score](https://m8ven.ai/badge/mcp/transgenia-mcp-odoo-tools-ce-ee-and-online-zllwvd)](https://m8ven.ai/mcp/transgenia-mcp-odoo-tools-ce-ee-and-online-zllwvd)

**Links:** [Homepage](https://transgenia.org/mcp-transgenia-odoo.html) · [Documentation](https://docs.transgenia.org/odoo-tools/) · [Support](SUPPORT.md) (dev@transgenia.org, WhatsApp +52 55 8034 0405) · [Privacy policy](PRIVACY.md) · [Terms of use](TERMS-OF-USE.en.md) · [License: MIT](LICENSE)

A **Claude Code plugin** that unifies Odoo tooling into one install. Its skills and
commands also load in Cowork and Claude chat, but the Odoo tools themselves run in
Claude Code only (see [Where it works](#where-it-works)):

- **MCP server (primary):** a clean-room, MIT-licensed Python server exposing
  native Odoo tools (`odoo_search`, `odoo_read`, `odoo_create`, `odoo_write`,
  `odoo_export_records_json/csv`, `odoo_version`, ...) over **JSON-2** (Odoo's
  new API, saas~18.4 / 19.0+) or JSON-RPC, with automatic XML-RPC fallback, and
  a **cross-version compatibility layer** that
  makes a single tool call work across **Community, Enterprise and online (SaaS)
  from Odoo 10 through 19**.
- **CLI fallback:** a lightweight TypeScript XML-RPC CLI (Node-only) for when
  you can't run the MCP server, or for scripted batch access.
- **Agents, skills, commands and domain context** to drive both surfaces.

Built and maintained by [Transgenia](https://transgenia.org), a **Registered
partner of Anthropic**. (Registered tier: this plugin is an independent
open-source project, not an Anthropic-certified or first-party product.)

## Why this exists

Odoo's model and field names drift across versions (`account.invoice` →
`account.move` at v13, analytic fields at v16, package models near v19, the
RPC API itself from v19, and more), and Enterprise adds models Community
lacks. This plugin absorbs those differences behind one stable tool surface so
you don't hand-branch per version.

## Where it works

| Surface | MCP server (the Odoo tools) | Skills, commands | Agents, hook |
|---|---|---|---|
| Claude Code (CLI, VS Code, JetBrains, Desktop **Code** tab) | **Yes** | Yes | Yes |
| Cowork (Claude Desktop) | **No** | Yes | Yes |
| Claude chat (claude.ai web, desktop, mobile) | **No** | Yes | No |

The Odoo tools run as a local stdio MCP server (`python3`, 3.9+) on the machine
where Claude Code runs, and the connection options (URL, database, login, API
key) are entered through Claude Code's plugin options (`userConfig` in
`plugin.json`). Per
[Anthropic's plugin support matrix](https://claude.com/docs/plugins/platform-support)
(checked 2026-10-20), Cowork "doesn't prompt for values" and ignores an MCP
server that references an option without a default (the URL, database, login and
credentials here have none), and chat ignores a plugin's local MCP server. In those
apps the plugin still installs and its skills and commands still load, but they
cannot reach Odoo without the tools. That is the app working as designed, not a
broken install.

Cowork and Claude chat do accept MCP connectors you add yourself: a remote MCP
server reachable at an `https` URL (on Team and Enterprise plans an Owner adds it in
**Organization settings > Connectors** and each member connects it under
**Customize > Connectors**; on other plans you add it under **Customize >
Connectors**) or, in the Claude desktop app, a desktop extension. This plugin
provides neither: its Odoo tools need the local server above.

### If the Odoo tools do not appear

The usual symptom, in Cowork or on claude.ai: the plugin installs and shows as on,
its **Connectors** tab lists **odoo — Runs in each session**, and opening that row
shows an empty panel with no fields to fill in. Anthropic's docs say that on the
web the Connectors tab marks a local MCP server that way while chat does not start
it, and there is no form because those apps do not prompt for plugin options.
When the plugin's local diagnostics record no recent connection or setup, its
session-start hook says where the Odoo tools run and how to reach them (see
[What runs on your machine](#what-runs-on-your-machine)).

1. **Use Claude Code** (terminal, VS Code or JetBrains, or the **Code** tab of
   Claude Desktop). A plugin installed on your Claude account appears there as a
   synced plugin at the next session start when you sign in to Claude Code (2.1.273
   or later) with that claude.ai account; if it does not show, run
   `/reload-plugins`, or install it with the commands under [Install](#install).
2. **Enter the options there.** `<id>` below is the plugin's full `name@marketplace`
   id as `claude plugin list` shows it (for example `odoo-tools@synced` for a
   plugin synced from your Claude account). Run `/plugin configure <id>` in a
   session, or `/plugin` → **odoo-tools** → **Configure options** (VS Code: the
   gear icon on the plugin's row). On a headless or scripted machine (Claude Code
   2.1.285 or later), `claude plugin configure <id> --json` lists the options
   without a saved value, and `claude plugin configure <id> --values-stdin` saves
   values read from stdin as a JSON object of single-line strings; restart Claude
   Code afterwards. Only `odoo_url`, `odoo_db`, `odoo_login` and one credential
   must be set: the unused one of API key and password, and the options that have
   defaults, stay in that list on a working setup. Pipe the JSON from a protected
   file or your secret manager; never type the key in the command line or in the
   chat.
3. **No Claude Code on that machine?** In Cowork, the Node-only CLI fallback
   (`/odoo-tools:odoo-setup-cli`) can work when the session can run Node, reach
   your Odoo, and you can edit the CLI's `.env` file yourself; use a dedicated,
   least-privilege, short-lived API key. Claude chat has no safe place to enter the
   key, so use Claude Code there. (On Claude Code without Python, use the container
   mode of `/odoo-tools:deploy-local`.)
4. Still blocked? See [`SUPPORT.md`](SUPPORT.md). Transgenia never asks for your
   API key or password in a chat or by email.

## Install

```
/plugin install odoo-tools --marketplace Transgenia/MCP-Odoo-Tools-CE-EE-and-online
/odoo-tools:odoo-setup-mcp
```

The first line adds the marketplace and installs the plugin in one step (Claude
Code 2.1.275 or later). On an older Claude Code, add the marketplace first:

```
/plugin marketplace add Transgenia/MCP-Odoo-Tools-CE-EE-and-online
/plugin install odoo-tools
```

**`/odoo-tools:odoo-setup-mcp` is the guided route**: it detects what is already
set up and walks you through **setup → verification → hands-on training →
daily use → deployment** to your team or production, one question at a time.
No Odoo to practise with? It offers a local sandbox (below).

Claude Code prompts for the connection options when the plugin is enabled
(change them later in `/plugin` → **odoo-tools** → **Configure options**; these
options exist only in Claude Code, see [Where it works](#where-it-works)). The
API key and password are `sensitive` options stored in the OS secure credential
store, never in `settings.json` or your shell profile. The setup skill then
verifies the connection with `odoo_version`.

### Requirements

- **MCP server:** Python 3.9+ available as **`python3`** on `PATH`. The plugin
  runs the bundled server source directly:
  `python3 ${CLAUDE_PLUGIN_ROOT}/server/run_stdio.py`. The server uses only the
  Python standard library, so nothing is installed or downloaded when it starts.
  - Linux and macOS usually already have `python3` (on macOS it comes with
    Apple's Command Line Tools).
  - **Windows:** the command must be named `python3`. The Microsoft Store Python
    provides `python3.exe`; the python.org installer provides only `python` and
    `py`. Either install Python from the Microsoft Store, or put a `python3.exe`
    on `PATH` (e.g. a copy of or hard link to `python.exe` in the Python folder).
    A PowerShell or `doskey` alias is not enough: Claude Code starts the command
    directly, not through your shell.
  - **Windows, session-start hooks:** they are shell commands, so they need Git for
    Windows (Git Bash). Without it Claude Code runs them in PowerShell, where they
    fail with a SessionStart hook error. The MCP server itself is not affected.
- **CLI fallback (optional):** Node.js 18+.

### What runs on your machine

- **MCP server:** `python3 ${CLAUDE_PLUGIN_ROOT}/server/run_stdio.py`, readable
  Python source shipped in this plugin, with zero third-party runtime
  dependencies. It talks only to the Odoo URL you configure (plus your own
  OTLP collector, if you opt in with `ODOO_OTEL_ENDPOINT`). It writes one audit
  line per tool call to daily files in the plugin's data folder, kept 90 days
  (see [Permissions](#permissions)), and small metadata-only diagnostics
  (`diagnostics/server.jsonl`: when it starts, connects, crashes or stops, never
  a value) that `/odoo-tools:odoo-doctor` turns into a support report. It reads
  only the credentials the plugin options pass to it.
- **SessionStart hooks:** two, and neither contacts anything:
  - runs `python3 --version` and prints a warning only when `python3` is not
    runnable (the MCP server could not start);
  - `hooks/session_start.py`, started only when `python3` is 3.9 or newer, reads
    no plugin option and no credential: only the plugin's own data folder (the
    server's diagnostics) and the name of the Claude app that started the
    session. When the last 14 days record neither a successful connection to Odoo
    nor a server start with every connection setting, it says where the Odoo
    tools run (not in Cowork or Claude chat), at most once a day at the start of
    a session, and tells Claude, with one diagnostics line for the doctor; when
    the last server start was locked by the permission policy, it says so with
    its E-code. It writes one metadata line per session to
    `diagnostics/hook.jsonl` and keeps two timestamp files for the daily notices;
    with the container mode of `/odoo-tools:deploy-local` it stays silent.
  - Claude Code exports every saved plugin option, sensitive ones included, to
    the environment of each plugin hook process as `CLAUDE_PLUGIN_OPTION_*`. The
    plugin's hooks read none of them.
- **Local infrastructure (only if you run `/odoo-tools:deploy-local` and
  confirm):** Docker containers on your machine: the sandbox (PostgreSQL + Odoo
  on `127.0.0.1`, files in `~/.odoo-tools/sandbox`) or the MCP server image.
  Nothing starts automatically; no hook runs Docker.
- **CLI fallback (only if you run `/odoo-tools:odoo-setup-cli`):** copies the
  bundled CLI source to `~/.claude/tools/odoo-cli`, runs `npm install` and
  `npm run build` there, and creates an owner-only `.env` with placeholders that
  you fill in with your credentials yourself.

### Local infrastructure: `/odoo-tools:deploy-local`

Provided by Transgenia, started only when you run the command (Docker required):

- **Sandbox:** PostgreSQL + **Odoo Community** 10.0 to 19.0 on your machine, bound to
  `127.0.0.1`, with a database (demo data optional) ready for the plugin. Images
  come from `ghcr.io/transgenia` (mirrors of the official `odoo` and `postgres`
  images) with automatic fallback to Docker Hub. Passwords are generated locally
  into `~/.odoo-tools/sandbox/.env` (owner-only) and never printed. Script:
  [`scripts/deploy_local.py`](scripts/deploy_local.py) (standard library only).
  `status`, `down`, `logs` and `destroy --yes` manage it afterwards. Odoo
  10.0-16.0 are for testing and migrations only (Odoo S.A. maintains the three
  latest series); images up to 15.0 are amd64-only (ARM Linux needs binfmt/QEMU
  emulation). Each series gets a PostgreSQL it supports.
  **Community (CE) only**: Transgenia cannot provide Odoo Enterprise (licensed by
  Odoo S.A.) or Odoo Online (Odoo S.A.'s SaaS) instances: connect your own
  instance to use them (on Odoo Online, the plan must include external API access).
- **MCP server as a container:** `ghcr.io/transgenia/odoo-mcp-tools`, for
  machines without Python 3.9+, connected to an existing Odoo.

### Configuration

As a plugin, configure through the plugin options above. When you run the server
standalone (`python3 server/run_stdio.py` from a checkout, `odoo-mcp` after
`pip install ./server`, or Docker), it reads these environment variables:

| Variable | Required | Notes |
|----------|----------|-------|
| `ODOO_URL` | yes | `https://host` (no trailing path) |
| `ODOO_DB` | yes | database name |
| `ODOO_LOGIN` | yes | login email |
| `ODOO_API_KEY` | yes* | Odoo ≥ 14; created in Account Security. The only credential JSON-2 accepts |
| `ODOO_PASSWORD` | yes* | use on Odoo < 14 (no API keys) |
| `ODOO_TRANSPORT_PREF` | no | `auto` (default) / `json2` / `jsonrpc` / `xmlrpc` (see [Transports](#transports)) |
| `ODOO_TIMEOUT` | no | seconds per Odoo call (default 120; plugin option **Request timeout**) |
| `ODOO_READONLY` | no | `1` lists and runs the read tools only (plugin option **Read-only mode**) |
| `ODOO_POLICY` | no | permission profile: `readonly`, `standard` (default), `builder` or `full` (plugin option **Permission profile**, see [Permissions](#permissions)) |
| `ODOO_POLICY_FILE` | no | absolute path to an optional policy file (plugin option **Permission policy file**, [`docs/policy.md`](docs/policy.md)) |
| `ODOO_AUDIT_DIR` | no | audit folder; `stderr` (the default outside the plugin) or `off` |
| `ODOO_AUDIT_RETENTION_DAYS` | no | days an audit file is kept (default 90, `0` keeps them) |
| `ODOO_CACHE_TTL` | no | int (seconds) |
| `ODOO_METRICS`, `ODOO_OTEL_ENDPOINT` | no | optional observability |

\* one of `ODOO_API_KEY` or `ODOO_PASSWORD`.

### Tools

28 MCP tools; with the default permission profile (`standard`) 25 are listed:
`odoo_unlink`, `odoo_add_field` and `odoo_add_automation` need another profile
(see [Permissions](#permissions)). With Read-only mode (`ODOO_READONLY=1`) the 9
write tools are not listed, and calling one is refused before anything reaches
Odoo.

| Group | Tools |
|-------|-------|
| Connection | `odoo_version`, `odoo_connections`, `odoo_telemetry_preview` |
| Read | `odoo_search`, `odoo_search_count`, `odoo_read`, `odoo_search_read`, `odoo_read_group`, `odoo_fields_get`, `odoo_list_models`, `odoo_module_info`, `odoo_translate_get` |
| Export | `odoo_export_records_json`, `odoo_export_records_csv` |
| Write | `odoo_create`, `odoo_write`, `odoo_unlink` (profiles `builder` and `full`), `odoo_execute`, `odoo_translate_set` |
| Studio-style (write; profiles `builder` and `full`) | `odoo_add_field`, `odoo_add_automation` |
| Odoo Online (useful on any Odoo) | read: `odoo_online_profile`, `odoo_api_catalog`, `odoo_access_check`, `odoo_record_documents`; write: `odoo_import_preview`, `odoo_import` |
| Deprecated | `odoo_report`: returns an error without calling Odoo. It relied on the private method `_render_qweb_pdf`, which Odoo refuses over RPC on every version, so it never worked. Use `odoo_record_documents` for stored PDFs. Removed in 2.0.0 |

The Odoo Online tools cover what an Online database makes hard: no custom
Python, API access on Custom plans only, API keys that expire (18+), a new
saas~X.Y line every few months, no PDF rendering over RPC, and imports as the
sanctioned bulk path.

| Tool | What it does | Odoo |
|------|--------------|------|
| `odoo_online_profile` | One read: series and line (`19.0` or `saas~19.2`), deployment and how sure that is, the transport, whether JSON-2 and Odoo's `/doc-bearer` catalog are usable, the deprecation notice and when `/xmlrpc` and `/jsonrpc` disappear, the user and companies, 2FA, the user's API keys with their expiry (names and dates only, never key material), installed applications, imported data modules, Studio, and the Online limits (Custom plan, about 1 call/s, 5-200 e-mails/day, data modules only) | 10-19; API keys 14+, expiry 18+; on 19.0 the module list needs an administrator |
| `odoo_api_catalog` | A model's methods with their parameter names in order, model-level and read-only flags, for JSON-2 and `odoo_execute` (`ids` + `kwargs`). Exact names from Odoo's own per-database catalog (`/doc-bearer`, custom and Studio methods included) with an administrator's API key on 19.0+; otherwise the plugin's built-in table: base names from saas~18.4 (a model's override may rename one), flags only (`parameters: null`) on 10.0 to saas~18.3 | 10-19 |
| `odoo_access_check` | Whether the signed-in user may read, write, create and unlink on a model, record by record with `ids` on 18+, and whether the user may export | 10-19; record level 18+, export group 16+ |
| `odoo_record_documents` | A record's attachments with the main one and an invoice's stored PDF flagged (17+), and one file's content on request (at most 5 MiB). Use it for PDFs: these tools render no reports (`odoo_report` is deprecated) | 10-19 |
| `odoo_import_preview` | Dry run with Odoo's own importer: the row errors and warnings, and `would_import`. Nothing is saved, but sequence numbers can be consumed and automated actions can fire webhooks | 16-19, JSON-RPC or JSON-2 |
| `odoo_import` | Atomic `load()`: every row is saved or none is. An `id` column holds external ids and **updates** the records that already have them | 12-19, JSON-RPC or JSON-2 |

Both import tools take at most 500 rows per call and never run by themselves:
the preview does not import, and the agent asks before `odoo_import`. Odoo's
XML-RPC cannot return the empty values an import result carries, so a session
on XML-RPC refuses them instead of risking a saved import reported as an error.
On Odoo Online, pace bulk work (about 1 call per second, no parallel calls).

### Transports

Odoo 19 deprecates `/xmlrpc` and `/jsonrpc` (every call logs a warning on the
Odoo server), and **Odoo 22 and Odoo Online saas~21.1 remove them**. Their
replacement, **JSON-2** (`/json/2/<model>/<method>`), exists from saas~18.4 and
19.0 and accepts an **API key only**.

With `ODOO_TRANSPORT_PREF=auto` (the default) the server reads the version first
(the web client's own route: no login, nothing in the Odoo log) and then:

- on Odoo 10 to 18 (and saas~18.1-18.3) it uses JSON-RPC, then XML-RPC, as before;
- on saas~18.4 / 19.0+ **with an API key** it uses JSON-2, falling back to JSON-RPC
  and XML-RPC only when a proxy blocks JSON-2;
- with a password, or with `user:pass@` in `ODOO_URL` (whose basic auth takes the
  `Authorization` header JSON-2 needs), it stays on the deprecated endpoints, and on
  19+ `odoo_version` returns a `transport_notice` saying how to switch;
- on saas~21.1 / Odoo 22+ it needs an API key (JSON-2 is the only endpoint left).

`json2` forces JSON-2; `jsonrpc` and `xmlrpc` force that endpoint. None of them
switch transport by themselves. `odoo_version` reports the transport in use.
A call moves to another transport only when that cannot run it twice, and a rate
limit (HTTP 429) never switches transport: reads wait for `Retry-After`, writes
are reported. On JSON-2, `odoo_execute` takes the record ids in `ids` and the
other arguments by name in `kwargs`. Details: [`docs/compat-matrix.md`](docs/compat-matrix.md#rpc-endpoints-and-transports).

The **MCP server** does not persist credentials to disk. Two caveats worth
stating plainly:

- **The optional CLI fallback keeps your credentials in a local `.env`** under
  `~/.claude/tools/odoo-cli` (owner-only; you type the secret in yourself). See
  [`SECURITY.md`](SECURITY.md).
- **When you drive Odoo through an AI agent**, the tool *results* (the Odoo records
  you query) are returned to your MCP client and sent to your model provider (e.g.
  Anthropic, for Claude) to be processed, exactly like any other tool an agent
  uses. The MCP server talking directly to Odoo means Transgenia never proxies or
  stores your data; it does not mean company data is withheld from the model.

### Telemetry (opt-in, disabled by default)

No usage data leaves your machine unless you opt in with `ODOO_TELEMETRY=opt-in`
and manually share the payload shown by `/odoo-doctor` (which calls the
read-only `odoo_telemetry_preview` tool). When enabled, only
`plugin_version`, `odoo_version_major`, edition/deployment labels and aggregate
generic tool counters are included, never URL, DB, login, secrets, PII,
modules or billing. No schedules, no boot hooks, no background sends.
(This covers the telemetry payload only; `ODOO_METRICS`/`ODOO_OTEL_ENDPOINT`
remain separate explicit opt-ins for local Prometheus/OTLP observability.)
Details: [`SECURITY.md`](SECURITY.md#opt-in-telemetry-disabled-by-default).

## Permissions

Since 1.5.0 the MCP server applies a **permission profile** on top of the Odoo
user's own access rights. It only removes rights; Odoo's access rules, record
rules and field groups always apply too. Choose it in `/plugin` → **odoo-tools**
→ **Configure options** → **Permission profile**:

| Profile | What the Odoo tools may do |
|---------|----------------------------|
| `readonly` | reads only, no stored secrets |
| `standard` (default) | read, create, update and run business methods; no deletes, no Studio-style changes, no e-mail or SMS out except internal notes, no users, rights, modules, settings, bank accounts, fiscal sequences or chatter history, no stored secrets |
| `builder` | `standard` plus fields, views and automations: for sandboxes and staging, because automations run code on the Odoo server (for confidentiality it equals `full`) |
| `full` | everything the Odoo user may do, as in 1.4, except creating, changing or revoking API keys and uninstalling modules |

**To keep the 1.4 behaviour, choose `full`.** That is the documented escape, for
example on your own company instance where you keep every right the Odoo user
has. To enforce its two refusals and a policy file, `full` still refuses a call
whose arguments it cannot read with certainty (pass them by name) or whose
related models it cannot look up with `fields_get` (`docs/policy.md`,
Profiles). Credential-like fields (passwords, tokens, keys) are withheld outside
`full`, and a tool the profile forbids on every model is not listed. Every
refusal names its rule and the option that changes it, and the agent is told
that a policy refusal is final.

An optional **Permission policy file** (an absolute path, read once at start)
adds per-model rules: method lists for `odoo_execute`, refusals, field rules and
openings of sensitive models that need a reason and may expire. Check one
offline with `python3 server/run_stdio.py --check-policy FILE --explain
res.users:write`. Every tool call, refusals included, leaves one line in a local
audit file (names and counts, never values or secrets). The lines are
hash-chained; `python3 server/run_stdio.py --verify-audit FILE` names the first
edited, reordered or incomplete line, but cannot, from one file alone, catch
whole trailing lines removed or a day file deleted outright (the surviving
prefix still chains). The full reference, with four example files:
[`docs/policy.md`](docs/policy.md).

In the local (stdio) mode the permission policy limits what Claude can do
**through the odoo-tools MCP tools**. It protects against mistakes and against
instructions hidden in data Claude reads. It does not limit the person who holds
the API key, and it is not a sandbox for an agent that has unrestricted shell
access on the same machine. The boundary that holds against everyone is the Odoo
user itself: give the agent a dedicated, least-privilege Odoo user (not an
administrator) and an API key with an expiry. In a future remote mode, where the
server keeps the Odoo credential, the same policy becomes real enforcement.

## Privacy

**[Privacy policy](PRIVACY.md)** · Transgenia receives and retains no data from
this plugin. It reads records (which may include personal data such as names,
emails and addresses) from your own Odoo only when asked. Services it contacts:

- **Your Odoo instance** (the URL you configure): from the MCP server, or from
  the optional CLI fallback.
- **Your model provider:** tool results go back to your MCP client and model,
  as with any tool.
- **npm**, only if you set up the optional CLI fallback (`npm install`; no Odoo
  data sent). The MCP server downloads nothing.
- **Optional, off by default:** your own OTLP collector (`ODOO_OTEL_ENDPOINT`).

Corporate notice: <https://transgenia.org/en/legal-privacy.html>.

## Support matrix

| Dimension | Coverage |
|-----------|----------|
| Versions | Odoo 10 to 19 (compat map + version detection) |
| Editions | Community & Enterprise (EE-only models gated with clear errors) |
| Deployment | Self-hosted & online/SaaS (transport auto-selected) |

Details and the delta table: [`docs/compat-matrix.md`](docs/compat-matrix.md).

## Architecture

See [`docs/architecture.md`](docs/architecture.md). In short: transport
(json2/jsonrpc/xmlrpc, selected per version and credential) → session (auth + version/edition facts + schema
cache) → compat (resolve model/field/capability) → tools → MCP stdio, with the
permission policy deciding each call before any session exists and a guarded
session checking every Odoo call a tool makes.

## Scope

This is the **public generic core**: it talks to Odoo and nothing else. A
generic, declarative permission policy is part of the public core; approval
workflows, localization engines (e.g. country e-invoicing), backups, document AI
and other tenant-specific engines are not, and are not part of this repository.

## Support: Transgenia

[Transgenia](https://transgenia.org) builds and maintains this plugin and provides
**maintenance, support, training and assisted deployment** of Claude + Odoo
(hosting, migrations, integrations, customizations). Official channels only:

- Email: **dev@transgenia.org**
- WhatsApp: **+52 55 8034 0405**, https://wa.me/525580340405

The plugin points you to these channels at the moments they matter (setup
blocked, end of training, deployment); it does not add them to unrelated
answers. It works with any Odoo instance, with or without a support contract.
See also [`SUPPORT.md`](SUPPORT.md).

## Development

```bash
cd server
python3 -m venv .venv && . .venv/bin/activate   # or: uv venv && uv pip install ...
pip install -e ".[dev,cache]"
pytest -q -m "not live"
ruff check src tests
```

The `dev` extra adds the official `mcp` package (Python 3.10+ only) for one
interop test that drives this server with the official MCP client; the server
itself never imports it, and the plugin never installs it.

## License

MIT © Transgenia (Centrum Transgenia SAS). See `LICENSE` and
[`NOTICE`](NOTICE) for third-party attributions.

The [Terms of Use](TERMS-OF-USE.en.md) ([Términos de uso](TERMS-OF-USE.es.md), the
prevailing text) complement the MIT license: trademarks, support, privacy,
third-party licenses and governing law (Mexico).