Mcp Server Odoo — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Mcp Server Odoo (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
An MCP server that enables AI assistants like Claude to interact with Odoo ERP systems. Access business data, search records, create new entries, update existing data, and manage your Odoo instance through natural language.
Works with any Odoo instance! Use YOLO mode for quick testing and demos with any standard Odoo installation. For enterprise security, access controls, and production use, install the Odoo MCP module.
Thank you for using this project! If you find it helpful and would like to support my work, kindly consider buying me a coffee. Your support is greatly appreciated!
<a href="https://www.buymeacoffee.com/lucianobustos" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
The MCP server runs on your local computer (where Claude Desktop is installed), not on your Odoo server. You need to install UV on your local machine:
<details> <summary>macOS/Linux</summary>
curl -LsSf https://astral.sh/uv/install.sh | sh</details>
<details> <summary>Windows</summary>
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"</details>
After installation, restart your terminal to ensure UV is in your PATH.
Add this configuration to your MCP settings:
{
"mcpServers": {
"odoo": {
"command": "uvx",
"args": ["mcp-server-odoo-ei"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here"
}
}
}
}<details> <summary>Claude Desktop</summary>
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"odoo": {
"command": "uvx",
"args": ["mcp-server-odoo-ei"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here",
"ODOO_DB": "your-database-name",
"ODOO_LOCALE": "es_ES"
}
}
}
}For Spanish (Argentina):
{
"mcpServers": {
"odoo": {
"command": "uvx",
"args": ["mcp-server-odoo-ei"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here",
"ODOO_DB": "your-database-name",
"ODOO_LOCALE": "es_AR"
}
}
}
}</details>
<details> <summary>Claude Code</summary>
Add to .mcp.json in your project root:
{
"mcpServers": {
"odoo": {
"command": "uvx",
"args": ["mcp-server-odoo"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here",
"ODOO_DB": "your-database-name"
}
}
}
}Or use the CLI:
claude mcp add odoo \
--env ODOO_URL=https://your-odoo-instance.com \
--env ODOO_API_KEY=your-api-key-here \
--env ODOO_DB=your-database-name \
-- uvx mcp-server-odoo</details>
<details> <summary>Cursor</summary>
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"odoo": {
"command": "uvx",
"args": ["mcp-server-odoo-ei"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here",
"ODOO_DB": "your-database-name"
}
}
}
}</details>
<details> <summary>VS Code (with GitHub Copilot)</summary>
Add to .vscode/mcp.json in your workspace:
{
"servers": {
"odoo": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-server-odoo"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here",
"ODOO_DB": "your-database-name"
}
}
}
}Note: VS Code uses"servers"as the root key, not"mcpServers".
</details>
<details> <summary>Windsurf</summary>
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"odoo": {
"command": "uvx",
"args": ["mcp-server-odoo-ei"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here",
"ODOO_DB": "your-database-name"
}
}
}
}</details>
<details> <summary>Zed</summary>
Add to ~/.config/zed/settings.json:
{
"context_servers": {
"odoo": {
"command": {
"path": "uvx",
"args": ["mcp-server-odoo-ei"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here",
"ODOO_DB": "your-database-name"
}
}
}
}
}</details>
<details> <summary>Using Docker</summary>
Run with Docker — no Python installation required:
{
"mcpServers": {
"odoo": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "ODOO_URL=http://host.docker.internal:8069",
"-e", "ODOO_API_KEY=your-api-key-here",
"ivnvxd/mcp-server-odoo"
]
}
}
}Note: Usehost.docker.internalinstead oflocalhostto connect to Odoo running on the host machine.
For HTTP transport:
docker run --rm -p 8000:8000 \
-e ODOO_URL=http://host.docker.internal:8069 \
-e ODOO_API_KEY=your-api-key-here \
ivnvxd/mcp-server-odoo --transport streamable-http --host 0.0.0.0The image is also available on GHCR: ghcr.io/ivnvxd/mcp-server-odoo </details>
<details> <summary>Using pip</summary>
# Install globally
pip install mcp-server-odoo-ei
# Or use pipx for isolated environment
pipx install mcp-server-odoo-eiThen use mcp-server-odoo-ei as the command in your MCP configuration. </details>
<details> <summary>From source</summary>
git clone https://github.com/elevateinformatics/mcp-server-odoo.git
cd mcp-server-odoo
pip install -e .Then use the full path to the package in your MCP configuration. </details>
The server requires the following environment variables:
| Variable | Required | Description | Example |
|---|---|---|---|
ODOO_URL | Yes | Your Odoo instance URL | https://mycompany.odoo.com |
ODOO_API_KEY | Yes* | API key for authentication | 0ef5b399e9ee9c11b053dfb6eeba8de473c29fcd |
ODOO_USER | Yes* | Username (if not using API key) | admin |
ODOO_PASSWORD | Yes* | Password (if not using API key) | admin |
ODOO_DB | No | Database name (auto-detected if not set) | mycompany |
ODOO_LOCALE | No | Default session locale for Odoo responses (mutable at runtime via set_locale) | es_ES, es_AR, en_US, fr_FR |
ODOO_YOLO | No | YOLO mode - bypasses MCP security (⚠️ DEV ONLY) | off, read, true |
ODOO_MCP_ENABLE_METHOD_CALLS | No | Enable the call_model_method tool — requires ODOO_YOLO=true (⚠️ Dangerous, see call_model_method) | false, true |
*Either ODOO_API_KEY or both ODOO_USER and ODOO_PASSWORD are required.
Notes:
ODOO_DBODOO_LOCALE is set, Odoo returns translated field labels, selection values, and messages in that language. The session locale is mutable at runtime via the set_locale tool, and per-call lang overrides are supported on every CRUD tool..env file in the working directory.#### Advanced Configuration
| Variable | Default | Description |
|---|---|---|
ODOO_MCP_DEFAULT_LIMIT | 10 | Default number of records returned per search |
ODOO_MCP_MAX_LIMIT | 100 | Maximum allowed record limit per request |
ODOO_MCP_MAX_SMART_FIELDS | 15 | Maximum fields returned by smart field selection |
ODOO_MCP_LOG_LEVEL | INFO | Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
ODOO_MCP_LOG_JSON | false | Enable structured JSON log output |
ODOO_MCP_LOG_FILE | — | Path for rotating log file (10 MB, 5 backups) |
ODOO_MCP_TRANSPORT | stdio | Transport type (stdio, streamable-http) |
ODOO_MCP_HOST | localhost | Host to bind for HTTP transport |
ODOO_MCP_PORT | 8000 | Port to bind for HTTP transport |
ODOO_CACHE_FIELD_TTL | 3600 | TTL (seconds) for cached field metadata |
ODOO_CACHE_PERMISSION_TTL | 300 | TTL (seconds) for cached MCP permissions |
The server supports multiple transport protocols for different use cases:
#### 1. stdio (Default) Standard input/output transport - used by desktop AI applications like Claude Desktop.
# Default transport - no additional configuration needed
uvx mcp-server-odoo-ei#### 2. streamable-http Standard HTTP transport for REST API-style access and remote connectivity.
# Run with HTTP transport
uvx mcp-server-odoo-ei --transport streamable-http --host 0.0.0.0 --port 8000
# Or use environment variables
export ODOO_MCP_TRANSPORT=streamable-http
export ODOO_MCP_HOST=0.0.0.0
export ODOO_MCP_PORT=8000
uvx mcp-server-odoo-eiThe HTTP endpoint will be available at: http://localhost:8000/mcp/
Note: SSE (Server-Sent Events) transport has been deprecated in MCP protocol version 2025-03-26. Use streamable-http transport instead for HTTP-based communication. Requires MCP library v1.9.4 or higher for proper session management.
<details> <summary>Running streamable-http transport for remote access</summary>
{
"mcpServers": {
"odoo-remote": {
"command": "uvx",
"args": ["mcp-server-odoo-ei", "--transport", "streamable-http", "--port", "8080"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here",
"ODOO_DB": "your-database-name"
}
}
}
}</details>
YOLO mode allows the MCP server to connect directly to any standard Odoo instance without requiring the MCP module. This mode bypasses all MCP security controls and is intended ONLY for development, testing, and demos.
🚨 WARNING: Never use YOLO mode in production environments!
#### YOLO Mode Levels
ODOO_YOLO=read):ODOO_YOLO=true):#### YOLO Mode Configuration
<details> <summary>Read-Only YOLO Mode (safer for demos)</summary>
{
"mcpServers": {
"odoo-demo": {
"command": "uvx",
"args": ["mcp-server-odoo-ei"],
"env": {
"ODOO_URL": "http://localhost:8069",
"ODOO_USER": "admin",
"ODOO_PASSWORD": "admin",
"ODOO_DB": "demo",
"ODOO_YOLO": "read"
}
}
}
}</details>
<details> <summary>Full Access YOLO Mode (⚠️ use with extreme caution)</summary>
{
"mcpServers": {
"odoo-test": {
"command": "uvx",
"args": ["mcp-server-odoo-ei"],
"env": {
"ODOO_URL": "http://localhost:8069",
"ODOO_USER": "admin",
"ODOO_PASSWORD": "admin",
"ODOO_DB": "test",
"ODOO_YOLO": "true"
}
}
}
}</details>
#### When to Use YOLO Mode
✅ Appropriate Uses:
❌ Never Use For:
#### YOLO Mode Security Notes
Once configured, you can ask Claude:
Search & Retrieve:
Create & Manage:
When you configure ODOO_LOCALE, Odoo will return all data in that language:
With `ODOO_LOCALE=es_ES` (Spanish):
# Field labels will be in Spanish
Cliente: Acme Corporation
Correo electrónico: [email protected]
Estado: Borrador
# Selection values will be in Spanish
Tipo: Cliente
País: EspañaWith `ODOO_LOCALE=es_AR` (Argentine Spanish):
# Uses Argentine terminology and formats
Razón Social: La Valeria S.A.
CUIT: 30-12345678-9
Provincia: Buenos AiresSupported locales include:
es_ES - Spanish (Spain)es_AR - Spanish (Argentina)es_MX - Spanish (Mexico)en_US - English (United States)en_GB - English (United Kingdom)fr_FR - French (France)pt_BR - Portuguese (Brazil)de_DE - German (Germany)search_recordsSearch for records in any Odoo model with filters.
{
"model": "res.partner",
"domain": [["is_company", "=", true], ["country_id.code", "=", "ES"]],
"fields": ["name", "email", "phone"],
"limit": 10
}Field Selection Options:
fields or set to null: Returns smart selection of common fields["__all__"]: Returns all fields (use with caution)get_recordRetrieve a specific record by ID.
{
"model": "res.partner",
"record_id": 42,
"fields": ["name", "email", "street", "city"]
}Field Selection Options:
fields or set to null: Returns smart selection of common fields with metadata["__all__"]: Returns all fields without metadataread_recordsRead multiple records by their IDs in a single API call (batch operation).
{
"model": "res.partner",
"record_ids": [1, 2, 3, 4, 5],
"fields": ["name", "email", "phone"]
}This is more efficient than calling get_record multiple times when you need to retrieve specific records by ID. Returns found records and reports any missing IDs.
list_modelsList all models enabled for MCP access.
{}list_resource_templatesList available resource URI templates and their patterns.
{}create_recordCreate a new record in Odoo.
{
"model": "res.partner",
"values": {
"name": "New Customer",
"email": "[email protected]",
"is_company": true
}
}update_recordUpdate an existing record.
{
"model": "res.partner",
"record_id": 42,
"values": {
"phone": "+1234567890",
"website": "https://example.com"
}
}update_recordsUpdate multiple records with the same values in a single API call (batch operation).
{
"model": "project.task",
"record_ids": [1, 2, 3, 4, 5],
"values": {
"display_in_project": true
}
}This is much more efficient than calling update_record multiple times when you need to apply the same changes to many records.
delete_recordDelete a record from Odoo.
{
"model": "res.partner",
"record_id": 42
}post_messagePost a message to a record's chatter (mail.thread). subtype="note" (default) is an internal log; subtype="comment" notifies followers. Set body_is_html=true for HTML markup. Optional partner_ids and attachment_ids reference existing partners and attachments.
{
"model": "res.partner",
"record_id": 42,
"body": "Called customer, will follow up Tuesday"
}{
"model": "sale.order",
"record_id": 17,
"body": "<p>Shipping confirmed for Monday</p>",
"subtype": "comment",
"body_is_html": true
}aggregate_recordsServer-side aggregation. Use this whenever the question is "totals/counts/groupings" rather than "list of records" — it pushes the work down to PostgreSQL instead of pulling raw rows. Dispatches to formatted_read_group on Odoo 19+ (the new dedicated method) and falls back to read_group with response normalization on older versions. Callers see a consistent response shape on every supported version. When aggregates is omitted, defaults to ["__count"] so each group always carries a count.
{
"model": "sale.order",
"groupby": ["date_order:month"],
"aggregates": ["amount_total:sum"],
"domain": [["state", "in", ["sale", "done"]]]
}{
"model": "res.partner",
"groupby": ["country_id"]
}call_model_methodGeneric XML-RPC execute_kw escape hatch — invokes any public method on any model, for workflow actions not covered by CRUD (post invoice, confirm sale order, validate picking, etc.). Available only when both ODOO_YOLO=true (full YOLO) and ODOO_MCP_ENABLE_METHOD_CALLS=true are set; otherwise the tool is not registered. Only public ASCII Python identifiers are accepted as method names — dotted, dashed, whitespace, non-ASCII, and _-prefixed names are rejected.
[!WARNING] This tool can invoke any public method, including destructive ones (e.g.unlink,button_draft, custom workflow methods). Enable only in trusted environments where you accept the blast radius. Odoo's record rules and ACLs still apply for the authenticated user.
{
"model": "account.move",
"method": "action_post",
"arguments": [[42]]
}{
"model": "sale.order",
"method": "action_confirm",
"arguments": [[7]],
"keyword_arguments": {"context": {"lang": "en_US"}}
}When you omit the fields parameter (or set it to null), the server automatically selects the most relevant fields for each model using a scoring algorithm:
id, name, display_name, and active are always includedThe default limit is 15 fields per request. Responses include metadata showing which fields were returned and how many total fields are available. You can adjust the limit with ODOO_MCP_MAX_SMART_FIELDS or bypass it entirely with fields: ["__all__"].
The server also provides direct access to Odoo data through resource URIs:
| URI Pattern | Description |
|---|---|
odoo://{model}/record/{id} | Retrieve a specific record by ID |
odoo://{model}/search | Search records with default settings (first 10 records) |
odoo://{model}/count | Count all records in a model |
odoo://{model}/fields | Get field definitions and metadata for a model |
Examples:
odoo://res.partner/record/1 — Get partner with ID 1odoo://product.product/search — List first 10 productsodoo://res.partner/count — Count all partnersodoo://product.product/fields — Show all fields for productsNote: Resource URIs don't support query parameters (like?domain=...). For filtering, pagination, and field selection, use thesearch_recordstool instead.
AI Assistant (Claude, Copilot, etc.)
↓ MCP Protocol (stdio or HTTP)
mcp-server-odoo
↓ XML-RPC
Odoo InstanceThe server translates MCP tool calls into Odoo XML-RPC requests. It handles authentication, access control, field selection, data formatting, and error handling — presenting Odoo data in an LLM-friendly hierarchical text format.
<details> <summary>Connection Issues</summary>
If you're getting connection errors:
https://your-odoo.com/mcp/health</details>
<details> <summary>Authentication Errors</summary>
If authentication fails:
</details>
<details> <summary>Model Access Errors</summary>
If you can't access certain models:
</details>
<details> <summary>"spawn uvx ENOENT" Error</summary>
This error means UV is not installed or not in your PATH:
Solution 1: Install UV (see Installation section above)
Solution 2: macOS PATH Issue Claude Desktop on macOS doesn't inherit your shell's PATH. Try:
open -a "Claude"Solution 3: Use Full Path Find UV location and use full path:
which uvx
# Example output: /Users/yourname/.local/bin/uvxThen update your config:
{
"command": "/Users/yourname/.local/bin/uvx",
"args": ["mcp-server-odoo-ei"]
}</details>
<details> <summary>Database Configuration Issues</summary>
If you see "Access Denied" when listing databases:
ODOO_DB in your configurationExample configuration:
{
"env": {
"ODOO_URL": "https://your-odoo.com",
"ODOO_API_KEY": "your-key",
"ODOO_DB": "your-database-name"
}
}Note: ODOO_DB is required if database listing is restricted on your server. </details>
<details> <summary>"SSL: CERTIFICATE_VERIFY_FAILED" Error</summary>
This error occurs when Python cannot verify SSL certificates, often on macOS or corporate networks.
Solution: Add SSL certificate path to your environment configuration:
{
"env": {
"ODOO_URL": "https://your-odoo.com",
"ODOO_API_KEY": "your-key",
"SSL_CERT_FILE": "/etc/ssl/cert.pem"
}
}This tells Python where to find the system's SSL certificate bundle for HTTPS connections. The path /etc/ssl/cert.pem is the standard location on most systems. </details>
<details> <summary>Connection Drops After Idle Period</summary>
If you experience connection errors after the server has been idle for a while, this is handled automatically. The server includes automatic reconnection logic that:
If you still experience issues, check your network connectivity or firewall settings. </details>
<details> <summary>Debug Mode</summary>
Enable debug logging for more information:
{
"env": {
"ODOO_URL": "https://your-odoo.com",
"ODOO_API_KEY": "your-key",
"ODOO_MCP_LOG_LEVEL": "DEBUG"
}
}</details>
The server includes several performance optimizations:
Field metadata and permissions are cached on-demand. Records always fetch fresh data from Odoo.
| Variable | Default | Description |
|---|---|---|
ODOO_CACHE_FIELD_TTL | 3600 | Field metadata cache TTL (seconds) |
ODOO_CACHE_PERMISSION_TTL | 300 | Permission check cache TTL (seconds) |
Example configuration:
{
"env": {
"ODOO_URL": "https://your-odoo.com",
"ODOO_API_KEY": "your-key",
"ODOO_CACHE_FIELD_TTL": "7200",
"ODOO_CACHE_PERMISSION_TTL": "600"
}
}For improved startup time and runtime performance, you can compile the server using Nuitka:
# Install build dependencies
pip install -e ".[build]"
# Build optimized executable
python scripts/build_nuitka.py
# Or build as standalone directory
python scripts/build_nuitka.py --standaloneThe compiled executable provides:
--onefile)<details> <summary>Running from source</summary>
# Clone the repository
git clone https://github.com/elevateinformatics/mcp-server-odoo.git
cd mcp-server-odoo
# Install in development mode
pip install -e ".[dev]"
# Run tests
pytest --cov
# Run the server
python -m mcp_server_odoo
# Check version
python -m mcp_server_odoo --version</details>
<details> <summary>Testing with MCP Inspector</summary>
# Using uvx
npx @modelcontextprotocol/inspector uvx mcp-server-odoo-ei
# Using local installation
npx @modelcontextprotocol/inspector python -m mcp_server_odoo</details>
# Unit tests (no Odoo needed)
uv run pytest -m "not yolo and not mcp" --cov
# YOLO integration tests (vanilla Odoo, no MCP module)
uv run pytest -m "yolo" -v
# MCP integration tests (Odoo + MCP module installed)
uv run pytest -m "mcp" -v
# All tests
uv run pytest --cov
# Run specific test categories
uv run pytest tests/test_tools.py -v
uv run pytest tests/test_server_foundation.py -vThis project is licensed under the Mozilla Public License 2.0 (MPL-2.0) - see the LICENSE file for details.
Contributions are very welcome! Please see the CONTRIBUTING guide for details.
And do not forget to give the project a star if you like it! :star:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.