MCP Server for Odoo Integration
Project description
Odoo MCP Server
An MCP server implementation that integrates with Odoo ERP systems, enabling AI assistants to interact with Odoo data and functionality through the Model Context Protocol.
Features
- Odoo Integration: Generic method execution plus resource-based model and record access
- Odoo Transports: XML-RPC for Odoo 16-18/backward compatibility, plus Odoo 19 External JSON-2 via
/json/2/<model>/<method> - MCP Transports:
stdioby default, plus opt-in Streamable HTTP or SSE for remote MCP clients - Agent-Friendly Tools: Safe read-only tools plus diagnostic/report tools for JSON-2 migration, model relationships, upgrade risk, and fit/gap analysis
- Flexible Configuration: Support for config files and environment variables
- Resource Pattern System: URI-based access to Odoo data structures
- Error Handling: Clear error messages for common Odoo API issues
- Stateless Operations: Clean request/response cycle for reliable integration
Tools
The current MCP tool surface has 12 tools: 7 execution/read tools and 5 diagnostic/report tools. Diagnostic/report tools are preview-only unless explicitly documented otherwise; they do not execute candidate Odoo model methods.
-
execute_method
- Execute a custom method on an Odoo model
- Inputs:
model(string): The model name (e.g., 'res.partner')method(string): Method name to executeargs(optional array): Positional argumentskwargs(optional object): Keyword arguments
- Returns: Dictionary with the method result and success indicator
-
list_models
- List Odoo model technical names and display names
- Inputs:
query(optional string): Filter by technical model name or display namelimit(optional number): Maximum number of models to return, capped for safety
- Returns: Object containing count and matching models
-
get_model_fields
- Read field metadata for one model
- Inputs:
model(string): Odoo technical model name, for exampleres.partnerfield_names(optional array): Field names to include
- Returns: Object containing field definitions
-
search_records
- Search and read records through bounded read-only
search_read - Inputs:
model(string): Odoo technical model namedomain(optional array/object/string): Odoo search domainfields(optional array): Field names to readlimit(optional number): Maximum records to read, capped at 100offset(optional number): Search offsetorder(optional string): Odoo order expression
- Returns: Object containing count and matching records
- Search and read records through bounded read-only
-
read_record
- Read one record by model and ID
- Inputs:
model(string): Odoo technical model namerecord_id(number): Record IDfields(optional array): Field names to read
- Returns: Object containing the record or a not-found error
-
search_employee
- Search for employees by name
- Inputs:
name(string): The name (or part of the name) to search forlimit(optional number): The maximum number of results to return (default 20)
- Returns: Object containing success indicator, list of matching employee names and IDs, and any error message
-
search_holidays
- Searches for holidays within a specified date range
- Inputs:
start_date(string): Start date in YYYY-MM-DD formatend_date(string): End date in YYYY-MM-DD formatemployee_id(optional number): Optional employee ID to filter holidays
- Returns: Object containing success indicator, list of holidays found, and any error message
-
diagnose_odoo_call
- Diagnose an Odoo model call without executing it
- Flags read-only, destructive, and unknown-risk methods; highlights JSON-2 named-argument issues; redacts Odoo error
debugdetails by default - Inputs:
model(string): Odoo technical model namemethod(string): Odoo method nameargs(optional array): XML-RPC-style positional arguments to diagnosekwargs(optional object): Keyword arguments to diagnoseobserved_error(optional string/object): Error text or Odoo-shaped error object
- Returns: Structured diagnosis, suggested payload, issues, and next actions
-
inspect_model_relationships
- Inspect relationship and required-field metadata for one model
- Uses caller-provided metadata or bounded read-only
fields_getmetadata - Inputs:
model(string): Odoo technical model namefields_metadata(optional object): Pre-fetchedfields_getmetadatause_live_metadata(optional boolean): Whether to call bounded livefields_get
- Returns: Grouped
many2one,one2many,many2many, required fields, and create/write hints
-
generate_json2_payload
- Build a JSON-2 endpoint, headers, and named JSON body from XML-RPC-style args or kwargs without network I/O
- Includes destructive-method warnings, optional
X-Odoo-Databaseguidance, and per-call transaction notes - Inputs:
model(string): Odoo technical model namemethod(string): Odoo method nameargs(optional array): XML-RPC-style positional arguments to mapkwargs(optional object): Named JSON argumentsbase_url(optional string): Odoo base URL for preview outputdatabase(optional string): Database name forX-Odoo-Database
- Returns: JSON-2 path/URL, headers, named body, warnings, and transaction note
-
upgrade_risk_report
- Report migration risks for Odoo version upgrades, deprecated XML-RPC/JSON-RPC usage, JSON-2 named-argument changes, transaction behavior, and destructive methods
- Inputs:
source_version/target_version(optional strings): Odoo versionsmodules,methods,source_findings,observed_errors(optional arrays): Input evidence
- Returns: Risk summary, transport risk, destructive methods, and next actions
-
fit_gap_report
- Classify requirements as
standard,configuration,studio,custom_module,avoid, orunknown - Inputs:
requirements(array): Requirements to classifyavailable_models,available_fields,installed_modules,business_context(optional): Evidence for classification
- Returns: Classification items, evidence, and safe next discovery calls
- Classify requirements as
Resources
The current MCP resource surface has 4 resource URI patterns:
-
odoo://models
- Lists all available models in the Odoo system
- Returns: JSON array of model information
-
odoo://model/{model_name}
- Get information about a specific model including fields
- Example:
odoo://model/res.partner - Returns: JSON object with model metadata and field definitions
-
odoo://record/{model_name}/{record_id}
- Get a specific record by ID
- Example:
odoo://record/res.partner/1 - Returns: JSON object with record data
-
odoo://search/{model_name}/{domain}
- Search for records that match a domain
- Example:
odoo://search/res.partner/[["is_company","=",true]] - Returns: JSON array of matching records (limited to 10 by default)
Configuration
Odoo Connection Setup
- Create a configuration file named
odoo_config.json:
{
"url": "https://your-odoo-instance.com",
"db": "your-database-name",
"username": "your-username",
"password": "your-password-or-api-key"
}
- Alternatively, use environment variables:
ODOO_URL: Your Odoo server URLODOO_DB: Database nameODOO_USERNAME: Login usernameODOO_PASSWORD: Password or API keyODOO_TRANSPORT:xmlrpc(default) orjson2ODOO_API_KEY: Odoo API key used as the JSON-2 bearer token; if omitted withODOO_TRANSPORT=json2,ODOO_PASSWORDis treated as the API keyODOO_JSON2_DATABASE_HEADER:1/true(default) to sendX-Odoo-Databaseon JSON-2 requests, or0/falseto rely on host/dbfilter routingODOO_TIMEOUT: Connection timeout in seconds (default: 30)ODOO_VERIFY_SSL: Whether to verify SSL certificates (default: true)HTTP_PROXY: Force the ODOO connection to use an HTTP proxy
MCP Transport Setup
The server defaults to stdio, which is the most widely supported local MCP transport:
odoo-mcp
python -m odoo_mcp
For clients that support MCP over Streamable HTTP:
odoo-mcp --transport streamable-http --host 127.0.0.1 --port 8000 --path /mcp
Equivalent environment variables:
export MCP_TRANSPORT=streamable-http
export MCP_HTTP_HOST=127.0.0.1
export MCP_HTTP_PORT=8000
export MCP_HTTP_PATH=/mcp
export MCP_LOG_LEVEL=INFO
The default HTTP bind host is 127.0.0.1. Keep it local unless you put the server behind your own authentication, TLS, and network policy. Odoo credentials and API keys are sensitive.
Usage with Claude Desktop
On macOS, Claude Desktop reads MCP server configuration from:
~/Library/Application Support/Claude/claude_desktop_config.json
Claude Desktop may not inherit the same shell PATH you use in Terminal, so prefer an absolute Python path. Find it with:
which python3
Then add this to claude_desktop_config.json, replacing /opt/homebrew/bin/python3 with your actual path if different:
{
"mcpServers": {
"odoo": {
"command": "/opt/homebrew/bin/python3",
"args": [
"-m",
"odoo_mcp"
],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_DB": "your-database-name",
"ODOO_USERNAME": "your-username",
"ODOO_PASSWORD": "your-password-or-api-key"
}
}
}
}
If you install into a virtual environment, point command at that environment's Python binary, for example /path/to/venv/bin/python.
Docker
Build the local image first:
docker build -t mcp/odoo:latest -f Dockerfile .
Then configure Claude Desktop to run the container over stdio:
{
"mcpServers": {
"odoo": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"ODOO_URL",
"-e",
"ODOO_DB",
"-e",
"ODOO_USERNAME",
"-e",
"ODOO_PASSWORD",
"-e",
"ODOO_TRANSPORT",
"-e",
"ODOO_API_KEY",
"-e",
"ODOO_TIMEOUT",
"-e",
"ODOO_VERIFY_SSL",
"mcp/odoo:latest"
],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_DB": "your-database-name",
"ODOO_USERNAME": "your-username",
"ODOO_PASSWORD": "your-password-or-api-key",
"ODOO_TRANSPORT": "xmlrpc",
"ODOO_TIMEOUT": "30",
"ODOO_VERIFY_SSL": "1"
}
}
}
}
The container entrypoint is odoo-mcp; it starts the MCP server over stdio using the installed package entry point.
To run the same image over Streamable HTTP for a local MCP client:
docker run --rm \
-p 127.0.0.1:8000:8000 \
-e ODOO_URL \
-e ODOO_DB \
-e ODOO_USERNAME \
-e ODOO_PASSWORD \
-e ODOO_TRANSPORT \
-e ODOO_API_KEY \
mcp/odoo:latest \
--transport streamable-http \
--host 0.0.0.0 \
--port 8000
Odoo API Compatibility
This package keeps XML-RPC as the default transport for backward compatibility. As of the Odoo 19.0 documentation checked on 2026-04-28, Odoo marks XML-RPC and JSON-RPC endpoints (/xmlrpc, /xmlrpc/2, and /jsonrpc) as deprecated and scheduled for removal in Odoo 20 (fall 2026), with the External JSON-2 API as the replacement: https://www.odoo.com/documentation/19.0/developer/reference/external_api.html
For Odoo 19, enable JSON-2 explicitly:
export ODOO_TRANSPORT=json2
export ODOO_API_KEY="your-odoo-api-key"
JSON-2 uses bearer authentication and named JSON arguments. The client maps common ORM positional calls (search, search_count, search_read, read, write, unlink, create, name_search, and fields_get) to JSON-2 named arguments so the existing MCP tools keep working. For arbitrary custom methods with positional-only XML-RPC style arguments, pass kwargs that match the Odoo method signature or keep ODOO_TRANSPORT=xmlrpc.
Odoo JSON-2 does not accept a database name in the request body the way XML-RPC does. For multi-database deployments, this server sends the selected database through X-Odoo-Database by default. Set ODOO_JSON2_DATABASE_HEADER=0 only when the Odoo host/dbfilter routing already resolves the intended database.
JSON-2 uses named JSON arguments and each call runs in its own transaction. The diagnostic/report tools surface this difference so agents do not assume XML-RPC-style positional arguments or multi-call transaction boundaries.
When Odoo returns a structured JSON-2 error, the server preserves Odoo-shaped fields such as name, message, arguments, context, and debug. The debug field is redacted by default and is returned only when the caller explicitly opts in.
Release Verification
Before publishing a compatibility release, verify at least:
python -m pytest
python -m build
python -m twine check dist/*
python -c "from importlib.metadata import version; assert version('odoo-mcp') == '0.0.4'"
docker build -t mcp/odoo:latest -f Dockerfile .
uv run --python 3.12 --with-editable . scripts/odoo_compose_smoke.py --versions 16.0 17.0 18.0 19.0 --timeout 360 --inspector-smoke
The Docker Compose smoke test boots disposable Postgres and official odoo:<version> containers, initializes a fresh Odoo database, checks HTTP and XML-RPC readiness, then starts this MCP server and validates list_tools, list_resources, list_resource_templates, read_resource, execute_method, the typed read-only tools, and the diagnostic/report tools against live Odoo data. For Odoo 19.0 it also generates a disposable API key inside the container and validates direct JSON-2, MCP stdio JSON-2, MCP Streamable HTTP JSON-2, and MCP Inspector tools/list.
The GitHub release workflow must keep PyPI upload gated behind successful test, build, and MCP Inspector smoke jobs. For live runtime validation, connect the server to a test Odoo database and confirm the 12 tools and 4 resource URI patterns listed above initialize and can read/search non-sensitive test records.
Installation
Python Package
pip install odoo-mcp
Running the Server
# Using the installed package
odoo-mcp
# Using the MCP development tools
mcp dev odoo_mcp/server.py
# With additional dependencies
mcp dev odoo_mcp/server.py --with pandas --with numpy
# Mount local code for development
mcp dev odoo_mcp/server.py --with-editable .
Build
Docker build:
docker build -t mcp/odoo:latest -f Dockerfile .
Parameter Formatting Guidelines
When using the MCP tools for Odoo, pay attention to these parameter formatting guidelines:
-
Domain Parameter:
- The following domain formats are supported:
- List format:
[["field", "operator", value], ...] - Object format:
{"conditions": [{"field": "...", "operator": "...", "value": "..."}]} - JSON string of either format
- List format:
- Examples:
- List format:
[["is_company", "=", true]] - Object format:
{"conditions": [{"field": "date_order", "operator": ">=", "value": "2025-03-01"}]} - Multiple conditions:
[["date_order", ">=", "2025-03-01"], ["date_order", "<=", "2025-03-31"]]
- List format:
- The following domain formats are supported:
-
Fields Parameter:
- Should be an array of field names:
["name", "email", "phone"] - The server will try to parse string inputs as JSON
- Should be an array of field names:
License
This MCP server is licensed under the MIT License.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file odoo_mcp-0.0.4.tar.gz.
File metadata
- Download URL: odoo_mcp-0.0.4.tar.gz
- Upload date:
- Size: 37.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bbf7b06c0d3f50a569af0645184fda2d91c7c926a3f4d0bc924df06cfbc4a24f
|
|
| MD5 |
af74a70490c07523792c31979273ebd1
|
|
| BLAKE2b-256 |
ae6b6ac4204f2cdaade9f315e1f6471769232adf6a6773ec4fd7813b083e2747
|
File details
Details for the file odoo_mcp-0.0.4-py3-none-any.whl.
File metadata
- Download URL: odoo_mcp-0.0.4-py3-none-any.whl
- Upload date:
- Size: 28.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
730ab5bea3da91e45471a47cb41df2361a92ad84cfbcdc3297cb7abf680de2d4
|
|
| MD5 |
3be5dfd829a16118399bf24900411e18
|
|
| BLAKE2b-256 |
5379d7daa4b255a8f2a69ecc16c05ef9d878754ceea8dda9bc2f3464432ec2b4
|