关于 Odoo Mcp Gateway
Odoo Mcp Gateway 是面向 Odoo 17、18、19 的 MCP 网关,供需要通过 AI 客户端查询或修改 Odoo 数据的团队使用。它以 YAML 配置访问控制,并在网关限制之外保留 Odoo 自身的 ACL 检查,无需安装 Odoo 插件。
主要功能
- 01兼容 Odoo 17、18、19
- 02YAML 模型、字段与 RBAC 限制
- 03限流、审计日志和安全校验
- 04支持自定义模块模型发现
- 05记录查询、创建、更新与删除
- 06提供 MCP 工具、资源和提示词
适用场景
- 01通过 MCP 客户端查询 Odoo 记录
- 02按角色限制模型和字段访问
- 03在写入前预览默认值或执行 dry run
- 04为自定义模块配置访问规则
MCP 相关
它作为 MCP 服务连接 Odoo,并向客户端提供记录操作等工具、资源和提示词。支持 stdio 与 streamable-http 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
odoo-mcp-gateway
以安全为先、版本无关的 Odoo 17/18/19 MCP 网关。通过 YAML 配置即可支持标准模块和自定义模块,无需编写任何 Odoo 端代码。
30 秒快速开始
pip install odoo-mcp-gateway
添加到 Claude Desktop 配置(claude_desktop_config.json):
{
"mcpServers": {
"odoo": {
"command": "python",
"args": ["-m", "odoo_mcp_gateway"],
"env": {
"ODOO_URL": "http://localhost:8069",
"ODOO_DB": "your_database"
}
}
}
}
重启 Claude Desktop。在任意对话中:
login with method "password", username "admin", credential "your_password"
连接成功。让 Claude 查询、创建或更新 Odoo 记录——每次调用都会受到速率限制、记录审计日志,并在到达 Odoo 前经过两层安全检查。
无需 Odoo 插件,也无需编写 Python 代码。 只需使用 YAML 配置进行精细的访问控制(可选——默认安全设置开箱即用)。
v0.2.1 新增内容
- 暴力破解防护——按用户名(5 次/5 分钟)和来源(30 次/15 分钟)进行锁定
create_record、update_record、delete_record、execute_method支持dry_run模式——验证但不执行- 新增 2 个工具:
get_defaults(预览 Odoo 默认值)、get_onchange(预览字段副作用) read_group支持 时间分组:create_date:month、date:quarter等- 强化屏蔽列表:32 个始终屏蔽的模型(原为 17 个)、29 个始终屏蔽的方法(原为 18 个)、10 个始终屏蔽的写入字段、8 个始终只读的模型
- 通过
has_group('base.group_system')进行 服务端管理员身份验证(此前信任认证响应) - 凭据包装器可防止通过
repr()/追踪信息泄露密码 - JSON-RPC 重试仅在发生
OdooSessionExpiredError时触发(此前每次认证错误都会重试)
完整的 21 项安全修复请参见 CHANGELOG.md。
为什么要开发这个项目
现有的 Odoo MCP 服务普遍存在一些问题:模型列表硬编码,无法涵盖自定义模块;安全性考虑不足;必须安装自定义 Odoo 插件;只支持单一版本。此网关解决了所有这些问题:
- 双层安全——MCP 限制(YAML)+ Odoo 内置 ACL(ir.model.access + ir.rule)
- YAML 驱动的配置——模型限制、RBAC、字段级访问控制、速率限制、审计日志
- 支持自定义模块——通过
ir.model自动发现模型,添加 YAML 配置即可使用 - 版本无关——支持 Odoo 17、18、19,并提供特定版本的适配器
- 无需 Odoo 端代码——
pip install+ YAML 配置即可完成,无需自定义插件 - 完整的 MCP 基元——31 个工具 + 6 个资源 + 12 个提示词(大多数服务只实现工具)
- 插件架构——通过 entry_points 使用可通过 pip 安装的领域扩展包进行扩展
架构
MCP Client (Claude Desktop / Claude Code / HTTP)
| User calls login tool with Odoo credentials
v
MCP Server (FastMCP)
|
|-- security_gate() --> Rate limit + RBAC tool access + audit logging
|-- restrictions --> Model/method/field block lists (YAML + hardcoded)
|-- rbac --> Field-level filtering + write sanitization
|
|-- tools/ --> 31 MCP tools (auth + schema + CRUD + workflow + plugins)
|-- resources/ --> 6 MCP resources (odoo:// URIs)
|-- prompts/ --> 12 reusable prompt templates
|-- plugins/ --> Entry-point plugin system (HR, Sales, Project, Helpdesk)
|
| JSON-RPC / XML-RPC as authenticated user
v
Odoo 17/18/19 (security enforced per user via ir.model.access + ir.rule)
安全管道
每次工具和资源调用都会经过此管道:
Request --> Rate Limit --> Authentication Check --> RBAC Tool Access
--> Model Restriction --> Method Restriction --> Field Validation
--> Handler Execution --> RBAC Field Filtering --> Audit Log --> Response
无法通过 YAML 覆盖的硬编码安全防护措施:
- 32 个始终禁止访问的模型 — 系统内部信息、身份验证/TOTP、支付令牌、附件、mail.mail、base.automation 等
- 8 个始终只读的模型 — mail.message、mail.followers、mail.activity、discuss.channel、mail.notification、mail.compose.message、mail.alias、discuss.channel.member(所有人都可以读取,禁止写入)
- 10 个始终禁止写入的字段 — password、password_crypt、groups_id、totp_secret、signup_token/type/expiration、api_key、share、active
- 29 个始终禁止调用的方法 — sudo、with_user/env/context、_sql、_write、_create、name_create、load、import_data、export_data 等
- execute_method 中禁止调用的 28 个 ORM 方法(防止绕过字段级检查)
- 按用户名实施暴力破解锁定 — 失败 5 次后锁定 5 分钟(时长固定,无法延长)
- 按来源实施暴力破解锁定 — 15 分钟内失败 30 次,防止轮换用户名攻击
- 凭据包装类 — 使用防泄露的
__repr__/__str__存储密码,关闭时清除 - 服务端管理员验证 —
has_group('base.group_system')优先于身份验证响应中的is_admin
快速开始
pip install odoo-mcp-gateway
# Copy and edit config files
cp config/restrictions.yaml.example config/restrictions.yaml
cp config/model_access.yaml.example config/model_access.yaml
cp config/rbac.yaml.example config/rbac.yaml
# Set environment variables
export ODOO_URL=http://localhost:8069
export ODOO_DB=mydb
# Run (stdio mode for Claude Desktop / Claude Code)
python -m odoo_mcp_gateway
# Or HTTP mode for web clients
MCP_TRANSPORT=streamable-http python -m odoo_mcp_gateway
Claude Desktop 配置
添加到 claude_desktop_config.json:
{
"mcpServers": {
"odoo": {
"command": "python",
"args": ["-m", "odoo_mcp_gateway"],
"env": {
"ODOO_URL": "http://localhost:8069",
"ODOO_DB": "mydb"
}
}
}
}
Claude Code 配置
# Add as MCP server
claude mcp add odoo -- python -m odoo_mcp_gateway
环境变量
| 变量 | 默认值 | 描述 |
|---|---|---|
ODOO_URL | http://localhost:8069 | Odoo 服务 URL |
ODOO_DB | (必填) | Odoo 数据库名称 |
MCP_TRANSPORT | stdio | 传输模式(stdio 或 streamable-http) |
MCP_HOST | 127.0.0.1 | HTTP 主机(streamable-http 模式) |
MCP_PORT | 8080 | HTTP 端口(streamable-http 模式) |
MCP_LOG_LEVEL | INFO | 日志级别 |
CONFIG_DIR | . | YAML 配置文件目录 |
SESSION_TIMEOUT_SECONDS | 1800 | 会话不活动超时时间 |
MAX_CONCURRENT_SESSIONS | 100 | 最大并发会话数 |
RATE_LIMIT_GLOBAL | 60 | 每分钟请求数(全局) |
RATE_LIMIT_WRITE | 20 | 每分钟写入操作数 |
安全
双层安全模型
- MCP 网关限制(YAML 配置 + 硬编码安全防护措施)——在调用任何 Odoo 接口之前,阻止访问敏感模型、危险方法和特权字段
- Odoo 内置 ACL ——通过
ir.model.access和ir.rule对实际记录执行逐用户访问控制
模型限制等级
| 等级 | 效果 | 示例 |
|---|---|---|
always_blocked | 任何人都无法访问,包括管理员 | ir.config_parameter、res.users.apikeys |
admin_only | 仅限管理员用户 | ir.model、ir.model.fields |
admin_write_only | 所有人都可以读取,写入需要管理员权限 | res.company、res.currency |
硬编码安全防护措施
这些措施无法通过 YAML 配置覆盖:
被屏蔽的模型(32 个):ir.config_parameter、res.users、res.users.apikeys、res.users.log、ir.cron、ir.module.module、ir.model.access、ir.rule、ir.mail_server、ir.ui.view、ir.actions.server、ir.logging、ir.attachment、ir.exports、ir.exports.line、iap.account、auth.totp.wizard、auth.totp.device、payment.token、payment.provider、base.automation、digest.digest、res.config.settings、change.password.wizard、change.password.user、base.module.update、base.module.upgrade、base.module.uninstall、fetchmail.server、bus.bus、mail.mail、mail.template
只读模型(8 个):mail.message、mail.followers、mail.activity、discuss.channel、mail.notification、mail.compose.message、mail.alias、discuss.channel.member(所有人都可以读取,但禁止写入)
禁止写入的字段(10 个):password、password_crypt、groups_id、totp_secret、signup_token、signup_type、signup_expiration、api_key、share、active
被屏蔽的方法(29 个):sudo、with_user、with_company、with_context、with_env、with_prefetch、_auto_init、_sql、_register_hook、_write、_create、_read、_setup_base、_setup_fields、_setup_complete、init、_table_query、_read_group_raw、name_create、load、import_data、export_data、flush_recordset、invalidate_recordset、_search_panel_select_range、_search_panel_select_multi_range、_search_panel_domain_image、_search、_read_progress_bar
其他安全功能
- 暴力破解防护 — 按用户名锁定(失败 5 次 → 5 分钟),并按来源 IP/连接锁定(失败 30 次 → 15 分钟,防止轮换用户名攻击)。锁定时长固定,后续尝试无法延长锁定时间(可抵御 DoS)。
- 凭据封装 — 密码/会话 ID 存储在
Credential类中,该类提供防泄漏的__repr__/__str__、用于取用凭据的显式.reveal(),并在关闭时调用.clear() - 服务端管理员验证 — 身份验证后,通过
has_group('base.group_system')重新验证is_admin,防止身份验证响应被篡改 - 私有方法防护 — 以下划线开头的方法(
_compute_*、_inverse_*等)会被屏蔽,除非明确加入白名单,否则所有人(包括管理员)都无法使用 - 速率限制 — 每个会话使用令牌桶,并分别设置全局和写入预算
- 基于角色的访问控制(RBAC) — 按用户组控制工具级访问权限、按字段过滤响应,并通过
return_dropped=True透明报告被丢弃的内容 - 输入验证 — 验证模型名称、方法名称、字段名称、域筛选器、ORDER BY 子句、带时间运算符的 groupby,以及写入值(大小/深度/类型)
- IDOR 防护 — 插件工具将数据访问范围限定为已通过身份验证的用户
- 审计日志 — 为所有允许和拒绝的操作记录结构化 JSON 日志
- 错误信息脱敏 — 从错误消息中移除内部 URL、SQL 片段、文件路径和堆栈跟踪
- XXE 防护 — 使用
defusedxml解析 XML-RPC 响应 - 域验证 — 验证 Odoo 域筛选器中的运算符、字段名称、值类型、嵌套深度和列表大小
- 会话过期重试 — 仅在出现
OdooSessionExpiredError时重试 JSON-RPC,不重试一般身份验证错误(访问被拒时不会重复往返)
身份验证
Odoo 内置三种身份验证方法,无需自定义插件:
| 方法 | 协议 | 用途 |
|---|---|---|
api_key | XML-RPC | 服务器间通信、CI/CD 流水线 |
password | JSON-RPC | 交互式用户、Claude Desktop |
session | JSON-RPC | 重用现有浏览器会话(开发) |
# Example: login via the MCP tool
> login(method="password", username="admin", credential="admin", database="mydb")
核心 MCP 工具(13 个)
| 工具 | 描述 |
|---|---|
login | 使用 Odoo 进行身份验证(api_key / password / session) |
list_models | 列出可访问的模型及其元数据,并支持关键词筛选 |
get_model_fields | 获取模型的字段定义,并支持可选筛选 |
search_read | 使用域筛选、字段选择和排序来搜索记录 |
get_record | 根据 ID 获取单条记录 |
search_count | 统计符合条件的记录数 |
create_record | 创建新记录(支持仅用于验证的 dry_run) |
update_record | 更新现有记录(支持仅用于验证的 dry_run) |
delete_record | 根据 ID 删除单条记录(支持 dry_run) |
read_group | 读取聚合分组数据,支持时间运算符(date:month、date:quarter 等) |
get_defaults | 在调用 create_record 前预览 Odoo 默认值 |
get_onchange | 预览字段的副作用(并应用 RBAC 筛选) |
execute_method | 调用允许的模型方法(支持 dry_run) |
工作流工具(2 个)
| 工具 | 描述 |
|---|---|
get_create_requirements | 在创建记录前获取必填字段和验证规则 |
get_record_actions | 获取现有记录可用的工作流操作 |
MCP 资源(6 个)
| URI | 描述 |
|---|---|
odoo://models | 列出所有可访问的模型 |
odoo://models/{name} | 包含字段定义的模型详情 |
odoo://record/{model}/{id} | 单条记录数据,并应用 RBAC 字段筛选 |
odoo://schema/{model} | 包含类型信息和重要性排序的字段架构 |
odoo://categories | 模型分类及数量 |
odoo://workflow/{model} | 模型的工作流定义,包含阶段和操作 |
MCP 提示词(12 个)
| 提示词 | 描述 |
|---|---|
analyze_model | 全面分析模型结构 |
explore_data | 自然语言数据探索指南 |
create_workflow | 引导完成特定模型的工作流 |
compare_records | 并排比较记录 |
generate_report | 生成分析报告 |
discover_custom_modules | 查找并了解自定义模块 |
debug_access | 排查访问和权限问题 |
workflow_guide | 模型工作流执行分步指南 |
record_creation_guide | 在字段验证的引导下创建记录 |
bulk_operations | 安全执行批量操作指南 |
field_mapping | 映射不同 Odoo 版本(v17/v18/v19)之间的字段 |
data_migration | 不同模型或版本之间的数据迁移指南 |
内置领域插件
HR 插件
| 工具 | 描述 |
|---|---|
check_in | 记录考勤签到 |
check_out | 记录考勤签退 |
get_my_attendance | 查看考勤记录(支持按月份筛选) |
get_my_leaves | 查看请假申请(支持按状态筛选) |
request_leave | 提交请假申请 |
get_my_profile | 查看员工个人资料 |
Sales 插件
| 工具 | 描述 |
|---|---|
get_my_quotations | 列出报价单/订单(支持按状态筛选) |
get_order_details | 获取订单完整详情及明细项 |
confirm_order | 确认草稿/已发送的报价单 |
get_sales_summary | 汇总销售统计数据(支持按时间段筛选) |
Project 插件
| 工具 | 描述 |
|---|---|
get_my_tasks | 列出分配的任务(支持按状态/项目筛选) |
get_project_summary | 项目统计:按阶段统计任务数及逾期任务 |
update_task_stage | 将任务移至其他阶段 |
Helpdesk 插件
| 工具 | 描述 |
|---|---|
get_my_tickets | 列出分配的工单(支持按状态/优先级筛选) |
create_ticket | 创建新的服务台工单 |
update_ticket_stage | 将工单移至其他阶段 |
自定义模块支持
无需编写 Python 代码即可添加自定义 Odoo 模块。编辑 model_access.yaml:
custom_models:
full_crud:
- custom.delivery.route
- custom.warehouse.zone
read_only:
- custom.delivery.log
allowed_methods:
custom.delivery.route:
- action_dispatch
- action_complete
- action_cancel
之后,所有 CRUD 工具(search_read、create_record、update_record、delete_record)和 execute_method 都可以在自定义模型上运行,并强制执行完整的安全策略。
插件系统
通过可使用 pip 安装的插件扩展网关:
from odoo_mcp_gateway.plugins.base import OdooPlugin
class ManufacturingPlugin(OdooPlugin):
@property
def name(self) -> str:
return "manufacturing"
@property
def required_odoo_modules(self) -> list[str]:
return ["mrp"]
@property
def required_models(self) -> list[str]:
return ["mrp.production", "mrp.bom"]
def register(self, server, context):
@server.tool()
async def get_production_orders(...):
...
通过 pyproject.toml 入口点注册:
[project.entry-points."odoo_mcp_gateway.plugins"]
manufacturing = "my_package:ManufacturingPlugin"
配置文件
| 文件 | 用途 |
|---|---|
config/restrictions.yaml | 模型/方法/字段阻止列表(3 个层级) |
config/model_access.yaml | 按模型设置访问策略、允许的方法和敏感字段 |
config/rbac.yaml | 基于角色的工具访问权限,以及按组进行的字段过滤 |
config/gateway.yaml | 服务、连接和身份验证设置 |
所有文件都提供 .example 模板,并附有详尽的内联文档。复制并自定义:
cp config/restrictions.yaml.example config/restrictions.yaml
cp config/model_access.yaml.example config/model_access.yaml
cp config/rbac.yaml.example config/rbac.yaml
示例:限制模型
# restrictions.yaml
restrictions:
always_blocked:
- my.secret.model
admin_only:
- hr.salary.rule
admin_write_only:
- res.company
blocked_write_fields:
- password_crypt
- api_key
- totp_secret
示例:按组进行 RBAC
# rbac.yaml
rbac:
tool_group_requirements:
delete_record:
- base.group_system
execute_method:
- base.group_erp_manager
sensitive_fields:
hr.employee:
salary:
required_group: hr.group_hr_manager
Docker
cp .env.example .env # Edit with your Odoo settings
docker compose up
服务:
- MCP 网关 — 端口 8080(streamable-http 模式)
- Odoo 18 — 仅限内部访问(默认不向主机公开端口)
- PostgreSQL — 仅限内部访问
网关在精简版 Python 镜像中以非 root 用户运行。
CLI 工具
# Test Odoo connectivity
odoo-mcp-tools test-connection --url http://localhost:8069
# Validate all YAML config files
odoo-mcp-tools validate-config --config-dir config
# List configured model access policies
odoo-mcp-tools list-models --config-dir config
开发
git clone https://github.com/parth-unjiya/odoo-mcp-gateway.git
cd odoo-mcp-gateway
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=odoo_mcp_gateway --cov-report=term-missing
# Lint
ruff check src/ tests/
# Type check (strict mode)
mypy src/
源码布局
src/odoo_mcp_gateway/
├── __main__.py # Entry point (stdio + HTTP)
├── server.py # FastMCP server setup, tool registration
├── config.py # Pydantic settings (env + .env)
├── client/
│ ├── base.py # OdooClientBase ABC, AuthResult
│ ├── jsonrpc.py # JSON-RPC client (session auth)
│ ├── xmlrpc.py # XML-RPC client (API key auth, defusedxml)
│ └── exceptions.py # OdooError hierarchy (7 types)
├── core/
│ ├── auth/manager.py # 3 auth strategies
│ ├── connection/manager.py # Circuit breaker + retry
│ ├── version/ # Odoo 17/18/19 detection + adapters
│ ├── workflow/
│ │ ├── definitions.py # WorkflowDef, StateDef, TransitionDef dataclasses
│ │ ├── registry.py # Workflow registration and lookup
│ │ └── stock_workflows/ # Built-in workflows (sale, purchase, HR, etc.)
│ ├── security/
│ │ ├── restrictions.py # 3-tier model/method restrictions + hardcoded guardrails
│ │ ├── rbac.py # Tool access + field filtering
│ │ ├── middleware.py # Security pipeline + security_gate()
│ │ ├── rate_limit.py # Token bucket rate limiter
│ │ ├── audit.py # Structured audit logging
│ │ ├── sanitizer.py # Error message sanitization
│ │ └── config_loader.py # YAML config → Pydantic models
│ └── discovery/
│ ├── model_registry.py # ir.model auto-discovery
│ ├── field_inspector.py # fields_get with TTL cache
│ └── suggestions.py # Category search + related models
├── tools/
│ ├── auth.py # login tool
│ ├── schema.py # list_models, get_model_fields
│ ├── crud.py # search_read, create/update/delete, execute_method
│ └── workflow.py # get_create_requirements, get_record_actions
├── resources/handlers.py # 6 MCP resources (odoo:// URIs)
├── prompts/handlers.py # 12 MCP prompt templates
├── plugins/
│ ├── base.py, registry.py # Plugin ABC + entry_point discovery
│ └── core/ # Built-in plugins (HR, Sales, Project, Helpdesk)
├── cli/tools.py # CLI: test-connection, validate-config
└── utils/ # Domain builder, formatting, token budget
测试
1,476 项测试通过,代码覆盖率为 93%;mypy strict 检查干净,ruff 检查干净:
tests/unit/
├── client/ # JSON-RPC, XML-RPC, auth manager, XXE protection
├── security/ # Restrictions, RBAC, audit, rate limit, sanitizer, security_gate
├── discovery/ # Model registry, field inspector, suggestions
├── tools/ # All 13 MCP tools + input validation + dry_run
├── plugins/ # Plugin system + 4 domain plugins + IDOR protection
└── cli/ # CLI utility tools
# Run all tests
pytest tests/ -v
# Run specific area
pytest tests/unit/security/ -v
pytest tests/unit/tools/ -v
pytest tests/unit/plugins/ -v
# Coverage report
pytest tests/ --cov=odoo_mcp_gateway --cov-report=html
错误处理
所有 Odoo 错误分为 7 种类型:
| 错误 | 原因 |
|---|---|
OdooConnectionError | 无法连接到 Odoo 服务 |
OdooAuthError | 凭据无效 |
OdooAccessError | ir.model.access 拒绝访问 |
OdooValidationError | 字段验证失败 |
OdooUserError | 业务逻辑错误 |
OdooMissingError | 找不到记录 |
OdooVersionError | 不支持的 Odoo 版本 |
所有错误消息在传递给 MCP 客户端之前都会经过净化处理,自动移除内部 URL、SQL 片段、文件路径和堆栈跟踪。
已知限制
- XML-RPC 凭据处理:使用 API 密钥身份验证(XML-RPC)时,按照协议要求,每次 RPC 调用都会发送凭据。请在生产环境中使用 HTTPS。(注意:密码存储在
Credential包装器中,可防止通过repr()/回溯泄露。) - HTTP 模式的会话隔离:
streamable-http传输目前存在已知的会话隔离限制——_current_session_keyContextVar 在登录工具内部设置,但后续来自不同请求上下文的工具调用可能会回退到第一个可用会话。在 v0.3.0 引入按请求中间件之前,HTTP 模式仅限单租户部署(每个服务进程仅供一位用户使用)。stdio 模式在设计上采用单会话,不受影响。
贡献
- Fork 此仓库
- 创建功能分支(
git checkout -b feature/my-feature) - 编写测试并完成更改
- 确保所有检查均通过:
pytest && ruff check src/ tests/ && mypy src/ - 提交 pull request
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。