mcpField
M
MCP Server for Odoo

MCP Server for Odoo

本地服务
github.com/ivnvxd商业与营销4073 周前更新

关于 MCP Server for Odoo

MCP Server for Odoo 是一个 MCP 服务,让 AI 助手通过标准化的资源和工具访问 Odoo ERP 系统,完成数据检索与维护。适用于需要用自然语言操作 Odoo 实例的用户。项目支持 YOLO 模式快速接入任意 Odoo 实例,也提供安装 Odoo MCP 模块后的标准模式。

主要功能

  1. 01通过工具搜索、创建、更新和删除 Odoo 记录
  2. 02支持记录计数与字段结构检查
  3. 03提供服务端聚合,无需拉取原始数据
  4. 04可调用模型的公开业务方法(需显式开启)
  5. 05支持附件与二进制资源的读取
  6. 06支持 API Key 或用户名密码认证

适用场景

  1. 01用自然语言查询客户、产品或发票数据
  2. 02在 AI 助手中批量统计或汇总 Odoo 记录
  3. 03在测试环境中快速验证 Odoo 数据操作

MCP 相关

该项目是一个 MCP 服务,向 MCP 客户端(如 Claude Desktop、Claude Code、Cursor)暴露 Odoo 的资源与工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"odoo": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"\\"
]
}
}
}
启动命令docker run -i --rm '\'

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
oci\

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

Odoo 的 MCP 服务

CI codecov Ruff Checked with ty Python 3.10+ License: MPL 2.0

一个 MCP 服务,可让 Claude 等 AI 助手与 Odoo ERP 系统交互。通过自然语言访问业务数据、搜索记录、创建新条目、更新现有数据并管理 Odoo 实例。

适用于任何 Odoo 实例! 使用 YOLO 模式 通过任何标准 Odoo 安装快速测试和演示。对于企业级安全性、访问控制和生产用途,请安装 Odoo MCP 模块。

功能

  • 🔍 搜索和检索 任意 Odoo 记录(客户、产品、发票等)
  • ✨ 创建新记录,并进行字段验证和权限检查
  • ✏️ 更新现有数据,并智能处理字段
  • 🗑️ 删除记录,遵循模型级权限
  • 🔢 统计记录数,匹配特定条件
  • 📋 检查模型字段,了解数据结构
  • 📊 服务端聚合 — 分组、求和和计数,无需拉取原始行
  • ⚡ 工作流操作 — 通过可选启用的扩展入口调用公开业务方法(过账发票、确认 SO 等)
  • 📎 二进制文件和附件资源 — 通过资源 URI 获取图像、文档和 ir.attachment 文件
  • 👤 个性化会话上下文 — 将已连接用户、时区和公司范围注入会话指令
  • 🔐 安全访问,支持 API 密钥或用户名/密码身份验证
  • 🎯 智能分页,适用于大型数据集
  • 🧠 智能字段选择 — 自动为每个模型挑选最相关的字段
  • 💬 针对大模型优化的输出,采用分层文本格式
  • 🌍 多语言支持 — 使用首选语言获取响应
  • 🚀 YOLO 模式,可快速访问任何 Odoo 实例(无需模块)

安装

先决条件
  • Python 3.10 或更高版本
  • 可访问 Odoo 实例:
    • 标准模式(生产环境):版本 16.0+,并已安装 Odoo MCP 模块
    • YOLO 模式(测试/演示):任何启用了 XML-RPC 的 Odoo 版本(无需模块)
首先安装 UV

MCP 服务运行在你的本地计算机(安装了 Claude Desktop 的计算机)上,而不是 Odoo 服务端。你需要在本地计算机上安装 UV:

macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

安装后,重启终端以确保 UV 已加入 PATH。

通过 MCP 设置安装(推荐)

将此配置添加到 MCP 设置中:

{
  "mcpServers": {
    "odoo": {
      "command": "uvx",
      "args": ["mcp-server-odoo"],
      "env": {
        "ODOO_URL": "https://your-odoo-instance.com",
        "ODOO_API_KEY": "your-api-key-here"
      }
    }
  }
}
Claude Desktop

添加到 ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "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"
      }
    }
  }
}
Claude Code

添加到项目根目录中的 .mcp.json:

{
  "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"
      }
    }
  }
}

或使用命令行:

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
Cursor

添加到 ~/.cursor/mcp.json:

{
  "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"
      }
    }
  }
}
VS Code(搭配 GitHub Copilot)

添加到工作区中的 .vscode/mcp.json:

{
  "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"
      }
    }
  }
}

注意: VS Code 使用 "servers" 作为根键,而不是 "mcpServers"。

Windsurf

添加到 ~/.codeium/windsurf/mcp_config.json:

{
  "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"
      }
    }
  }
}
Zed

添加到 ~/.config/zed/settings.json:

{
  "context_servers": {
    "odoo": {
      "command": {
        "path": "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"
        }
      }
    }
  }
}
其他安装方式
使用 Docker

