关于 MCP Server for Odoo
MCP Server for Odoo 是一个 MCP 服务,让 AI 助手通过标准化的资源和工具访问 Odoo ERP 系统,完成数据检索与维护。适用于需要用自然语言操作 Odoo 实例的用户。项目支持 YOLO 模式快速接入任意 Odoo 实例,也提供安装 Odoo MCP 模块后的标准模式。
主要功能
- 01通过工具搜索、创建、更新和删除 Odoo 记录
- 02支持记录计数与字段结构检查
- 03提供服务端聚合,无需拉取原始数据
- 04可调用模型的公开业务方法(需显式开启)
- 05支持附件与二进制资源的读取
- 06支持 API Key 或用户名密码认证
适用场景
- 01用自然语言查询客户、产品或发票数据
- 02在 AI 助手中批量统计或汇总 Odoo 记录
- 03在测试环境中快速验证 Odoo 数据操作
MCP 相关
该项目是一个 MCP 服务,向 MCP 客户端(如 Claude Desktop、Claude Code、Cursor)暴露 Odoo 的资源与工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Odoo 的 MCP 服务
一个 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 实例 URL | https://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_LIMIT | 25 | 每次搜索默认返回的记录数 |
ODOO_MCP_MAX_LIMIT | 100 | 每个请求允许的最大记录数 |
ODOO_MCP_MAX_SMART_FIELDS | 15 | 智能字段选择返回的最大字段数 |
ODOO_MCP_LOG_LEVEL | INFO | 日志级别(DEBUG、INFO、WARNING、ERROR、CRITICAL) |
ODOO_MCP_LOG_JSON | false | 启用结构化 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_MS | 1000 | 操作被记录为慢操作的毫秒阈值 |
ODOO_MCP_TRANSPORT | stdio | 传输类型(stdio、streamable-http) |
ODOO_MCP_HOST | localhost | HTTP 传输绑定的主机 |
ODOO_MCP_PORT | 8000 | HTTP 传输绑定的端口 |
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_SIZE | 52428800 | 单个二进制/附件 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"
}
}
}
}
-
安装 MCP 模块:
- 下载 mcp_server 模块
- 在你的 Odoo 实例中安装该模块
- 前往 Settings > MCP Server
-
启用供 MCP 访问的模型:
- 前往 Settings > MCP Server > Enabled Models
- 添加你想要访问的模型(例如,res.partner、product.product)
- 为每个模型配置权限(读取、写入、创建、删除)
-
生成 API 密钥:
- 前往 Settings > Users & Companies > Users
- 选择你的用户
- 在 "API Keys" 选项卡下创建新密钥
- 在 Odoo 20 上,为密钥授予 RPC 范围(
rpc)。Odoo 20 仅接受带有此范围的密钥用于其 RPC 路由。 - 复制密钥以用于 MCP 配置
-
授予用户 MCP 访问权限:
- 在用户的访问权限中,将该用户添加到 MCP User 组
- 较新版本的模块会拒绝不属于此组的用户使用 API 密钥和密码登录。服务器会在启动时报告模块提供的原因。
YOLO 模式(仅限开发/测试)⚠️
YOLO 模式允许 MCP 服务直接连接任何标准 Odoo 实例,无需 MCP 模块。此模式会绕过所有 MCP 安全控制,仅用于开发、测试和演示。
🚨 警告:切勿在生产环境中使用 YOLO 模式!
YOLO 模式级别
-
只读模式(
ODOO_YOLO=read):- 允许所有读取操作(搜索、读取、计数)
- 阻止所有写入操作(创建、更新、删除)
- 适用于演示和测试
- 响应中会显示“只读”标识
-
完全访问模式(
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_test | false 会在搜索中包含已归档记录。 |
工具会拒绝任何其他键,并指出其名称。每家公司都必须属于该用户的公司之一;如果设置了 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 自身的访问权限和记录规则适用于每次调用。
故障排除
连接问题
如果遇到连接错误:
- 确认你的 Odoo URL 正确且可访问
- 检查是否已安装 MCP 模块:访问
https://your-odoo.com/mcp/health - 确保防火墙允许连接到 Odoo
身份验证错误
如果身份验证失败:
- 确认你的 API 密钥在 Odoo 中处于启用状态
- 检查用户是否拥有适当的权限
- 尝试重新生成 API 密钥
- 如果使用用户名/密码身份验证,请确保未启用 2FA
- 在 Odoo 20 上,确保 API 密钥具有
rpc作用域 - 在标准模式下,确保用户属于 MCP User 组
模型访问错误
如果无法访问某些模型:
- 在 Odoo 中前往 Settings > MCP Server > Enabled Models
- 确保模型位于列表中且具有适当的权限
- 检查用户在 Odoo 的安全设置中是否有权访问该模型
“spawn uvx ENOENT”错误
此错误表示未安装 UV,或 UV 不在你的 PATH 中:
解决方案 1:安装 UV(见上方的安装部分)
解决方案 2:macOS PATH 问题 macOS 上的 Claude Desktop 不会继承 shell 的 PATH。请尝试:
- 完全退出 Claude Desktop(Cmd+Q)
- 打开终端
- 从终端启动 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:
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。
