Skip to main content
Glama
altinkaya-opensource

mcp-server-odoo

🔌 mcp-server-odoo

A Model Context Protocol server that gives AI assistants full access to your Odoo ERP instance over XML-RPC.

No Odoo module installation required. Just point it at any Odoo 12+ instance.

🤖 AI Assistant (Claude Code, Claude Desktop, etc.)
       │ MCP (stdio)
       ▼
  📡 mcp-server-odoo
       │ XML-RPC
       ▼
  🏢 Odoo Instance

⚡ Quick Start

No cloning required — just run directly from GitHub with uv:

🖥️ With Claude Code

claude mcp add odoo \
    -e ODOO_URL=http://localhost:8069 \
    -e ODOO_DB=mydb \
    -e ODOO_USER=admin \
    -e ODOO_PASSWORD=admin \
    -- uvx --from git+https://github.com/altinkaya-opensource/odoo-mcp mcp-server-odoo

🖱️ With Claude Desktop

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "odoo": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/altinkaya-opensource/odoo-mcp",
        "mcp-server-odoo"
      ],
      "env": {
        "ODOO_URL": "http://localhost:8069",
        "ODOO_DB": "mydb",
        "ODOO_USER": "admin",
        "ODOO_PASSWORD": "admin"
      }
    }
  }
}

🔒 Readonly Mode

Block all write operations by adding READONLY_MODE=true:

claude mcp add odoo \
    -e ODOO_URL=http://localhost:8069 \
    -e ODOO_DB=mydb \
    -e ODOO_USER=admin \
    -e ODOO_PASSWORD=admin \
    -e READONLY_MODE=true \
    -- uvx --from git+https://github.com/altinkaya-opensource/odoo-mcp mcp-server-odoo

🛠️ Tools

📖 Read Operations

Tool

Description

search_records

🔍 Search any model with domain filters, field selection, pagination, and sorting

read_record

📄 Read a single record by ID with smart field selection

get_record_count

🔢 Count records matching a domain filter (lightweight, no data fetched)

list_models

📋 List all non-transient models available in the database

get_model_fields

🏗️ Inspect field definitions (type, required, help text, etc.) for any model

read_group

📊 Group records and compute aggregations (sum, avg, count) with date granularity

save_binary_field

💾 Save a binary/image field from a record directly to a local file

✏️ Write Operations

Tool

Description

create_record

➕ Create a new record in any model

update_record

📝 Update fields on an existing record

delete_record

🗑️ Delete a record by ID

copy_record

📋 Duplicate an existing record with optional field overrides

execute_method

⚙️ Call any business method (e.g. action_confirm, button_validate, action_post)

🚫 Write tools are disabled when READONLY_MODE=true.

✨ Features

🧠 Smart Field Selection

When you don't specify which fields to fetch, the server automatically picks the most useful ones. It scores fields based on type, importance patterns (state, amount, partner, etc.), and excludes noisy fields like message_ids, binary blobs, and computed non-stored fields. You always get id, name, display_name, and active.

Pass fields=["__all__"] to override and get everything.

🔄 Flexible Domain Parsing

Domains can be passed as JSON strings, Python repr strings, or native lists:

# All of these work:
[["is_company", "=", true]]
'[["is_company", "=", true]]'
"[('is_company', '=', True)]"

📅 ISO 8601 Dates

Odoo's "2025-06-07 21:55:52" datetime strings are automatically converted to "2025-06-07T21:55:52+00:00" for standard ISO 8601 output.

💡 Tool Usage Examples

🔍 Search for Turkish companies:

search_records("res.partner", [["is_company", "=", true], ["country_id.code", "=", "TR"]], limit=20)

🔢 Count open sale orders:

get_record_count("sale.order", [["state", "=", "sale"]])

📄 Read a specific product with all fields:

read_record("product.product", 42, fields=["__all__"])

✅ Confirm a sale order:

execute_method("sale.order", "action_confirm", [42])

📦 Validate a stock picking:

execute_method("stock.picking", "button_validate", [15])

💰 Post an invoice:

execute_method("account.move", "action_post", [100])

📋 Duplicate a sale order with a different partner:

copy_record("sale.order", 10, default={"partner_id": 99})

💾 Save a product image to disk:

save_binary_field("product.product", 42, "image_1920", "/tmp/product_image.png")

📊 Total sales by partner:

read_group("sale.order", "partner_id", domain=[["state", "=", "sale"]], fields=["amount_total:sum"])

📅 Monthly order counts:

read_group("sale.order", "date_order:month", fields=["id:count"])

📈 Average price by category:

read_group("product.template", "categ_id", fields=["list_price:avg"])

🏗️ Discover fields on a model:

get_model_fields("sale.order", attributes=["string", "type", "required"])

⚙️ Configuration

All configuration is done through environment variables:

Variable

Required

Default

Description

ODOO_URL

Odoo server URL (e.g. http://localhost:8069)

ODOO_DB

Database name

ODOO_USER

Username

ODOO_PASSWORD

Password or API key

READONLY_MODE

false

Set to true to disable all write operations

ODOO_MCP_LOG_LEVEL

INFO

Log level (DEBUG, INFO, WARNING, ERROR)

ODOO_MCP_LOG_FILE

stderr

Path to log file

ODOO_MCP_DEFAULT_LIMIT

10

Default record limit for search operations

Alternatively, create a .env file in the project root.

📋 Requirements

  • 🐍 Python >= 3.10

  • 📦 uv (recommended) or pip

  • 🏢 Access to an Odoo instance (12.0+) with XML-RPC enabled

📜 License

AGPL-3.0-or-later

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/altinkaya-opensource/odoo-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server