使用 Docker 运行,无需安装 Python:

{
  "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"
      ]
    }
  }
}

注意: 连接到主机上运行的 Odoo 时,请使用 host.docker.internal 而不是 localhost。

对于 HTTP 传输:

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.0

⚠️ 安全: HTTP 传输没有内置身份验证机制——任何能够访问该端口的人,都可以通过服务的凭据访问 Odoo。仅在可信网络上发布该端口,或在其前方部署经过身份验证的反向代理。请参阅传输选项。

该映像也可在 GHCR 上获取:ghcr.io/ivnvxd/mcp-server-odoo

使用 pip
# Install globally
pip install mcp-server-odoo

# Or use pipx for isolated environment
pipx install mcp-server-odoo

然后在 MCP 配置中将 mcp-server-odoo 用作命令。

从源代码安装
git clone https://github.com/ivnvxd/mcp-server-odoo.git
cd mcp-server-odoo
pip install -e .

然后在 MCP 配置中使用该软件包的完整路径。

配置

环境变量

服务需要以下环境变量:

变量必需说明示例
ODOO_URL是Odoo 实例 URLhttps://mycompany.odoo.com
ODOO_API_KEY是*用于身份验证的 API 密钥0ef5b399e9ee9c11b053dfb6eeba8de473c29fcd
ODOO_USER是*用户名(如果不使用 API 密钥)admin
ODOO_PASSWORD是*密码(如果不使用 API 密钥)admin
ODOO_DB否数据库名称(未设置时自动检测)mycompany
ODOO_LOCALE否Odoo 响应使用的语言/区域设置es_ES、fr_FR、de_DE
ODOO_ALLOWED_COMPANIES否用于限定所有操作范围的公司 ID,以逗号分隔(适用于多公司设置)1、1,3
ODOO_YOLO否YOLO 模式——绕过 MCP 安全保护(⚠️ 仅限开发环境)off、read、true
ODOO_MCP_ENABLE_METHOD_CALLS否启用 call_model_method 工具——需要 ODOO_YOLO=true(⚠️ 危险,参见 call_model_method)false、true
ODOO_RPC_TRANSPORT否YOLO 模式下的 RPC 协议:auto(在 Odoo 19 及更高版本中使用 API 密钥时采用 JSON-2,否则使用 XML-RPC)、xmlrpc,或用于 Odoo JSON-2 API 的 json2(Odoo 19 及更高版本,仅限 API 密钥)auto、json2

*必须设置 ODOO_API_KEY,或同时设置 ODOO_USER 和 ODOO_PASSWORD。在 YOLO 模式下通过 XML-RPC 连接时,即使使用 API 密钥,也必须设置 ODOO_USER。通过 JSON-2 连接时,仅需 API 密钥即可,因为 Odoo 会从密钥中读取用户信息。

注意:

  • 如果服务器限制了数据库列表功能,必须指定 ODOO_DB
  • 建议使用 API 密钥身份验证,以提高安全性
  • 服务还会从工作目录中的 .env 文件加载环境变量
  • 在标准模式下,服务会将每个模型的 MCP 权限缓存 5 分钟。如果你在 Odoo 中移除某项权限,下次调用会立即被拒绝,因为 MCP 模块会检查每次调用。如果你授予某项权限,最多可能需要 5 分钟才能生效。重启服务即可立即应用权限变更。

多公司范围限定(ODOO_ALLOWED_COMPANIES): 在多公司数据库中,经过身份验证的用户的默认公司适用于 服务创建的每条记录,且记录可见性涵盖该用户获准访问的所有公司。设置 ODOO_ALLOWED_COMPANIES 会将 allowed_company_ids 注入每次 RPC 调用的上下文,因此记录规则、 env.company 和创建默认值都会限定在列出的公司范围内。一种实用 做法是为每家公司配置一个 MCP 服务条目,同时共用一个 Odoo 用户:

{
  "mcpServers": {
    "odoo-company-a": {
      "command": "uvx",
      "args": ["mcp-server-odoo"],
      "env": { "ODOO_URL": "...", "ODOO_API_KEY": "...", "ODOO_ALLOWED_COMPANIES": "1" }
    },
    "odoo-company-b": {
      "command": "uvx",
      "args": ["mcp-server-odoo"],
      "env": { "ODOO_URL": "...", "ODOO_API_KEY": "...", "ODOO_ALLOWED_COMPANIES": "3" }
    }
  }
}

启动时,服务会确保每个 ID 都属于该用户的公司,否则不会启动。如果用户无法读取自己的 res.users 记录(标准模式下未启用 res.users),则会跳过检查并发出警告;此时 Odoo 会在每次调用时拒绝访问外部公司的请求。第一个 ID 是当前公司:Odoo 会将其用于创建默认值,get_current_context 和会话说明也会显示该公司。调用可以将范围缩小到所列公司的其中一部分,但不能扩大范围。

请注意,这是上下文级别的范围限定,并非安全边界:这些凭据仍可访问该 Odoo 用户获准访问的所有公司。如需严格隔离,请直接在 Odoo 中限制该用户获准访问的公司。

