MCP-Odoo-Tools — CE, EE & online (Odoo 10-19)
Links: Homepage · Documentation · Support (dev@transgenia.org, WhatsApp +52 55 8034 0405) · Privacy policy · Terms of use · License: MIT
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):
- 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, 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
(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. In Claude Code the plugin also says at session start which required options are missing (whether Cowork shows that notice has not been verified yet).
- 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. - Enter the options there.
<id>below is the plugin's fullname@marketplaceid asclaude plugin listshows it (for exampleodoo-tools@syncedfor 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> --jsonlists the options without a saved value, andclaude plugin configure <id> --values-stdinsaves values read from stdin as a JSON object of single-line strings; restart Claude Code afterwards. Onlyodoo_url,odoo_db,odoo_loginand 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. - 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.envfile 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.) - Still blocked? See
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). 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
python3onPATH. 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 providespython3.exe; the python.org installer provides onlypythonandpy. Either install Python from the Microsoft Store, or put apython3.exeonPATH(e.g. a copy of or hard link topython.exein the Python folder). A PowerShell ordoskeyalias 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.
- Linux and macOS usually already have
- 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 withODOO_OTEL_ENDPOINT). It writes one audit line per tool call to daily files in the plugin's data folder, kept 90 days (see Permissions). - SessionStart hooks — two, and neither contacts anything:
- runs
python3 --versionand prints a warning only whenpython3is not runnable (the MCP server could not start); hooks/check_options.py, started only whenpython3is 3.9 or newer, checks whether the three required, non-sensitive options (URL, database, login) have a saved value. It never reads the API key or password option and never prints, stores or sends a value. When some are missing it tells you, at most once a day at the start of a session, and tells Claude why the Odoo tools are off; when the container mode's~/.odoo-tools/mcp/odoo.envexists (it checks that the file exists, without opening it) it tells only Claude. When Permission profile or Permission policy file is set, it also checks them with the server's own loader (reading the policy file, which holds rules, not credentials) and says when the server would start locked. Its only state is two timestamp files in the plugin's data folder; a non-interactive session started that day (claude -p, the Agent SDK) also uses up the daily notice.- 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 do not read the sensitive ones.
- runs
- Local infrastructure (only if you run
/odoo-tools:deploy-localand confirm) — Docker containers on your machine: the sandbox (PostgreSQL + Odoo on127.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, runsnpm installandnpm run buildthere, and creates an owner-only.envwith 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 fromghcr.io/transgenia(mirrors of the officialodooandpostgresimages) 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(standard library only).status,down,logsanddestroy --yesmanage 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) |
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) |
ODOO_POLICY_FILE |
no | absolute path to an optional policy file (plugin option Permission policy file, 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). 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 saasparameters: null) on 10.0 to saas |
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@inODOO_URL(whose basic auth takes theAuthorizationheader JSON-2 needs), it stays on the deprecated endpoints, and on 19+odoo_versionreturns atransport_noticesaying 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.
The MCP server does not persist credentials to disk. Two caveats worth stating plainly:
- The optional CLI fallback keeps your credentials in a local
.envunder~/.claude/tools/odoo-cli(owner-only; you type the secret in yourself). SeeSECURITY.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 yo
