Advanced MCP (Model Context Protocol) server for Odoo ERP — full CRUD, BI analytics, workflow navigation, security audit and more.
The Odoo MCP server has 11 tools with complete input schemas and descriptions, but inconsistent quality across dimensions. Naming is clear and action-oriented (search_*, read_*, create_*, update_*, delete_*, count_*, get_*). Descriptions are present for all tools and most parameters, though some are brief. Output schemas are not documented in the visible source code, responses are wrapped in {success, data/error} but the structure of 'data' for each tool is inferred from Odoo RPC docs, not declared. Error handling returns structured {success, error} tuples but lacks recovery guidance (no actionable next steps for LLMs). Parameter descriptions are generally adequate but some lack format/constraint details. The execute_method tool is dangerously generic, it accepts any Odoo method on any model with arbitrary args/kwargs, creating a security and composability risk. Tools are well-separated (no 'and' in names) and follow verb_noun convention. Pagination is handled via limit/offset with clear defaults. No tool accepts passwords or secrets as parameters (good). However, credentials are required as environment variables, which is correct for server-side injection, but the tool error messages reference 'Check credentials' without providing remediation steps.
Count matching records without loading them (very fast).
Create a new record.
Delete records. USE WITH CAUTION.
Call ANY public method on ANY Odoo model. Infinitely flexible.
Discover the schema of an Odoo model.
Get the FINAL merged XML of an Odoo view (base + all inheritances).
execute_method tool is overly generic and unsafe. It accepts arbitrary methods on any model with unconstrained args/kwargs, creating a massive attack surface and making it impossible for LLMs to reason about what will happen. This violates the single-responsibility principle, it should be split into specific, documented method wrappers or removed entirely in favor of model-specific tools.
Output schemas are not documented in source code. Tools return {success, data/error} but the structure of 'data' varies by tool (list of IDs, list of records, boolean, integer count, dict of field metadata). LLMs cannot plan downstream calls without knowing what fields are present in each response. E.g., does search_records return integers or dicts? Does create_record return just the ID or {id, name, ...}?
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 68 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 0 | - | v1 |
Discover workflow states and transitions of an Odoo model. Returns the selection values of the 'state' field, stage_id records, and the action buttons that trigger transitions.
Read fields from records by their IDs.
Search and read in one call (optimised).
Search for record IDs matching a domain filter.
Update existing records.
Error messages lack recovery guidance. When credentials are missing or auth fails, the tool returns 'Missing credentials. Set ODOO_URL, ODOO_DB, ODOO_USERNAME, ODOO_PASSWORD.' but does not tell the LLM what it should do next (retry with verified creds, ask user for creds, abort the request). LLMs need actionable next steps, not just a problem statement.
delete_record lacks a confirmation/dry-run pattern. Deleting records is irreversible, but the tool executes immediately without a chance for the LLM to review affected records or confirm intent. A confirmation_required response would prevent accidental data loss.
Tool annotations (readOnlyHint, destructiveHint, idempotentHint) are not declared. The MCP protocol supports tool annotations to mark delete_record as destructive and search_records as read-only, but the server does not use them. This prevents clients from displaying warnings or gating sensitive tools.
Parameter descriptions lack format/constraint details. E.g., 'domain' is described as 'Domain list (e.g. [['is_company','=',True]])' but does not specify that it must be a valid Odoo domain filter (what operators are allowed? ['is_company','=',True] or ['is_company','in',[True,False]]?). The 'limit' parameter defaults to 10 but does not specify a valid range (1 - 1000? 1 - 100?). LLMs cannot self-validate without explicit constraints.
No rate limiting or timeout guards. An LLM in a retry loop or mis-configured agent could generate thousands of Odoo API calls per minute without throttling, potentially overwhelming the instance or triggering abuse blocks. The code does not set explicit timeouts on _opener.open() calls.