高级配置
变量默认值描述
ODOO_MCP_DEFAULT_LIMIT25每次搜索默认返回的记录数
ODOO_MCP_MAX_LIMIT100每个请求允许的最大记录数
ODOO_MCP_MAX_SMART_FIELDS15智能字段选择返回的最大字段数
ODOO_MCP_LOG_LEVELINFO日志级别(DEBUG、INFO、WARNING、ERROR、CRITICAL)
ODOO_MCP_LOG_JSONfalse启用结构化 JSON 日志输出
ODOO_MCP_LOG_FILE—轮转日志文件的路径(10 MB,保留 5 个备份)
ODOO_MCP_LOG_FORMAT—自定义 Python 日志格式字符串(默认值:%(asctime)s - %(name)s - %(levelname)s - %(message)s)
ODOO_MCP_SLOW_OPERATION_THRESHOLD_MS1000操作被记录为慢操作的毫秒阈值
ODOO_MCP_TRANSPORTstdio传输类型(stdio、streamable-http)
ODOO_MCP_HOSTlocalhostHTTP 传输绑定的主机
ODOO_MCP_PORT8000HTTP 传输绑定的端口
ODOO_MCP_ALLOWED_HOSTS—HTTP 传输接受的以逗号分隔的 Host 标头(用于防范 DNS 重绑定)。当通过转发外部主机的反向代理运行 streamable-http 时设置,例如 odoo.example.com,localhost。IPv6 字面地址可以带方括号,也可以不带([::1]:8000、::1)。未设置时,仅在绑定到环回地址时自动启用保护——绑定到其他任何主机(例如 0.0.0.0)时,完全不会进行 Host/Origin 验证。
ODOO_MCP_SESSION_IDLE_TIMEOUT—streamable-http 会话关闭并释放其服务端状态前的闲置秒数,例如 600。未设置时,会话永不过期。
ODOO_MCP_MAX_BINARY_SIZE52428800单个二进制/附件 resources/read 返回的最大字节数。在获取负载前进行检查(对于记录字段,在 Odoo 19 及更早版本中探测 bin_size,在 Odoo 20 中检查底层附件大小或 field.size 计数;对于附件,检查已存储的 file_size),因此超大读取会被干净地拒绝并返回错误,而不会先载入内存再重新编码为 base64 以供网络传输。在 Odoo 20 中,非存储的二进制字段(例如 avatar_128),或用户无权读取其附件的存储字段,只能在获取后检查。
传输选项

服务器支持多种传输协议,以适用于不同用例:

1. stdio(默认)

标准输入/输出传输——供 Claude Desktop 等桌面 AI 应用使用。

# Default transport - no additional configuration needed
uvx mcp-server-odoo
2. streamable-http

用于 REST API 风格访问和远程连接的标准 HTTP 传输。

⚠️ 安全性:此传输没有内置客户端身份验证。任何能够访问该端口的客户端,都可以使用服务器持有的 Odoo 凭据调用所有工具和资源——在 YOLO 完全访问模式下也包括写入操作。除非网络可信,否则请保留默认的 localhost 绑定;如需远程访问,请在服务器前部署经过身份验证的反向代理(例如使用基本身份验证或 OAuth 的 nginx)。绑定到非环回主机时,服务器会记录警告。

# 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

HTTP 端点可通过以下地址访问:http://localhost:8000/mcp/

注意:SSE(服务器发送事件)传输已在 MCP 协议版本 2025-03-26 中弃用。HTTP 通信请改用 streamable-http 传输。

注意:HTTP 传输会拒绝超过 4 MiB 的请求正文,并返回 HTTP 413。最多可保持 10,000 个打开的会话;超过此限制时,新会话会收到 HTTP 503。若未设置 ODOO_MCP_SESSION_IDLE_TIMEOUT,会话将永不过期,因此请在长期运行的公共服务器上设置该值。

运行 streamable-http 传输以进行远程访问
{
  "mcpServers": {
    "odoo-remote": {
      "command": "uvx",
      "args": ["mcp-server-odoo", "--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"
      }
    }
  }
}
### 设置 Odoo
  1. 安装 MCP 模块:

    • 下载 mcp_server 模块
    • 在你的 Odoo 实例中安装该模块
    • 前往 Settings > MCP Server
  2. 启用供 MCP 访问的模型:

    • 前往 Settings > MCP Server > Enabled Models
    • 添加你想要访问的模型(例如,res.partner、product.product)
    • 为每个模型配置权限(读取、写入、创建、删除)
  3. 生成 API 密钥:

    • 前往 Settings > Users & Companies > Users
    • 选择你的用户
    • 在 "API Keys" 选项卡下创建新密钥
    • 在 Odoo 20 上,为密钥授予 RPC 范围(rpc)。Odoo 20 仅接受带有此范围的密钥用于其 RPC 路由。
    • 复制密钥以用于 MCP 配置
  4. 授予用户 MCP 访问权限:

    • 在用户的访问权限中,将该用户添加到 MCP User 组
    • 较新版本的模块会拒绝不属于此组的用户使用 API 密钥和密码登录。服务器会在启动时报告模块提供的原因。
