MCP Server for Odoo
Search, read, create, update and delete records in an Odoo ERP database over XML-RPC
Self-hosted Python MCP server for Odoo 16-19 with schema tools, diagnostics and gated writes
By erpipe-org Python Local · stdio CRM and salesFinance and paymentsDeveloper tools
59 popularity score ★ 427 ↓ 3.2k/mo
Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.
It needs ODOO_URL, ODOO_DB, ODOO_USERNAME, ODOO_PASSWORD. Replace each <NAME> with your value.
claude mcp add odoo -e ODOO_URL=<ODOO_URL> -e ODOO_DB=<ODOO_DB> -e ODOO_USERNAME=<ODOO_USERNAME> -e ODOO_PASSWORD=<ODOO_PASSWORD> -- uvx odoo-mcp{
"mcpServers": {
"odoo": {
"command": "uvx",
"args": [
"odoo-mcp"
],
"env": {
"ODOO_URL": "<ODOO_URL>",
"ODOO_DB": "<ODOO_DB>",
"ODOO_USERNAME": "<ODOO_USERNAME>",
"ODOO_PASSWORD": "<ODOO_PASSWORD>"
}
}
}
}{
"mcpServers": {
"odoo": {
"command": "uvx",
"args": [
"odoo-mcp"
],
"env": {
"ODOO_URL": "<ODOO_URL>",
"ODOO_DB": "<ODOO_DB>",
"ODOO_USERNAME": "<ODOO_USERNAME>",
"ODOO_PASSWORD": "<ODOO_PASSWORD>"
}
}
}
}{
"servers": {
"odoo": {
"type": "stdio",
"command": "uvx",
"args": [
"odoo-mcp"
],
"env": {
"ODOO_URL": "<ODOO_URL>",
"ODOO_DB": "<ODOO_DB>",
"ODOO_USERNAME": "<ODOO_USERNAME>",
"ODOO_PASSWORD": "<ODOO_PASSWORD>"
}
}
}
}[mcp_servers.odoo]
command = "uvx"
args = ["odoo-mcp"]
[mcp_servers.odoo.env]
ODOO_URL = "<ODOO_URL>"
ODOO_DB = "<ODOO_DB>"
ODOO_USERNAME = "<ODOO_USERNAME>"
ODOO_PASSWORD = "<ODOO_PASSWORD>"gemini mcp add --scope user -e ODOO_URL=<ODOO_URL> -e ODOO_DB=<ODOO_DB> -e ODOO_USERNAME=<ODOO_USERNAME> -e ODOO_PASSWORD=<ODOO_PASSWORD> odoo uvx -- odoo-mcpOpens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.
It needs ODOO_URL, ODOO_DB, ODOO_USERNAME, ODOO_PASSWORD. Replace each <NAME> with your value.
claude mcp add odoo -e ODOO_URL=<ODOO_URL> -e ODOO_DB=<ODOO_DB> -e ODOO_USERNAME=<ODOO_USERNAME> -e ODOO_PASSWORD=<ODOO_PASSWORD> -- docker run -i --rm -e ODOO_URL -e ODOO_DB -e ODOO_USERNAME -e ODOO_PASSWORD ghcr.io/erpipe-org/mcp-odoo:latest{
"mcpServers": {
"odoo": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"ODOO_URL",
"-e",
"ODOO_DB",
"-e",
"ODOO_USERNAME",
"-e",
"ODOO_PASSWORD",
"ghcr.io/erpipe-org/mcp-odoo:latest"
],
"env": {
"ODOO_URL": "<ODOO_URL>",
"ODOO_DB": "<ODOO_DB>",
"ODOO_USERNAME": "<ODOO_USERNAME>",
"ODOO_PASSWORD": "<ODOO_PASSWORD>"
}
}
}
}{
"mcpServers": {
"odoo": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"ODOO_URL",
"-e",
"ODOO_DB",
"-e",
"ODOO_USERNAME",
"-e",
"ODOO_PASSWORD",
"ghcr.io/erpipe-org/mcp-odoo:latest"
],
"env": {
"ODOO_URL": "<ODOO_URL>",
"ODOO_DB": "<ODOO_DB>",
"ODOO_USERNAME": "<ODOO_USERNAME>",
"ODOO_PASSWORD": "<ODOO_PASSWORD>"
}
}
}
}{
"servers": {
"odoo": {
"type": "stdio",
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"ODOO_URL",
"-e",
"ODOO_DB",
"-e",
"ODOO_USERNAME",
"-e",
"ODOO_PASSWORD",
"ghcr.io/erpipe-org/mcp-odoo:latest"
],
"env": {
"ODOO_URL": "<ODOO_URL>",
"ODOO_DB": "<ODOO_DB>",
"ODOO_USERNAME": "<ODOO_USERNAME>",
"ODOO_PASSWORD": "<ODOO_PASSWORD>"
}
}
}
}[mcp_servers.odoo]
command = "docker"
args = ["run", "-i", "--rm", "-e", "ODOO_URL", "-e", "ODOO_DB", "-e", "ODOO_USERNAME", "-e", "ODOO_PASSWORD", "ghcr.io/erpipe-org/mcp-odoo:latest"]
[mcp_servers.odoo.env]
ODOO_URL = "<ODOO_URL>"
ODOO_DB = "<ODOO_DB>"
ODOO_USERNAME = "<ODOO_USERNAME>"
ODOO_PASSWORD = "<ODOO_PASSWORD>"gemini mcp add --scope user -e ODOO_URL=<ODOO_URL> -e ODOO_DB=<ODOO_DB> -e ODOO_USERNAME=<ODOO_USERNAME> -e ODOO_PASSWORD=<ODOO_PASSWORD> odoo docker -- run -i --rm -e ODOO_URL -e ODOO_DB -e ODOO_USERNAME -e ODOO_PASSWORD ghcr.io/erpipe-org/mcp-odoo:latestODOO_URL |
Required: Address of the Odoo instance. |
|---|---|
ODOO_DB |
Required: Database name. |
ODOO_USERNAME |
Required: Odoo login used for every call. |
ODOO_PASSWORD |
Required: Password or API key for that login (or use a config file instead of these four). |
ODOO_TRANSPORT |
Optional: xmlrpc (default) or json2 for Odoo 19. |
ODOO_API_KEY |
Optional: API key for JSON-2 mode. |
ODOO_CONFIG_FILE |
Optional: Path to a JSON config file, needed for multiple instances. |
ODOO_MCP_ENABLE_WRITES |
Optional: Set to 1 to let execute_approved_write change data. |
ODOO_MCP_ALLOWED_SIDE_EFFECT_METHODS |
Optional: Exact model.method allowlist for execute_method. |
ODOO_MCP_AUDIT_LOG |
Optional: Path for a JSONL log of write-path events. |
ODOO_MCP_TOOLS_INCLUDE |
Optional: Globs that trim which tools are registered (also _EXCLUDE). |
ODOO_LOCALE |
Optional: Language passed as context.lang on every call. |
In a container, a setting goes in with -e NAME=value after docker run.
Odoo MCP is a Python server that connects an assistant to one or more Odoo databases using an ordinary Odoo login or API key; nothing has to be installed inside Odoo. It talks XML-RPC to Odoo 16-18 and can switch to the External JSON-2 API on Odoo 19 (ODOO_TRANSPORT=json2), and it runs over stdio or as a local Streamable HTTP service.
Most of its tools read: searching and reading records, server-side grouping and totals, attachments, field metadata, and accounting summaries such as aged receivables and payables. A second group helps Odoo developers and consultants: it explains why a call or an access rule fails, previews JSON-2 payloads, maps renamed models across versions, scans local addon source and classifies requirements into fit/gap buckets. It can also build an in-process BM25 search index over a slice of records, and fan read queries out across several configured instances.
Writes go through a three-step flow (preview_write, validate_write, execute_approved_write). The final step runs only with ODOO_MCP_ENABLE_WRITES=1, a token issued by the same process and an explicit confirm. Plain create, write and unlink calls through execute_method are refused.
The v1.3.0 source registers 41 tools, matching the README's count, but the README's tool tables list only 39: data_quality_report (duplicate, missing-value and orphan checks on one model) and analyze_upgrade_log (classifies failures in a pasted Odoo upgrade log) are registered in the code but missing from the tables. The same maintainer runs a separate hosted service, ERPipe, with its own codebase and tool set; this page covers the self-hosted package only.
| Runtime | Python 3.10+orDocker |
|---|
Python 3.10 or newer; the documented launch uses uvx, which needs uv (pip or pipx also work). An Odoo 16 or newer database (Community or Enterprise) reachable over HTTPS, plus its URL, database name and a username with password or API key. Odoo 19 JSON-2 mode needs an Odoo API key. Docker is an alternative to Python.
Without ODOO_MCP_ENABLE_WRITES=1 nothing can be changed except through allowlisted methods. Side-effect methods such as sale.order.action_confirm need an exact entry in ODOO_MCP_ALLOWED_SIDE_EFFECT_METHODS. MCP resources (odoo://...) always use the default instance in this release. search_records returns 10 rows by default (tools_read.py). read_attachment returns up to 1 MiB of content by default (ODOO_MCP_MAX_ATTACHMENT_BYTES, hard cap 16 MiB). The HTTP transport has no built-in authentication unless the OAuth introspection settings are configured, and it refuses non-local binds without --allow-remote-http. Odoo's own access rules still apply to the user it signs in as.
Fits Odoo admins, partners and developers who want an assistant to query and audit their own Odoo databases from a local client, especially across several client databases or when planning a move to Odoo 19's JSON-2 API. Because writes are off by default and gated, it also suits teams that want read access first and controlled writes later. People who would rather not run a process, or who want a fixed remote URL for ChatGPT, are pointed by its README to the maintainer's hosted ERPipe service instead. It is a community project, not published by Odoo SA.
list_modelsget_model_fieldssearch_recordsread_recordaggregate_recordssearch_employeesearch_holidaysget_odoo_profileschema_catalogbuild_domainread_attachmentpreview_writevalidate_writeexecute_approved_writeexecute_methodchatter_postdiagnose_odoo_calldiagnose_accessinspect_model_relationshipsgenerate_json2_payloadupgrade_risk_reportanalyze_upgrade_loglookup_model_historyscan_addons_sourcefit_gap_reportbusiness_pack_reportdata_quality_reportindex_knowledgesearch_knowledgeknowledge_statsreceivable_payable_agingaccounting_health_summarysubmit_async_taskget_async_taskcancel_async_tasklist_async_taskssearch_across_instancesaggregate_across_instancesaccounting_health_across_instanceshealth_checklist_instances