Two design choices carry this. aggregate_records pushes totals and groupings down to PostgreSQL rather than pulling rows into the model's context, which is the difference between a monthly sales question working and blowing your budget. And call_model_method — which can invoke any public method, including destructive ones — is simply not registered unless you set two separate flags. Odoo's own record rules and ACLs still apply throughout.
An Odoo ERP bridge: search, read, create, update and delete records in any model, with server-side aggregation and an opt-in escape hatch for workflow actions.
- search_records — search any model with an Odoo domain, chosen fields and a limit
- get_record, create_record, update_record and delete_record — single-record CRUD with field validation and permission checks
- list_models and list_resource_templates — which models are exposed, and the resource URI patterns available
- aggregate_records — group, sum and count in PostgreSQL instead of pulling raw rows; it defaults to a count per group
- post_message — write to a record's chatter, as an internal note or a comment that notifies followers, with optional HTML
- call_model_method — invoke any public model method for workflow actions like posting an invoice or confirming a sale order
- Smart field selection when you omit fields: essential and business-relevant fields are picked, technical and expensive ones skipped, defaulting to 15 fields
- Resource URIs under odoo:// for a record, a search, a count or a model's fields
Python 3.10 or higher and uv. Set ODOO_URL and ODOO_API_KEY, plus ODOO_DB when the database is not implied; runs via uvx as mcp-server-odoo on your local machine, not the Odoo server. For production use, install the Odoo MCP module on version 16.0 or later; YOLO mode works against any Odoo with XML-RPC enabled and no module, for testing and demos. call_model_method only registers when both ODOO_YOLO and ODOO_MCP_ENABLE_METHOD_CALLS are true.
One command plus a key — uvx mcp-server-odoo, then supply credentials
