The Odoo MCP that survives Odoo 20. Five-minute install. Zero Odoo-side setup. Safe writes, real diagnostics, JSON-2 ready. Odoo MCP turns any Odoo 16+ database into a Model Context Protocol server — using only your existing credentials. No App Store module, no permission setup, no admin access required. Built for local agents, IDEs, and automation tools that need real Odoo context without hand-ro
Add this skill
npx mdskills install tuanle96/mcp-odoo@tuanle96? Sign in with GitHub to claim this listing.Production-grade MCP bridge to Odoo 16-19 with safe write gates, diagnostics, and migration tools
1# Odoo MCP23<p align="center">4 <strong>The Odoo MCP that survives Odoo 20.</strong><br>5 Five-minute install. Zero Odoo-side setup. Safe writes, real diagnostics, JSON-2 ready.6</p>78<p align="center">9 <a href="https://pypi.org/project/odoo-mcp/"><img alt="PyPI" src="https://img.shields.io/pypi/v/odoo-mcp.svg"></a>10 <a href="https://pypi.org/project/odoo-mcp/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/odoo-mcp.svg"></a>11 <a href="https://pypi.org/project/odoo-mcp/"><img alt="Downloads" src="https://img.shields.io/pypi/dm/odoo-mcp.svg"></a>12 <a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-black.svg"></a>13 <a href="https://github.com/tuanle96/mcp-odoo/actions/workflows/publish.yml"><img alt="CI" src="https://github.com/tuanle96/mcp-odoo/actions/workflows/publish.yml/badge.svg"></a>14 <a href="https://github.com/tuanle96/mcp-odoo/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/tuanle96/mcp-odoo?style=flat"></a>15 <a href="https://github.com/tuanle96/mcp-odoo/network/members"><img alt="Forks" src="https://img.shields.io/github/forks/tuanle96/mcp-odoo?style=flat"></a>16</p>1718Odoo MCP turns any Odoo 16+ database into a Model Context Protocol server — using only your existing credentials. **No App Store module, no permission setup, no admin access required.** Built for local agents, IDEs, and automation tools that need real Odoo context without hand-rolled scripts or unsafe direct write access.1920It speaks XML-RPC for Odoo 16-18 and External JSON-2 for Odoo 19+. It exposes a compact MCP surface with read tools, diagnostics, schema discovery, migration helpers, local addon scanning, and a gated write workflow.2122## Try it in 30 seconds2324Once configured (see [Install](#install) and [Configure](#configure)), ask your agent things like:2526> "Show me all customers from Spain with unpaid invoices."27>28> "Find products with stock below 10 units in the main warehouse."29>30> "Audit the `custom_billing` addon for upgrade risks before we move to Odoo 19."3132## Highlights3334| Capability | What it gives you |35| --- | --- |36| 24 MCP tools | Read records, aggregate server-side, post chatter, inspect schema, build domains, scan addons, diagnose calls, access rules, and validate writes. |37| 5 agent prompts | Reusable workflows for failed calls, fit/gap workshops, JSON-2 migration, safe writes, and module audits. |38| Odoo 16-19 coverage | XML-RPC by default, JSON-2 opt-in for Odoo 19. |39| Streamable HTTP | Local HTTP/SSE support for clients that do not use stdio. |40| Smart field selection | `search_records` and `read_record` curate business-relevant fields when no `fields` argument is supplied — drops audit, message, binary, and unstored compute noise. Pass `fields=["*"]` to opt out. |41| Server-side aggregation | `aggregate_records` pushes groupby/sum/count/avg into Postgres via `formatted_read_group` (Odoo 19+) or `read_group` (16-18). |42| Chatter integration | `chatter_post` adds messages to any `mail.thread` record under the same approval-token gate as writes — or directly via `MCP_CHATTER_DIRECT=1`. |43| Locale plumbing | `ODOO_LOCALE` injects `context.lang` automatically on every Odoo call (caller can override). |44| Structured logging | JSON formatter and rotating file handler via `ODOO_MCP_LOG_LEVEL`, `ODOO_MCP_LOG_JSON`, `ODOO_MCP_LOG_FILE`. |45| Safe writes | Direct `create`, `write`, and `unlink` are blocked; approved writes require live metadata, a same-session token, explicit confirmation, and an env gate. |46| Real smoke tests | Docker Compose validation boots disposable Odoo 16.0, 17.0, 18.0, and 19.0 stacks, including restricted users, custom record rules, and packaged addon XML install/update. |4748## Why Odoo MCP4950| Trait | Odoo MCP | Other MCP-Odoo bridges |51| --- | --- | --- |52| Setup steps on Odoo side | **0** — works with any Odoo 16+ instance using credentials you already have. | Often require installing an App Store module, configuring enabled models, and granting per-tool permissions. |53| Safe write workflow | Approval token + live `fields_get` validation + explicit confirm + env gate. | Often expose direct `create`/`write`/`unlink` or a "yolo" bypass. |54| Diagnostics | `diagnose_odoo_call`, `diagnose_access`, `inspect_model_relationships`, `upgrade_risk_report`, `fit_gap_report`, `business_pack_report`, `scan_addons_source`. | Usually CRUD only. |55| Transport | XML-RPC (16-19) **and** External JSON-2 (Odoo 19+). Ready for Odoo 20. | Usually XML-RPC only — XML-RPC is deprecated in Odoo 20. |56| Migration helpers | `generate_json2_payload` previews the JSON-2 body for any XML-RPC call before you migrate. | None. |57| Agent prompts | 5 ready-made prompts for diagnose / fit-gap / JSON-2 migration / safe-write / module-audit. | Usually none. |58| HTTP transport security | DNS-rebinding protection, host/origin allowlists, local-bind by default. | Often missing. |59| Real Odoo smoke tests | Docker Compose harness boots disposable Odoo 16/17/18/19 stacks per release. | Often mock-based only. |6061## Install6263The fastest path is `uvx`, which fetches the package on demand:6465```bash66uvx odoo-mcp --health67```6869Or install into your environment:7071```bash72pip install odoo-mcp73# or: pipx install odoo-mcp74```7576Pull the prebuilt container from GitHub Container Registry:7778```bash79docker pull ghcr.io/tuanle96/mcp-odoo:latest80```8182For local development:8384```bash85git clone https://github.com/tuanle96/mcp-odoo.git86cd mcp-odoo87uv sync --extra dev88```8990## Configure9192Set connection values in the environment:9394```bash95export ODOO_URL="https://your-odoo-instance.com"96export ODOO_DB="your-database"97export ODOO_USERNAME="your-user"98export ODOO_PASSWORD="your-password-or-api-key"99export ODOO_TRANSPORT="xmlrpc"100```101102For Odoo 19 JSON-2:103104```bash105export ODOO_TRANSPORT="json2"106export ODOO_API_KEY="your-odoo-api-key"107export ODOO_JSON2_DATABASE_HEADER="1"108```109110`ODOO_JSON2_DATABASE_HEADER=1` sends `X-Odoo-Database` on JSON-2 calls. Set it to `0` only when host or dbfilter routing already selects the intended database.111112Optional environment variables:113114| Variable | Default | Effect |115| --- | --- | --- |116| `ODOO_LOCALE` | unset | Inject `context.lang` on every Odoo call. Caller-supplied `context.lang` always wins. |117| `ODOO_MCP_MAX_SMART_FIELDS` | `15` | Cap for smart-field selection when caller omits `fields`. |118| `ODOO_MCP_LOG_LEVEL` | `INFO` | Process logger level (DEBUG/INFO/WARNING/ERROR/CRITICAL). |119| `ODOO_MCP_LOG_JSON` | `0` | Truthy → emit JSON-formatted log lines. |120| `ODOO_MCP_LOG_FILE` | unset | Path → enable rotating file handler (10MB × 3 backups). |121| `ODOO_MCP_ENABLE_WRITES` | `0` | Required for `execute_approved_write`. |122| `ODOO_MCP_ALLOWED_SIDE_EFFECT_METHODS` | empty | Exact `model.method` allowlist (e.g. `sale.order.action_confirm`). |123| `ODOO_MCP_ALLOW_UNKNOWN_METHODS` | `0` | Broad mode for `execute_method`. Prefer the exact allowlist above. |124| `MCP_CHATTER_DIRECT` | `0` | Truthy → `chatter_post` skips the approval token gate and posts immediately. |125| `MCP_ALLOW_REMOTE_HTTP` | `0` | Truthy → permit non-local HTTP binds (still requires external auth/TLS). |126| `MCP_ALLOWED_HOSTS` / `MCP_ALLOWED_ORIGINS` | local | CSV allowlists for HTTP transports. |127128You can also use `odoo_config.json`:129130```json131{132 "url": "https://your-odoo-instance.com",133 "db": "your-database",134 "username": "your-user",135 "password": "your-password-or-api-key"136}137```138139## Run140141Start the MCP server over stdio:142143```bash144odoo-mcp145```146147or:148149```bash150python -m odoo_mcp151```152153Start Streamable HTTP for local clients:154155```bash156odoo-mcp --transport streamable-http --host 127.0.0.1 --port 8000 --path /mcp157```158159Non-local HTTP binds are rejected unless you pass `--allow-remote-http` or set `MCP_ALLOW_REMOTE_HTTP=1`. This server does not include built-in HTTP authentication. Put remote HTTP deployments behind your own authentication, TLS, and network policy.160161Check runtime posture without starting the server loop:162163```bash164odoo-mcp --health165```166167## MCP Tools16816924 tools grouped by use case. Each tool name is a single-purpose handle the agent can call.170171### Read & Discover (10)172173| Tool | Purpose |174| --- | --- |175| `list_models` | List Odoo model technical names and labels. |176| `get_model_fields` | Read field metadata for one model. |177| `search_records` | Run bounded read-only `search_read`. Smart-field selection when caller omits `fields`. |178| `read_record` | Read one record by model and ID. Smart-field selection when caller omits `fields`. |179| `aggregate_records` | Server-side groupby/aggregation via `formatted_read_group` (Odoo 19+) or `read_group` (16-18). |180| `search_employee` | Search employees by name. |181| `search_holidays` | Search leave records by date range. |182| `get_odoo_profile` | Read server version, user context, transport, database, and installed module summary. |183| `schema_catalog` | Build a bounded model catalog with optional field metadata. |184| `build_domain` | Build and validate an Odoo domain from structured conditions. |185186### Write & Operate (5)187188| Tool | Purpose |189| --- | --- |190| `preview_write` | Produce a non-executing approval payload for `create`, `write`, or `unlink`. |191| `validate_write` | Validate a write payload against trusted live `fields_get` metadata. |192| `execute_approved_write` | Execute only a same-session, live-validated, confirmed write when `ODOO_MCP_ENABLE_WRITES=1`. |193| `execute_method` | Execute a reviewed model method. Direct `create`, `write`, and `unlink` are blocked. Side-effect methods require an exact allowlist or `ODOO_MCP_ALLOW_UNKNOWN_METHODS=1`. |194| `chatter_post` | Post a chatter message on a `mail.thread` record. Default mode requires the approval-token preview/execute flow. |195196### Diagnose (3)197198| Tool | Purpose |199| --- | --- |200| `diagnose_odoo_call` | Diagnose a model call without executing it. |201| `diagnose_access` | Diagnose ACL and record-rule visibility for the current Odoo credential. |202| `inspect_model_relationships` | Group relationship fields, required fields, and create/write hints. |203204### Migrate (2)205206| Tool | Purpose |207| --- | --- |208| `generate_json2_payload` | Convert XML-RPC-shaped input into JSON-2 endpoint, headers, and named body. |209| `upgrade_risk_report` | Surface transport, method, and migration risks across Odoo versions. |210211### Audit & Plan (3)212213| Tool | Purpose |214| --- | --- |215| `scan_addons_source` | Scan local addon source without importing addon code. |216| `fit_gap_report` | Classify requirements into standard, configuration, Studio, custom module, avoid, or unknown. |217| `business_pack_report` | Report expected modules, models, and discovery calls for sales, CRM, inventory, accounting, or HR. |218219### Utility (1)220221| Tool | Purpose |222| --- | --- |223| `health_check` | Report non-secret MCP runtime posture. |224225## Resources226227| URI | Description |228| --- | --- |229| `odoo://models` | List available models. |230| `odoo://model/{model_name}` | Read model metadata and fields. |231| `odoo://record/{model_name}/{record_id}` | Read one record. |232| `odoo://search/{model_name}/{domain}` | Search records with a bounded domain. |233234## Prompts235236| Prompt | Use it for |237| --- | --- |238| `diagnose_failed_odoo_call` | Root-cause a failing Odoo call before retrying. |239| `fit_gap_workshop` | Turn raw requirements into Odoo fit/gap buckets. |240| `json2_migration_plan` | Plan XML-RPC or JSON-RPC migration to External JSON-2. |241| `safe_write_review` | Review a proposed `create`, `write`, or `unlink`. |242| `custom_module_audit` | Audit local addon source with scan, risk, and business evidence. |243244## Safe Write Model245246Writes are intentionally boring.2472481. `preview_write` creates a canonical, non-executing payload.2492. `validate_write` checks model metadata, required fields, readonly fields, relation hints, record IDs, and payload shape.2503. `execute_approved_write` runs only when all gates pass:251 - the approval came from `validate_write` in the same server process,252 - validation used trusted, non-empty live Odoo `fields_get` metadata,253 - the token has not expired or been consumed,254 - `confirm=true` is passed,255 - `ODOO_MCP_ENABLE_WRITES=1` is set.256257Odoo access rules, record rules, and server-side constraints still decide the final result.258259Reviewed side-effect methods such as `sale.order.action_confirm` can be enabled260one by one:261262```bash263export ODOO_MCP_ALLOWED_SIDE_EFFECT_METHODS="sale.order.action_confirm,res.partner.message_post"264```265266`ODOO_MCP_ALLOW_UNKNOWN_METHODS=1` is still supported for trusted deployments,267but `health_check` reports it as broad mode. Prefer exact allowlist entries when268you only need a small number of reviewed methods.269270## Client Setup271272Claude Desktop on macOS reads MCP configuration from:273274```text275~/Library/Application Support/Claude/claude_desktop_config.json276```277278Use an absolute Python path because GUI apps may not inherit your shell `PATH`:279280```json281{282 "mcpServers": {283 "odoo": {284 "command": "/opt/homebrew/bin/python3",285 "args": ["-m", "odoo_mcp"],286 "env": {287 "ODOO_URL": "https://your-odoo-instance.com",288 "ODOO_DB": "your-database",289 "ODOO_USERNAME": "your-user",290 "ODOO_PASSWORD": "your-password-or-api-key",291 "ODOO_TRANSPORT": "xmlrpc"292 }293 }294 }295}296```297298More examples are in [docs/client-configs.md](./docs/client-configs.md).299300## Docker301302Use the prebuilt GHCR image:303304```bash305docker pull ghcr.io/tuanle96/mcp-odoo:latest306```307308Or build it locally:309310```bash311docker build -t mcp/odoo:latest -f Dockerfile .312```313314Run over stdio from an MCP client (replace `mcp/odoo:latest` with `ghcr.io/tuanle96/mcp-odoo:latest` to use the prebuilt image):315316```json317{318 "mcpServers": {319 "odoo": {320 "command": "docker",321 "args": [322 "run",323 "-i",324 "--rm",325 "-e", "ODOO_URL",326 "-e", "ODOO_DB",327 "-e", "ODOO_USERNAME",328 "-e", "ODOO_PASSWORD",329 "-e", "ODOO_TRANSPORT",330 "-e", "ODOO_API_KEY",331 "mcp/odoo:latest"332 ]333 }334 }335}336```337338Run Streamable HTTP locally:339340```bash341docker run --rm \342 -p 127.0.0.1:8000:8000 \343 -e ODOO_URL \344 -e ODOO_DB \345 -e ODOO_USERNAME \346 -e ODOO_PASSWORD \347 -e ODOO_TRANSPORT \348 -e ODOO_API_KEY \349 mcp/odoo:latest \350 --transport streamable-http \351 --host 0.0.0.0 \352 --port 8000 \353 --allow-remote-http354```355356## Test357358Run the normal quality gates:359360```bash361uv run python -m ruff check .362uv run python -m mypy src363uv run python -m pytest364```365366Run real Odoo smoke tests:367368```bash369uv run --python 3.12 --with-editable . scripts/odoo_compose_smoke.py \370 --versions 16.0 17.0 18.0 19.0 \371 --timeout 360 \372 --inspector-smoke373```374375The smoke harness boots disposable Docker Compose stacks, validates direct Odoo access, validates MCP stdio, and for Odoo 19 also validates JSON-2 and Streamable HTTP.376377## Compatibility378379XML-RPC remains the default transport for broad compatibility. Odoo 19 supports External JSON-2 through `ODOO_TRANSPORT=json2`. Odoo has documented XML-RPC and JSON-RPC deprecation for Odoo 20, so new integrations should plan for JSON-2.380381## Contributing382383Issues, pull requests, and compatibility reports are welcome. Start with [CONTRIBUTING.md](./CONTRIBUTING.md), include your Odoo version, transport, client type, and the verification you ran.384385## Security386387Do not publish logs that contain Odoo credentials, API keys, database names from private environments, or full Odoo debug traces. Report vulnerabilities through [SECURITY.md](./SECURITY.md).388389## License390391MIT. See [LICENSE](./LICENSE).392
Full transparency — inspect the skill content before installing.