MCP Servers

模型上下文协议服务器、框架、SDK 和模板的综合目录。

O
Odoo MCP Server
作者 @torina

MCP server by torina

创建于 4/16/2026
更新于 about 6 hours ago
Repository documentation and setup instructions

Odoo 17 | 18 MCP Python 3.11+ MIT License

odoo-mcp-server

Let AI talk to your Odoo ERP. Natively.
The most capable Model Context Protocol server for Odoo — onchange simulation, JSON-RPC, aggregations, safety controls, and a domain DSL that LLMs actually understand.

Quick StartExamplesToolsDSLSafetyConfig


Why this exists

Odoo stores everything — sales, inventory, accounting, HR, projects. But getting data out of it programmatically means fighting XML-RPC, memorizing Polish-notation domains, and writing boilerplate for every query.

odoo-mcp-server gives any MCP-compatible AI (Claude, GPT, Copilot, etc.) direct, safe, structured access to your Odoo instance. Ask questions in plain English. Get real answers from real data.


Comparison with mcp-server-odoo

| Feature | mcp-server-odoo | odoo-mcp-server | |---|---|---| | Tools | 7 | 14 | | Protocol | XML-RPC only | JSON-RPC + XML-RPC fallback | | Onchange simulation | ✗ | Full simulation — computed defaults before create | | Aggregations | ✗ | read_group — sums, counts, grouped analytics | | Domain syntax | Odoo native only | JSON DSL + native (LLM-friendly) | | Dry-run / preview | ✗ | Yes — see what would happen before committing | | Safety controls | Binary YOLO mode | Env tags + write scopes + confirmation gates | | name_search | ✗ | Yes — fast partner/product lookup | | Connection pooling | ✗ | httpx.AsyncClient with keepalive | | Metadata caching | ✗ | LRU + TTL for field metadata |


Quick Start

pip install odoo-mcp-server
# or run directly
uvx odoo-mcp-server
Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "odoo": {
      "command": "uvx",
      "args": ["odoo-mcp-server", "--unsafe-bare"],
      "env": {
        "ODOO_URL": "http://localhost:8069",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mydb"
      }
    }
  }
}
Claude Code
claude mcp add odoo -- uvx odoo-mcp-server --unsafe-bare

Set env vars in your shell or .env file.

Cursor / VS Code

Add to your workspace .vscode/mcp.json or settings:

{
  "mcp": {
    "servers": {
      "odoo": {
        "command": "uvx",
        "args": ["odoo-mcp-server", "--unsafe-bare"],
        "env": {
          "ODOO_URL": "http://localhost:8069",
          "ODOO_API_KEY": "your-api-key-here",
          "ODOO_DB": "mydb"
        }
      }
    }
  }
}
Docker
docker run -e ODOO_URL=http://host.docker.internal:8069 \
           -e ODOO_API_KEY=your-key \
           -e ODOO_DB=mydb \
           -p 8000:8000 \
           odoo-mcp-server

Or use the included docker-compose.yml that spins up Odoo 17 + PostgreSQL:

git clone https://github.com/torina/odoo-mcp-server.git
cd odoo-mcp-server
docker compose up -d

What You Can Ask Your AI

"Show me all draft quotations over $5,000"

Uses odoo_search with JSON DSL: {"state": "draft", "amount_total": {"$gt": 5000}}

"Find the customer called Azure Interior"

Uses odoo_name_search on res.partner — one call, instant result.

"What's our revenue by sales team this quarter?"

Uses odoo_read_group — one aggregation call instead of fetching thousands of records.

"Create a quotation for 100 Widget Pros to Acme Corp"

Uses odoo_name_search to resolve IDs, then odoo_create with onchange simulation to auto-fill pricelist, payment terms, and fiscal position.

"Preview what would happen if I update partner 42's payment terms"

Uses odoo_write with dry_run=True — shows a field-by-field diff without touching your data.

"Describe the sale.order model"

Uses odoo_describe_model — returns every field with type, required/readonly flags, selection values, relations, and help text. Cached for 5 minutes.


Tools Reference

Discovery & Metadata

| Tool | What it does | |---|---| | odoo_list_models | List available models with optional text filter | | odoo_describe_model | Full field schema — types, required, selection values, relations, help text | | odoo_name_search | Fast lookup by display name (partners, products, etc.) |

Query

| Tool | What it does | |---|---| | odoo_search | Search with native domain OR simplified JSON DSL | | odoo_read | Read specific records by ID, optional relation resolution | | odoo_read_group | Aggregations (sum, count, avg) grouped by fields |

Mutation

| Tool | What it does | |---|---| | odoo_create | Create with automatic onchange simulation + dry-run preview | | odoo_write | Update with field-by-field dry-run diff | | odoo_unlink | Delete with bulk confirmation safety gate | | odoo_onchange | Simulate field changes to preview computed values |

Admin

| Tool | What it does | |---|---| | odoo_health | Connection health, server version, user info, environment |


Domain DSL

Odoo's native domain syntax uses Polish-notation prefix operators that LLMs frequently get wrong. The JSON DSL is intuitive:

# Native Odoo (error-prone for LLMs)
["|", ("state", "=", "draft"), "&", ("amount_total", ">", 1000), ("partner_id.name", "ilike", "Acme")]

