@marcfargas/odoo-mcp
v0.1.3
Published
MCP server for safe, policy-governed access to Odoo
Downloads
428
Maintainers
Readme
@marcfargas/odoo-mcp
Remote-first MCP server for Odoo with policy-based access control.
Features
- 7 tools:
odoo_discover,odoo_model_info,odoo_search,odoo_get,odoo_create,odoo_write,odoo_get_related - 3 resources:
odoo://models(model catalogue),odoo://modules(installed modules),odoo://schema/{model}(field metadata) - HTTP transport (
POST /mcp) — credentials per-request viaX-Odoo-*headers - Policy engine: JSON file with ordered glob rules, hot reload (SIGHUP)
- URL whitelist (SSRF protection) —
ODOO_MCP_ALLOWED_URLSmandatory - Credential pool with configurable cap (
ODOO_MCP_POOL_MAX_SIZE)
How auth works
The server has no Odoo credentials of its own. Each MCP client provides its own Odoo connection via four custom headers on every request. The server validates the URL against a whitelist and authenticates against Odoo; bad credentials return 401.
X-Odoo-Url: https://prod.mycompany.com
X-Odoo-Db: mydb
X-Odoo-User: admin
X-Odoo-Password: secretAuthenticated OdooClient instances are pooled (keyed by hashed credentials) and
evicted after 30 minutes of idle time.
Install
npm install @marcfargas/odoo-mcpClaude Desktop / Cursor (remote HTTP)
One server, multiple environments:
{
"mcpServers": {
"odoo-prod": {
"url": "https://odoo-mcp.mycompany.com/mcp",
"headers": {
"X-Odoo-Url": "https://prod.mycompany.com",
"X-Odoo-Db": "mydb",
"X-Odoo-User": "admin",
"X-Odoo-Password": "secret"
}
},
"odoo-staging": {
"url": "https://odoo-mcp.mycompany.com/mcp",
"headers": {
"X-Odoo-Url": "https://staging.mycompany.com",
"X-Odoo-Db": "staging_db",
"X-Odoo-User": "admin",
"X-Odoo-Password": "secret"
}
}
}
}Local dev with npx (stdio mode)
Stdio mode reads Odoo credentials from environment variables — no headers needed.
{
"mcpServers": {
"odoo-local": {
"command": "npx",
"args": ["-y", "@marcfargas/odoo-mcp", "--transport", "stdio"],
"env": {
"ODOO_URL": "https://myodoo.com",
"ODOO_DB": "mydb",
"ODOO_USER": "mcp_user",
"ODOO_PASSWORD": "secret"
}
}
}
}Reverse proxy (nginx reference)
location /mcp {
proxy_pass http://localhost:3100;
proxy_http_version 1.1;
proxy_buffering off;
proxy_read_timeout 600s;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}Reverse proxy (Caddy reference)
odoo-mcp.mycompany.com {
reverse_proxy /mcp localhost:3100 {
flush_interval -1
transport http {
read_timeout 10m
}
}
}Environment variables
HTTP transport (required)
| Variable | Required | Default | Description |
|---|---:|---|---|
| ODOO_MCP_ALLOWED_URLS | yes | — | Comma-separated Odoo base URLs the server will proxy to, e.g. https://prod.example.com,https://staging.example.com. Server refuses to start if unset. |
| ODOO_MCP_PORT | no | 3100 | HTTP listen port |
| ODOO_MCP_TRUST_PROXY | no | 0 | Use leftmost X-Forwarded-For when set to 1 |
stdio transport (required)
| Variable | Required | Description |
|---|---:|---|
| ODOO_URL | yes | Odoo base URL |
| ODOO_DB | yes | Odoo database |
| ODOO_USER | yes | Odoo username |
| ODOO_PASSWORD | yes | Odoo password |
Shared (both transports)
| Variable | Required | Default | Description |
|---|---:|---|---|
| ODOO_MCP_POLICY_FILE | no | — | JSON policy file path (hot-reloaded on SIGHUP / file change) |
| ODOO_MCP_POLICY | no | read-only default | Inline JSON fallback policy |
| ODOO_MCP_AUDIT_LOG | no | — | JSONL audit file path |
Policy example
[
{ "model": "res.users", "ops": ["read"] },
{ "model": "sale.*", "ops": ["read", "write"] },
{ "model": "*", "ops": ["read"] }
]Rules are evaluated in order; first match wins. Default (empty or missing policy): read-only on all models.
Security notes
- Whitelist is mandatory —
ODOO_MCP_ALLOWED_URLSprevents using the server as an open Odoo proxy. - TLS at the reverse proxy — the
X-Odoo-Passwordheader is cleartext in transit; always use HTTPS. - Dedicated Odoo user — each client authenticates as itself; apply Odoo ACLs to limit exposure.
- Policy as defence-in-depth — policy restricts operations on top of Odoo's own access rules.
MCP SDK version
Pinned to @modelcontextprotocol/[email protected].
License
LGPL-3.0 — see LICENSE.