YOLO 模式(仅限开发/测试)⚠️

YOLO 模式允许 MCP 服务直接连接任何标准 Odoo 实例,无需 MCP 模块。此模式会绕过所有 MCP 安全控制,仅用于开发、测试和演示。

🚨 警告:切勿在生产环境中使用 YOLO 模式!

YOLO 模式级别
  1. 只读模式(ODOO_YOLO=read):

    • 允许所有读取操作(搜索、读取、计数)
    • 阻止所有写入操作(创建、更新、删除)
    • 适用于演示和测试
    • 响应中会显示“只读”标识
  2. 完全访问模式(ODOO_YOLO=true):

    • 不受限制地允许所有操作
    • 对所有模型拥有完整的 CRUD 访问权限
    • 极其危险——仅在隔离环境中使用
    • 响应中会显示“完全访问”警告
YOLO 模式配置
只读 YOLO 模式(更适合演示)
{
  "mcpServers": {
    "odoo-demo": {
      "command": "uvx",
      "args": ["mcp-server-odoo"],
      "env": {
        "ODOO_URL": "http://localhost:8069",
        "ODOO_USER": "admin",
        "ODOO_PASSWORD": "admin",
        "ODOO_DB": "demo",
        "ODOO_YOLO": "read"
      }
    }
  }
}
完全访问 YOLO 模式(⚠️ 请极其谨慎地使用)
{
  "mcpServers": {
    "odoo-test": {
      "command": "uvx",
      "args": ["mcp-server-odoo"],
      "env": {
        "ODOO_URL": "http://localhost:8069",
        "ODOO_USER": "admin",
        "ODOO_PASSWORD": "admin",
        "ODOO_DB": "test",
        "ODOO_YOLO": "true"
      }
    }
  }
}
何时使用 YOLO 模式

✅ 适用场景:

  • 使用测试数据进行本地开发
  • 使用非敏感数据进行快速演示
  • 安装 MCP 模块前测试 MCP 客户端
  • 在隔离环境中制作原型

❌ 切勿用于:

  • 生产环境
  • 包含真实客户数据的实例
  • 共享开发服务
  • 任何包含敏感信息的环境
YOLO 模式安全说明
  • 直接连接 Odoo 的标准 XML-RPC 端点;在 Odoo 19 及更高版本中,使用 API 密钥时也可连接 JSON-2(/json/2)(参见 ODOO_RPC_TRANSPORT)
  • 绕过所有 MCP 访问控制和模型限制
  • 不会应用速率限制
  • 所有操作都会记录日志,但不会受到限制
  • 模型列表会显示 200 多个模型,而非仅显示已启用的模型
  • 在完全 YOLO 模式(true)下,创建、更新和删除工具可以操作所有模型,包括计划操作(ir.cron)和服务器操作(ir.actions.server)。call_model_method 会拒绝直接运行这些操作,但更改后的操作会在下次计划时间或触发时运行。这与管理员在 Odoo 界面中拥有的权限相同。

使用示例

配置完成后,你可以向 Claude 提问:

搜索与检索:

  • “显示所有来自西班牙的客户”
  • “查找库存低于 10 件的产品”
  • “列出今天金额超过 $1000 的销售订单”
  • “搜索上个月的未付款发票”
  • “统计我们有多少名在职员工”
  • “显示 Microsoft 的联系信息”

创建与管理:

  • “为 Acme Corporation 创建新的客户联系人”
  • “添加一个名为 ‘Premium Widget’、价格为 $99.99 的新产品”
  • “创建一个明天下午 2 点的日历活动”
  • “将客户 John Doe 的电话号码更新为 +1-555-0123”
  • “将订单 SO/2024/001 的状态改为已确认”
  • “删除我们之前创建的测试联系人”

可用工具

search_records

使用筛选条件搜索任意 Odoo 模型中的记录。

{
  "model": "res.partner",
  "domain": [["is_company", "=", true], ["country_id.code", "=", "ES"]],
  "fields": ["name", "email", "phone"],
  "limit": 10
}

字段选择选项:

  • 省略 fields 或将其设为 null:返回智能选择的常用字段
  • 指定字段列表:仅返回指定字段
  • 空列表 [] 会按 null 处理(使用智能默认值)
  • 使用 ["__all__"]:返回所有字段(请谨慎使用)——类似凭据的字段会被隐去,并列在响应的 note 中;如有需要,请按名称明确请求这些字段
get_record

按 ID 检索特定记录。

{
  "model": "res.partner",
  "record_id": 42,
  "fields": ["name", "email", "street", "city"]
}