# JSON DSL (LLM-friendly)
{
  "$or": [
    {"state": "draft"},
    {"$and": [
      {"amount_total": {"$gt": 1000}},
      {"partner_id.name": {"$ilike": "Acme"}}
    ]}
  ]
}

Operators

| DSL | Odoo | Example | |---|---|---| | $eq | = | {"state": {"$eq": "draft"}} | | $ne | != | {"state": {"$ne": "cancel"}} | | $gt / $gte | > / >= | {"amount": {"$gt": 1000}} | | $lt / $lte | < / <= | {"amount": {"$lt": 500}} | | $like / $ilike | like / ilike | {"name": {"$ilike": "acme"}} | | $in / $nin | in / not in | {"state": {"$in": ["draft", "sent"]}} | | $child_of / $parent_of | child_of / parent_of | {"parent_id": {"$child_of": 1}} |

Logical: $and, $or, $not

Both formats are always accepted. Every response includes the compiled_domain so the LLM learns native syntax over time.

Full reference: docs/domain-dsl.md


Safety Model

Environment Tags

| Tag | Behavior | |---|---| | dev (default) | All operations allowed, dry-run off | | staging | All operations allowed, dry-run off | | prod | Destructive ops require confirm=True, dry-run on by default |

Write Scopes

| Scope | What's allowed | |---|---| | read_only | Discovery + query tools only | | write_safe (default) | Above + create, write, unlink | | full | Everything including future admin operations |

Dry-Run

odoo_create and odoo_write accept a dry_run parameter:

  • Production: defaults to True — preview first, opt in to commit
  • Dev / Staging: defaults to False — execute immediately
  • Always overridable with explicit dry_run=True or dry_run=False

Architecture

Claude / GPT / Copilot
        |
        | MCP protocol (stdio or streamable-http)
        v
+---------------------+
| odoo-mcp-server  |
|                     |
|  FastMCP server     |
|  Safety gate        |
|  Domain DSL         |  ───> LRU + TTL cache
|  Onchange engine    |
|  JSON-RPC client    |  ───> httpx async pool
+---------------------+
        |
        | JSON-RPC (or XML-RPC fallback)
        v
   Odoo 17 / 18
  • FastMCP — tool registration, transport, lifespan management
  • JSON-RPC primary protocol with connection pooling via httpx.AsyncClient
  • XML-RPC fallback for legacy environments
  • LRU + TTL cache — model metadata cached to avoid redundant round-trips
  • Safety gate — scopes, env tags, dry-run, confirmation gates checked before every mutation

Configuration

All settings via environment variables (prefix ODOO_) or .env file:

| Variable | Required | Default | Description | |---|---|---|---| | ODOO_URL | Yes | — | Odoo instance URL | | ODOO_API_KEY | * | — | API key authentication | | ODOO_USERNAME | * | — | Username (if no API key) | | ODOO_PASSWORD | * | — | Password (if no API key) | | ODOO_DB | No | auto-detect | Database name | | ODOO_ENV_TAG | No | dev | dev / staging / prod | | ODOO_WRITE_SCOPE | No | write_safe | read_only / write_safe / full | | ODOO_PROTOCOL | No | jsonrpc | jsonrpc / xmlrpc | | ODOO_TRANSPORT | No | stdio | stdio / streamable-http | | ODOO_DEFAULT_LIMIT | No | 20 | Default search result limit | | ODOO_MAX_LIMIT | No | 200 | Maximum search result limit | | ODOO_CACHE_TTL | No | 300 | Metadata cache TTL in seconds | | ODOO_UNSAFE_BARE | No | false | Skip companion module check |

* Provide ODOO_API_KEY or both ODOO_USERNAME + ODOO_PASSWORD.


Development

git clone https://github.com/torina/odoo-mcp-server.git
cd odoo-mcp-server

# Install uv (if needed)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Create venv and install with dev dependencies
uv venv --python 3.11
uv pip install -e ".[dev]"

# Run tests
python -m pytest tests/ -v

# Lint & format
ruff check src/
ruff format --check src/

# Type check
mypy src/

CI runs on Python 3.11, 3.12, and 3.13.


Roadmap

  • Business actionscall_method with allowlist, workflow transitions
  • Companion Odoo module (mcp_bridge) — server-side allowlists, audit logging, scope enforcement
  • Messagingmessage_post, attachment upload/download
  • Reports — PDF/HTML rendering via MCP resources
  • MCP Prompts — guided workflows (quote-to-cash, payment reconciliation, AR aging)
  • Field redaction — configurable sensitive field masking
  • Rate limiting — per-session token bucket

Contributing

Contributions are welcome! Whether it's a bug fix, a new tool, or better docs:

  1. Fork the project
  2. Create a feature branch (git checkout -b feat/amazing-feature)
  3. Write tests for your changes
  4. Make sure CI passes (pytest, ruff, mypy)
  5. Open a merge request

Please open an issue first for larger changes so we can discuss the approach.


License

MIT — use it in your company, your side project, wherever.


Built with MCP, FastMCP, and httpx.
If this saves you time, consider giving it a star.

快速设置
此服务器的安装指南

安装包 (如果需要)

uvx odoo-mcp-server

Cursor 配置 (mcp.json)

{ "mcpServers": { "torina-odoo-mcp-server": { "command": "uvx", "args": [ "odoo-mcp-server" ] } } }