Architecture¶
For the curious and for contributors. The authoritative source is the repository's
docs/architecture.md.
Claude (MCP client)
│ stdio (JSON-RPC MCP)
▼
odoo_mcp.server ──lists/dispatches──▶ registry (ToolRegistry)
│ │
│ ▼
│ tools/ (crud, meta, export, i18n, report)
│ │ resolve_model / resolve_fields
│ ▼
│ compat/ (detect → deltas → resolve)
▼ │
tenancy.ConnectionManager ──▶ session.OdooSession ──▶ transport/
(per-tenant) (auth, facts, cache) fallback → jsonrpc | xmlrpc
│
▼
Odoo instance
Layers¶
- transport/ —
XmlRpcTransport,JsonRpcTransportandFallbackTransport(auto: JSON-RPC first, transparent fallback to XML-RPC on API key rejection or transport error; it pins XML-RPC after the first fallback and warns once). - session.py —
OdooSessionstores credentials, authenticates lazily (uid), caches the version/edition/deployment facts and wraps the schema reads in theSchemaCacheTTL cache.ConnectionManager(tenancy.py) maps the tenant fingerprint (url|db|login, never the secret) to a session. - compat/ —
detect.probe()buildsEnvFacts;deltas.pyis the declarative delta map;resolve.pyconverts a requested model/field/capability into whatever exists in the target. Each tool callsresolve_*before the ORM. - tools/ — thin handlers registered on the shared
registry. The write tools carryread_only=Falsefor future policy gates; the public core does not apply approval gates (that belongs to a private governance layer). - observability.py — optional Prometheus metrics and OTLP traces, both off by default and no-ops if the extras are not installed.
- server.py / main.py — MCP stdio wiring and the
odoo-mcpentry point. The handlers run on a worker thread (anyio.to_thread) so that a blocking RPC never stalls the event loop. The logs go to stderr; stdout is exclusive to the MCP channel.
Transports and modes¶
- stdio (default): a single tenant, credentials from the environment. It is the mode
used by the plugin's
mcpServersentry. - HTTP (docker, optional/roadmap): multi-tenant via
X-Odoo-Url/Db/Loginheaders +Bearersecret, resolved bytenancy.from_headers.
Design principles¶
- A single tool surface across versions — the caller uses modern names.
- Fail with remediation —
CompatErrorexplains what to change; the unavailable fields degrade to warnings, not to hard failures. - Lightweight base install — the optional deps (cache/metrics/otel) never block startup.
- No secrets in logs nor on disk.