字段选择选项:

  • 省略 fields 或将其设为 null:返回智能选择的常用字段及元数据
  • 指定字段列表:仅返回指定字段
  • 空列表 [] 会按 null 处理(使用智能默认值)
  • 使用 ["__all__"]:返回所有字段——类似凭据的字段会被隐去,并在响应元数据中注明;如有需要,请按名称明确请求这些字段

响应还会包含 related_summaries:对于最多包含 5 个 ID 的 one2many/many2many 集合,返回其显示名称,这样无需额外查询也能读取较小的关联集合。

get_fields

描述模型的字段,包括类型、标签、是否必填/只读、关联目标和选择选项。在读取或写入记录之前,可用它了解模型的架构。省略 attributes 时,使用精选的默认集合(type、string、required、readonly、relation、selection);显式列表会替换精选集合——如果仍需要默认项,请将它们包含在列表中(例如 ["type", "string", "help", "store"])。省略 field_names 时,返回简要视图:最相关的 60 个值字段,以及所有 one2many、many2many、文件和 HTML 字段;选择列表最多显示 20 个值。响应随后会包含 omitted(省略的字段数量)和 note。传入 ["__all__"] 可获取所有字段,也可以指定所需字段名称。这两种形式都不会截断选择列表。任一参数传入空列表 [] 时,均按省略该参数处理。

{
  "model": "res.partner",
  "field_names": ["name", "email", "parent_id"]
}
get_current_context

返回当前会话上下文:已连接的用户、其时区、当前活动公司以及其他允许访问的公司,还有 UTC 日期时间处理指南。当不确定请求以哪个用户或公司身份执行,或不确定如何解读日期时间时,此工具很有用。符合规范的客户端也会通过 initialize 响应说明获取此上下文。

{}
list_models

列出所有已启用 MCP 访问的模型。

{}
list_resource_templates

列出可用的资源 URI 模板及其模式。

{}
create_record

在 Odoo 中创建新记录。

{
  "model": "res.partner",
  "values": {
    "name": "New Customer",
    "email": "[email protected]",
    "is_company": true
  }
}
create_records

在一次调用中为同一模型创建多条记录。一次最多接受 100 条记录。这是一个事务:要么创建所有记录,要么一条也不创建。

{
  "model": "res.partner",
  "records": [
    {"name": "Customer A", "email": "[email protected]"},
    {"name": "Customer B", "email": "[email protected]"}
  ]
}
update_record

更新现有记录。

{
  "model": "res.partner",
  "record_id": 42,
  "values": {
    "phone": "+1234567890",
    "website": "https://example.com"
  }
}
update_records

在一次调用中更新同一模型的多条记录,最多可更新 100 条不同的记录。如果某个 ID 不存在,则不会写入任何内容。可以更新已归档的记录,例如通过设置 "active": true 将其取消归档。可使用以下两种形式之一。

在任何 Odoo 版本中,对每条记录使用相同的值:

{
  "model": "res.partner",
  "record_ids": [42, 43, 44],
  "values": {
    "category_id": [[4, 7]]
  }
}

在 Odoo 19 及更高版本中,在同一事务中为每条记录使用不同的值:

{
  "model": "res.partner",
  "updates": [
    {"id": 42, "values": {"phone": "+1 555 0100"}},
    {"id": 43, "values": {"phone": "+1 555 0101"}}
  ]
}

第二种形式使用 Odoo 的 web_save_multi。在标准模式下,Odoo MCP 模块必须允许使用该方法。

delete_record

从 Odoo 中删除记录。

{
  "model": "res.partner",
  "record_id": 42
}
read_attachment

