| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Lines of code | 1992 |
| Technical Name |
ow_mcp_server |
| License | LGPL-3 |
| Website | https://www.openworx.nl |
OW MCP Server.
Connect AI to your Odoo.
Native Model Context Protocol server for Odoo 18. Plug Claude, Cursor, and Copilot straight into your database — no bridge process, no pip dependencies.
$ claude mcp add --transport http odoo \
https://odoo.example.com/mcp
→ Connected. 11 tools loaded.
What it does
Exposes an MCP (JSON-RPC 2.0) endpoint at /mcp on your Odoo server.
MCP-compatible AI assistants — Claude Code, Claude Desktop, Cursor, GitHub Copilot —
speak to it directly to read and write Odoo data. Eleven well-defined tools,
LLM-friendly output, and fine-grained permissions.
Key features
Native MCP, no bridge
Speaks MCP protocol itself. No external translator process — the addon is the MCP server.
Eleven typed tools
Full CRUD plus search_count, read_group, get_model_schema. Each ships a JSON schema so LLMs fill arguments correctly.
LLM-friendly output
Many2one as {id, name}, ISO 8601 dates, pagination envelopes with has_more, HTML stripped, binaries summarised.
Bearer API keys only
Odoo built-in User API keys, scope mcp. No password login, no session cookies. Revoke = instant cut-off.
Per-model access control
Read / Write / Create / Delete per model. Optional JSON field allow-lists. Layered on top of Odoo record rules and groups.
Hardcoded safety blocklist
Most of ir.*, all res.users.*, auth_*, mail.mail, bus.* — never exposed, even in YOLO mode.
Multi-database ready
Works with OCA's dbfilter_from_header. One Odoo instance → multiple MCP endpoints, one per tenant.
Stdio bridge included
Bundled ow_mcp_stdio.py (stdlib only, no pip) for clients that need stdio transport.
YOLO dev mode
Bypass MCP access config for fast local testing. Red banner in admin UI. Odoo native ACL always enforced.
Battle-tested
200+ unit and integration tests: auth, pagination, blocklist, domain walker, nested-write guard, multicompany, audit redaction, full HttpCase flows.
Eleven tools. One protocol.
| Tool | What it does |
|---|---|
list_models |
Enumerate exposed models with CRUD flags and field allow-lists. |
search_records |
Domain + fields + pagination. Returns {records, total, has_more, next_offset}. |
get_record |
Fetch one or many by id(s); reports missing ids. |
create_record |
Create a record; returns new id and echo of created values. |
update_record |
Update one or many records with a values dict. |
delete_record |
Delete one or many records by id(s). |
search_count |
Count matching records without fetching them. |
get_model_schema |
Field definitions (name, type, required, relation, selection). |
read_group |
Group + aggregate, e.g. totals per state or amounts per month. |
get_user_context |
Caller identity, allowed companies, language, timezone. |
list_modules |
Installed-modules inventory (MCP Administrator only). |
Every tool except list_models and list_modules accepts an optional company_id argument, validated against the user's allowed companies.
Installation
addons_path (or git-clone into custom/addons/).
Dependencies: none beyond base and base_setup. No pip packages on the Odoo server.
Setup in three minutes
My Profile → Account Security → New API Key → Scope:
mcp. Copy the key (shown only once).
Open MCP Server app → Model Access. Toggle Read / Write / Create / Delete per model. Optional JSON field allow-list.
Use one of the snippets below.
Client configuration
Claude Code (native HTTP)
claude mcp add --transport http odoo https://odoo.example.com/mcp \ --header "Authorization: Bearer $ODOO_MCP_KEY"
Cursor (native HTTP — add to ~/.cursor/mcp.json)
{
"mcpServers": {
"odoo": {
"url": "https://odoo.example.com/mcp",
"headers": { "Authorization": "Bearer YOUR_API_KEY" }
}
}
}
Claude Desktop (stdio bridge — add to claude_desktop_config.json)
{
"mcpServers": {
"odoo": {
"command": "python3",
"args": [
"/path/to/ow_mcp_server/tools/ow_mcp_stdio.py",
"--url", "https://odoo.example.com/mcp"
],
"env": { "ODOO_MCP_KEY": "YOUR_API_KEY" }
}
}
}
Bundled bridge uses Python stdlib only — no pip install required.
Multi-database (OCA dbfilter_from_header)
{
"mcpServers": {
"odoo-tenant-a": {
"command": "python3",
"args": [
"/path/to/tools/ow_mcp_stdio.py",
"--url", "https://odoo.example.com/mcp",
"--database", "tenant_a"
],
"env": { "ODOO_MCP_KEY": "KEY_FOR_TENANT_A" }
}
}
}
Security model
mcp; other-scope keys can't authenticate here.check_access_rights and check_access_rule all fire as in the web client.ow.mcp.model.access.ir.*, all res.users.*, auth_*, mail.mail, bus.* — never exposed.--dev=* + env var OW_MCP_ALLOW_YOLO=1. Red banner warns when on.(0,…)/(1,…)/(2,…) opcodes. Each related model through its own MCP call.company_id validated against allowed companies. Response cache keys on group + company — revoked access can't replay.FAQ
Do I need to install anything on the client machine?
For Claude Code and Cursor: nothing. They speak HTTP MCP natively. For Claude Desktop: copy ow_mcp_stdio.py to client machine. Python 3 only — no pip.
Does this replace XML-RPC / JSON-RPC Odoo endpoints?
No. /mcp is additive — lives alongside /xmlrpc/2/* and /jsonrpc. Existing integrations unchanged.
How does it differ from MCP bridges that proxy to REST?
Bridge-style modules run a second Python process translating MCP to Odoo REST/XML-RPC. This addon serves MCP inside Odoo: fewer moving parts, one auth surface, native record-rule enforcement, no translator lag.
Can Claude delete production data?
Only if you enable allow_delete on a specific model via Model Access. Default is read-only. Even then the user behind the API key needs Odoo-level delete rights.
HTTPS in production?
Always. API keys travel in the Authorization header — TLS only. Use your existing reverse proxy (nginx / Caddy / traefik).
Built by Openworx — Odoo specialists.
openworx.nl
Please log in to comment on this module