Model Context Protocol (MCP) server that enables AI assistants to securely interact with Odoo ERP systems through standardized resources and tools for data retrieval and manipulation.
Обзор
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. 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. - 🔍 any Odoo record (customers, products, invoices, etc.) - ✨ with field validation and permission checks - ✏️ with smart field handling - 🗑️ respecting model-level permissions - 🔢 matching specific criteria - 📋 to understand data structure - 📊 — group, sum, and count without pulling raw rows - ⚡ — invoke any public Odoo method (post invoice, confirm SO, etc.
README
MCP Server for Odoo
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.
Features
- 🔍 Search and retrieve any Odoo record (customers, products, invoices, etc.)
- ✨ Create new records with field validation and permission checks
- ✏️ Update existing data with smart field handling
- 🗑️ Delete records respecting model-level permissions
- 🔢 Count records matching specific criteria
- 📋 Inspect model fields to understand data structure
- 📊 Server-side aggregation — group, sum, and count without pulling raw rows
- ⚡ Workflow actions — invoke any public Odoo method (post invoice, confirm SO, etc.) via an opt-in escape hatch
- 🔐 Secure access with API key or username/password authentication
- 🎯 Smart pagination for large datasets
- 🧠 Smart field selection — automatically picks the most relevant fields per model
- 💬 LLM-optimized output with hierarchical text formatting
- 🌍 Multi-language support — get responses in your preferred language
- 🚀 YOLO Mode for quick access with any Odoo instance (no module required)
Installation
Prerequisites
- Python 3.10 or higher
- Access to an Odoo instance:
- Standard mode (production): Version 16.0+ with the Odoo MCP module installed
- YOLO mode (testing/demos): Any Odoo version with XML-RPC enabled (no module required)
Install UV First
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:
After installation, restart your terminal to ensure UV is in your PATH.
Installing via MCP Settings (Recommended)
Add this configuration to your MCP settings:
{
"mcpServers": {
"odoo": {
"command": "uvx",
"args": ["mcp-server-odoo"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here"
}
}
}
}
Alternative Installation Methods
Configuration
Environment Variables
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 | Language/locale for Odoo responses | es_ES, fr_FR, de_DE |
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:
- If database listing is restricted on your server, you must specify
ODOO_DB - API key authentication is recommended for better security
- The server also loads environment variables from a
.envfile 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_MCP_ALLOWED_HOSTS |
— | Comma-separated Host headers to accept for HTTP transport (DNS-rebinding protection). Set when running streamable-http behind a reverse proxy that forwards an external host, e.g. odoo.example.com,localhost. Unset leaves the default (no host validation). |
ODOO_MCP_SESSION_IDLE_TIMEOUT |
— | Seconds of inactivity before a streamable-http session is closed and its server-side state freed, e.g. 600. Unset means sessions never expire. |
Transport Options
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
2. streamable-http
Standard HTTP transport for REST API-style access and remote connectivity.
⚠️ Security: this transport has no built-in client authentication. Any client that can reach the port can use every tool and resource with the Odoo credentials the server holds — including writes in YOLO full-access mode. Keep the default
localhostbind unless the network is trusted, and front the server with an authenticating reverse proxy (e.g. nginx with basic auth or OAuth) for remote access. The server logs a warning when binding a non-loopback host.
# Run with HTTP transport (localhost only — safe default)
uvx mcp-server-odoo --transport streamable-http --port 8000
# Binding 0.0.0.0 exposes the server to the network — see the security note above
uvx mcp-server-odoo --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
The 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.
Setting up Odoo
-
Install the MCP module:
- Download the mcp_server module
- Install it in your Odoo instance
- Navigate to Settings > MCP Server
-
Enable models for MCP access:
- Go to Settings > MCP Server > Enabled Models
- Add models you want to access (e.g., res.partner, product.product)
- Configure permissions (read, write, create, delete) per model
-
Generate an API key:
- Go to Settings > Users & Companies > Users
- Select your user
- Under the “API Keys” tab, create a new key
- Copy the key for your MCP configuration
YOLO Mode (Development/Testing Only) ⚠️
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
-
Read-Only Mode (
ODOO_YOLO=read):- Allows all read operations (search, read, count)
- Blocks all write operations (create, update, delete)
- Safe for demos and testing
- Shows “READ-ONLY” indicators in responses
-
Full Access Mode (
ODOO_YOLO=true):- Allows ALL operations without restrictions
- Full CRUD access to all models
- EXTREMELY DANGEROUS - use only in isolated environments
- Shows “FULL ACCESS” warnings in responses
YOLO Mode Configuration
When to Use YOLO Mode
✅ Appropriate Uses:
- Local development with test data
- Quick demos with non-sensitive data
- Testing MCP clients before installing the MCP module
- Prototyping in isolated environments
❌ Never Use For:
- Production environments
- Instances with real customer data
- Shared development servers
- Any environment with sensitive information
YOLO Mode Security Notes
- Connects directly to Odoo’s standard XML-RPC endpoints
- Bypasses all MCP access controls and model restrictions
- No rate limiting is applied
- All operations are logged but not restricted
- Model listing shows 200+ models instead of just enabled ones
Usage Examples
Once configured, you can ask Claude:
Search & Retrieve:
- “Show me all customers from Spain”
- “Find products with stock below 10 units”
- “List today’s sales orders over $1000”
- “Search for unpaid invoices from last month”
- “Count how many active employees we have”
- “Show me the contact information for Microsoft”
Create & Manage:
- “Create a new customer contact for Acme Corporation”
- “Add a new product called ‘Premium Widget’ with price $99.99”
- “Create a calendar event for tomorrow at 2 PM”
- “Update the phone number for customer John Doe to +1-555-0123”
- “Change the status of order SO/2024/001 to confirmed”
- “Delete the test contact we created earlier”
Available Tools
search_records
Search 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:
- Omit
fieldsor set tonull: Returns smart selection of common fields - Specify field list: Returns only those specific fields
- An empty list
[]is treated likenull(smart defaults) - Use
["__all__"]: Returns all fields (use with caution)
get_record
Retrieve a specific record by ID.
{
"model": "res.partner",
"record_id": 42,
"fields": ["name", "email", "street", "city"]
}
Field Selection Options:
- Omit
fieldsor set tonull: Returns smart selection of common fields with metadata - Specify field list: Returns only those specific fields
- An empty list
[]is treated likenull(smart defaults) - Use
["__all__"]: Returns all fields without metadata
list_models
List all models enabled for MCP access.
{}
list_resource_templates
List available resource URI templates and their patterns.
{}
create_record
Create a new record in Odoo.
{
"model": "res.partner",
"values": {
"name": "New Customer",
"email": "[email protected]",
"is_company": true
}
}
update_record
Update an existing record.
{
"model": "res.partner",
"record_id": 42,
"values": {
"phone": "+1234567890",
"website": "https://example.com"
}
}
delete_record
Delete a record from Odoo.
{
"model": "res.partner",
"record_id": 42
}
post_message
Post 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": "Shipping confirmed for Monday",
"subtype": "comment",
"body_is_html": true
}
aggregate_records
Server-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_method
Generic 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"}}
}
Smart Field Selection
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:
- Essential fields like
id,name,display_name, andactiveare always included - Business-relevant fields (state, amount, email, phone, partner, etc.) are prioritized
- Technical fields (message threads, activity tracking, website metadata) are excluded
- Expensive fields (binary, HTML, large text, computed non-stored) are skipped
The 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__"].
Resources
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 products
Note: Resource URIs don’t support query parameters (like
?domain=...). For filtering, pagination, and field selection, use thesearch_recordstool instead.
How It Works
AI Assistant (Claude, Copilot, etc.)
↓ MCP Protocol (stdio or HTTP)
mcp-server-odoo
↓ XML-RPC
Odoo Instance
The 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.
Security
- Always use HTTPS in production environments
- Keep your API keys secure and rotate them regularly
- Configure model access carefully - only enable necessary models
- The MCP module respects Odoo’s built-in access rights and record rules
- Each API key is linked to a specific user with their permissions
Troubleshooting
Development
Testing
Running Tests
# 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 -v
License
This project is licensed under the Mozilla Public License 2.0 (MPL-2.0) - see the LICENSE file for details.
Contributing
Contributions are very welcome! Please see the CONTRIBUTING guide for details.
Support
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!
And do not forget to give the project a star if you like it! :star:
Установка
uvx mcp-server-odooКонфигурация
{
"mcpServers": {
"odoo": {
"command": "uvx",
"args": ["mcp-server-odoo"],
"env": {
"ODOO_URL": "https://your-odoo-instance.com",
"ODOO_API_KEY": "your-api-key-here"
}
}
}
}