读取文件:附件或图像等二进制字段。请准确传入 uri(来自工具结果的 odoo://attachment/{id} 或 odoo://{model}/record/{id}/{field} URI)或 attachment_id 中的一个。返回结果取决于文件类型:

  • 文本文件:文件文本,最多 100,000 个字符
  • PDF 和 Office 文件:Odoo 从文件中提取的文本(Odoo 仅在启用 attachment_indexation 模块时提取 PDF 文本)
  • 不超过 256 KB 的 PNG、JPEG、GIF 和 WebP 图像:图像本身
  • 其他文件:供已登录 Odoo 的用户使用的下载链接
{
  "uri": "odoo://res.partner/record/42/image_1920"
}

大多数聊天客户端不会自行读取 MCP 资源,因此模型需要通过此工具查看文件。

list_record_attachments

按最新到最旧的顺序列出记录所附的文件,并提供每个文件的名称、MIME 类型、大小、日期和 odoo://attachment/{id} URI。不会列出 image_1920 等二进制字段中的文件,因为 get_record 会将这些文件作为 URI 返回。

{
  "model": "res.partner",
  "record_id": 42
}
upload_attachment

将文件附加到记录。data 是文件的纯 base64 编码,解码后大小最多约为 2.9 MB。如果未提供 mimetype,Odoo 会检测 MIME 类型。返回结果包含新附件的 ID 及其 odoo://attachment/{id} URI。若要在聊天记录中显示文件,请将其 ID 作为 attachment_ids 传给 post_message。

{
  "model": "res.partner",
  "record_id": 42,
  "name": "contract.pdf",
  "data": "JVBERi0xLjQK...",
  "mimetype": "application/pdf"
}

在标准模式下,用户需要对记录所属模型具有写入权限,并对 ir.attachment 具有创建权限。

post_message

向记录的聊天记录(mail.thread)发布消息。subtype="note"(默认值)会创建内部日志;subtype="comment" 会通知关注者。设置 body_is_html=true 可使用 HTML 标记。可选参数 subject 用于设置消息主题;可选参数 partner_ids 和 attachment_ids 引用现有的合作伙伴和附件。

{
  "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_records

在服务端进行聚合。当问题涉及“总数/计数/分组”而不是“记录列表”时,请使用此工具——它会将计算下推至 PostgreSQL,而不是拉取原始行。在 Odoo 19 及更高版本中调用 formatted_read_group(新的专用方法);在较旧版本中则回退到 read_group 并规范化响应。所有受支持版本的调用方都会看到一致的响应结构。如果省略 aggregates,则默认为 ["__count"],确保每个分组都包含计数。如果分组数量超过请求的页面所能显示的数量,响应会设置 has_more: true,并提供包含后续偏移量的 next_hint。

{
  "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

通用 XML-RPC execute_kw 备用入口——调用公开的业务方法,执行 CRUD 未涵盖的工作流操作(过账发票、确认销售订单、验证拣货单等)。只有同时设置 ODOO_YOLO=true(完整 YOLO 模式)和 ODOO_MCP_ENABLE_METHOD_CALLS=true 时才可用;否则不会注册此工具。方法名仅接受公开的 ASCII Python 标识符——带点号、连字符、空白字符、非 ASCII 字符以及以下划线 _ 开头的名称均会被拒绝。

即使在完整 YOLO 模式下,为安全起见,以下调用仍会被阻止:

  • ir.actions.* / ir.cron 模型——其方法会以提升后的权限运行(服务器操作、计划任务)
  • 任何模型上的 run / method_direct_trigger——通过代理也存在相同的权限提升风险
  • ORM CRUD/数据访问原语(create、write、unlink、read、search*、copy、sudo 等)——请改用专用工具
  • web_* 方法——Web 客户端数据访问方法系列

列表结果最多返回 100 项。

在 JSON-2 中(Odoo 19 及更高版本在 YOLO 模式下使用 API 密钥时,或设置了 ODOO_RPC_TRANSPORT=json2 时),Odoo 仅接受命名参数。此时,arguments 只能将记录 ID 作为第一项。其他所有参数都必须按参数名传入 keyword_arguments,例如 {"partner_ids": [3]}。

警告

此工具仍可调用具有破坏性的工作流方法(例如 button_draft、action_cancel、toggle_active 和自定义方法)。仅在可信环境中启用,并确保你能接受其影响范围。Odoo 的记录规则和 ACL 仍适用于已认证用户。

{
  "model": "account.move",
  "method": "action_post",
  "arguments": [[42]]
}
{
  "model": "sale.order",
  "method": "action_confirm",
  "arguments": [[7]],
  "keyword_arguments": {"context": {"lang": "en_US"}}
}
智能字段选择

省略 fields 参数(或将其设为 null)时,服务端会使用评分算法为每个模型自动选择最相关的字段:

  • 必要字段(如 id、name、display_name 和 active)始终包含在内
  • 与业务相关的字段(state、amount、email、phone、partner 等)优先选择
  • 技术字段(消息线程、活动跟踪、网站元数据)会被排除
  • 开销较大的字段(二进制、HTML、大段文本)会被跳过;计算得出但未存储的字段优先级较低
  • 类似凭据的字段(名称以 *password、*_pass(如 smtp_pass)、passwd、*secret、*_token、*apikey 结尾,或名称中包含 *_key 组合(如 api_key/secret_key)的字段)不会纳入智能默认结果,也不会在 ["__all__"] 读取中返回,并附有说明;但按名称显式请求此类字段仍会返回

每个请求默认最多返回 15 个字段。响应包含元数据,显示返回了哪些字段以及可用字段总数。你可以通过 ODOO_MCP_MAX_SMART_FIELDS 调整此上限,或使用 fields: ["__all__"] 完全绕过上限。

如果 Odoo 拒绝当前连接用户访问某个字段,例如不具备会计权限的用户读取联系人的会计总额字段,那么智能默认读取或 ["__all__"] 读取会省略该字段。响应会在 skipped_fields 和说明中列出该字段。使用显式字段列表读取时,仍会因访问错误而失败。

单次调用上下文

search_records、get_record、aggregate_records、create_record、create_records、update_record 和 update_records 可接受可选的 context 对象。它支持四个键:

键效果
allowed_company_ids调用使用的公司。第一个公司是当前公司,因此 standard_price 等依赖公司的字段会读取和写入该公司的值。
lang标签和翻译值使用的语言。Odoo 未安装的语言会被拒绝。在 Odoo 16 和 17 上,服务端会自行检查;在标准模式下,需要为 MCP 启用 res.partner 或 res.lang,否则只接受 en_US。
tz调用使用的时区。
active_testfalse 会在搜索中包含已归档记录。

工具会拒绝任何其他键,并指出其名称。每家公司都必须属于该用户的公司之一;如果设置了 ODOO_ALLOWED_COMPANIES,还必须属于其中之一。该上下文适用于搜索、计数、读取、存在性检查以及写入后的回读。

{
  "model": "product.product",
  "record_id": 42,
  "values": {"standard_price": 12.5},
  "context": {"allowed_company_ids": [5]}
}

资源

该服务还通过资源 URI 提供对 Odoo 数据的直接访问:

URI 模式描述
odoo://{model}/record/{id}按 ID 获取特定记录
odoo://{model}/search使用默认设置搜索记录(前 ODOO_MCP_DEFAULT_LIMIT 条,默认 25 条)
odoo://{model}/count统计模型中的所有记录
odoo://{model}/fields获取模型的字段定义和元数据
odoo://{model}/record/{id}/{field}获取记录中的二进制/图像字段,并以正确的 mimeType 提供
odoo://attachment/{id}按 ID 获取 ir.attachment(URL 类型的附件会以文本形式返回其 URL)

示例:

  • odoo://res.partner/record/1 — 获取 ID 为 1 的合作伙伴
  • odoo://product.product/search — 列出前几种产品(ODOO_MCP_DEFAULT_LIMIT,默认 25 条)
  • odoo://res.partner/count — 统计所有合作伙伴
  • odoo://product.product/fields — 显示产品的所有字段
  • odoo://res.partner/record/1/image_128 — 获取合作伙伴 1 的头像图片
  • odoo://attachment/42 — 下载附件 42

get_record/search_records 结果中的非空二进制字段会以这些资源 URI 的形式返回,而不是内联的 base64 — 读取 URI 即可获取实际字节。字节内容通过 resources/read 获取,也可通过 read_attachment 工具获取;对于不读取资源的客户端,该工具会以内联形式返回文本文件(最大 1 MB)以及 PNG、JPEG、GIF 和 WebP 图片(最大 256 KB)。

记录和搜索资源读取会像工具的批量读取一样,隐藏类似凭据的字段 — 如需读取此类字段,请通过工具的 fields 参数按名称明确请求。

二进制和附件读取会完整提供内容,最大为 ODOO_MCP_MAX_BINARY_SIZE(默认 50 MB)。系统会在获取负载前检查大小,因此超大字段或附件会被拒绝并返回清晰的错误,而不会缓冲成相应的大型响应。在 Odoo 20 上,非存储型二进制字段,或用户无权读取其附件的存储型二进制字段,只能在获取内容后检查。

注意: 资源 URI 不支持查询参数(例如 ?domain=...)。如需筛选、分页和选择字段,请改用 search_records 工具。

工作原理

AI Assistant (Claude, Copilot, etc.)
        ↓ MCP Protocol (stdio or HTTP)
   mcp-server-odoo
        ↓ XML-RPC, or JSON-2 on Odoo 19+ in YOLO mode
   Odoo Instance

该服务会将 MCP 工具调用转换为 Odoo XML-RPC 请求;在 Odoo 19 及更高版本的 YOLO 模式下,使用 API 密钥时则转换为 JSON-2 请求。它负责处理身份验证、访问控制、字段选择、数据格式化和错误处理,以适合大模型的分层文本格式呈现 Odoo 数据。

安全

  • 在生产环境中始终使用 HTTPS
  • 妥善保管 API 密钥并定期轮换
  • 谨慎配置模型访问权限 — 只启用必要的模型
  • MCP 模块遵循 Odoo 内置的访问权限和记录规则
  • 每个 API 密钥都关联到一个具有相应权限的特定用户
标准模式如何应用模型允许列表

在标准模式下,服务端会在每次调用前检查 MCP 模块的模型允许列表。它还会检查调用通过另一个模型访问到的模型:

  • values 中嵌套的 x2many 命令。创建命令([0, 0, {...}])需要对相关模型拥有创建权限,更新命令([1, id, {...}])需要写入权限,删除命令([2, id])需要删除权限。
  • 对于 one2many 字段,链接([4, id])需要对相关模型拥有写入权限。移除([3, id]、[5] 或 [6, 0, ids])需要写入和删除权限,因为 Odoo 会在反向字段级联时删除相关记录。如果相关模型不允许删除,请改为更新相关记录的链接字段。
  • 附件、消息、邮件、关注者、活动、跟踪值和通知。读取时只会返回允许读取的模型中的行。创建、更改、移动或删除一行,需要对其所属模型拥有写入权限;即使是通过嵌套命令(例如 message_ids: [[1, id, {...}]])进行操作,也需要该权限。
  • 要创建活动,服务端会读取 ir.model,以查找 res_model_id 对应的模型,因此 MCP 必须能够读取 ir.model。
  • 通过关系进行读取。点分路径(例如 user_ids.groups_id.name)上的条件、any 或 not any 条件、x2many 字段上的名称条件,以及通过关系排序的 order,都需要对其经过的每个相关模型拥有读取权限。按 x2many 字段分组需要对其相关模型拥有读取权限。按 many2one 名称筛选的条件(country_id ilike Germany)仍然允许,但深入其点分路径的条件(country_id.code = DE)需要对相关模型拥有读取权限。

这些检查不涵盖可写的相关字段和 _inherits 父模型。例如,对用户的 email 执行写入,也会写入其合作伙伴记录。同样,公司的名称、电子邮件、电话和地址都是其合作伙伴记录的字段:如果 res.partner 允许写入,即使 res.company 为只读,也可以在那里修改这些字段。many2one 值视为其所属记录的一部分:读取和分组时会返回其名称,并且可以将其设为未启用模型中的记录。many2many 链接([4, id]、[3, id]、[6, 0, ids])也适用相同规则。Odoo 自身的访问权限和记录规则适用于每次调用。

故障排除

连接问题

如果遇到连接错误:

  1. 确认你的 Odoo URL 正确且可访问
  2. 检查是否已安装 MCP 模块:访问 https://your-odoo.com/mcp/health
  3. 确保防火墙允许连接到 Odoo
身份验证错误

如果身份验证失败:

  1. 确认你的 API 密钥在 Odoo 中处于启用状态
  2. 检查用户是否拥有适当的权限
  3. 尝试重新生成 API 密钥
  4. 如果使用用户名/密码身份验证,请确保未启用 2FA
  5. 在 Odoo 20 上,确保 API 密钥具有 rpc 作用域
  6. 在标准模式下,确保用户属于 MCP User 组
模型访问错误

如果无法访问某些模型:

  1. 在 Odoo 中前往 Settings > MCP Server > Enabled Models
  2. 确保模型位于列表中且具有适当的权限
  3. 检查用户在 Odoo 的安全设置中是否有权访问该模型
“spawn uvx ENOENT”错误

此错误表示未安装 UV,或 UV 不在你的 PATH 中:

解决方案 1:安装 UV(见上方的安装部分)

解决方案 2:macOS PATH 问题 macOS 上的 Claude Desktop 不会继承 shell 的 PATH。请尝试:

  1. 完全退出 Claude Desktop(Cmd+Q)
  2. 打开终端
  3. 从终端启动 Claude:
    open -a "Claude"
    

解决方案 3:使用完整路径 找到 UV 的位置并使用完整路径:

which uvx
# Example output: /Users/yourname/.local/bin/uvx

然后更新配置:

{
  "command": "/Users/yourname/.local/bin/uvx",
  "args": ["mcp-server-odoo"]
}
数据库配置问题

如果列出数据库时看到“Access Denied”:

  • 这是正常的——出于安全考虑,某些 Odoo 实例会限制数据库列表
  • 确保在配置中指定 ODOO_DB
  • 服务将使用你指定的数据库,而不进行验证

配置示例:

{
  "env": {
    "ODOO_URL": "https://your-odoo.com",
    "ODOO_API_KEY": "your-key",
    "ODOO_DB": "your-database-name"
  }
}

注意:如果服务器限制列出数据库,则必须设置 ODOO_DB。

“SSL: CERTIFICATE_VERIFY_FAILED”错误

当 Python 无法验证 SSL 证书时会发生此错误,在 macOS 或企业网络中尤为常见。

解决方案:在环境配置中添加 SSL 证书路径:

{
  "env": {
    "ODOO_URL": "https://your-odoo.com",
    "ODOO_API_KEY": "your-key",
    "SSL_CERT_FILE": "/etc/ssl/cert.pem"
  }
}

这会告知 Python 在哪里查找系统的 SSL 证书包,以用于 HTTPS 连接。路径 /etc/ssl/cert.pem 是大多数系统上的标准位置。

调试模式

启用调试日志以获取更多信息:

{
  "env": {
    "ODOO_URL": "https://your-odoo.com",
    "ODOO_API_KEY": "your-key",
    "ODOO_MCP_LOG_LEVEL": "DEBUG"
  }
}

开发

从源代码运行
# Clone the repository
git clone https://github.com/ivnvxd/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
使用 MCP Inspector 进行测试
# Using uvx
npx @modelcontextprotocol/inspector uvx mcp-server-odoo

# Using local installation
npx @modelcontextprotocol/inspector python -m mcp_server_odoo

测试

运行测试
# 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

许可证

本项目采用 Mozilla Public License 2.0(MPL-2.0)授权,详情请参阅 LICENSE 文件。

贡献

非常欢迎贡献!详情请参阅 CONTRIBUTING 指南。

支持

感谢你使用本项目!如果你觉得它有帮助,并希望支持我的工作,欢迎请我喝杯咖啡。非常感谢你的支持!

请我喝杯咖啡

如果你喜欢这个项目,别忘了给它点个星!:star:

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。